├── .document ├── .github ├── dependabot.yml └── workflows │ ├── push_gem.yml │ ├── test.yml │ └── update.yml ├── .gitignore ├── .rdoc_options ├── BSDL ├── COPYING ├── Gemfile ├── README.md ├── Rakefile ├── bin ├── console └── setup ├── date.gemspec ├── doc ├── date │ └── calendars.rdoc └── time.rb ├── ext └── date │ ├── date_core.c │ ├── date_parse.c │ ├── date_strftime.c │ ├── date_strptime.c │ ├── date_tmx.h │ ├── extconf.rb │ ├── prereq.mk │ ├── update-abbr │ ├── zonetab.h │ └── zonetab.list ├── lib └── date.rb ├── rakelib ├── epoch.rake └── version.rake ├── test ├── date │ ├── test_date.rb │ ├── test_date_arith.rb │ ├── test_date_attr.rb │ ├── test_date_compat.rb │ ├── test_date_conv.rb │ ├── test_date_marshal.rb │ ├── test_date_new.rb │ ├── test_date_parse.rb │ ├── test_date_ractor.rb │ ├── test_date_strftime.rb │ ├── test_date_strptime.rb │ └── test_switch_hitter.rb └── lib │ └── helper.rb └── tool └── gperf.sed /.document: -------------------------------------------------------------------------------- 1 | BSDL 2 | COPYING 3 | README.md 4 | ext/date/*.[ch] 5 | lib/date.rb 6 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: 'github-actions' 4 | directory: '/' 5 | schedule: 6 | interval: 'weekly' 7 | -------------------------------------------------------------------------------- /.github/workflows/push_gem.yml: -------------------------------------------------------------------------------- 1 | name: Publish gem to rubygems.org 2 | 3 | on: 4 | push: 5 | tags: 6 | - 'v*' 7 | 8 | permissions: 9 | contents: read 10 | 11 | jobs: 12 | push: 13 | if: github.repository == 'ruby/date' 14 | runs-on: ubuntu-latest 15 | 16 | environment: 17 | name: rubygems.org 18 | url: https://rubygems.org/gems/date 19 | 20 | permissions: 21 | contents: write 22 | id-token: write 23 | 24 | strategy: 25 | matrix: 26 | ruby: [3.3, jruby] 27 | 28 | steps: 29 | - name: Harden Runner 30 | uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0 31 | with: 32 | egress-policy: audit 33 | 34 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 35 | 36 | - name: Set up Ruby 37 | uses: ruby/setup-ruby@eaecf785f6a34567a6d97f686bbb7bccc1ac1e5c # v1.237.0 38 | with: 39 | bundler-cache: true 40 | ruby-version: ${{ matrix.ruby }} 41 | 42 | - name: Publish to RubyGems 43 | uses: rubygems/release-gem@a25424ba2ba8b387abc8ef40807c2c85b96cbe32 # v1.1.1 44 | 45 | - name: Create GitHub release 46 | run: | 47 | tag_name="$(git describe --tags --abbrev=0)" 48 | gh release create "${tag_name}" --verify-tag --generate-notes 49 | env: 50 | GITHUB_TOKEN: ${{ secrets.MATZBOT_GITHUB_WORKFLOW_TOKEN }} 51 | if: ${{ matrix.ruby != 'jruby' }} 52 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | 3 | on: 4 | push: 5 | pull_request: 6 | schedule: 7 | - cron: '10 3 * * *' 8 | 9 | jobs: 10 | ruby-versions: 11 | uses: ruby/actions/.github/workflows/ruby_versions.yml@master 12 | with: 13 | engine: cruby-truffleruby 14 | min_version: 2.6 15 | 16 | build: 17 | if: ${{ startsWith(github.repository, 'ruby/') || github.event_name != 'schedule' }} 18 | name: build (${{ matrix.ruby }} / ${{ matrix.os }}) 19 | needs: ruby-versions 20 | strategy: 21 | matrix: 22 | ruby: ${{ fromJson(needs.ruby-versions.outputs.versions) }} 23 | os: [ ubuntu-latest, macos-latest, windows-latest ] 24 | exclude: 25 | - ruby: head 26 | os: windows-latest 27 | - ruby: truffleruby # need truffleruby 24.2+ 28 | os: ubuntu-latest 29 | - ruby: truffleruby # need truffleruby 24.2+ 30 | os: macos-latest 31 | - ruby: truffleruby 32 | os: windows-latest 33 | - ruby: truffleruby-head 34 | os: windows-latest 35 | include: 36 | - ruby: mingw 37 | os: windows-latest 38 | - ruby: mswin 39 | os: windows-2022 40 | runs-on: ${{ matrix.os }} 41 | steps: 42 | - uses: actions/checkout@v4 43 | - name: Set up Ruby 44 | uses: ruby/setup-ruby@v1 45 | with: 46 | ruby-version: ${{ matrix.ruby }} 47 | bundler-cache: true # 'bundle install' and cache 48 | - run: choco install gperf 49 | if: ${{ matrix.ruby == 'mswin' }} 50 | - name: Run test 51 | run: bundle exec rake compile test 52 | -------------------------------------------------------------------------------- /.github/workflows/update.yml: -------------------------------------------------------------------------------- 1 | name: update 2 | 3 | on: 4 | schedule: 5 | - cron: '0 10 * * 3' 6 | 7 | jobs: 8 | update: 9 | if: ${{ startsWith(github.repository, 'ruby/') }} 10 | name: update zonetab 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v4 14 | - name: Set up Ruby 15 | run: sudo apt-get --no-install-recommends -q -y install ruby-dev gperf 16 | - name: Install dependencies 17 | run: sudo gem install --no-document nokogiri 18 | - name: Update zonetab 19 | working-directory: ext/date 20 | run: | 21 | make -f prereq.mk update-zonetab 22 | make -f prereq.mk zonetab.h 23 | env: 24 | top_srcdir: ../.. 25 | srcdir: . 26 | RUBY: /usr/bin/ruby 27 | - name: Check diffs 28 | id: diff 29 | run: | 30 | git diff --no-ext-diff --ignore-submodules --exit-code || 31 | echo "diff=true" >> $GITHUB_OUTPUT 32 | - name: Commit 33 | run: | 34 | git commit --message="Update zonetab.h at $(date +%F)" ext/date 35 | git pull --ff-only origin ${GITHUB_REF#refs/heads/} 36 | git push origin ${GITHUB_REF#refs/heads/} 37 | env: 38 | EMAIL: nobu@ruby-lang.org 39 | GIT_AUTHOR_NAME: Nobuyoshi Nakada 40 | GIT_COMMITTER_NAME: Nobuyoshi Nakada 41 | if: ${{ steps.diff.outputs.diff }} 42 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.bundle/ 2 | /Gemfile.lock 3 | /coverage/ 4 | /pkg/ 5 | *.bundle 6 | *.dll 7 | *.lib 8 | *.so 9 | *.[ao] 10 | /tmp 11 | -------------------------------------------------------------------------------- /.rdoc_options: -------------------------------------------------------------------------------- 1 | --- 2 | main_page: README.md 3 | page_dir: doc 4 | -------------------------------------------------------------------------------- /BSDL: -------------------------------------------------------------------------------- 1 | Copyright (C) 1993-2013 Yukihiro Matsumoto. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 1. Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 12 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 13 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 14 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 15 | ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 16 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 17 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 18 | OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 19 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 20 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 21 | OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 22 | SUCH DAMAGE. 23 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | Ruby is copyrighted free software by Yukihiro Matsumoto . 2 | You can redistribute it and/or modify it under either the terms of the 3 | 2-clause BSDL (see the file BSDL), or the conditions below: 4 | 5 | 1. You may make and give away verbatim copies of the source form of the 6 | software without restriction, provided that you duplicate all of the 7 | original copyright notices and associated disclaimers. 8 | 9 | 2. You may modify your copy of the software in any way, provided that 10 | you do at least ONE of the following: 11 | 12 | a. place your modifications in the Public Domain or otherwise 13 | make them Freely Available, such as by posting said 14 | modifications to Usenet or an equivalent medium, or by allowing 15 | the author to include your modifications in the software. 16 | 17 | b. use the modified software only within your corporation or 18 | organization. 19 | 20 | c. give non-standard binaries non-standard names, with 21 | instructions on where to get the original software distribution. 22 | 23 | d. make other distribution arrangements with the author. 24 | 25 | 3. You may distribute the software in object code or binary form, 26 | provided that you do at least ONE of the following: 27 | 28 | a. distribute the binaries and library files of the software, 29 | together with instructions (in the manual page or equivalent) 30 | on where to get the original distribution. 31 | 32 | b. accompany the distribution with the machine-readable source of 33 | the software. 34 | 35 | c. give non-standard binaries non-standard names, with 36 | instructions on where to get the original software distribution. 37 | 38 | d. make other distribution arrangements with the author. 39 | 40 | 4. You may modify and include the part of the software into any other 41 | software (possibly commercial). But some files in the distribution 42 | are not written by the author, so that they are not under these terms. 43 | 44 | For the list of those files and their copying conditions, see the 45 | file LEGAL. 46 | 47 | 5. The scripts and library files supplied as input to or produced as 48 | output from the software do not automatically fall under the 49 | copyright of the software, but belong to whomever generated them, 50 | and may be sold commercially, and may be aggregated with this 51 | software. 52 | 53 | 6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR 54 | IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 55 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 56 | PURPOSE. 57 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gemspec 4 | 5 | group :development do 6 | gem "bundler" 7 | gem "rake" 8 | gem "rake-compiler" 9 | gem "test-unit" 10 | gem "test-unit-ruby-core", ">= 1.0.7" 11 | end 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # `Date` 2 | 3 | The official date library for Ruby. 4 | 5 | ## Installation 6 | 7 | Add this line to your application's Gemfile: 8 | 9 | ```ruby 10 | gem 'date' 11 | ``` 12 | 13 | And then execute: 14 | 15 | $ bundle 16 | 17 | Or install it yourself as: 18 | 19 | $ gem install date 20 | 21 | ## Usage 22 | 23 | ```ruby 24 | require 'date' 25 | ``` 26 | 27 | A `Date` object is created with `Date::new`, `Date::jd`, `Date::ordinal`, `Date::commercial`, `Date::parse`, `Date::strptime`, `Date::today`, `Time#to_date`, etc. 28 | 29 | ```ruby 30 | require 'date' 31 | 32 | Date.new(2001,2,3) 33 | #=> # 34 | Date.jd(2451944) 35 | #=> # 36 | Date.ordinal(2001,34) 37 | #=> # 38 | Date.commercial(2001,5,6) 39 | #=> # 40 | Date.parse('2001-02-03') 41 | #=> # 42 | Date.strptime('03-02-2001', '%d-%m-%Y') 43 | #=> # 44 | Time.new(2001,2,3).to_date 45 | #=> # 46 | ``` 47 | 48 | All `Date` objects are immutable; hence cannot modify themselves. 49 | 50 | The concept of a date object can be represented as a tuple of the day count, the offset and the day of calendar reform. 51 | 52 | The day count denotes the absolute position of a temporal dimension. The offset is relative adjustment, which determines decoded local time with the day count. The day of calendar reform denotes the start day of the new style. The old style of the West is the Julian calendar which was adopted by Caesar. The new style is the Gregorian calendar, which is the current civil calendar of many countries. 53 | 54 | The day count is virtually the astronomical Julian day number. The offset in this class is usually zero, and cannot be specified directly. 55 | 56 | A `Date` object can be created with an optional argument, the day of calendar reform as a Julian day number, which should be 2298874 to 2426355 or negative/positive infinity. The default value is `Date::ITALY` (2299161=1582-10-15). See also sample/cal.rb. 57 | 58 | ``` 59 | $ ruby sample/cal.rb -c it 10 1582 60 | October 1582 61 | S M Tu W Th F S 62 | 1 2 3 4 15 16 63 | 17 18 19 20 21 22 23 64 | 24 25 26 27 28 29 30 65 | 31 66 | ``` 67 | 68 | ``` 69 | $ ruby sample/cal.rb -c gb 9 1752 70 | September 1752 71 | S M Tu W Th F S 72 | 1 2 14 15 16 73 | 17 18 19 20 21 22 23 74 | 24 25 26 27 28 29 30 75 | ``` 76 | 77 | A `Date` object has various methods. See each reference. 78 | 79 | ```ruby 80 | d = Date.parse('3rd Feb 2001') 81 | #=> # 82 | d.year #=> 2001 83 | d.mon #=> 2 84 | d.mday #=> 3 85 | d.wday #=> 6 86 | d += 1 #=> # 87 | d.strftime('%a %d %b %Y') #=> "Sun 04 Feb 2001" 88 | ``` 89 | 90 | ## Development 91 | 92 | After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment. 93 | 94 | To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org). 95 | 96 | ## Contributing 97 | 98 | Bug reports and pull requests are welcome on GitHub at https://github.com/ruby/date. 99 | 100 | ## License 101 | 102 | The gem is available as open source under the terms of the [2-Clause BSD License](https://opensource.org/licenses/BSD-2-Clause). 103 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require "bundler/gem_tasks" 2 | require "rake/testtask" 3 | require "shellwords" 4 | require "rake/extensiontask" 5 | 6 | extask = Rake::ExtensionTask.new("date") do |ext| 7 | ext.name = "date_core" 8 | ext.lib_dir.sub!(%r[(?=/|\z)], "/#{RUBY_VERSION}/#{ext.platform}") 9 | end 10 | 11 | Rake::TestTask.new(:test) do |t| 12 | t.libs << extask.lib_dir 13 | t.libs << "test/lib" 14 | t.ruby_opts << "-rhelper" 15 | t.test_files = FileList['test/**/test_*.rb'] 16 | end 17 | 18 | task compile: "ext/date/zonetab.h" 19 | file "ext/date/zonetab.h" => "ext/date/zonetab.list" do |t| 20 | dir, hdr = File.split(t.name) 21 | make_program_name = 22 | ENV['MAKE'] || ENV['make'] || 23 | RbConfig::CONFIG['configure_args'][/with-make-prog\=\K\w+/] || 24 | (/mswin/ =~ RUBY_PLATFORM ? 'nmake' : 'make') 25 | make_program = Shellwords.split(make_program_name) 26 | sh(*make_program, "-f", "prereq.mk", "top_srcdir=.."+"/.."*dir.count("/"), 27 | hdr, chdir: dir) 28 | end 29 | 30 | task :default => [:compile, :test] 31 | -------------------------------------------------------------------------------- /bin/console: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require "bundler/setup" 4 | require "date" 5 | 6 | # You can add fixtures and/or initialization code here to make experimenting 7 | # with your gem easier. You can also use a different console, if you like. 8 | 9 | # (If you use this, don't forget to add pry to your Gemfile!) 10 | # require "pry" 11 | # Pry.start 12 | 13 | require "irb" 14 | IRB.start(__FILE__) 15 | -------------------------------------------------------------------------------- /bin/setup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -euo pipefail 3 | IFS=$'\n\t' 4 | set -vx 5 | 6 | bundle install 7 | 8 | # Do any other automated setup that you need to do here 9 | -------------------------------------------------------------------------------- /date.gemspec: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | version = File.foreach(File.expand_path("../lib/date.rb", __FILE__)).find do |line| 4 | /^\s*VERSION\s*=\s*["'](.*)["']/ =~ line and break $1 5 | end 6 | 7 | Gem::Specification.new do |s| 8 | s.name = "date" 9 | s.version = version 10 | s.summary = "The official date library for Ruby." 11 | s.description = "The official date library for Ruby." 12 | 13 | if Gem::Platform === s.platform and s.platform =~ 'java' or RUBY_ENGINE == 'jruby' 14 | s.platform = 'java' 15 | # No files shipped, no require path, no-op for now on JRuby 16 | else 17 | s.require_path = %w{lib} 18 | 19 | s.files = [ 20 | "README.md", "COPYING", "BSDL", 21 | "lib/date.rb", "ext/date/date_core.c", "ext/date/date_parse.c", "ext/date/date_strftime.c", 22 | "ext/date/date_strptime.c", "ext/date/date_tmx.h", "ext/date/extconf.rb", "ext/date/prereq.mk", 23 | "ext/date/zonetab.h", "ext/date/zonetab.list" 24 | ] 25 | s.extensions = "ext/date/extconf.rb" 26 | end 27 | 28 | s.required_ruby_version = ">= 2.6.0" 29 | 30 | s.authors = ["Tadayoshi Funaba"] 31 | s.email = [nil] 32 | s.homepage = "https://github.com/ruby/date" 33 | s.licenses = ["Ruby", "BSD-2-Clause"] 34 | 35 | s.metadata["changelog_uri"] = s.homepage + "/releases" 36 | end 37 | -------------------------------------------------------------------------------- /doc/date/calendars.rdoc: -------------------------------------------------------------------------------- 1 | == Julian and Gregorian Calendars 2 | 3 | The difference between the 4 | {Julian calendar}[https://en.wikipedia.org/wiki/Julian_calendar] 5 | and the 6 | {Gregorian calendar}[https://en.wikipedia.org/wiki/Gregorian_calendar] 7 | may matter to your program if it uses dates before the switchovers. 8 | 9 | - October 15, 1582. 10 | - September 14, 1752. 11 | 12 | A date will be different in the two calendars, in general. 13 | 14 | === Different switchover dates 15 | 16 | The reasons for the difference are religious/political histories. 17 | 18 | - On October 15, 1582, several countries changed 19 | from the Julian calendar to the Gregorian calendar; 20 | these included Italy, Poland, Portugal, and Spain. 21 | Other countries in the Western world retained the Julian calendar. 22 | - On September 14, 1752, most of the British empire 23 | changed from the Julian calendar to the Gregorian calendar. 24 | 25 | When your code uses a date before these switchover dates, 26 | it will matter whether it considers the switchover date 27 | to be the earlier date or the later date (or neither). 28 | 29 | See also {a concrete example here}[rdoc-ref:DateTime@When+should+you+use+DateTime+and+when+should+you+use+Time-3F]. 30 | 31 | === Argument +start+ 32 | 33 | Certain methods in class \Date handle differences in the 34 | {Julian and Gregorian calendars}[rdoc-ref:date/calendars.rdoc@Julian+and+Gregorian+Calendars] 35 | by accepting an optional argument +start+, whose value may be: 36 | 37 | - Date::ITALY (the default): the created date is Julian 38 | if before October 15, 1582, Gregorian otherwise: 39 | 40 | d = Date.new(1582, 10, 15) 41 | d.prev_day.julian? # => true 42 | d.julian? # => false 43 | d.gregorian? # => true 44 | 45 | - Date::ENGLAND: the created date is Julian if before September 14, 1752, 46 | Gregorian otherwise: 47 | 48 | d = Date.new(1752, 9, 14, Date::ENGLAND) 49 | d.prev_day.julian? # => true 50 | d.julian? # => false 51 | d.gregorian? # => true 52 | 53 | - Date::JULIAN: the created date is Julian regardless of its value: 54 | 55 | d = Date.new(1582, 10, 15, Date::JULIAN) 56 | d.julian? # => true 57 | 58 | - Date::GREGORIAN: the created date is Gregorian regardless of its value: 59 | 60 | d = Date.new(1752, 9, 14, Date::GREGORIAN) 61 | d.prev_day.gregorian? # => true 62 | 63 | -------------------------------------------------------------------------------- /doc/time.rb: -------------------------------------------------------------------------------- 1 | # # 2 | class Time 3 | end 4 | -------------------------------------------------------------------------------- /ext/date/date_strftime.c: -------------------------------------------------------------------------------- 1 | /* 2 | date_strftime.c: based on a public-domain implementation of ANSI C 3 | library routine strftime, which is originally written by Arnold 4 | Robbins. 5 | */ 6 | 7 | #include "ruby/ruby.h" 8 | #include "date_tmx.h" 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #if defined(HAVE_SYS_TIME_H) 16 | #include 17 | #endif 18 | 19 | #undef strchr /* avoid AIX weirdness */ 20 | 21 | #define range(low, item, hi) (item) 22 | 23 | #define add(x,y) (rb_funcall((x), '+', 1, (y))) 24 | #define sub(x,y) (rb_funcall((x), '-', 1, (y))) 25 | #define mul(x,y) (rb_funcall((x), '*', 1, (y))) 26 | #define quo(x,y) (rb_funcall((x), rb_intern("quo"), 1, (y))) 27 | #define div(x,y) (rb_funcall((x), rb_intern("div"), 1, (y))) 28 | #define mod(x,y) (rb_funcall((x), '%', 1, (y))) 29 | 30 | static void 31 | upcase(char *s, size_t i) 32 | { 33 | do { 34 | if (ISLOWER(*s)) 35 | *s = TOUPPER(*s); 36 | } while (s++, --i); 37 | } 38 | 39 | static void 40 | downcase(char *s, size_t i) 41 | { 42 | do { 43 | if (ISUPPER(*s)) 44 | *s = TOLOWER(*s); 45 | } while (s++, --i); 46 | } 47 | 48 | /* strftime --- produce formatted time */ 49 | 50 | static size_t 51 | date_strftime_with_tmx(char *s, const size_t maxsize, const char *format, 52 | const struct tmx *tmx) 53 | { 54 | char *endp = s + maxsize; 55 | char *start = s; 56 | const char *sp, *tp; 57 | auto char tbuf[100]; 58 | ptrdiff_t i; 59 | int v, w; 60 | size_t colons; 61 | int precision, flags; 62 | char padding; 63 | /* LOCALE_[OE] and COLONS are actually modifiers, not flags */ 64 | enum {LEFT, CHCASE, LOWER, UPPER, LOCALE_O, LOCALE_E, COLONS}; 65 | #define BIT_OF(n) (1U<<(n)) 66 | 67 | /* various tables for locale C */ 68 | static const char days_l[][10] = { 69 | "Sunday", "Monday", "Tuesday", "Wednesday", 70 | "Thursday", "Friday", "Saturday", 71 | }; 72 | static const char months_l[][10] = { 73 | "January", "February", "March", "April", 74 | "May", "June", "July", "August", "September", 75 | "October", "November", "December", 76 | }; 77 | static const char ampm[][3] = { "AM", "PM", }; 78 | 79 | if (s == NULL || format == NULL || tmx == NULL || maxsize == 0) 80 | return 0; 81 | 82 | /* quick check if we even need to bother */ 83 | if (strchr(format, '%') == NULL && strlen(format) + 1 >= maxsize) { 84 | err: 85 | errno = ERANGE; 86 | return 0; 87 | } 88 | 89 | for (; *format && s < endp - 1; format++) { 90 | #define FLAG_FOUND() do { \ 91 | if (precision > 0 || flags & (BIT_OF(LOCALE_E) | BIT_OF(LOCALE_O) | BIT_OF(COLONS))) \ 92 | goto unknown; \ 93 | } while (0) 94 | #define NEEDS(n) do if (s >= endp || (n) >= endp - s - 1) goto err; while (0) 95 | #define FILL_PADDING(i) do { \ 96 | if (!(flags & BIT_OF(LEFT)) && precision > (i)) { \ 97 | NEEDS(precision); \ 98 | memset(s, padding ? padding : ' ', precision - (i)); \ 99 | s += precision - (i); \ 100 | } \ 101 | else { \ 102 | NEEDS(i); \ 103 | } \ 104 | } while (0); 105 | #define FMT(def_pad, def_prec, fmt, val) \ 106 | do { \ 107 | int l; \ 108 | if (precision <= 0) precision = (def_prec); \ 109 | if (flags & BIT_OF(LEFT)) precision = 1; \ 110 | l = snprintf(s, endp - s, \ 111 | ((padding == '0' || (!padding && (def_pad) == '0')) ? \ 112 | "%0*"fmt : "%*"fmt), \ 113 | precision, (val)); \ 114 | if (l < 0) goto err; \ 115 | s += l; \ 116 | } while (0) 117 | #define STRFTIME(fmt) \ 118 | do { \ 119 | i = date_strftime_with_tmx(s, endp - s, (fmt), tmx); \ 120 | if (!i) return 0; \ 121 | if (flags & BIT_OF(UPPER)) \ 122 | upcase(s, i); \ 123 | if (!(flags & BIT_OF(LEFT)) && precision > i) { \ 124 | if (start + maxsize < s + precision) { \ 125 | errno = ERANGE; \ 126 | return 0; \ 127 | } \ 128 | memmove(s + precision - i, s, i); \ 129 | memset(s, padding ? padding : ' ', precision - i); \ 130 | s += precision; \ 131 | } \ 132 | else s += i; \ 133 | } while (0) 134 | #define FMTV(def_pad, def_prec, fmt, val) \ 135 | do { \ 136 | VALUE tmp = (val); \ 137 | if (FIXNUM_P(tmp)) { \ 138 | FMT((def_pad), (def_prec), "l"fmt, FIX2LONG(tmp)); \ 139 | } \ 140 | else { \ 141 | VALUE args[2], result; \ 142 | size_t l; \ 143 | if (precision <= 0) precision = (def_prec); \ 144 | if (flags & BIT_OF(LEFT)) precision = 1; \ 145 | args[0] = INT2FIX(precision); \ 146 | args[1] = (val); \ 147 | if (padding == '0' || (!padding && (def_pad) == '0')) \ 148 | result = rb_str_format(2, args, rb_str_new2("%0*"fmt)); \ 149 | else \ 150 | result = rb_str_format(2, args, rb_str_new2("%*"fmt)); \ 151 | l = strlcpy(s, StringValueCStr(result), endp - s); \ 152 | if ((size_t)(endp - s) <= l) \ 153 | goto err; \ 154 | s += l; \ 155 | } \ 156 | } while (0) 157 | 158 | if (*format != '%') { 159 | *s++ = *format; 160 | continue; 161 | } 162 | tp = tbuf; 163 | sp = format; 164 | precision = -1; 165 | flags = 0; 166 | padding = 0; 167 | colons = 0; 168 | again: 169 | switch (*++format) { 170 | case '\0': 171 | format--; 172 | goto unknown; 173 | 174 | case 'A': /* full weekday name */ 175 | case 'a': /* abbreviated weekday name */ 176 | if (flags & BIT_OF(CHCASE)) { 177 | flags &= ~(BIT_OF(LOWER) | BIT_OF(CHCASE)); 178 | flags |= BIT_OF(UPPER); 179 | } 180 | { 181 | int wday = tmx_wday; 182 | if (wday < 0 || wday > 6) 183 | i = 1, tp = "?"; 184 | else { 185 | if (*format == 'A') 186 | i = strlen(tp = days_l[wday]); 187 | else 188 | i = 3, tp = days_l[wday]; 189 | } 190 | } 191 | break; 192 | 193 | case 'B': /* full month name */ 194 | case 'b': /* abbreviated month name */ 195 | case 'h': /* same as %b */ 196 | if (flags & BIT_OF(CHCASE)) { 197 | flags &= ~(BIT_OF(LOWER) | BIT_OF(CHCASE)); 198 | flags |= BIT_OF(UPPER); 199 | } 200 | { 201 | int mon = tmx_mon; 202 | if (mon < 1 || mon > 12) 203 | i = 1, tp = "?"; 204 | else { 205 | if (*format == 'B') 206 | i = strlen(tp = months_l[mon - 1]); 207 | else 208 | i = 3, tp = months_l[mon - 1]; 209 | } 210 | } 211 | break; 212 | 213 | case 'C': /* century (year/100) */ 214 | FMTV('0', 2, "d", div(tmx_year, INT2FIX(100))); 215 | continue; 216 | 217 | case 'c': /* appropriate date and time representation */ 218 | STRFTIME("%a %b %e %H:%M:%S %Y"); 219 | continue; 220 | 221 | case 'D': 222 | STRFTIME("%m/%d/%y"); 223 | continue; 224 | 225 | case 'd': /* day of the month, 01 - 31 */ 226 | case 'e': /* day of month, blank padded */ 227 | v = range(1, tmx_mday, 31); 228 | FMT((*format == 'd') ? '0' : ' ', 2, "d", v); 229 | continue; 230 | 231 | case 'F': 232 | STRFTIME("%Y-%m-%d"); 233 | continue; 234 | 235 | case 'G': /* year of ISO week with century */ 236 | case 'Y': /* year with century */ 237 | { 238 | VALUE year = (*format == 'G') ? tmx_cwyear : tmx_year; 239 | if (FIXNUM_P(year)) { 240 | long y = FIX2LONG(year); 241 | FMT('0', 0 <= y ? 4 : 5, "ld", y); 242 | } 243 | else { 244 | FMTV('0', 4, "d", year); 245 | } 246 | } 247 | continue; 248 | 249 | case 'g': /* year of ISO week without a century */ 250 | case 'y': /* year without a century */ 251 | v = NUM2INT(mod((*format == 'g') ? tmx_cwyear : tmx_year, INT2FIX(100))); 252 | FMT('0', 2, "d", v); 253 | continue; 254 | 255 | case 'H': /* hour, 24-hour clock, 00 - 23 */ 256 | case 'k': /* hour, 24-hour clock, blank pad */ 257 | v = range(0, tmx_hour, 23); 258 | FMT((*format == 'H') ? '0' : ' ', 2, "d", v); 259 | continue; 260 | 261 | case 'I': /* hour, 12-hour clock, 01 - 12 */ 262 | case 'l': /* hour, 12-hour clock, 1 - 12, blank pad */ 263 | v = range(0, tmx_hour, 23); 264 | if (v == 0) 265 | v = 12; 266 | else if (v > 12) 267 | v -= 12; 268 | FMT((*format == 'I') ? '0' : ' ', 2, "d", v); 269 | continue; 270 | 271 | case 'j': /* day of the year, 001 - 366 */ 272 | v = range(1, tmx_yday, 366); 273 | FMT('0', 3, "d", v); 274 | continue; 275 | 276 | case 'L': /* millisecond */ 277 | case 'N': /* nanosecond */ 278 | if (*format == 'L') 279 | w = 3; 280 | else 281 | w = 9; 282 | if (precision <= 0) 283 | precision = w; 284 | NEEDS(precision); 285 | 286 | { 287 | VALUE subsec = tmx_sec_fraction; 288 | int ww; 289 | long n; 290 | 291 | ww = precision; 292 | while (9 <= ww) { 293 | subsec = mul(subsec, INT2FIX(1000000000)); 294 | ww -= 9; 295 | } 296 | n = 1; 297 | for (; 0 < ww; ww--) 298 | n *= 10; 299 | if (n != 1) 300 | subsec = mul(subsec, INT2FIX(n)); 301 | subsec = div(subsec, INT2FIX(1)); 302 | 303 | if (FIXNUM_P(subsec)) { 304 | (void)snprintf(s, endp - s, "%0*ld", 305 | precision, FIX2LONG(subsec)); 306 | s += precision; 307 | } 308 | else { 309 | VALUE args[2], result; 310 | args[0] = INT2FIX(precision); 311 | args[1] = subsec; 312 | result = rb_str_format(2, args, rb_str_new2("%0*d")); 313 | (void)strlcpy(s, StringValueCStr(result), endp - s); 314 | s += precision; 315 | } 316 | } 317 | continue; 318 | 319 | case 'M': /* minute, 00 - 59 */ 320 | v = range(0, tmx_min, 59); 321 | FMT('0', 2, "d", v); 322 | continue; 323 | 324 | case 'm': /* month, 01 - 12 */ 325 | v = range(1, tmx_mon, 12); 326 | FMT('0', 2, "d", v); 327 | continue; 328 | 329 | case 'n': /* same as \n */ 330 | FILL_PADDING(1); 331 | *s++ = '\n'; 332 | continue; 333 | 334 | case 't': /* same as \t */ 335 | FILL_PADDING(1); 336 | *s++ = '\t'; 337 | continue; 338 | 339 | case 'P': /* am or pm based on 12-hour clock */ 340 | case 'p': /* AM or PM based on 12-hour clock */ 341 | if ((*format == 'p' && (flags & BIT_OF(CHCASE))) || 342 | (*format == 'P' && !(flags & (BIT_OF(CHCASE) | BIT_OF(UPPER))))) { 343 | flags &= ~(BIT_OF(UPPER) | BIT_OF(CHCASE)); 344 | flags |= BIT_OF(LOWER); 345 | } 346 | v = range(0, tmx_hour, 23); 347 | if (v < 12) 348 | tp = ampm[0]; 349 | else 350 | tp = ampm[1]; 351 | i = 2; 352 | break; 353 | 354 | case 'Q': /* milliseconds since Unix epoch */ 355 | FMTV('0', 1, "d", tmx_msecs); 356 | continue; 357 | 358 | case 'R': 359 | STRFTIME("%H:%M"); 360 | continue; 361 | 362 | case 'r': 363 | STRFTIME("%I:%M:%S %p"); 364 | continue; 365 | 366 | case 'S': /* second, 00 - 59 */ 367 | v = range(0, tmx_sec, 59); 368 | FMT('0', 2, "d", v); 369 | continue; 370 | 371 | case 's': /* seconds since Unix epoch */ 372 | FMTV('0', 1, "d", tmx_secs); 373 | continue; 374 | 375 | case 'T': 376 | STRFTIME("%H:%M:%S"); 377 | continue; 378 | 379 | case 'U': /* week of year, Sunday is first day of week */ 380 | case 'W': /* week of year, Monday is first day of week */ 381 | v = range(0, (*format == 'U') ? tmx_wnum0 : tmx_wnum1, 53); 382 | FMT('0', 2, "d", v); 383 | continue; 384 | 385 | case 'u': /* weekday, Monday == 1, 1 - 7 */ 386 | v = range(1, tmx_cwday, 7); 387 | FMT('0', 1, "d", v); 388 | continue; 389 | 390 | case 'V': /* week of year according ISO 8601 */ 391 | v = range(1, tmx_cweek, 53); 392 | FMT('0', 2, "d", v); 393 | continue; 394 | 395 | case 'v': 396 | STRFTIME("%e-%^b-%Y"); 397 | continue; 398 | 399 | case 'w': /* weekday, Sunday == 0, 0 - 6 */ 400 | v = range(0, tmx_wday, 6); 401 | FMT('0', 1, "d", v); 402 | continue; 403 | 404 | case 'X': /* appropriate time representation */ 405 | STRFTIME("%H:%M:%S"); 406 | continue; 407 | 408 | case 'x': /* appropriate date representation */ 409 | STRFTIME("%m/%d/%y"); 410 | continue; 411 | 412 | case 'Z': /* time zone name or abbreviation */ 413 | if (flags & BIT_OF(CHCASE)) { 414 | flags &= ~(BIT_OF(UPPER) | BIT_OF(CHCASE)); 415 | flags |= BIT_OF(LOWER); 416 | } 417 | { 418 | char *zone = tmx_zone; 419 | if (zone == NULL) 420 | tp = ""; 421 | else 422 | tp = zone; 423 | i = strlen(tp); 424 | } 425 | break; 426 | 427 | case 'z': /* offset from UTC */ 428 | { 429 | long off, aoff; 430 | int hl, hw; 431 | 432 | off = tmx_offset; 433 | aoff = off; 434 | if (aoff < 0) 435 | aoff = -off; 436 | 437 | if ((aoff / 3600) < 10) 438 | hl = 1; 439 | else 440 | hl = 2; 441 | hw = 2; 442 | if (flags & BIT_OF(LEFT) && hl == 1) 443 | hw = 1; 444 | 445 | switch (colons) { 446 | case 0: /* %z -> +hhmm */ 447 | precision = precision <= (3 + hw) ? hw : precision - 3; 448 | NEEDS(precision + 3); 449 | break; 450 | 451 | case 1: /* %:z -> +hh:mm */ 452 | precision = precision <= (4 + hw) ? hw : precision - 4; 453 | NEEDS(precision + 4); 454 | break; 455 | 456 | case 2: /* %::z -> +hh:mm:ss */ 457 | precision = precision <= (7 + hw) ? hw : precision - 7; 458 | NEEDS(precision + 7); 459 | break; 460 | 461 | case 3: /* %:::z -> +hh[:mm[:ss]] */ 462 | { 463 | if (aoff % 3600 == 0) { 464 | precision = precision <= (1 + hw) ? 465 | hw : precision - 1; 466 | NEEDS(precision + 3); 467 | } 468 | else if (aoff % 60 == 0) { 469 | precision = precision <= (4 + hw) ? 470 | hw : precision - 4; 471 | NEEDS(precision + 4); 472 | } 473 | else { 474 | precision = precision <= (7 + hw) ? 475 | hw : precision - 7; 476 | NEEDS(precision + 7); 477 | } 478 | } 479 | break; 480 | 481 | default: 482 | format--; 483 | goto unknown; 484 | } 485 | if (padding == ' ' && precision > hl) { 486 | i = snprintf(s, endp - s, "%*s", precision - hl, ""); 487 | precision = hl; 488 | if (i < 0) goto err; 489 | s += i; 490 | } 491 | if (off < 0) { 492 | off = -off; 493 | *s++ = '-'; 494 | } else { 495 | *s++ = '+'; 496 | } 497 | i = snprintf(s, endp - s, "%.*ld", precision, off / 3600); 498 | if (i < 0) goto err; 499 | s += i; 500 | off = off % 3600; 501 | if (colons == 3 && off == 0) 502 | continue; 503 | if (1 <= colons) 504 | *s++ = ':'; 505 | i = snprintf(s, endp - s, "%02d", (int)(off / 60)); 506 | if (i < 0) goto err; 507 | s += i; 508 | off = off % 60; 509 | if (colons == 3 && off == 0) 510 | continue; 511 | if (2 <= colons) { 512 | *s++ = ':'; 513 | i = snprintf(s, endp - s, "%02d", (int)off); 514 | if (i < 0) goto err; 515 | s += i; 516 | } 517 | } 518 | continue; 519 | 520 | case '+': 521 | STRFTIME("%a %b %e %H:%M:%S %Z %Y"); 522 | continue; 523 | 524 | case 'E': 525 | /* POSIX locale extensions, ignored for now */ 526 | flags |= BIT_OF(LOCALE_E); 527 | if (*(format + 1) && strchr("cCxXyY", *(format + 1))) 528 | goto again; 529 | goto unknown; 530 | case 'O': 531 | /* POSIX locale extensions, ignored for now */ 532 | flags |= BIT_OF(LOCALE_O); 533 | if (*(format + 1) && strchr("deHkIlmMSuUVwWy", *(format + 1))) 534 | goto again; 535 | goto unknown; 536 | 537 | case ':': 538 | flags |= BIT_OF(COLONS); 539 | { 540 | size_t l = strspn(format, ":"); 541 | format += l; 542 | if (*format == 'z') { 543 | colons = l; 544 | format--; 545 | goto again; 546 | } 547 | format -= l; 548 | } 549 | goto unknown; 550 | 551 | case '_': 552 | FLAG_FOUND(); 553 | padding = ' '; 554 | goto again; 555 | 556 | case '-': 557 | FLAG_FOUND(); 558 | flags |= BIT_OF(LEFT); 559 | goto again; 560 | 561 | case '^': 562 | FLAG_FOUND(); 563 | flags |= BIT_OF(UPPER); 564 | goto again; 565 | 566 | case '#': 567 | FLAG_FOUND(); 568 | flags |= BIT_OF(CHCASE); 569 | goto again; 570 | 571 | case '0': 572 | FLAG_FOUND(); 573 | padding = '0'; 574 | case '1': case '2': case '3': case '4': 575 | case '5': case '6': case '7': case '8': case '9': 576 | { 577 | char *e; 578 | unsigned long prec = strtoul(format, &e, 10); 579 | if (prec > INT_MAX || prec > maxsize) { 580 | errno = ERANGE; 581 | return 0; 582 | } 583 | precision = (int)prec; 584 | format = e - 1; 585 | goto again; 586 | } 587 | 588 | case '%': 589 | FILL_PADDING(1); 590 | *s++ = '%'; 591 | continue; 592 | 593 | default: 594 | unknown: 595 | i = format - sp + 1; 596 | tp = sp; 597 | precision = -1; 598 | flags = 0; 599 | padding = 0; 600 | colons = 0; 601 | break; 602 | } 603 | if (i) { 604 | FILL_PADDING(i); 605 | memcpy(s, tp, i); 606 | switch (flags & (BIT_OF(UPPER) | BIT_OF(LOWER))) { 607 | case BIT_OF(UPPER): 608 | upcase(s, i); 609 | break; 610 | case BIT_OF(LOWER): 611 | downcase(s, i); 612 | break; 613 | } 614 | s += i; 615 | } 616 | } 617 | if (s >= endp) { 618 | goto err; 619 | } 620 | if (*format == '\0') { 621 | *s = '\0'; 622 | return (s - start); 623 | } 624 | return 0; 625 | } 626 | 627 | size_t 628 | date_strftime(char *s, size_t maxsize, const char *format, 629 | const struct tmx *tmx) 630 | { 631 | return date_strftime_with_tmx(s, maxsize, format, tmx); 632 | } 633 | 634 | /* 635 | Local variables: 636 | c-file-style: "ruby" 637 | End: 638 | */ 639 | -------------------------------------------------------------------------------- /ext/date/date_strptime.c: -------------------------------------------------------------------------------- 1 | /* 2 | date_strptime.c: Coded by Tadayoshi Funaba 2011,2012 3 | */ 4 | 5 | #include "ruby.h" 6 | #include "ruby/encoding.h" 7 | #include "ruby/re.h" 8 | #include 9 | 10 | #undef strncasecmp 11 | #define strncasecmp STRNCASECMP 12 | 13 | static const char *day_names[] = { 14 | "Sunday", "Monday", "Tuesday", "Wednesday", 15 | "Thursday", "Friday", "Saturday", 16 | }; 17 | static const int ABBREVIATED_DAY_NAME_LENGTH = 3; 18 | 19 | static const char *month_names[] = { 20 | "January", "February", "March", "April", 21 | "May", "June", "July", "August", "September", 22 | "October", "November", "December", 23 | }; 24 | static const int ABBREVIATED_MONTH_NAME_LENGTH = 3; 25 | 26 | #define sizeof_array(o) (sizeof o / sizeof o[0]) 27 | 28 | #define f_negate(x) rb_funcall(x, rb_intern("-@"), 0) 29 | #define f_add(x,y) rb_funcall(x, '+', 1, y) 30 | #define f_sub(x,y) rb_funcall(x, '-', 1, y) 31 | #define f_mul(x,y) rb_funcall(x, '*', 1, y) 32 | #define f_div(x,y) rb_funcall(x, '/', 1, y) 33 | #define f_idiv(x,y) rb_funcall(x, rb_intern("div"), 1, y) 34 | #define f_mod(x,y) rb_funcall(x, '%', 1, y) 35 | #define f_expt(x,y) rb_funcall(x, rb_intern("**"), 1, y) 36 | 37 | #define f_lt_p(x,y) rb_funcall(x, '<', 1, y) 38 | #define f_gt_p(x,y) rb_funcall(x, '>', 1, y) 39 | #define f_le_p(x,y) rb_funcall(x, rb_intern("<="), 1, y) 40 | #define f_ge_p(x,y) rb_funcall(x, rb_intern(">="), 1, y) 41 | 42 | #define f_match(r,s) rb_funcall(r, rb_intern("match"), 1, s) 43 | #define f_aref(o,i) rb_funcall(o, rb_intern("[]"), 1, i) 44 | #define f_end(o,i) rb_funcall(o, rb_intern("end"), 1, i) 45 | 46 | #define issign(c) ((c) == '-' || (c) == '+') 47 | 48 | static int 49 | num_pattern_p(const char *s) 50 | { 51 | if (isdigit((unsigned char)*s)) 52 | return 1; 53 | if (*s == '%') { 54 | s++; 55 | if (*s == 'E' || *s == 'O') 56 | s++; 57 | if (*s && 58 | (strchr("CDdeFGgHIjkLlMmNQRrSsTUuVvWwXxYy", *s) || 59 | isdigit((unsigned char)*s))) 60 | return 1; 61 | } 62 | return 0; 63 | } 64 | 65 | #define NUM_PATTERN_P() num_pattern_p(&fmt[fi + 1]) 66 | 67 | static long 68 | read_digits(const char *s, size_t slen, VALUE *n, size_t width) 69 | { 70 | size_t l; 71 | 72 | if (!width) 73 | return 0; 74 | 75 | l = 0; 76 | while (l < slen && ISDIGIT(s[l])) { 77 | if (++l == width) break; 78 | } 79 | 80 | if (l == 0) 81 | return 0; 82 | 83 | if ((4 * l * sizeof(char)) <= (sizeof(long)*CHAR_BIT)) { 84 | const char *os = s; 85 | long v; 86 | 87 | v = 0; 88 | while ((size_t)(s - os) < l) { 89 | v *= 10; 90 | v += *s - '0'; 91 | s++; 92 | } 93 | if (os == s) 94 | return 0; 95 | *n = LONG2NUM(v); 96 | return l; 97 | } 98 | else { 99 | VALUE vbuf = 0; 100 | char *s2 = ALLOCV_N(char, vbuf, l + 1); 101 | memcpy(s2, s, l); 102 | s2[l] = '\0'; 103 | *n = rb_cstr_to_inum(s2, 10, 0); 104 | ALLOCV_END(vbuf); 105 | return l; 106 | } 107 | } 108 | 109 | #define set_hash(k,v) rb_hash_aset(hash, ID2SYM(rb_intern(k"")), v) 110 | #define ref_hash(k) rb_hash_aref(hash, ID2SYM(rb_intern(k""))) 111 | #define del_hash(k) rb_hash_delete(hash, ID2SYM(rb_intern(k""))) 112 | 113 | #define fail() \ 114 | do { \ 115 | set_hash("_fail", Qtrue); \ 116 | return 0; \ 117 | } while (0) 118 | 119 | #define fail_p() (!NIL_P(ref_hash("_fail"))) 120 | 121 | #define READ_DIGITS(n,w) \ 122 | do { \ 123 | size_t l; \ 124 | l = read_digits(&str[si], slen - si, &n, w); \ 125 | if (l == 0) { \ 126 | fail(); \ 127 | } \ 128 | si += l; \ 129 | } while (0) 130 | 131 | #define READ_DIGITS_MAX(n) READ_DIGITS(n, LONG_MAX) 132 | 133 | static int 134 | valid_range_p(VALUE v, int a, int b) 135 | { 136 | if (FIXNUM_P(v)) { 137 | int vi = FIX2INT(v); 138 | return !(vi < a || vi > b); 139 | } 140 | return !(f_lt_p(v, INT2NUM(a)) || f_gt_p(v, INT2NUM(b))); 141 | } 142 | 143 | #define recur(fmt) \ 144 | do { \ 145 | size_t l; \ 146 | l = date__strptime_internal(&str[si], slen - si, \ 147 | fmt, sizeof fmt - 1, hash); \ 148 | if (fail_p()) \ 149 | return 0; \ 150 | si += l; \ 151 | } while (0) 152 | 153 | VALUE date_zone_to_diff(VALUE); 154 | 155 | static inline int 156 | head_match_p(size_t len, const char *name, const char *str, size_t slen, size_t si) 157 | { 158 | return slen - si >= len && strncasecmp(name, &str[si], len) == 0; 159 | } 160 | 161 | static size_t 162 | date__strptime_internal(const char *str, size_t slen, 163 | const char *fmt, size_t flen, VALUE hash) 164 | { 165 | size_t si, fi; 166 | int c; 167 | 168 | #define HEAD_MATCH_P(len, name) head_match_p(len, name, str, slen, si) 169 | si = fi = 0; 170 | 171 | while (fi < flen) { 172 | if (isspace((unsigned char)fmt[fi])) { 173 | while (si < slen && isspace((unsigned char)str[si])) 174 | si++; 175 | while (++fi < flen && isspace((unsigned char)fmt[fi])); 176 | continue; 177 | } 178 | 179 | if (si >= slen) fail(); 180 | 181 | switch (fmt[fi]) { 182 | case '%': 183 | 184 | again: 185 | fi++; 186 | c = fmt[fi]; 187 | 188 | switch (c) { 189 | case 'E': 190 | if (fmt[fi + 1] && strchr("cCxXyY", fmt[fi + 1])) 191 | goto again; 192 | fi--; 193 | goto ordinal; 194 | case 'O': 195 | if (fmt[fi + 1] && strchr("deHImMSuUVwWy", fmt[fi + 1])) 196 | goto again; 197 | fi--; 198 | goto ordinal; 199 | case ':': 200 | { 201 | int i; 202 | 203 | for (i = 1; i < 3 && fi + i < flen && fmt[fi+i] == ':'; ++i); 204 | if (fmt[fi+i] == 'z') { 205 | fi += i - 1; 206 | goto again; 207 | } 208 | fail(); 209 | } 210 | 211 | case 'A': 212 | case 'a': 213 | { 214 | int i; 215 | 216 | for (i = 0; i < (int)sizeof_array(day_names); i++) { 217 | const char *day_name = day_names[i]; 218 | size_t l = strlen(day_name); 219 | if (HEAD_MATCH_P(l, day_name) || 220 | HEAD_MATCH_P(l = ABBREVIATED_DAY_NAME_LENGTH, day_name)) { 221 | si += l; 222 | set_hash("wday", INT2FIX(i)); 223 | goto matched; 224 | } 225 | } 226 | fail(); 227 | } 228 | case 'B': 229 | case 'b': 230 | case 'h': 231 | { 232 | int i; 233 | 234 | for (i = 0; i < (int)sizeof_array(month_names); i++) { 235 | const char *month_name = month_names[i]; 236 | size_t l = strlen(month_name); 237 | if (HEAD_MATCH_P(l, month_name) || 238 | HEAD_MATCH_P(l = ABBREVIATED_MONTH_NAME_LENGTH, month_name)) { 239 | si += l; 240 | set_hash("mon", INT2FIX(i + 1)); 241 | goto matched; 242 | } 243 | } 244 | fail(); 245 | } 246 | 247 | case 'C': 248 | { 249 | VALUE n; 250 | 251 | if (NUM_PATTERN_P()) 252 | READ_DIGITS(n, 2); 253 | else 254 | READ_DIGITS_MAX(n); 255 | set_hash("_cent", n); 256 | goto matched; 257 | } 258 | 259 | case 'c': 260 | recur("%a %b %e %H:%M:%S %Y"); 261 | goto matched; 262 | 263 | case 'D': 264 | recur("%m/%d/%y"); 265 | goto matched; 266 | 267 | case 'd': 268 | case 'e': 269 | { 270 | VALUE n; 271 | 272 | if (str[si] == ' ') { 273 | si++; 274 | READ_DIGITS(n, 1); 275 | } else { 276 | READ_DIGITS(n, 2); 277 | } 278 | if (!valid_range_p(n, 1, 31)) 279 | fail(); 280 | set_hash("mday", n); 281 | goto matched; 282 | } 283 | 284 | case 'F': 285 | recur("%Y-%m-%d"); 286 | goto matched; 287 | 288 | case 'G': 289 | { 290 | VALUE n; 291 | 292 | if (NUM_PATTERN_P()) 293 | READ_DIGITS(n, 4); 294 | else 295 | READ_DIGITS_MAX(n); 296 | set_hash("cwyear", n); 297 | goto matched; 298 | } 299 | 300 | case 'g': 301 | { 302 | VALUE n; 303 | 304 | READ_DIGITS(n, 2); 305 | if (!valid_range_p(n, 0, 99)) 306 | fail(); 307 | set_hash("cwyear",n); 308 | if (NIL_P(ref_hash("_cent"))) 309 | set_hash("_cent", 310 | INT2FIX(f_ge_p(n, INT2FIX(69)) ? 19 : 20)); 311 | goto matched; 312 | } 313 | 314 | case 'H': 315 | case 'k': 316 | { 317 | VALUE n; 318 | 319 | if (str[si] == ' ') { 320 | si++; 321 | READ_DIGITS(n, 1); 322 | } else { 323 | READ_DIGITS(n, 2); 324 | } 325 | if (!valid_range_p(n, 0, 24)) 326 | fail(); 327 | set_hash("hour", n); 328 | goto matched; 329 | } 330 | 331 | case 'I': 332 | case 'l': 333 | { 334 | VALUE n; 335 | 336 | if (str[si] == ' ') { 337 | si++; 338 | READ_DIGITS(n, 1); 339 | } else { 340 | READ_DIGITS(n, 2); 341 | } 342 | if (!valid_range_p(n, 1, 12)) 343 | fail(); 344 | set_hash("hour", n); 345 | goto matched; 346 | } 347 | 348 | case 'j': 349 | { 350 | VALUE n; 351 | 352 | READ_DIGITS(n, 3); 353 | if (!valid_range_p(n, 1, 366)) 354 | fail(); 355 | set_hash("yday", n); 356 | goto matched; 357 | } 358 | 359 | case 'L': 360 | case 'N': 361 | { 362 | VALUE n; 363 | int sign = 1; 364 | size_t osi; 365 | 366 | if (issign(str[si])) { 367 | if (str[si] == '-') 368 | sign = -1; 369 | si++; 370 | } 371 | osi = si; 372 | if (NUM_PATTERN_P()) 373 | READ_DIGITS(n, c == 'L' ? 3 : 9); 374 | else 375 | READ_DIGITS_MAX(n); 376 | if (sign == -1) 377 | n = f_negate(n); 378 | set_hash("sec_fraction", 379 | rb_rational_new2(n, 380 | f_expt(INT2FIX(10), 381 | ULONG2NUM(si - osi)))); 382 | goto matched; 383 | } 384 | 385 | case 'M': 386 | { 387 | VALUE n; 388 | 389 | READ_DIGITS(n, 2); 390 | if (!valid_range_p(n, 0, 59)) 391 | fail(); 392 | set_hash("min", n); 393 | goto matched; 394 | } 395 | 396 | case 'm': 397 | { 398 | VALUE n; 399 | 400 | READ_DIGITS(n, 2); 401 | if (!valid_range_p(n, 1, 12)) 402 | fail(); 403 | set_hash("mon", n); 404 | goto matched; 405 | } 406 | 407 | case 'n': 408 | case 't': 409 | recur(" "); 410 | goto matched; 411 | 412 | case 'P': 413 | case 'p': 414 | if (slen - si < 2) fail(); 415 | { 416 | char c = str[si]; 417 | const int hour = (c == 'P' || c == 'p') ? 12 : 0; 418 | if (!hour && !(c == 'A' || c == 'a')) fail(); 419 | if ((c = str[si+1]) == '.') { 420 | if (slen - si < 4 || str[si+3] != '.') fail(); 421 | c = str[si += 2]; 422 | } 423 | if (!(c == 'M' || c == 'm')) fail(); 424 | si += 2; 425 | set_hash("_merid", INT2FIX(hour)); 426 | goto matched; 427 | } 428 | 429 | case 'Q': 430 | { 431 | VALUE n; 432 | int sign = 1; 433 | 434 | if (str[si] == '-') { 435 | sign = -1; 436 | si++; 437 | } 438 | READ_DIGITS_MAX(n); 439 | if (sign == -1) 440 | n = f_negate(n); 441 | set_hash("seconds", 442 | rb_rational_new2(n, INT2FIX(1000))); 443 | goto matched; 444 | } 445 | 446 | case 'R': 447 | recur("%H:%M"); 448 | goto matched; 449 | 450 | case 'r': 451 | recur("%I:%M:%S %p"); 452 | goto matched; 453 | 454 | case 'S': 455 | { 456 | VALUE n; 457 | 458 | READ_DIGITS(n, 2); 459 | if (!valid_range_p(n, 0, 60)) 460 | fail(); 461 | set_hash("sec", n); 462 | goto matched; 463 | } 464 | 465 | case 's': 466 | { 467 | VALUE n; 468 | int sign = 1; 469 | 470 | if (str[si] == '-') { 471 | sign = -1; 472 | si++; 473 | } 474 | READ_DIGITS_MAX(n); 475 | if (sign == -1) 476 | n = f_negate(n); 477 | set_hash("seconds", n); 478 | goto matched; 479 | } 480 | 481 | case 'T': 482 | recur("%H:%M:%S"); 483 | goto matched; 484 | 485 | case 'U': 486 | case 'W': 487 | { 488 | VALUE n; 489 | 490 | READ_DIGITS(n, 2); 491 | if (!valid_range_p(n, 0, 53)) 492 | fail(); 493 | set_hash(c == 'U' ? "wnum0" : "wnum1", n); 494 | goto matched; 495 | } 496 | 497 | case 'u': 498 | { 499 | VALUE n; 500 | 501 | READ_DIGITS(n, 1); 502 | if (!valid_range_p(n, 1, 7)) 503 | fail(); 504 | set_hash("cwday", n); 505 | goto matched; 506 | } 507 | 508 | case 'V': 509 | { 510 | VALUE n; 511 | 512 | READ_DIGITS(n, 2); 513 | if (!valid_range_p(n, 1, 53)) 514 | fail(); 515 | set_hash("cweek", n); 516 | goto matched; 517 | } 518 | 519 | case 'v': 520 | recur("%e-%b-%Y"); 521 | goto matched; 522 | 523 | case 'w': 524 | { 525 | VALUE n; 526 | 527 | READ_DIGITS(n, 1); 528 | if (!valid_range_p(n, 0, 6)) 529 | fail(); 530 | set_hash("wday", n); 531 | goto matched; 532 | } 533 | 534 | case 'X': 535 | recur("%H:%M:%S"); 536 | goto matched; 537 | 538 | case 'x': 539 | recur("%m/%d/%y"); 540 | goto matched; 541 | 542 | case 'Y': 543 | { 544 | VALUE n; 545 | int sign = 1; 546 | 547 | if (issign(str[si])) { 548 | if (str[si] == '-') 549 | sign = -1; 550 | si++; 551 | } 552 | if (NUM_PATTERN_P()) 553 | READ_DIGITS(n, 4); 554 | else 555 | READ_DIGITS_MAX(n); 556 | if (sign == -1) 557 | n = f_negate(n); 558 | set_hash("year", n); 559 | goto matched; 560 | } 561 | 562 | case 'y': 563 | { 564 | VALUE n; 565 | int sign = 1; 566 | 567 | READ_DIGITS(n, 2); 568 | if (!valid_range_p(n, 0, 99)) 569 | fail(); 570 | if (sign == -1) 571 | n = f_negate(n); 572 | set_hash("year", n); 573 | if (NIL_P(ref_hash("_cent"))) 574 | set_hash("_cent", 575 | INT2FIX(f_ge_p(n, INT2FIX(69)) ? 19 : 20)); 576 | goto matched; 577 | } 578 | 579 | case 'Z': 580 | case 'z': 581 | { 582 | static const char pat_source[] = 583 | "\\A(" 584 | "(?:gmt|utc?)?[-+]\\d+(?:[,.:]\\d+(?::\\d+)?)?" 585 | "|(?-i:[[:alpha:].\\s]+)(?:standard|daylight)\\s+time\\b" 586 | "|(?-i:[[:alpha:]]+)(?:\\s+dst)?\\b" 587 | ")"; 588 | static VALUE pat = Qnil; 589 | VALUE m, b; 590 | 591 | if (NIL_P(pat)) { 592 | pat = rb_reg_new(pat_source, sizeof pat_source - 1, 593 | ONIG_OPTION_IGNORECASE); 594 | rb_obj_freeze(pat); 595 | rb_gc_register_mark_object(pat); 596 | } 597 | 598 | b = rb_backref_get(); 599 | rb_match_busy(b); 600 | m = f_match(pat, rb_usascii_str_new(&str[si], slen - si)); 601 | 602 | if (!NIL_P(m)) { 603 | VALUE s, l, o; 604 | 605 | s = rb_reg_nth_match(1, m); 606 | l = f_end(m, INT2FIX(0)); 607 | o = date_zone_to_diff(s); 608 | si += NUM2LONG(l); 609 | set_hash("zone", s); 610 | set_hash("offset", o); 611 | rb_backref_set(b); 612 | goto matched; 613 | } 614 | rb_backref_set(b); 615 | fail(); 616 | } 617 | 618 | case '%': 619 | if (str[si] != '%') 620 | fail(); 621 | si++; 622 | goto matched; 623 | 624 | case '+': 625 | recur("%a %b %e %H:%M:%S %Z %Y"); 626 | goto matched; 627 | 628 | default: 629 | if (str[si] != '%') 630 | fail(); 631 | si++; 632 | if (fi < flen) { 633 | if (si >= slen || str[si] != fmt[fi]) 634 | fail(); 635 | si++; 636 | } 637 | goto matched; 638 | } 639 | default: 640 | ordinal: 641 | if (str[si] != fmt[fi]) 642 | fail(); 643 | si++; 644 | fi++; 645 | break; 646 | matched: 647 | fi++; 648 | break; 649 | } 650 | } 651 | 652 | return si; 653 | } 654 | 655 | VALUE 656 | date__strptime(const char *str, size_t slen, 657 | const char *fmt, size_t flen, VALUE hash) 658 | { 659 | size_t si; 660 | VALUE cent, merid; 661 | 662 | si = date__strptime_internal(str, slen, fmt, flen, hash); 663 | 664 | if (slen > si) { 665 | VALUE s; 666 | 667 | s = rb_usascii_str_new(&str[si], slen - si); 668 | set_hash("leftover", s); 669 | } 670 | 671 | if (fail_p()) 672 | return Qnil; 673 | 674 | cent = del_hash("_cent"); 675 | if (!NIL_P(cent)) { 676 | VALUE year; 677 | 678 | year = ref_hash("cwyear"); 679 | if (!NIL_P(year)) 680 | set_hash("cwyear", f_add(year, f_mul(cent, INT2FIX(100)))); 681 | year = ref_hash("year"); 682 | if (!NIL_P(year)) 683 | set_hash("year", f_add(year, f_mul(cent, INT2FIX(100)))); 684 | } 685 | 686 | merid = del_hash("_merid"); 687 | if (!NIL_P(merid)) { 688 | VALUE hour; 689 | 690 | hour = ref_hash("hour"); 691 | if (!NIL_P(hour)) { 692 | hour = f_mod(hour, INT2FIX(12)); 693 | set_hash("hour", f_add(hour, merid)); 694 | } 695 | } 696 | 697 | return hash; 698 | } 699 | 700 | /* 701 | Local variables: 702 | c-file-style: "ruby" 703 | End: 704 | */ 705 | -------------------------------------------------------------------------------- /ext/date/date_tmx.h: -------------------------------------------------------------------------------- 1 | #ifndef DATE_TMX_H 2 | #define DATE_TMX_H 3 | 4 | struct tmx_funcs { 5 | VALUE (*year)(void *dat); 6 | int (*yday)(void *dat); 7 | int (*mon)(void *dat); 8 | int (*mday)(void *dat); 9 | VALUE (*cwyear)(void *dat); 10 | int (*cweek)(void *dat); 11 | int (*cwday)(void *dat); 12 | int (*wnum0)(void *dat); 13 | int (*wnum1)(void *dat); 14 | int (*wday)(void *dat); 15 | int (*hour)(void *dat); 16 | int (*min)(void *dat); 17 | int (*sec)(void *dat); 18 | VALUE (*sec_fraction)(void *dat); 19 | VALUE (*secs)(void *dat); 20 | VALUE (*msecs)(void *dat); 21 | int (*offset)(void *dat); 22 | char *(*zone)(void *dat); 23 | }; 24 | struct tmx { 25 | void *dat; 26 | const struct tmx_funcs *funcs; 27 | }; 28 | 29 | #define tmx_attr(x) (tmx->funcs->x)(tmx->dat) 30 | 31 | #define tmx_year tmx_attr(year) 32 | #define tmx_yday tmx_attr(yday) 33 | #define tmx_mon tmx_attr(mon) 34 | #define tmx_mday tmx_attr(mday) 35 | #define tmx_cwyear tmx_attr(cwyear) 36 | #define tmx_cweek tmx_attr(cweek) 37 | #define tmx_cwday tmx_attr(cwday) 38 | #define tmx_wnum0 tmx_attr(wnum0) 39 | #define tmx_wnum1 tmx_attr(wnum1) 40 | #define tmx_wday tmx_attr(wday) 41 | #define tmx_hour tmx_attr(hour) 42 | #define tmx_min tmx_attr(min) 43 | #define tmx_sec tmx_attr(sec) 44 | #define tmx_sec_fraction tmx_attr(sec_fraction) 45 | #define tmx_secs tmx_attr(secs) 46 | #define tmx_msecs tmx_attr(msecs) 47 | #define tmx_offset tmx_attr(offset) 48 | #define tmx_zone tmx_attr(zone) 49 | 50 | #endif 51 | 52 | /* 53 | Local variables: 54 | c-file-style: "ruby" 55 | End: 56 | */ 57 | -------------------------------------------------------------------------------- /ext/date/extconf.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require 'mkmf' 3 | 4 | config_string("strict_warnflags") {|w| $warnflags += " #{w}"} 5 | 6 | append_cflags("-Wno-compound-token-split-by-macro") if RUBY_VERSION < "2.7." 7 | have_func("rb_category_warn") 8 | with_werror("", {:werror => true}) do |opt, | 9 | have_var("timezone", "time.h", opt) 10 | have_var("altzone", "time.h", opt) 11 | end 12 | 13 | create_makefile('date_core') 14 | -------------------------------------------------------------------------------- /ext/date/prereq.mk: -------------------------------------------------------------------------------- 1 | .SUFFIXES: .list 2 | 3 | .list.h: 4 | gperf --ignore-case -L ANSI-C -C -c -P -p -j1 -i 1 -g -o -t -N $(*F) $< \ 5 | | sed -f $(top_srcdir)/tool/gperf.sed \ 6 | > $(@F) 7 | 8 | zonetab.h: zonetab.list 9 | 10 | .PHONY: update-zonetab 11 | update-zonetab: 12 | $(RUBY) -C $(srcdir) update-abbr 13 | 14 | .PHONY: update-nothing 15 | update-nothing: 16 | 17 | update = nothing 18 | 19 | zonetab.list: update-$(update) 20 | -------------------------------------------------------------------------------- /ext/date/update-abbr: -------------------------------------------------------------------------------- 1 | # -*- mode: ruby -*- 2 | require 'nokogiri' 3 | require 'open-uri' 4 | 5 | doc = Nokogiri::HTML(URI.open(ARGV[0] || 'https://www.timeanddate.com/time/zones/')) 6 | 7 | h = {} 8 | 9 | doc.css('#tz-abb tbody tr').each do |tr| 10 | tds = tr.css('td') 11 | abbr = tds[0].text.strip.downcase 12 | offset = tds[3].text.strip.gsub(/UTC\s*/, '') 13 | next if offset.include?('/') # skip ambiguous timezones 14 | next if offset.empty? 15 | 16 | 17 | hour, min = offset.split(':', 2) 18 | offset = (Integer(hour) * 60 + (Integer(min || 0)))*60 19 | if h.has_key?(abbr) 20 | h[abbr] = false 21 | else 22 | h[abbr] = offset 23 | end 24 | end 25 | 26 | h.delete_if{|_,v| !v} 27 | 28 | lines = File.readlines('zonetab.list') 29 | lines.map! do |l| 30 | if (sep = /^%%/ =~ l)...(sep = /^%%/ =~ l) and !sep 31 | z, o = l.split(/,\s*/, 2) 32 | o.strip! 33 | if ho = h.delete(z) and ho != eval(o) 34 | warn "offset of #{z}: #{o} -> #{ho}" 35 | l = l.sub(/,\s*\K.*/) { 36 | if o.include?("*") 37 | o1, o2 = ho.abs.divmod(3600) 38 | o1 = "#{o1}*3600" 39 | o1 = "(#{o1}+#{o2})" if o2 != 0 40 | ho < 0 ? "-#{o1}" : o1 41 | else 42 | ho.to_s 43 | end 44 | } 45 | end 46 | end 47 | l 48 | end 49 | 50 | lines.insert(-2, h.sort.map{|k,v| "#{k},#{v}\n"}) 51 | lines.flatten! 52 | File.write('zonetab.list', lines.join) 53 | -------------------------------------------------------------------------------- /ext/date/zonetab.list: -------------------------------------------------------------------------------- 1 | %{ 2 | #define GPERF_DOWNCASE 1 3 | #define GPERF_CASE_STRNCMP 1 4 | #define gperf_case_strncmp strncasecmp 5 | struct zone { 6 | int name; 7 | int offset; 8 | }; 9 | static const struct zone *zonetab(register const char *str, register size_t len); 10 | %} 11 | 12 | struct zone; 13 | %% 14 | ut, 0*3600 15 | gmt, 0*3600 16 | est, -5*3600 17 | edt, -4*3600 18 | cst, -6*3600 19 | cdt, -5*3600 20 | mst, -7*3600 21 | mdt, -6*3600 22 | pst, -8*3600 23 | pdt, -7*3600 24 | a, 1*3600 25 | b, 2*3600 26 | c, 3*3600 27 | d, 4*3600 28 | e, 5*3600 29 | f, 6*3600 30 | g, 7*3600 31 | h, 8*3600 32 | i, 9*3600 33 | k, 10*3600 34 | l, 11*3600 35 | m, 12*3600 36 | n, -1*3600 37 | o, -2*3600 38 | p, -3*3600 39 | q, -4*3600 40 | r, -5*3600 41 | s, -6*3600 42 | t, -7*3600 43 | u, -8*3600 44 | v, -9*3600 45 | w, -10*3600 46 | x, -11*3600 47 | y, -12*3600 48 | z, 0*3600 49 | utc, 0*3600 50 | wet, 0*3600 51 | at, -2*3600 52 | brst,-2*3600 53 | ndt, -(1*3600+1800) 54 | art, -3*3600 55 | adt, -3*3600 56 | brt, -3*3600 57 | clst,-3*3600 58 | nst, -(2*3600+1800) 59 | ast, -4*3600 60 | clt, -4*3600 61 | akdt,-8*3600 62 | ydt, -8*3600 63 | akst,-9*3600 64 | hadt,-9*3600 65 | hdt, -9*3600 66 | yst, -9*3600 67 | ahst,-10*3600 68 | cat,2*3600 69 | hast,-10*3600 70 | hst,-10*3600 71 | nt, -11*3600 72 | idlw,-12*3600 73 | bst, 1*3600 74 | cet, 1*3600 75 | fwt, 1*3600 76 | met, 1*3600 77 | mewt, 1*3600 78 | mez, 1*3600 79 | swt, 1*3600 80 | wat, 1*3600 81 | west, 1*3600 82 | cest, 2*3600 83 | eet, 2*3600 84 | fst, 2*3600 85 | mest, 2*3600 86 | mesz, 2*3600 87 | sast, 2*3600 88 | sst, -11*3600 89 | bt, 3*3600 90 | eat, 3*3600 91 | eest, 3*3600 92 | msk, 3*3600 93 | msd, 4*3600 94 | zp4, 4*3600 95 | zp5, 5*3600 96 | ist, (5*3600+1800) 97 | zp6, 6*3600 98 | wast, 2*3600 99 | cct, (6*3600+1800) 100 | sgt, 8*3600 101 | wadt, 8*3600 102 | jst, 9*3600 103 | kst, 9*3600 104 | east,-6*3600 105 | gst, 10*3600 106 | eadt,11*3600 107 | idle,12*3600 108 | nzst,12*3600 109 | nzt, 12*3600 110 | nzdt,13*3600 111 | afghanistan, 16200 112 | alaskan, -32400 113 | arab, 10800 114 | arabian, 14400 115 | arabic, 10800 116 | atlantic, -14400 117 | aus central, 34200 118 | aus eastern, 36000 119 | azores, -3600 120 | canada central, -21600 121 | cape verde, -3600 122 | caucasus, 14400 123 | cen. australia, 34200 124 | central america, -21600 125 | central asia, 21600 126 | central europe, 3600 127 | central european, 3600 128 | central pacific, 39600 129 | central, -21600 130 | china, 28800 131 | dateline, -43200 132 | e. africa, 10800 133 | e. australia, 36000 134 | e. europe, 7200 135 | e. south america, -10800 136 | eastern, -18000 137 | egypt, 7200 138 | ekaterinburg, 18000 139 | fiji, 43200 140 | fle, 7200 141 | greenland, -10800 142 | greenwich, 0 143 | gtb, 7200 144 | hawaiian, -36000 145 | india, 19800 146 | iran, 12600 147 | jerusalem, 7200 148 | korea, 32400 149 | mexico, -21600 150 | mid-atlantic, -7200 151 | mountain, -25200 152 | myanmar, 23400 153 | n. central asia, 21600 154 | nepal, 20700 155 | new zealand, 43200 156 | newfoundland, -12600 157 | north asia east, 28800 158 | north asia, 25200 159 | pacific sa, -14400 160 | pacific, -28800 161 | romance, 3600 162 | russian, 10800 163 | sa eastern, -10800 164 | sa pacific, -18000 165 | sa western, -14400 166 | samoa, -39600 167 | se asia, 25200 168 | malay peninsula, 28800 169 | south africa, 7200 170 | sri lanka, 21600 171 | taipei, 28800 172 | tasmania, 36000 173 | tokyo, 32400 174 | tonga, 46800 175 | us eastern, -18000 176 | us mountain, -25200 177 | vladivostok, 36000 178 | w. australia, 28800 179 | w. central africa, 3600 180 | w. europe, 3600 181 | west asia, 18000 182 | west pacific, 36000 183 | yakutsk, 32400 184 | acdt,37800 185 | acst,34200 186 | act,-18000 187 | acwst,31500 188 | aedt,39600 189 | aest,36000 190 | aft,16200 191 | almt,21600 192 | anast,43200 193 | anat,43200 194 | aoe,-43200 195 | aqtt,18000 196 | awdt,32400 197 | awst,28800 198 | azost,0 199 | azot,-3600 200 | azst,18000 201 | azt,14400 202 | bnt,28800 203 | bot,-14400 204 | btt,21600 205 | cast,28800 206 | chadt,49500 207 | chast,45900 208 | chost,32400 209 | chot,28800 210 | chst,36000 211 | chut,36000 212 | cidst,-14400 213 | cist,-18000 214 | ckt,-36000 215 | cot,-18000 216 | cvt,-3600 217 | cxt,25200 218 | davt,25200 219 | ddut,36000 220 | easst,-18000 221 | ect,-18000 222 | egst,0 223 | egt,-3600 224 | fet,10800 225 | fjst,46800 226 | fjt,43200 227 | fkst,-10800 228 | fkt,-14400 229 | fnt,-7200 230 | galt,-21600 231 | gamt,-32400 232 | get,14400 233 | gft,-10800 234 | gilt,43200 235 | gyt,-14400 236 | hkt,28800 237 | hovst,28800 238 | hovt,25200 239 | ict,25200 240 | idt,10800 241 | iot,21600 242 | irdt,16200 243 | irkst,32400 244 | irkt,28800 245 | irst,12600 246 | kgt,21600 247 | kost,39600 248 | krast,28800 249 | krat,25200 250 | kuyt,14400 251 | lhdt,39600 252 | lhst,37800 253 | lint,50400 254 | magst,43200 255 | magt,39600 256 | mart,-30600 257 | mawt,18000 258 | mht,43200 259 | mmt,23400 260 | mut,14400 261 | mvt,18000 262 | myt,28800 263 | nct,39600 264 | nfdt,43200 265 | nft,39600 266 | novst,25200 267 | novt,25200 268 | npt,20700 269 | nrt,43200 270 | nut,-39600 271 | omsst,25200 272 | omst,21600 273 | orat,18000 274 | pet,-18000 275 | petst,43200 276 | pett,43200 277 | pgt,36000 278 | phot,46800 279 | pht,28800 280 | pkt,18000 281 | pmdt,-7200 282 | pmst,-10800 283 | pont,39600 284 | pwt,32400 285 | pyst,-10800 286 | qyzt,21600 287 | ret,14400 288 | rott,-10800 289 | sakt,39600 290 | samt,14400 291 | sbt,39600 292 | sct,14400 293 | sret,39600 294 | srt,-10800 295 | syot,10800 296 | taht,-36000 297 | tft,18000 298 | tjt,18000 299 | tkt,46800 300 | tlt,32400 301 | tmt,18000 302 | tost,50400 303 | tot,46800 304 | trt,10800 305 | tvt,43200 306 | ulast,32400 307 | ulat,28800 308 | uyst,-7200 309 | uyt,-10800 310 | uzt,18000 311 | vet,-14400 312 | vlast,39600 313 | vlat,36000 314 | vost,21600 315 | vut,39600 316 | wakt,43200 317 | warst,-10800 318 | wft,43200 319 | wgst,-3600 320 | wgt,-7200 321 | wib,25200 322 | wit,32400 323 | wita,28800 324 | wt,0 325 | yakst,36000 326 | yakt,32400 327 | yapt,36000 328 | yekst,21600 329 | yekt,18000 330 | %% 331 | -------------------------------------------------------------------------------- /lib/date.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | # date.rb: Written by Tadayoshi Funaba 1998-2011 3 | 4 | require 'date_core' 5 | 6 | class Date 7 | VERSION = "3.4.1" # :nodoc: 8 | 9 | # call-seq: 10 | # infinite? -> false 11 | # 12 | # Returns +false+ 13 | def infinite? 14 | false 15 | end 16 | 17 | class Infinity < Numeric # :nodoc: 18 | 19 | def initialize(d=1) @d = d <=> 0 end 20 | 21 | def d() @d end 22 | 23 | protected :d 24 | 25 | def zero?() false end 26 | def finite?() false end 27 | def infinite?() d.nonzero? end 28 | def nan?() d.zero? end 29 | 30 | def abs() self.class.new end 31 | 32 | def -@() self.class.new(-d) end 33 | def +@() self.class.new(+d) end 34 | 35 | def <=>(other) 36 | case other 37 | when Infinity; return d <=> other.d 38 | when Float::INFINITY; return d <=> 1 39 | when -Float::INFINITY; return d <=> -1 40 | when Numeric; return d 41 | else 42 | begin 43 | l, r = other.coerce(self) 44 | return l <=> r 45 | rescue NoMethodError 46 | end 47 | end 48 | nil 49 | end 50 | 51 | def coerce(other) 52 | case other 53 | when Numeric; return -d, d 54 | else 55 | super 56 | end 57 | end 58 | 59 | def to_f 60 | return 0 if @d == 0 61 | if @d > 0 62 | Float::INFINITY 63 | else 64 | -Float::INFINITY 65 | end 66 | end 67 | 68 | end 69 | 70 | end 71 | -------------------------------------------------------------------------------- /rakelib/epoch.rake: -------------------------------------------------------------------------------- 1 | task "build" => "date_epoch" 2 | 3 | task "date_epoch" do 4 | ENV["SOURCE_DATE_EPOCH"] = IO.popen(%W[git -C #{__dir__} log -1 --format=%ct], &:read).chomp 5 | end 6 | -------------------------------------------------------------------------------- /rakelib/version.rake: -------------------------------------------------------------------------------- 1 | class << (helper = Bundler::GemHelper.instance) 2 | def mainfile 3 | "lib/#{File.basename(gemspec.loaded_from, ".gemspec")}.rb" 4 | end 5 | 6 | def update_version 7 | File.open(mainfile, "r+b") do |f| 8 | d = f.read 9 | if d.sub!(/^(\s*VERSION\s*=\s*)(['"']).*?\2/) {$1 + gemspec.version.to_s.dump} 10 | f.rewind 11 | f.truncate(0) 12 | f.print(d) 13 | end 14 | end 15 | end 16 | 17 | def commit_bump 18 | sh(%W[git -C #{File.dirname(gemspec.loaded_from)} commit -m bump\ up\ to\ #{gemspec.version} 19 | #{mainfile}]) 20 | end 21 | 22 | def version=(v) 23 | gemspec.version = v 24 | update_version 25 | commit_bump 26 | end 27 | end 28 | 29 | major, minor, teeny = helper.gemspec.version.segments 30 | 31 | task "bump:teeny" do 32 | helper.version = Gem::Version.new("#{major}.#{minor}.#{teeny+1}") 33 | end 34 | 35 | task "bump:minor" do 36 | helper.version = Gem::Version.new("#{major}.#{minor+1}.0") 37 | end 38 | 39 | task "bump:major" do 40 | helper.version = Gem::Version.new("#{major+1}.0.0") 41 | end 42 | 43 | task "bump" => "bump:teeny" 44 | 45 | task "tag" do 46 | helper.__send__(:tag_version) 47 | end 48 | -------------------------------------------------------------------------------- /test/date/test_date.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require 'test/unit' 3 | require 'date' 4 | 5 | class DateSub < Date; end 6 | class DateTimeSub < DateTime; end 7 | 8 | class TestDate < Test::Unit::TestCase 9 | def test_range_infinite_float 10 | today = Date.today 11 | r = today...Float::INFINITY 12 | assert_equal today, r.begin 13 | assert_equal Float::INFINITY, r.end 14 | assert_equal true, r.cover?(today+1) 15 | assert_equal false, r.cover?(today-1) 16 | r = (-Float::INFINITY)...today 17 | assert_equal(-Float::INFINITY, r.begin) 18 | assert_equal today, r.end 19 | assert_equal false, r.cover?(today+1) 20 | assert_equal true, r.cover?(today-1) 21 | end 22 | 23 | def test__const 24 | assert_nil(Date::MONTHNAMES[0]) 25 | assert_equal('January', Date::MONTHNAMES[1]) 26 | assert_equal(13, Date::MONTHNAMES.size) 27 | assert_equal('Sunday', Date::DAYNAMES[0]) 28 | assert_equal(7, Date::DAYNAMES.size) 29 | 30 | assert_nil(Date::ABBR_MONTHNAMES[0]) 31 | assert_equal('Jan', Date::ABBR_MONTHNAMES[1]) 32 | assert_equal(13, Date::ABBR_MONTHNAMES.size) 33 | assert_equal('Sun', Date::ABBR_DAYNAMES[0]) 34 | assert_equal(7, Date::ABBR_DAYNAMES.size) 35 | 36 | assert(Date::MONTHNAMES.frozen?) 37 | assert(Date::MONTHNAMES[1].frozen?) 38 | assert(Date::DAYNAMES.frozen?) 39 | assert(Date::DAYNAMES[0].frozen?) 40 | 41 | assert(Date::ABBR_MONTHNAMES.frozen?) 42 | assert(Date::ABBR_MONTHNAMES[1].frozen?) 43 | assert(Date::ABBR_DAYNAMES.frozen?) 44 | assert(Date::ABBR_DAYNAMES[0].frozen?) 45 | end 46 | 47 | def test_sub 48 | d = DateSub.new 49 | dt = DateTimeSub.new 50 | 51 | assert_instance_of(DateSub, d) 52 | assert_instance_of(DateTimeSub, dt) 53 | 54 | assert_instance_of(DateSub, DateSub.today) 55 | assert_instance_of(DateTimeSub, DateTimeSub.now) 56 | 57 | assert_equal('-4712-01-01', d.to_s) 58 | assert_equal('-4712-01-01T00:00:00+00:00', dt.to_s) 59 | 60 | d2 = d + 1 61 | assert_instance_of(DateSub, d2) 62 | d2 = d - 1 63 | assert_instance_of(DateSub, d2) 64 | d2 = d >> 1 65 | assert_instance_of(DateSub, d2) 66 | d2 = d << 1 67 | assert_instance_of(DateSub, d2) 68 | d2 = d.succ 69 | assert_instance_of(DateSub, d2) 70 | d2 = d.next 71 | assert_instance_of(DateSub, d2) 72 | d2 = d.italy 73 | assert_instance_of(DateSub, d2) 74 | d2 = d.england 75 | assert_instance_of(DateSub, d2) 76 | d2 = d.julian 77 | assert_instance_of(DateSub, d2) 78 | d2 = d.gregorian 79 | assert_instance_of(DateSub, d2) 80 | s = Marshal.dump(d) 81 | d2 = Marshal.load(s) 82 | assert_equal(d2, d) 83 | assert_instance_of(DateSub, d2) 84 | 85 | dt2 = dt + 1 86 | assert_instance_of(DateTimeSub, dt2) 87 | dt2 = dt - 1 88 | assert_instance_of(DateTimeSub, dt2) 89 | dt2 = dt >> 1 90 | assert_instance_of(DateTimeSub, dt2) 91 | dt2 = dt << 1 92 | assert_instance_of(DateTimeSub, dt2) 93 | dt2 = dt.succ 94 | assert_instance_of(DateTimeSub, dt2) 95 | dt2 = dt.next 96 | assert_instance_of(DateTimeSub, dt2) 97 | dt2 = dt.italy 98 | assert_instance_of(DateTimeSub, dt2) 99 | dt2 = dt.england 100 | assert_instance_of(DateTimeSub, dt2) 101 | dt2 = dt.julian 102 | assert_instance_of(DateTimeSub, dt2) 103 | dt2 = dt.gregorian 104 | assert_instance_of(DateTimeSub, dt2) 105 | s = Marshal.dump(dt) 106 | dt2 = Marshal.load(s) 107 | assert_equal(dt2, dt) 108 | assert_instance_of(DateTimeSub, dt2) 109 | end 110 | 111 | def test_eql_p 112 | d = Date.jd(0) 113 | d2 = Date.jd(0) 114 | dt = DateTime.jd(0) 115 | dt2 = DateTime.jd(0) 116 | 117 | assert_equal(d, d2) 118 | assert_not_equal(d, 0) 119 | 120 | assert_equal(dt, dt2) 121 | assert_not_equal(dt, 0) 122 | 123 | assert_equal(d, dt) 124 | assert_equal(d2, dt2) 125 | end 126 | 127 | def test_hash 128 | h = {} 129 | h[Date.new(1999,5,23)] = 0 130 | h[Date.new(1999,5,24)] = 1 131 | h[Date.new(1999,5,25)] = 2 132 | h[Date.new(1999,5,25)] = 9 133 | assert_equal(3, h.size) 134 | assert_equal(9, h[Date.new(1999,5,25)]) 135 | assert_equal(9, h[DateTime.new(1999,5,25)]) 136 | 137 | h = {} 138 | h[DateTime.new(1999,5,23)] = 0 139 | h[DateTime.new(1999,5,24)] = 1 140 | h[DateTime.new(1999,5,25)] = 2 141 | h[DateTime.new(1999,5,25)] = 9 142 | assert_equal(3, h.size) 143 | assert_equal(9, h[Date.new(1999,5,25)]) 144 | assert_equal(9, h[DateTime.new(1999,5,25)]) 145 | 146 | assert_instance_of(String, Date.new(1999,5,25).hash.to_s) 147 | end 148 | 149 | def test_freeze 150 | d = Date.new 151 | d.freeze 152 | assert_equal(true, d.frozen?) 153 | assert_instance_of(Integer, d.yday) 154 | assert_instance_of(String, d.to_s) 155 | end 156 | 157 | def test_submillisecond_comparison 158 | d1 = DateTime.new(2013, 12, 6, 0, 0, Rational(1, 10000)) 159 | d2 = DateTime.new(2013, 12, 6, 0, 0, Rational(2, 10000)) 160 | # d1 is 0.0001s earlier than d2 161 | assert_equal(-1, d1 <=> d2) 162 | assert_equal(0, d1 <=> d1) 163 | assert_equal(1, d2 <=> d1) 164 | end 165 | 166 | def test_infinity_comparison 167 | assert_equal(0, Float::INFINITY <=> Date::Infinity.new) 168 | assert_equal(0, Date::Infinity.new <=> Float::INFINITY) 169 | assert_equal(0, -Float::INFINITY <=> -Date::Infinity.new) 170 | assert_equal(0, -Date::Infinity.new <=> -Float::INFINITY) 171 | 172 | assert_equal(1, Float::INFINITY <=> -Date::Infinity.new) 173 | assert_equal(1, Date::Infinity.new <=> -Float::INFINITY) 174 | 175 | assert_equal(-1, -Float::INFINITY <=> Date::Infinity.new) 176 | assert_equal(-1, -Date::Infinity.new <=> Float::INFINITY) 177 | end 178 | 179 | def test_deconstruct_keys 180 | d = Date.new(1999,5,23) 181 | assert_equal({year: 1999, month: 5, day: 23, wday: 0, yday: 143}, d.deconstruct_keys(nil)) 182 | assert_equal({year: 1999}, d.deconstruct_keys([:year, :century])) 183 | assert_equal( 184 | {year: 1999, month: 5, day: 23, wday: 0, yday: 143}, 185 | d.deconstruct_keys([:year, :month, :day, :wday, :yday]) 186 | ) 187 | 188 | dt = DateTime.new(1999, 5, 23, 4, 20, Rational(1, 10000)) 189 | 190 | assert_equal( 191 | {year: 1999, month: 5, day: 23, wday: 0, yday: 143, 192 | hour: 4, min: 20, sec: 0, sec_fraction: Rational(1, 10000), zone: "+00:00"}, 193 | dt.deconstruct_keys(nil) 194 | ) 195 | 196 | assert_equal({year: 1999}, dt.deconstruct_keys([:year, :century])) 197 | 198 | assert_equal( 199 | {year: 1999, month: 5, day: 23, wday: 0, yday: 143, 200 | hour: 4, min: 20, sec: 0, sec_fraction: Rational(1, 10000), zone: "+00:00"}, 201 | dt.deconstruct_keys([:year, :month, :day, :wday, :yday, :hour, :min, :sec, :sec_fraction, :zone]) 202 | ) 203 | 204 | dtz = DateTime.parse('3rd Feb 2001 04:05:06+03:30') 205 | assert_equal({zone: '+03:30'}, dtz.deconstruct_keys([:zone])) 206 | end 207 | end 208 | -------------------------------------------------------------------------------- /test/date/test_date_arith.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require 'test/unit' 3 | require 'date' 4 | 5 | class TestDateArith < Test::Unit::TestCase 6 | class Rat < Numeric 7 | def to_r; self; end 8 | end 9 | 10 | def test_new_offset 11 | d = DateTime.new(2002, 3, 14) 12 | assert_equal(Rational(9, 24), d.new_offset(Rational(9, 24)).offset) 13 | assert_equal(Rational(9, 24), d.new_offset('+0900').offset) 14 | n = Rat.new 15 | assert_raise(TypeError) do 16 | Timeout.timeout(1) {d.new_offset(n)} 17 | end 18 | end 19 | 20 | def test__plus 21 | d = Date.new(2000,2,29) + -1 22 | assert_equal([2000, 2, 28], [d.year, d.mon, d.mday]) 23 | d = Date.new(2000,2,29) + 0 24 | assert_equal([2000, 2, 29], [d.year, d.mon, d.mday]) 25 | d = Date.new(2000,2,29) + 1 26 | assert_equal([2000, 3, 1], [d.year, d.mon, d.mday]) 27 | 28 | d = DateTime.new(2000,2,29) + 1.to_r/2 29 | assert_equal([2000, 2, 29, 12, 0, 0], 30 | [d.year, d.mon, d.mday, d.hour, d.min, d.sec]) 31 | end 32 | 33 | def test__plus__ex 34 | e = TypeError 35 | assert_raise(e) do 36 | Date.new(2000,2,29) + 'foo' 37 | end 38 | assert_raise(e) do 39 | DateTime.new(2000,2,29) + 'foo' 40 | end 41 | assert_raise(e) do 42 | Date.new(2000,2,29) + Time.mktime(2000,2,29) 43 | end 44 | assert_raise(e) do 45 | DateTime.new(2000,2,29) + Time.mktime(2000,2,29) 46 | end 47 | n = Rat.new 48 | assert_raise(e) do 49 | Timeout.timeout(1) {Date.new(2000,2,29) + n} 50 | end 51 | assert_raise(e) do 52 | Timeout.timeout(1) {DateTime.new(2000,2,29) + n} 53 | end 54 | end 55 | 56 | def test__minus 57 | d = Date.new(2000,3,1) - -1 58 | assert_equal([2000, 3, 2], [d.year, d.mon, d.mday]) 59 | d = Date.new(2000,3,1) - 0 60 | assert_equal([2000, 3, 1], [d.year, d.mon, d.mday]) 61 | d = Date.new(2000,3,1) - 1 62 | assert_equal([2000, 2, 29], [d.year, d.mon, d.mday]) 63 | 64 | d = Date.new(2000,3,1) - Date.new(2000,2,29) 65 | assert_equal(1, d) 66 | d = Date.new(2000,2,29) - Date.new(2000,3,1) 67 | assert_equal(-1, d) 68 | 69 | d = DateTime.new(2000,3,1) - 1.to_r/2 70 | assert_equal([2000, 2, 29, 12, 0, 0], 71 | [d.year, d.mon, d.mday, d.hour, d.min, d.sec]) 72 | end 73 | 74 | def test__minus__ex 75 | e = TypeError 76 | assert_raise(e) do 77 | Date.new(2000,2,29) - 'foo' 78 | end 79 | assert_raise(e) do 80 | DateTime.new(2000,2,29) - 'foo' 81 | end 82 | assert_raise(e) do 83 | Date.new(2000,2,29) - Time.mktime(2000,2,29) 84 | end 85 | assert_raise(e) do 86 | DateTime.new(2000,2,29) - Time.mktime(2000,2,29) 87 | end 88 | end 89 | 90 | def test__compare 91 | assert_equal(0, (Date.new(2000,1,1) <=> Date.new(2000,1,1))) 92 | assert_equal(-1, (Date.new(2000,1,1) <=> Date.new(2000,1,2))) 93 | assert_equal(1, (Date.new(2000,1,2) <=> Date.new(2000,1,1))) 94 | assert_equal(0, (Date.new(2001,1,4,Date::JULIAN) <=> 95 | Date.new(2001,1,17, Date::GREGORIAN))) 96 | assert_equal(0, (DateTime.new(2001,1,4,0,0,0,0,Date::JULIAN) <=> 97 | DateTime.new(2001,1,17,0,0,0,0,Date::GREGORIAN))) 98 | end 99 | 100 | def test_prev 101 | d = Date.new(2000,1,1) 102 | assert_raise(NoMethodError) do 103 | d.prev 104 | end 105 | end 106 | 107 | def test_prev_day 108 | d = Date.new(2001,1,1).prev_day 109 | assert_equal([2000, 12, 31], [d.year, d.mon, d.mday]) 110 | d = Date.new(2001,1,1).prev_day(2) 111 | assert_equal([2000, 12, 30], [d.year, d.mon, d.mday]) 112 | d = Date.new(2000,12,31).prev_day(-2) 113 | assert_equal([2001, 1, 2], [d.year, d.mon, d.mday]) 114 | 115 | d = DateTime.new(2000,3,1).prev_day(1.to_r/2) 116 | assert_equal([2000, 2, 29, 12, 0, 0], [d.year, d.mon, d.mday, d.hour, d.min, d.sec]) 117 | end 118 | 119 | def test_prev_month 120 | d = Date.new(2000,1,31) << -1 121 | assert_equal([2000, 2, 29], [d.year, d.mon, d.mday]) 122 | d = Date.new(2000,1,31) << 1 123 | assert_equal([1999, 12, 31], [d.year, d.mon, d.mday]) 124 | d = Date.new(2000,1,31) << 12 125 | assert_equal([1999, 1, 31], [d.year, d.mon, d.mday]) 126 | d = Date.new(2000,1,31) << 14 127 | assert_equal([1998, 11, 30], [d.year, d.mon, d.mday]) 128 | 129 | end 130 | 131 | def test_prev_month__2 132 | d = Date.new(2000,1,31).prev_month(-1) 133 | assert_equal([2000, 2, 29], [d.year, d.mon, d.mday]) 134 | d = Date.new(2000,1,31).prev_month 135 | assert_equal([1999, 12, 31], [d.year, d.mon, d.mday]) 136 | d = Date.new(2000,1,31).prev_month(12) 137 | assert_equal([1999, 1, 31], [d.year, d.mon, d.mday]) 138 | d = Date.new(2000,1,31).prev_month(14) 139 | assert_equal([1998, 11, 30], [d.year, d.mon, d.mday]) 140 | end 141 | 142 | def test_prev_year 143 | d = Date.new(2000,1,31).prev_year(-1) 144 | assert_equal([2001, 1, 31], [d.year, d.mon, d.mday]) 145 | d = Date.new(2000,1,31).prev_year 146 | assert_equal([1999, 1, 31], [d.year, d.mon, d.mday]) 147 | d = Date.new(2000,1,31).prev_year(10) 148 | assert_equal([1990, 1, 31], [d.year, d.mon, d.mday]) 149 | d = Date.new(2000,1,31).prev_year(100) 150 | assert_equal([1900, 1, 31], [d.year, d.mon, d.mday]) 151 | end 152 | 153 | def test_next 154 | d = Date.new(2000,12,31).next 155 | assert_equal([2001, 1, 1], [d.year, d.mon, d.mday]) 156 | d = Date.new(2000,12,31).succ 157 | assert_equal([2001, 1, 1], [d.year, d.mon, d.mday]) 158 | 159 | d = Date.today 160 | d2 = d.next 161 | assert_equal(d, (d2 - 1)) 162 | d = Date.today 163 | d2 = d.succ 164 | assert_equal(d, (d2 - 1)) 165 | 166 | d = DateTime.now 167 | d2 = d.next 168 | assert_equal(d, (d2 - 1)) 169 | d = DateTime.now 170 | d2 = d.succ 171 | assert_equal(d, (d2 - 1)) 172 | end 173 | 174 | def test_next_day 175 | d = Date.new(2000,12,31).next_day 176 | assert_equal([2001, 1, 1], [d.year, d.mon, d.mday]) 177 | d = Date.new(2000,12,31).next_day(2) 178 | assert_equal([2001, 1, 2], [d.year, d.mon, d.mday]) 179 | d = Date.new(2001,1,1).next_day(-2) 180 | assert_equal([2000, 12, 30], [d.year, d.mon, d.mday]) 181 | 182 | d = DateTime.new(2000,2,29).next_day(1.to_r/2) 183 | assert_equal([2000, 2, 29, 12, 0, 0], [d.year, d.mon, d.mday, d.hour, d.min, d.sec]) 184 | end 185 | 186 | def test_next_month 187 | d = Date.new(2000,1,31) >> -1 188 | assert_equal([1999, 12, 31], [d.year, d.mon, d.mday]) 189 | d = Date.new(2000,1,31) >> 1 190 | assert_equal([2000, 2, 29], [d.year, d.mon, d.mday]) 191 | d = Date.new(2000,1,31) >> 12 192 | assert_equal([2001, 1, 31], [d.year, d.mon, d.mday]) 193 | d = Date.new(2000,1,31) >> 13 194 | assert_equal([2001, 2, 28], [d.year, d.mon, d.mday]) 195 | end 196 | 197 | def test_next_month__2 198 | d = Date.new(2000,1,31).next_month(-1) 199 | assert_equal([1999, 12, 31], [d.year, d.mon, d.mday]) 200 | d = Date.new(2000,1,31).next_month 201 | assert_equal([2000, 2, 29], [d.year, d.mon, d.mday]) 202 | d = Date.new(2000,1,31).next_month(12) 203 | assert_equal([2001, 1, 31], [d.year, d.mon, d.mday]) 204 | d = Date.new(2000,1,31).next_month(13) 205 | assert_equal([2001, 2, 28], [d.year, d.mon, d.mday]) 206 | end 207 | 208 | def test_next_year 209 | d = Date.new(2000,1,31).next_year(-1) 210 | assert_equal([1999, 1, 31], [d.year, d.mon, d.mday]) 211 | d = Date.new(2000,1,31).next_year 212 | assert_equal([2001, 1, 31], [d.year, d.mon, d.mday]) 213 | d = Date.new(2000,1,31).next_year(10) 214 | assert_equal([2010, 1, 31], [d.year, d.mon, d.mday]) 215 | d = Date.new(2000,1,31).next_year(100) 216 | assert_equal([2100, 1, 31], [d.year, d.mon, d.mday]) 217 | end 218 | 219 | def test_downto 220 | p = Date.new(2001,1,14) 221 | q = Date.new(2001,1,7) 222 | i = 0 223 | p.downto(q) do 224 | i += 1 225 | end 226 | assert_equal(8, i) 227 | end 228 | 229 | def test_downto__noblock 230 | p = Date.new(2001,1,14) 231 | q = Date.new(2001,1,7) 232 | e = p.downto(q) 233 | assert_equal(8, e.to_a.size) 234 | end 235 | 236 | def test_upto 237 | p = Date.new(2001,1,14) 238 | q = Date.new(2001,1,21) 239 | i = 0 240 | p.upto(q) do 241 | i += 1 242 | end 243 | assert_equal(8, i) 244 | end 245 | 246 | def test_upto__noblock 247 | p = Date.new(2001,1,14) 248 | q = Date.new(2001,1,21) 249 | e = p.upto(q) 250 | assert_equal(8, e.to_a.size) 251 | end 252 | 253 | def test_step 254 | p = Date.new(2001,1,14) 255 | q = Date.new(2001,1,21) 256 | i = 0 257 | p.step(q, 2) do 258 | i += 1 259 | end 260 | assert_equal(4, i) 261 | 262 | i = 0 263 | p.step(q) do 264 | i += 1 265 | end 266 | assert_equal(8, i) 267 | end 268 | 269 | def test_step__noblock 270 | p = Date.new(2001,1,14) 271 | q = Date.new(2001,1,21) 272 | e = p.step(q, 2) 273 | assert_equal(4, e.to_a.size) 274 | 275 | e = p.step(q) 276 | assert_equal(8, e.to_a.size) 277 | end 278 | 279 | def test_step__compare 280 | p = Date.new(2000, 1, 1) 281 | q = Date.new(1999, 12, 31) 282 | o = Object.new 283 | def o.<=>(*);end 284 | assert_raise(ArgumentError) { 285 | p.step(q, o).to_a 286 | } 287 | 288 | o = Object.new 289 | def o.<=>(*);2;end 290 | a = [] 291 | p.step(q, o) {|d| a << d} 292 | assert_empty(a) 293 | end 294 | end 295 | -------------------------------------------------------------------------------- /test/date/test_date_attr.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require 'test/unit' 3 | require 'date' 4 | 5 | class TestDateAttr < Test::Unit::TestCase 6 | 7 | def test__attr 8 | date = Date.new(1965, 5, 23) 9 | datetime = DateTime.new(1965, 5, 23, 22, 31, 59) 10 | 11 | [date, datetime].each_with_index do |d, i| 12 | 13 | if i == 0 14 | assert_equal('1965-05-23', d.to_s) 15 | else 16 | assert_equal('1965-05-23T22:31:59+00:00', d.to_s) 17 | end 18 | 19 | assert_equal('', d.inspect.gsub!(/./,'')) 20 | assert_equal('', d.to_s.gsub!(/./,'')) 21 | 22 | assert_equal(2438904, d.jd) 23 | 24 | if i == 0 25 | assert_equal(0, d.day_fraction) 26 | else 27 | assert_equal(22.to_r/24 + 31.to_r/1440 + 59.to_r/86400, d.day_fraction) 28 | end 29 | 30 | assert_equal(38903, d.mjd) 31 | assert_equal(139744, d.ld) 32 | 33 | assert_equal(1965, d.year) 34 | assert_equal(143, d.yday) 35 | assert_equal(5, d.mon) 36 | assert_equal(d.mon, d.month) 37 | assert_equal(23, d.mday) 38 | assert_equal(d.mday, d.day) 39 | 40 | if i == 0 41 | assert_equal(false, d.respond_to?(:hour)) 42 | assert_equal(false, d.respond_to?(:min)) 43 | assert_equal(false, d.respond_to?(:sec)) 44 | assert_equal(false, d.respond_to?(:sec_fraction)) 45 | assert_equal(false, d.respond_to?(:zone)) 46 | assert_equal(false, d.respond_to?(:offset)) 47 | else 48 | assert_equal(22, d.hour) 49 | assert_equal(31, d.min) 50 | assert_equal(59, d.sec) 51 | assert_equal(0, d.sec_fraction) 52 | assert_equal('+00:00', d.zone) 53 | assert_equal(0, d.offset) 54 | end 55 | 56 | assert_equal(1965, d.cwyear) 57 | assert_equal(20, d.cweek) 58 | assert_equal(7, d.cwday) 59 | 60 | assert_equal(0, d.wday) 61 | assert_equal(false, d.leap?) 62 | assert_equal(false, d.julian?) 63 | assert_equal(true, d.gregorian?) 64 | 65 | assert_equal(Date::ITALY, d.start) 66 | assert_equal(d.start, d.start) 67 | end 68 | 69 | d = DateTime.new(1965, 5, 23, 22, 31, 59) + 1.to_r/(86400*2) 70 | assert_equal(1.to_r/2, d.sec_fraction) 71 | end 72 | 73 | def test__wday_predicate 74 | d = Date.new(2005, 10, 23) 75 | assert_equal(true, d.sunday?) 76 | assert_equal(false, d.monday?) 77 | assert_equal(false, d.tuesday?) 78 | assert_equal(false, d.wednesday?) 79 | assert_equal(false, d.thursday?) 80 | assert_equal(false, d.friday?) 81 | assert_equal(false, d.saturday?) 82 | 83 | d = Date.new(2005, 10, 30) 84 | 14.times do |i| 85 | assert((d + i).__send__(%w(sunday? monday? tuesday? wednesday? 86 | thursday? friday? saturday?)[i % 7])) 87 | end 88 | end 89 | 90 | def test_nth_kday 91 | assert_equal(false, Date.new(2001,1,14).nth_kday?(1,0)) 92 | assert_equal(true, Date.new(2001,1,14).nth_kday?(2,0)) 93 | assert_equal(false, Date.new(2001,1,14).nth_kday?(3,0)) 94 | assert_equal(false, Date.new(2001,1,14).nth_kday?(4,0)) 95 | assert_equal(false, Date.new(2001,1,14).nth_kday?(5,0)) 96 | assert_equal(false, Date.new(2001,1,14).nth_kday?(-1,0)) 97 | assert_equal(false, Date.new(2001,1,14).nth_kday?(-2,0)) 98 | assert_equal(true, Date.new(2001,1,14).nth_kday?(-3,0)) 99 | assert_equal(false, Date.new(2001,1,14).nth_kday?(-4,0)) 100 | assert_equal(false, Date.new(2001,1,14).nth_kday?(-5,0)) 101 | end if Date.new.respond_to?(:nth_kday?, true) 102 | 103 | end 104 | -------------------------------------------------------------------------------- /test/date/test_date_compat.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require 'test/unit' 3 | require 'date' 4 | 5 | class TestDateCompat < Test::Unit::TestCase 6 | 7 | def test_compat 8 | assert_equal(DateTime.new, Date.new) 9 | assert_equal(DateTime.new(2002,3,19), Date.new(2002,3,19)) 10 | assert_equal(DateTime.new(2002,3,19, 0,0,0), Date.new(2002,3,19)) 11 | assert_equal(DateTime.new(2002,3,19, 0,0,0, 0), Date.new(2002,3,19)) 12 | assert_equal(DateTime.new(2002,3,19, 0,0,0, 0.to_r), Date.new(2002,3,19)) 13 | assert_equal(DateTime.new(2002,3,19, 0,0,0, 0, Date::GREGORIAN), Date.new(2002,3,19, Date::GREGORIAN)) 14 | assert_equal(DateTime.new(2002,3,19, 0,0,0, 0, Date::JULIAN), Date.new(2002,3,19, Date::JULIAN)) 15 | 16 | assert(Date.new(2002,3,19) != DateTime.new(2002,3,19, 12,0,0)) 17 | assert(Date.new(2002,3,19) != DateTime.new(2002,3,19, 0,0,1)) 18 | assert(Date.new(2002,3,19) === DateTime.new(2002,3,19, 12,0,0)) 19 | assert(Date.new(2002,3,19) === DateTime.new(2002,3,19, 0,0,1)) 20 | end 21 | 22 | end 23 | -------------------------------------------------------------------------------- /test/date/test_date_conv.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require 'test/unit' 3 | require 'date' 4 | 5 | class TestDateConv < Test::Unit::TestCase 6 | def with_tz(tz) 7 | old = ENV["TZ"] 8 | begin 9 | ENV["TZ"] = tz 10 | yield 11 | ensure 12 | ENV["TZ"] = old 13 | end 14 | end 15 | 16 | def test_to_class 17 | [Time.now, Date.today, DateTime.now].each do |o| 18 | assert_instance_of(Time, o.to_time) 19 | assert_instance_of(Date, o.to_date) 20 | assert_instance_of(DateTime, o.to_datetime) 21 | end 22 | end 23 | 24 | def test_to_time__from_time 25 | t = Time.mktime(2004, 9, 19, 1, 2, 3, 456789) 26 | t2 = t.to_time 27 | assert_equal([2004, 9, 19, 1, 2, 3, 456789], 28 | [t2.year, t2.mon, t2.mday, t2.hour, t2.min, t2.sec, t2.usec]) 29 | 30 | t = Time.utc(2004, 9, 19, 1, 2, 3, 456789) 31 | t2 = t.to_time.utc 32 | assert_equal([2004, 9, 19, 1, 2, 3, 456789], 33 | [t2.year, t2.mon, t2.mday, t2.hour, t2.min, t2.sec, t2.usec]) 34 | 35 | t = Time.new(2004, 9, 19, 1, 2, 3, '+03:00') 36 | with_tz('Asia/Tokyo') do 37 | t2 = t.to_time 38 | assert_equal([2004, 9, 19, 1, 2, 3], 39 | [t2.year, t2.mon, t2.mday, t2.hour, t2.min, t2.sec]) 40 | assert_equal(3 * 60 * 60, t2.gmt_offset) 41 | end 42 | end 43 | 44 | def test_to_time__from_date 45 | d = Date.new(2004, 9, 19) 46 | t = d.to_time 47 | assert_equal([2004, 9, 19, 0, 0, 0, 0], 48 | [t.year, t.mon, t.mday, t.hour, t.min, t.sec, t.usec]) 49 | end 50 | 51 | def test_to_time_to_date_roundtrip__from_gregorian_date 52 | d = Date.new(1582, 10, 15) 53 | t = d.to_time 54 | assert_equal([1582, 10, 15, 0, 0, 0, 0], 55 | [t.year, t.mon, t.mday, t.hour, t.min, t.sec, t.usec]) 56 | assert_equal(d, t.to_date) 57 | assert_equal(d.jd, t.to_date.jd) 58 | end 59 | 60 | def test_to_time_to_date_roundtrip__from_julian_date 61 | d = Date.new(1582, 10, 4) 62 | t = d.to_time 63 | assert_equal([1582, 10, 14, 0, 0, 0, 0], 64 | [t.year, t.mon, t.mday, t.hour, t.min, t.sec, t.usec]) 65 | assert_equal(d, t.to_date) 66 | assert_equal(d.jd, t.to_date.jd) 67 | end 68 | 69 | def test_to_time__from_datetime 70 | d = DateTime.new(2004, 9, 19, 1, 2, 3, 8.to_r/24) + 456789.to_r/86400000000 71 | t = d.to_time 72 | assert_equal([2004, 9, 19, 1, 2, 3, 456789, 8*60*60], 73 | [t.year, t.mon, t.mday, t.hour, t.min, t.sec, t.usec, t.utc_offset]) 74 | 75 | d = DateTime.new(2004, 9, 19, 1, 2, 3, 0) + 456789.to_r/86400000000 76 | t = d.to_time.utc 77 | assert_equal([2004, 9, 19, 1, 2, 3, 456789], 78 | [t.year, t.mon, t.mday, t.hour, t.min, t.sec, t.usec]) 79 | 80 | d = DateTime.new(1582, 10, 3, 1, 2, 3, 0) + 456789.to_r/86400000000 81 | t = d.to_time.utc 82 | assert_equal([1582, 10, 13, 1, 2, 3, 456789], 83 | [t.year, t.mon, t.mday, t.hour, t.min, t.sec, t.usec]) 84 | 85 | if Time.allocate.respond_to?(:nsec) 86 | d = DateTime.new(2004, 9, 19, 1, 2, 3, 0) + 456789123.to_r/86400000000000 87 | t = d.to_time.utc 88 | assert_equal([2004, 9, 19, 1, 2, 3, 456789123], 89 | [t.year, t.mon, t.mday, t.hour, t.min, t.sec, t.nsec]) 90 | end 91 | 92 | # TruffleRuby does not support more than nanoseconds 93 | unless RUBY_ENGINE == 'truffleruby' 94 | if Time.allocate.respond_to?(:subsec) 95 | d = DateTime.new(2004, 9, 19, 1, 2, 3, 0) + 456789123456789123.to_r/86400000000000000000000 96 | t = d.to_time.utc 97 | assert_equal([2004, 9, 19, 1, 2, 3, Rational(456789123456789123,1000000000000000000)], 98 | [t.year, t.mon, t.mday, t.hour, t.min, t.sec, t.subsec]) 99 | end 100 | end 101 | end 102 | 103 | def test_to_date__from_time 104 | t = Time.mktime(2004, 9, 19, 1, 2, 3, 456789) 105 | d = t.to_date 106 | assert_equal([2004, 9, 19, 0], [d.year, d.mon, d.mday, d.day_fraction]) 107 | 108 | t = Time.utc(2004, 9, 19, 1, 2, 3, 456789) 109 | d = t.to_date 110 | assert_equal([2004, 9, 19, 0], [d.year, d.mon, d.mday, d.day_fraction]) 111 | 112 | t = Time.utc(1582, 10, 13, 1, 2, 3, 456789) 113 | d = t.to_date # using ITALY 114 | assert_equal([1582, 10, 3, 0], [d.year, d.mon, d.mday, d.day_fraction]) 115 | end 116 | 117 | def test_to_date__from_date 118 | d = Date.new(2004, 9, 19) + 1.to_r/2 119 | d2 = d.to_date 120 | assert_equal([2004, 9, 19, 1.to_r/2], 121 | [d2.year, d2.mon, d2.mday, d2.day_fraction]) 122 | end 123 | 124 | def test_to_date__from_datetime 125 | d = DateTime.new(2004, 9, 19, 1, 2, 3, 9.to_r/24) + 456789.to_r/86400000000 126 | d2 = d.to_date 127 | assert_equal([2004, 9, 19, 0], [d2.year, d2.mon, d2.mday, d2.day_fraction]) 128 | 129 | d = DateTime.new(2004, 9, 19, 1, 2, 3, 0) + 456789.to_r/86400000000 130 | d2 = d.to_date 131 | assert_equal([2004, 9, 19, 0], [d2.year, d2.mon, d2.mday, d2.day_fraction]) 132 | end 133 | 134 | def test_to_datetime__from_time 135 | t = Time.mktime(2004, 9, 19, 1, 2, 3, 456789) 136 | d = t.to_datetime 137 | assert_equal([2004, 9, 19, 1, 2, 3, 138 | 456789.to_r/1000000, 139 | t.utc_offset.to_r/86400], 140 | [d.year, d.mon, d.mday, d.hour, d.min, d.sec, 141 | d.sec_fraction, d.offset]) 142 | 143 | t = Time.utc(2004, 9, 19, 1, 2, 3, 456789) 144 | d = t.to_datetime 145 | assert_equal([2004, 9, 19, 1, 2, 3, 146 | 456789.to_r/1000000, 147 | 0], 148 | [d.year, d.mon, d.mday, d.hour, d.min, d.sec, 149 | d.sec_fraction, d.offset]) 150 | 151 | t = Time.utc(1582, 10, 13, 1, 2, 3, 456789) 152 | d = t.to_datetime # using ITALY 153 | assert_equal([1582, 10, 3, 1, 2, 3, 154 | 456789.to_r/1000000, 155 | 0], 156 | [d.year, d.mon, d.mday, d.hour, d.min, d.sec, 157 | d.sec_fraction, d.offset]) 158 | 159 | t = Time.now 160 | d = t.to_datetime 161 | require 'time' 162 | assert_equal(t.iso8601(10), d.iso8601(10)) 163 | end 164 | 165 | def test_to_datetime__from_date 166 | d = Date.new(2004, 9, 19) + 1.to_r/2 167 | d2 = d.to_datetime 168 | assert_equal([2004, 9, 19, 0, 0, 0, 0, 0], 169 | [d2.year, d2.mon, d2.mday, d2.hour, d2.min, d2.sec, 170 | d2.sec_fraction, d2.offset]) 171 | end 172 | 173 | def test_to_datetime__from_datetime 174 | d = DateTime.new(2004, 9, 19, 1, 2, 3, 9.to_r/24) + 456789.to_r/86400000000 175 | d2 = d.to_datetime 176 | assert_equal([2004, 9, 19, 1, 2, 3, 177 | 456789.to_r/1000000, 178 | 9.to_r/24], 179 | [d2.year, d2.mon, d2.mday, d2.hour, d2.min, d2.sec, 180 | d2.sec_fraction, d2.offset]) 181 | 182 | d = DateTime.new(2004, 9, 19, 1, 2, 3, 0) + 456789.to_r/86400000000 183 | d2 = d.to_datetime 184 | assert_equal([2004, 9, 19, 1, 2, 3, 185 | 456789.to_r/1000000, 186 | 0], 187 | [d2.year, d2.mon, d2.mday, d2.hour, d2.min, d2.sec, 188 | d2.sec_fraction, d2.offset]) 189 | end 190 | 191 | end 192 | -------------------------------------------------------------------------------- /test/date/test_date_marshal.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require 'test/unit' 3 | require 'date' 4 | 5 | class TestDateMarshal < Test::Unit::TestCase 6 | 7 | def test_marshal 8 | d = Date.new 9 | m = Marshal.dump(d) 10 | d2 = Marshal.load(m) 11 | assert_equal(d, d2) 12 | assert_equal(d.start, d2.start) 13 | assert_instance_of(String, d2.to_s) 14 | 15 | d = Date.today 16 | m = Marshal.dump(d) 17 | d2 = Marshal.load(m) 18 | assert_equal(d, d2) 19 | assert_equal(d.start, d2.start) 20 | assert_instance_of(String, d2.to_s) 21 | 22 | d = DateTime.now 23 | m = Marshal.dump(d) 24 | d2 = Marshal.load(m) 25 | assert_equal(d, d2) 26 | assert_equal(d.start, d2.start) 27 | assert_instance_of(String, d2.to_s) 28 | 29 | d = Date.today 30 | a = d.marshal_dump 31 | d.freeze 32 | assert(d.frozen?) 33 | expected_error = defined?(FrozenError) ? FrozenError : RuntimeError 34 | assert_raise(expected_error){d.marshal_load(a)} 35 | 36 | d = DateTime.now 37 | a = d.marshal_dump 38 | d.freeze 39 | assert(d.frozen?) 40 | expected_error = defined?(FrozenError) ? FrozenError : RuntimeError 41 | assert_raise(expected_error){d.marshal_load(a)} 42 | 43 | d = Date.new + 1/2r + 2304/65437r/86400 44 | m = Marshal.dump(d) 45 | d2 = Marshal.load(m) 46 | assert_equal(d, d2) 47 | assert_equal(d.start, d2.start) 48 | assert_instance_of(String, d2.to_s) 49 | end 50 | 51 | def test_memsize 52 | require 'objspace' 53 | t = DateTime.new(2018, 11, 13) 54 | size = ObjectSpace.memsize_of(t) 55 | t2 = Marshal.load(Marshal.dump(t)) 56 | assert_equal(t, t2) 57 | assert_equal(size, ObjectSpace.memsize_of(t2), "not reallocated but memsize changed") 58 | end 59 | end 60 | -------------------------------------------------------------------------------- /test/date/test_date_new.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require 'test/unit' 3 | require 'date' 4 | 5 | class TestDateNew < Test::Unit::TestCase 6 | 7 | def test_jd 8 | d = Date.jd 9 | dt = DateTime.jd 10 | assert_equal([-4712, 1, 1], [d.year, d.mon, d.mday]) 11 | assert_equal([-4712, 1, 1], [dt.year, dt.mon, dt.mday]) 12 | assert_equal([0, 0, 0], [dt.hour, dt.min, dt.sec]) 13 | 14 | d2 = Date.jd 15 | dt2 = DateTime.jd 16 | assert_equal(d, d2) 17 | assert_equal(dt, dt2) 18 | 19 | d = Date.jd(0) 20 | assert_equal([-4712, 1, 1], [d.year, d.mon, d.mday]) 21 | d = DateTime.jd(0, 0,0,0, 0) 22 | assert_equal([-4712, 1, 1, 0, 0, 0, 0], 23 | [d.year, d.mon, d.mday, d.hour, d.min, d.sec, d.offset]) 24 | d = DateTime.jd(0, 0,0,0, '+0900') 25 | assert_equal([-4712, 1, 1, 0, 0, 0, 9.to_r/24], 26 | [d.year, d.mon, d.mday, d.hour, d.min, d.sec, d.offset]) 27 | end 28 | 29 | def test_jd__ex 30 | assert_raise(Date::Error) do 31 | DateTime.jd(0, 23,59,60,0) 32 | end 33 | end 34 | 35 | def test_valid_with_invalid_types 36 | o = Object.new 37 | assert_equal(false, Date.valid_jd?(o)) 38 | assert_equal(false, Date.valid_civil?(o, 1, 1)) 39 | assert_equal(false, Date.valid_civil?(1, o, 1)) 40 | assert_equal(false, Date.valid_civil?(1, 1, o)) 41 | assert_equal(false, Date.valid_ordinal?(o, 1)) 42 | assert_equal(false, Date.valid_ordinal?(1, o)) 43 | assert_equal(false, Date.valid_commercial?(o, 1, 1)) 44 | assert_equal(false, Date.valid_commercial?(1, o, 1)) 45 | assert_equal(false, Date.valid_commercial?(1, 1, o)) 46 | end 47 | 48 | def test_invalid_types 49 | o = Object.new 50 | assert_raise(TypeError) { Date.julian_leap?(o) } 51 | assert_raise(TypeError) { Date.gregorian_leap?(o) } 52 | assert_raise(TypeError) { Date.jd(o) } 53 | assert_raise(TypeError) { Date.new(o) } 54 | assert_raise(TypeError) { Date.new(1, o) } 55 | assert_raise(TypeError) { Date.new(1, 1, o) } 56 | assert_raise(TypeError) { Date.ordinal(o) } 57 | assert_raise(TypeError) { Date.ordinal(1, o) } 58 | assert_raise(TypeError) { Date.commercial(o) } 59 | assert_raise(TypeError) { Date.commercial(1, o) } 60 | assert_raise(TypeError) { Date.commercial(1, 1, o) } 61 | 62 | assert_raise(TypeError) { DateTime.jd(o) } 63 | assert_raise(TypeError) { DateTime.jd(1, o) } 64 | assert_raise(TypeError) { DateTime.jd(1, 1, o) } 65 | assert_raise(TypeError) { DateTime.jd(1, 1, 1, o) } 66 | assert_raise(TypeError) { DateTime.new(o) } 67 | assert_raise(TypeError) { DateTime.new(1, o) } 68 | assert_raise(TypeError) { DateTime.new(1, 1, o) } 69 | assert_raise(TypeError) { DateTime.new(1, 1, 1, o) } 70 | assert_raise(TypeError) { DateTime.new(1, 1, 1, 1, o) } 71 | assert_raise(TypeError) { DateTime.new(1, 1, 1, 1, 1, o) } 72 | assert_raise(TypeError) { DateTime.ordinal(o) } 73 | assert_raise(TypeError) { DateTime.ordinal(1, o) } 74 | assert_raise(TypeError) { DateTime.ordinal(1, 1, o) } 75 | assert_raise(TypeError) { DateTime.ordinal(1, 1, 1, o) } 76 | assert_raise(TypeError) { DateTime.ordinal(1, 1, 1, 1, o) } 77 | assert_raise(TypeError) { DateTime.commercial(o) } 78 | assert_raise(TypeError) { DateTime.commercial(1, o) } 79 | assert_raise(TypeError) { DateTime.commercial(1, 1, o) } 80 | assert_raise(TypeError) { DateTime.commercial(1, 1, 1, o) } 81 | assert_raise(TypeError) { DateTime.commercial(1, 1, 1, 1, o) } 82 | assert_raise(TypeError) { DateTime.commercial(1, 1, 1, 1, 1, o) } 83 | end 84 | 85 | def test_ordinal 86 | d = Date.ordinal 87 | dt = DateTime.ordinal 88 | assert_equal([-4712, 1, 1], [d.year, d.mon, d.mday]) 89 | assert_equal([-4712, 1, 1], [dt.year, dt.mon, dt.mday]) 90 | assert_equal([0, 0, 0], [dt.hour, dt.min, dt.sec]) 91 | 92 | d2 = Date.ordinal 93 | dt2 = DateTime.ordinal 94 | assert_equal(d, d2) 95 | assert_equal(dt, dt2) 96 | 97 | d = Date.ordinal(-4712,1) 98 | assert_equal([-4712, 1, 1], [d.year, d.mon, d.mday]) 99 | 100 | d = Date.ordinal(-4712,1.0) 101 | assert_equal([-4712, 1, 1], [d.year, d.mon, d.mday]) 102 | 103 | d = DateTime.ordinal(-4712,1, 0,0,0, 0) 104 | assert_equal([-4712, 1, 1, 0, 0, 0, 0], 105 | [d.year, d.mon, d.mday, d.hour, d.min, d.sec, d.offset]) 106 | d = DateTime.ordinal(-4712,1, 0,0,0, '+0900') 107 | assert_equal([-4712, 1, 1, 0, 0, 0, 9.to_r/24], 108 | [d.year, d.mon, d.mday, d.hour, d.min, d.sec, d.offset]) 109 | end 110 | 111 | def test_ordinal__neg 112 | d = Date.ordinal(-1,-1) 113 | assert_equal([-1, 365], [d.year, d.yday]) 114 | 115 | d = DateTime.ordinal(-1,-1, -1,-1,-1, 0) 116 | assert_equal([-1, 365, 23, 59, 59, 0], 117 | [d.year, d.yday, d.hour, d.min, d.sec, d.offset]) 118 | end 119 | 120 | def test_ordinal__ex 121 | assert_raise(Date::Error) do 122 | Date.ordinal(2001,366) 123 | end 124 | assert_raise(Date::Error) do 125 | DateTime.ordinal(2001,365, 23,59,60, 0) 126 | end 127 | end 128 | 129 | def test_civil 130 | d = Date.civil 131 | dt = DateTime.civil 132 | assert_equal([-4712, 1, 1], [d.year, d.mon, d.mday]) 133 | assert_equal([-4712, 1, 1], [dt.year, dt.mon, dt.mday]) 134 | assert_equal([0, 0, 0], [dt.hour, dt.min, dt.sec]) 135 | 136 | d2 = Date.civil 137 | dt2 = DateTime.civil 138 | assert_equal(d, d2) 139 | assert_equal(dt, dt2) 140 | 141 | d = Date.civil(-4712,1,1) 142 | assert_equal([-4712, 1, 1], [d.year, d.mon, d.mday]) 143 | 144 | d = Date.civil(-4712,1,1.0) 145 | assert_equal([-4712, 1, 1], [d.year, d.mon, d.mday]) 146 | 147 | d = DateTime.civil(-4712,1,1, 0,0,0, 0) 148 | assert_equal([-4712, 1, 1, 0, 0, 0, 0], 149 | [d.year, d.mon, d.mday, d.hour, d.min, d.sec, d.offset]) 150 | d = DateTime.civil(-4712,1,1, 0,0,0, '+0900') 151 | assert_equal([-4712, 1, 1, 0, 0, 0, 9.to_r/24], 152 | [d.year, d.mon, d.mday, d.hour, d.min, d.sec, d.offset]) 153 | 154 | 155 | d = DateTime.civil(2001,2,3 + 1.to_r/2) 156 | assert_equal([2001, 2, 3, 12, 0, 0, 0], 157 | [d.year, d.mon, d.mday, d.hour, d.min, d.sec, d.offset]) 158 | d = DateTime.civil(2001,2,3, 4 + 1.to_r/2) 159 | assert_equal([2001, 2, 3, 4, 30, 0, 0], 160 | [d.year, d.mon, d.mday, d.hour, d.min, d.sec, d.offset]) 161 | d = DateTime.civil(2001,2,3, 4,5 + 1.to_r/2) 162 | assert_equal([2001, 2, 3, 4, 5, 30, 0], 163 | [d.year, d.mon, d.mday, d.hour, d.min, d.sec, d.offset]) 164 | d = DateTime.civil(2001,2,3, 4,5,6 + 1.to_r/2) 165 | assert_equal([2001, 2, 3, 4, 5, 6, 0], 166 | [d.year, d.mon, d.mday, d.hour, d.min, d.sec, d.offset]) 167 | assert_equal(1.to_r/2, d.sec_fraction) 168 | 169 | d = DateTime.civil(2001, 2) 170 | assert_equal([2001, 2, 1, 0, 0, 0, 0], 171 | [d.year, d.mon, d.mday, d.hour, d.min, d.sec, d.offset]) 172 | end 173 | 174 | def test_civil__neg 175 | d = Date.civil(-1,-1,-1) 176 | assert_equal([-1, 12, 31], [d.year, d.mon, d.mday]) 177 | 178 | d = DateTime.civil(-1,-1,-1, -1,-1,-1, 0) 179 | assert_equal([-1, 12, 31, 23, 59, 59, 0], 180 | [d.year, d.mon, d.mday, d.hour, d.min, d.sec, d.offset]) 181 | end 182 | 183 | def test_civil__ex 184 | assert_raise(Date::Error) do 185 | Date.civil(2001,2,29) 186 | end 187 | assert_raise(Date::Error) do 188 | DateTime.civil(2001,2,28, 23,59,60, 0) 189 | end 190 | assert_raise(Date::Error) do 191 | DateTime.civil(2001,2,28, 24,59,59, 0) 192 | end 193 | end 194 | 195 | def test_civil__reform 196 | d = Date.jd(Date::ENGLAND, Date::ENGLAND) 197 | dt = DateTime.jd(Date::ENGLAND, 0,0,0,0, Date::ENGLAND) 198 | assert_equal([1752, 9, 14], [d.year, d.mon, d.mday]) 199 | assert_equal([1752, 9, 14], [dt.year, dt.mon, dt.mday]) 200 | d -= 1 201 | dt -= 1 202 | assert_equal([1752, 9, 2], [d.year, d.mon, d.mday]) 203 | assert_equal([1752, 9, 2], [dt.year, dt.mon, dt.mday]) 204 | 205 | d = Date.jd(Date::ITALY, Date::ITALY) 206 | dt = DateTime.jd(Date::ITALY, 0,0,0,0, Date::ITALY) 207 | assert_equal([1582, 10, 15], [d.year, d.mon, d.mday]) 208 | assert_equal([1582, 10, 15], [dt.year, dt.mon, dt.mday]) 209 | d -= 1 210 | dt -= 1 211 | assert_equal([1582, 10, 4], [d.year, d.mon, d.mday]) 212 | assert_equal([1582, 10, 4], [dt.year, dt.mon, dt.mday]) 213 | end 214 | 215 | def test_commercial 216 | d = Date.commercial 217 | dt = DateTime.commercial 218 | assert_equal([-4712, 1, 1], [d.year, d.mon, d.mday]) 219 | assert_equal([-4712, 1, 1], [dt.year, dt.mon, dt.mday]) 220 | assert_equal([0, 0, 0], [dt.hour, dt.min, dt.sec]) 221 | 222 | d2 = Date.commercial 223 | dt2 = DateTime.commercial 224 | assert_equal(d, d2) 225 | assert_equal(dt, dt2) 226 | 227 | d = Date.commercial(1582,40,5) 228 | assert_equal([1582, 10, 15], [d.year, d.mon, d.mday]) 229 | 230 | d = Date.commercial(1582,40,5.0) 231 | assert_equal([1582, 10, 15], [d.year, d.mon, d.mday]) 232 | 233 | d = DateTime.commercial(1582,40,5, 0,0,0, 0) 234 | assert_equal([1582, 10, 15, 0, 0, 0, 0], 235 | [d.year, d.mon, d.mday, d.hour, d.min, d.sec, d.offset]) 236 | d = DateTime.commercial(1582,40,5, 0,0,0, '+0900') 237 | assert_equal([1582, 10, 15, 0, 0, 0, 9.to_r/24], 238 | [d.year, d.mon, d.mday, d.hour, d.min, d.sec, d.offset]) 239 | end 240 | 241 | def test_commercial__neg 242 | d = Date.commercial(1998,-1,-1) 243 | assert_equal([1999, 1, 3], [d.year, d.mon, d.mday]) 244 | 245 | d = DateTime.commercial(1998,-1,-1, -1,-1,-1, 0) 246 | assert_equal([1999, 1, 3, 23, 59, 59, 0], 247 | [d.year, d.mon, d.mday, d.hour, d.min, d.sec, d.offset]) 248 | end 249 | 250 | def test_commercial__ex 251 | assert_raise(Date::Error) do 252 | Date.commercial(1997,53,1) 253 | end 254 | assert_raise(Date::Error) do 255 | DateTime.commercial(1997,52,1, 23,59,60, 0) 256 | end 257 | end 258 | 259 | def test_weeknum 260 | d = Date.weeknum 261 | dt = DateTime.weeknum 262 | assert_equal([-4712, 1, 1], [d.year, d.mon, d.mday]) 263 | assert_equal([-4712, 1, 1], [dt.year, dt.mon, dt.mday]) 264 | assert_equal([0, 0, 0], [dt.hour, dt.min, dt.sec]) 265 | 266 | d = Date.weeknum(2002,11,4, 0) 267 | assert_equal(2452355, d.jd) 268 | 269 | d = DateTime.weeknum(2002,11,4, 0, 11,22,33) 270 | assert_equal(2452355, d.jd) 271 | assert_equal([11,22,33], [d.hour, d.min, d.sec]) 272 | 273 | assert_raise(Date::Error) do 274 | Date.weeknum(1999,53,0, 0) 275 | end 276 | assert_raise(Date::Error) do 277 | Date.weeknum(1999,-53,-1, 0) 278 | end 279 | end if Date.respond_to?(:weeknum, true) 280 | 281 | def test_nth_kday 282 | d = Date.nth_kday 283 | dt = DateTime.nth_kday 284 | assert_equal([-4712, 1, 1], [d.year, d.mon, d.mday]) 285 | assert_equal([-4712, 1, 1], [dt.year, dt.mon, dt.mday]) 286 | assert_equal([0, 0, 0], [dt.hour, dt.min, dt.sec]) 287 | 288 | d = Date.nth_kday(1992,2, 5,6) 289 | assert_equal(2448682, d.jd) 290 | 291 | d = DateTime.nth_kday(1992,2, 5,6, 11,22,33) 292 | assert_equal(2448682, d.jd) 293 | assert_equal([11,22,33], [d.hour, d.min, d.sec]) 294 | 295 | assert_raise(Date::Error) do 296 | Date.nth_kday(2006,5, 5,0) 297 | end 298 | assert_raise(Date::Error) do 299 | Date.nth_kday(2006,5, -5,0) 300 | end 301 | end if Date.respond_to?(:nth_kday, true) 302 | 303 | def test_today 304 | z = Time.now 305 | d = Date.today 306 | t = Time.now 307 | t2 = Time.utc(t.year, t.mon, t.mday) 308 | t3 = Time.utc(d.year, d.mon, d.mday) 309 | assert_in_delta(t2, t3, t - z + 2) 310 | 311 | assert_equal(false, DateTime.respond_to?(:today)) 312 | end 313 | 314 | def test_now 315 | assert_equal(false, Date.respond_to?(:now)) 316 | 317 | z = Time.now 318 | d = DateTime.now 319 | t = Time.now 320 | t2 = Time.local(d.year, d.mon, d.mday, d.hour, d.min, d.sec) 321 | assert_in_delta(t, t2, t - z + 2) 322 | end 323 | 324 | def test_memsize 325 | require 'objspace' 326 | t = DateTime.now 327 | size = ObjectSpace.memsize_of(t) 328 | t.__send__(:initialize_copy, Date.today) 329 | assert_instance_of(DateTime, t) 330 | assert_equal(size, ObjectSpace.memsize_of(t), "not reallocated but memsize changed") 331 | end 332 | end 333 | -------------------------------------------------------------------------------- /test/date/test_date_ractor.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require 'test/unit' 3 | require 'date' 4 | 5 | class TestDateParseRactor < Test::Unit::TestCase 6 | def code(klass = Date, share: false) 7 | <<~RUBY.gsub('Date', klass.name) 8 | share = #{share} 9 | d = Date.parse('Aug 23:55') 10 | Ractor.make_shareable(d) if share 11 | d2, d3 = Ractor.new(d) { |d| [d, Date.parse(d.to_s)] }.value 12 | if share 13 | assert_same d, d2 14 | else 15 | assert_equal d, d2 16 | end 17 | assert_equal d, d3 18 | RUBY 19 | end 20 | 21 | def test_date_ractor 22 | assert_ractor(code , require: 'date') 23 | assert_ractor(code( share: true), require: 'date') 24 | assert_ractor(code(DateTime ), require: 'date') 25 | assert_ractor(code(DateTime, share: true), require: 'date') 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /test/date/test_date_strftime.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require 'test/unit' 3 | require 'date' 4 | 5 | class TestDateStrftime < Test::Unit::TestCase 6 | 7 | STRFTIME_2001_02_03 = { 8 | '%A'=>['Saturday',{:wday=>6}], 9 | '%a'=>['Sat',{:wday=>6}], 10 | '%B'=>['February',{:mon=>2}], 11 | '%b'=>['Feb',{:mon=>2}], 12 | '%c'=>['Sat Feb 3 00:00:00 2001', 13 | {:wday=>6,:mon=>2,:mday=>3,:hour=>0,:min=>0,:sec=>0,:year=>2001}], 14 | '%d'=>['03',{:mday=>3}], 15 | '%e'=>[' 3',{:mday=>3}], 16 | '%H'=>['00',{:hour=>0}], 17 | '%I'=>['12',{:hour=>0}], 18 | '%j'=>['034',{:yday=>34}], 19 | '%M'=>['00',{:min=>0}], 20 | '%m'=>['02',{:mon=>2}], 21 | '%p'=>['AM',{}], 22 | '%S'=>['00',{:sec=>0}], 23 | '%U'=>['04',{:wnum0=>4}], 24 | '%W'=>['05',{:wnum1=>5}], 25 | '%X'=>['00:00:00',{:hour=>0,:min=>0,:sec=>0}], 26 | '%x'=>['02/03/01',{:mon=>2,:mday=>3,:year=>2001}], 27 | '%Y'=>['2001',{:year=>2001}], 28 | '%y'=>['01',{:year=>2001}], 29 | '%Z'=>['+00:00',{:zone=>'+00:00',:offset=>0}], 30 | '%%'=>['%',{}], 31 | '%C'=>['20',{}], 32 | '%D'=>['02/03/01',{:mon=>2,:mday=>3,:year=>2001}], 33 | '%F'=>['2001-02-03',{:year=>2001,:mon=>2,:mday=>3}], 34 | '%G'=>['2001',{:cwyear=>2001}], 35 | '%g'=>['01',{:cwyear=>2001}], 36 | '%h'=>['Feb',{:mon=>2}], 37 | '%k'=>[' 0',{:hour=>0}], 38 | '%L'=>['000',{:sec_fraction=>0}], 39 | '%l'=>['12',{:hour=>0}], 40 | '%N'=>['000000000',{:sec_fraction=>0}], 41 | '%n'=>["\n",{}], 42 | '%P'=>['am',{}], 43 | '%Q'=>['981158400000',{:seconds=>981158400.to_r}], 44 | '%R'=>['00:00',{:hour=>0,:min=>0}], 45 | '%r'=>['12:00:00 AM',{:hour=>0,:min=>0,:sec=>0}], 46 | '%s'=>['981158400',{:seconds=>981158400}], 47 | '%T'=>['00:00:00',{:hour=>0,:min=>0,:sec=>0}], 48 | '%t'=>["\t",{}], 49 | '%u'=>['6',{:cwday=>6}], 50 | '%V'=>['05',{:cweek=>5}], 51 | '%v'=>[' 3-FEB-2001',{:mday=>3,:mon=>2,:year=>2001}], 52 | '%z'=>['+0000',{:zone=>'+0000',:offset=>0}], 53 | '%+'=>['Sat Feb 3 00:00:00 +00:00 2001', 54 | {:wday=>6,:mon=>2,:mday=>3, 55 | :hour=>0,:min=>0,:sec=>0,:zone=>'+00:00',:offset=>0,:year=>2001}], 56 | } 57 | 58 | STRFTIME_2001_02_03_CVS19 = { 59 | } 60 | 61 | STRFTIME_2001_02_03_GNUext = { 62 | '%:z'=>['+00:00',{:zone=>'+00:00',:offset=>0}], 63 | '%::z'=>['+00:00:00',{:zone=>'+00:00:00',:offset=>0}], 64 | '%:::z'=>['+00',{:zone=>'+00',:offset=>0}], 65 | } 66 | 67 | STRFTIME_2001_02_03.update(STRFTIME_2001_02_03_CVS19) 68 | STRFTIME_2001_02_03.update(STRFTIME_2001_02_03_GNUext) 69 | 70 | def test_strftime 71 | d = Date.new(2001,2,3) 72 | STRFTIME_2001_02_03.each do |f, s| 73 | assert_equal(s[0], d.strftime(f), [f, s].inspect) 74 | case f[-1,1] 75 | when 'c', 'C', 'x', 'X', 'y', 'Y' 76 | f2 = f.sub(/\A%/, '%E') 77 | assert_equal(s[0], d.strftime(f2), [f2, s].inspect) 78 | else 79 | f2 = f.sub(/\A%/, '%E') 80 | assert_equal(f2, d.strftime(f2), [f2, s].inspect) 81 | end 82 | case f[-1,1] 83 | when 'd', 'e', 'H', 'k', 'I', 'l', 'm', 'M', 'S', 'u', 'U', 'V', 'w', 'W', 'y' 84 | f2 = f.sub(/\A%/, '%O') 85 | assert_equal(s[0], d.strftime(f2), [f2, s].inspect) 86 | else 87 | f2 = f.sub(/\A%/, '%O') 88 | assert_equal(f2, d.strftime(f2), [f2, s].inspect) 89 | end 90 | end 91 | end 92 | 93 | def test_strftime__2 94 | d = Date.new(2001,2,3) 95 | assert_equal('2001-02-03', d.strftime) 96 | 97 | d = DateTime.new(2001,2,3) 98 | assert_equal('2001-02-03T00:00:00+00:00', d.strftime) 99 | 100 | assert_equal('', d.strftime('')) 101 | assert_equal("\s"*3, d.strftime("\s"*3)) 102 | assert_equal("\tfoo\n\000\r", d.strftime("\tfoo\n\000\r")) 103 | assert_equal("%\n", d.strftime("%\n")) # gnu 104 | assert_equal('Saturday'*1024 + ',', d.strftime('%A'*1024 + ',')) 105 | assert_equal('%%', d.strftime('%%%')) 106 | assert_equal('Anton von Webern', d.strftime('Anton von Webern')) 107 | 108 | d = DateTime.new(2001,2,3, 1,2,3) 109 | assert_equal('2001-02-03T01:02:03+00:00', d.strftime) 110 | assert_equal('AM', d.strftime('%p')) 111 | assert_equal('am', d.strftime('%P')) 112 | d = DateTime.new(2001,2,3, 13,14,15) 113 | assert_equal('2001-02-03T13:14:15+00:00', d.strftime) 114 | assert_equal('PM', d.strftime('%p')) 115 | assert_equal('pm', d.strftime('%P')) 116 | end 117 | 118 | def test_strftime__3_1 119 | (Date.new(1970,1,1)..Date.new(2037,12,31)).each do |d| 120 | t = Time.utc(d.year,d.mon,d.mday) 121 | assert_equal(t.strftime('%U'), d.strftime('%U')) 122 | assert_equal(t.strftime('%W'), d.strftime('%W')) 123 | end 124 | end 125 | 126 | def test_strftime__3_2 127 | s = Time.now.strftime('%G') 128 | omit if s.empty? || s == '%G' 129 | (Date.new(1970,1,1)..Date.new(2037,12,31)).each do |d| 130 | t = Time.utc(d.year,d.mon,d.mday) 131 | assert_equal(t.strftime('%G'), d.strftime('%G')) 132 | assert_equal(t.strftime('%g'), d.strftime('%g')) 133 | assert_equal(t.strftime('%V'), d.strftime('%V')) 134 | assert_equal(t.strftime('%u'), d.strftime('%u')) 135 | end 136 | end 137 | 138 | def test_strftime__4 139 | s = '2006-08-08T23:15:33.123456789' 140 | f = '%FT%T.%N' 141 | d = DateTime.parse(s) 142 | assert_equal(s, d.strftime(f)) 143 | d = DateTime.strptime(s, f) 144 | assert_equal(s, d.strftime(f)) 145 | 146 | s = '2006-08-08T23:15:33.123456789' 147 | f = '%FT%T.%N' 148 | d = DateTime.parse(s + '123456789') 149 | assert_equal(s, d.strftime(f)) 150 | d = DateTime.strptime(s + '123456789', f) 151 | assert_equal(s, d.strftime(f)) 152 | 153 | si = '2006-08-08T23:15:33.9' 154 | so = '2006-08-08T23:15:33.900000000' 155 | f = '%FT%T.%N' 156 | d = DateTime.parse(si) 157 | assert_equal(so, d.strftime(f)) 158 | d = DateTime.strptime(si, f) 159 | assert_equal(so, d.strftime(f)) 160 | 161 | s = '2006-08-08T23:15:33.123' 162 | f = '%FT%T.%L' 163 | d = DateTime.parse(s) 164 | assert_equal(s, d.strftime(f)) 165 | d = DateTime.strptime(s, f) 166 | assert_equal(s, d.strftime(f)) 167 | 168 | s = '2006-08-08T23:15:33.123' 169 | f = '%FT%T.%L' 170 | d = DateTime.parse(s + '123') 171 | assert_equal(s, d.strftime(f)) 172 | d = DateTime.strptime(s + '123', f) 173 | assert_equal(s, d.strftime(f)) 174 | 175 | si = '2006-08-08T23:15:33.9' 176 | so = '2006-08-08T23:15:33.900' 177 | f = '%FT%T.%L' 178 | d = DateTime.parse(si) 179 | assert_equal(so, d.strftime(f)) 180 | d = DateTime.strptime(si, f) 181 | assert_equal(so, d.strftime(f)) 182 | end 183 | 184 | def test_strftime__offset 185 | s = '2006-08-08T23:15:33' 186 | (-24..24).collect{|x| '%+.2d' % x}.each do |hh| 187 | %w(00 30).each do |mm| 188 | r = hh + mm 189 | next if r.end_with?('2430') 190 | d = DateTime.parse(s + hh + mm) 191 | assert_equal(r, d.strftime('%z')) 192 | end 193 | end 194 | %w[+2430 -2430].each do |r| 195 | assert_warning(/invalid offset/) do 196 | DateTime.parse(s + r) 197 | end 198 | end 199 | end 200 | 201 | def test_strftime_milli 202 | s = '1970-01-01T00:00:00.123456789' 203 | d = DateTime.parse(s) 204 | assert_equal('123', d.strftime('%Q')) 205 | s = '1970-01-02T02:03:04.123456789' 206 | d = DateTime.parse(s) 207 | assert_equal('93784123', d.strftime('%Q')) 208 | end 209 | 210 | def test_strftime__minus 211 | d = DateTime.new(1969, 12, 31, 23, 59, 59) 212 | assert_equal('-1', d.strftime('%s')) 213 | assert_equal('-1000', d.strftime('%Q')) 214 | end 215 | 216 | def test_strftime__gnuext # coreutils 217 | d = DateTime.new(2006,8,8,23,15,33,9.to_r/24) 218 | 219 | assert_equal('2006', d.strftime('%-Y')) 220 | assert_equal('2006', d.strftime('%-5Y')) 221 | assert_equal('02006', d.strftime('%5Y')) 222 | assert_equal('2006', d.strftime('%_Y')) 223 | assert_equal(' 2006', d.strftime('%_5Y')) 224 | assert_equal('02006', d.strftime('%05Y')) 225 | 226 | assert_equal('8', d.strftime('%-d')) 227 | assert_equal('8', d.strftime('%-3d')) 228 | assert_equal('008', d.strftime('%3d')) 229 | assert_equal(' 8', d.strftime('%_d')) 230 | assert_equal(' 8', d.strftime('%_3d')) 231 | assert_equal('008', d.strftime('%03d')) 232 | 233 | assert_equal('8', d.strftime('%-e')) 234 | assert_equal('8', d.strftime('%-3e')) 235 | assert_equal(' 8', d.strftime('%3e')) 236 | assert_equal(' 8', d.strftime('%_e')) 237 | assert_equal(' 8', d.strftime('%_3e')) 238 | assert_equal('008', d.strftime('%03e')) 239 | 240 | assert_equal('Tuesday', d.strftime('%-10A')) 241 | assert_equal(' Tuesday', d.strftime('%10A')) 242 | assert_equal(' Tuesday', d.strftime('%_10A')) 243 | assert_equal('000Tuesday', d.strftime('%010A')) 244 | assert_equal('TUESDAY', d.strftime('%^A')) 245 | assert_equal('TUESDAY', d.strftime('%#A')) 246 | 247 | assert_equal('Tue', d.strftime('%-6a')) 248 | assert_equal(' Tue', d.strftime('%6a')) 249 | assert_equal(' Tue', d.strftime('%_6a')) 250 | assert_equal('000Tue', d.strftime('%06a')) 251 | assert_equal('TUE', d.strftime('%^a')) 252 | assert_equal('TUE', d.strftime('%#a')) 253 | assert_equal(' TUE', d.strftime('%#6a')) 254 | 255 | assert_equal('August', d.strftime('%-10B')) 256 | assert_equal(' August', d.strftime('%10B')) 257 | assert_equal(' August', d.strftime('%_10B')) 258 | assert_equal('0000August', d.strftime('%010B')) 259 | assert_equal('AUGUST', d.strftime('%^B')) 260 | assert_equal('AUGUST', d.strftime('%#B')) 261 | 262 | assert_equal('Aug', d.strftime('%-6b')) 263 | assert_equal(' Aug', d.strftime('%6b')) 264 | assert_equal(' Aug', d.strftime('%_6b')) 265 | assert_equal('000Aug', d.strftime('%06b')) 266 | assert_equal('AUG', d.strftime('%^b')) 267 | assert_equal('AUG', d.strftime('%#b')) 268 | assert_equal(' AUG', d.strftime('%#6b')) 269 | 270 | assert_equal('Aug', d.strftime('%-6h')) 271 | assert_equal(' Aug', d.strftime('%6h')) 272 | assert_equal(' Aug', d.strftime('%_6h')) 273 | assert_equal('000Aug', d.strftime('%06h')) 274 | assert_equal('AUG', d.strftime('%^h')) 275 | assert_equal('AUG', d.strftime('%#h')) 276 | assert_equal(' AUG', d.strftime('%#6h')) 277 | 278 | assert_equal('PM', d.strftime('%^p')) 279 | assert_equal('pm', d.strftime('%#p')) 280 | assert_equal('PM', d.strftime('%^P')) 281 | assert_equal('PM', d.strftime('%#P')) 282 | 283 | assert_equal('+000900', d.strftime('%7z')) 284 | assert_equal(' +900', d.strftime('%_7z')) 285 | assert_equal('+09:00', d.strftime('%:z')) 286 | assert_equal('+0009:00', d.strftime('%8:z')) 287 | assert_equal(' +9:00', d.strftime('%_8:z')) 288 | assert_equal('+09:00:00', d.strftime('%::z')) 289 | assert_equal('+0009:00:00', d.strftime('%11::z')) 290 | assert_equal(' +9:00:00', d.strftime('%_11::z')) 291 | assert_equal('+09', d.strftime('%:::z')) 292 | assert_equal('+0009', d.strftime('%5:::z')) 293 | assert_equal(' +9', d.strftime('%_5:::z')) 294 | assert_equal('+9', d.strftime('%-:::z')) 295 | 296 | d = DateTime.new(-200,8,8,23,15,33,9.to_r/24) 297 | 298 | assert_equal('-0200', d.strftime('%Y')) 299 | assert_equal('-200', d.strftime('%-Y')) 300 | assert_equal('-200', d.strftime('%-5Y')) 301 | assert_equal('-0200', d.strftime('%5Y')) 302 | assert_equal(' -200', d.strftime('%_Y')) 303 | assert_equal(' -200', d.strftime('%_5Y')) 304 | assert_equal('-0200', d.strftime('%05Y')) 305 | 306 | d = DateTime.new(-2000,8,8,23,15,33,9.to_r/24) 307 | 308 | assert_equal('-2000', d.strftime('%Y')) 309 | assert_equal('-2000', d.strftime('%-Y')) 310 | assert_equal('-2000', d.strftime('%-5Y')) 311 | assert_equal('-2000', d.strftime('%5Y')) 312 | assert_equal('-2000', d.strftime('%_Y')) 313 | assert_equal('-2000', d.strftime('%_5Y')) 314 | assert_equal('-2000', d.strftime('%05Y')) 315 | end 316 | 317 | def test_strftime__gnuext_LN # coreutils 318 | d = DateTime.parse('2008-11-25T00:11:22.0123456789') 319 | assert_equal('012', d.strftime('%L')) 320 | assert_equal('012', d.strftime('%0L')) 321 | assert_equal('0', d.strftime('%1L')) 322 | assert_equal('01', d.strftime('%2L')) 323 | assert_equal('01234567890', d.strftime('%11L')) 324 | assert_equal('01234567890', d.strftime('%011L')) 325 | assert_equal('01234567890', d.strftime('%_11L')) 326 | assert_equal('012345678', d.strftime('%N')) 327 | assert_equal('012345678', d.strftime('%0N')) 328 | assert_equal('0', d.strftime('%1N')) 329 | assert_equal('01', d.strftime('%2N')) 330 | assert_equal('01234567890', d.strftime('%11N')) 331 | assert_equal('01234567890', d.strftime('%011N')) 332 | assert_equal('01234567890', d.strftime('%_11N')) 333 | end 334 | 335 | def test_strftime__gnuext_z # coreutils 336 | d = DateTime.parse('2006-08-08T23:15:33+09:08:07') 337 | assert_equal('+0908', d.strftime('%z')) 338 | assert_equal('+09:08', d.strftime('%:z')) 339 | assert_equal('+09:08:07', d.strftime('%::z')) 340 | assert_equal('+09:08:07', d.strftime('%:::z')) 341 | end 342 | 343 | def test_strftime__gnuext_complex 344 | d = DateTime.parse('2001-02-03T04:05:06+09:00') 345 | assert_equal('Sat Feb 3 04:05:06 2001', d.strftime('%-100c')) 346 | assert_equal('Sat Feb 3 04:05:06 2001'.rjust(100), d.strftime('%100c')) 347 | assert_equal('Sat Feb 3 04:05:06 2001'.rjust(100), d.strftime('%_100c')) 348 | assert_equal('Sat Feb 3 04:05:06 2001'.rjust(100, '0'), d.strftime('%0100c')) 349 | assert_equal('SAT FEB 3 04:05:06 2001', d.strftime('%^c')) 350 | 351 | assert_equal('Sat Feb 3 04:05:06 +09:00 2001', d.strftime('%-100+')) 352 | assert_equal('Sat Feb 3 04:05:06 +09:00 2001'.rjust(100), d.strftime('%100+')) 353 | assert_equal('Sat Feb 3 04:05:06 +09:00 2001'.rjust(100), d.strftime('%_100+')) 354 | assert_equal('Sat Feb 3 04:05:06 +09:00 2001'.rjust(100, '0'), d.strftime('%0100+')) 355 | assert_equal('SAT FEB 3 04:05:06 +09:00 2001', d.strftime('%^+')) 356 | end 357 | 358 | def test__different_format 359 | d = Date.new(2001,2,3) 360 | 361 | assert_equal('Sat Feb 3 00:00:00 2001', d.ctime) 362 | assert_equal(d.ctime, d.asctime) 363 | 364 | assert_equal('2001-02-03', d.iso8601) 365 | assert_equal(d.xmlschema, d.iso8601) 366 | assert_equal('2001-02-03T00:00:00+00:00', d.rfc3339) 367 | assert_equal('Sat, 3 Feb 2001 00:00:00 +0000', d.rfc2822) 368 | assert_equal(d.rfc822, d.rfc2822) 369 | assert_equal('Sat, 03 Feb 2001 00:00:00 GMT', d.httpdate) 370 | assert_equal('H13.02.03', d.jisx0301) 371 | 372 | d = DateTime.new(2001,2,3) 373 | 374 | assert_equal('Sat Feb 3 00:00:00 2001', d.ctime) 375 | assert_equal(d.ctime, d.asctime) 376 | 377 | assert_equal('2001-02-03T00:00:00+00:00', d.iso8601) 378 | assert_equal(d.rfc3339, d.iso8601) 379 | assert_equal(d.xmlschema, d.iso8601) 380 | assert_equal('Sat, 3 Feb 2001 00:00:00 +0000', d.rfc2822) 381 | assert_equal(d.rfc822, d.rfc2822) 382 | assert_equal('Sat, 03 Feb 2001 00:00:00 GMT', d.httpdate) 383 | assert_equal('H13.02.03T00:00:00+00:00', d.jisx0301) 384 | 385 | d2 = DateTime.parse('2001-02-03T04:05:06.123456') 386 | assert_equal('2001-02-03T04:05:06.123+00:00', d2.iso8601(3)) 387 | assert_equal('2001-02-03T04:05:06.123+00:00', d2.rfc3339(3)) 388 | assert_equal('H13.02.03T04:05:06.123+00:00', d2.jisx0301(3)) 389 | assert_equal('2001-02-03T04:05:06.123+00:00', d2.iso8601(3.5)) 390 | assert_equal('2001-02-03T04:05:06.123+00:00', d2.rfc3339(3.5)) 391 | assert_equal('H13.02.03T04:05:06.123+00:00', d2.jisx0301(3.5)) 392 | assert_equal('2001-02-03T04:05:06.123456000+00:00', d2.iso8601(9)) 393 | assert_equal('2001-02-03T04:05:06.123456000+00:00', d2.rfc3339(9)) 394 | assert_equal('H13.02.03T04:05:06.123456000+00:00', d2.jisx0301(9)) 395 | assert_equal('2001-02-03T04:05:06.123456000+00:00', d2.iso8601(9.9)) 396 | assert_equal('2001-02-03T04:05:06.123456000+00:00', d2.rfc3339(9.9)) 397 | assert_equal('H13.02.03T04:05:06.123456000+00:00', d2.jisx0301(9.9)) 398 | 399 | assert_equal('1800-01-01T00:00:00+00:00', DateTime.new(1800).jisx0301) 400 | 401 | assert_equal('1868-01-25', Date.parse('1868-01-25').jisx0301) 402 | assert_equal('1872-12-31', Date.parse('1872-12-31').jisx0301) 403 | 404 | assert_equal('M06.01.01', Date.parse('1873-01-01').jisx0301) 405 | assert_equal('M45.07.29', Date.parse('1912-07-29').jisx0301) 406 | assert_equal('T01.07.30', Date.parse('1912-07-30').jisx0301) 407 | assert_equal('T15.12.24', Date.parse('1926-12-24').jisx0301) 408 | assert_equal('S01.12.25', Date.parse('1926-12-25').jisx0301) 409 | assert_equal('S64.01.07', Date.parse('1989-01-07').jisx0301) 410 | assert_equal('H01.01.08', Date.parse('1989-01-08').jisx0301) 411 | assert_equal('H18.09.01', Date.parse('2006-09-01').jisx0301) 412 | assert_equal('H31.04.30', Date.parse('2019-04-30').jisx0301) 413 | assert_equal('R01.05.01', Date.parse('2019-05-01').jisx0301) 414 | 415 | assert_equal(d2, DateTime.iso8601('2001-02-03T04:05:06.123456+00:00', limit: 64)) 416 | assert_equal(d2, DateTime.rfc3339('2001-02-03T04:05:06.123456+00:00', limit: 64)) 417 | assert_equal(d2, DateTime.jisx0301('H13.02.03T04:05:06.123456+00:00', limit: 64)) 418 | 419 | exceeds = /string length \(\d+\) exceeds/ 420 | assert_raise_with_message(ArgumentError, exceeds) {DateTime.iso8601('2001-02-03T04:05:06.123456+00:00', limit: 1)} 421 | assert_raise_with_message(ArgumentError, exceeds) {DateTime.rfc3339('2001-02-03T04:05:06.123456+00:00', limit: 1)} 422 | assert_raise_with_message(ArgumentError, exceeds) {DateTime.jisx0301('H13.02.03T04:05:06.123456+00:00', limit: 1)} 423 | 424 | %w(M06.01.01 425 | M45.07.29 426 | T01.07.30 427 | T15.12.24 428 | S01.12.25 429 | S64.01.07 430 | H01.01.08 431 | H18.09.01 432 | H31.04.30 433 | R01.05.01 434 | ).each do |s| 435 | assert_equal(s, Date.parse(s).jisx0301) 436 | end 437 | 438 | end 439 | 440 | def test_overflow 441 | assert_raise(ArgumentError, Errno::ERANGE) { 442 | Date.new(2000,1,1).strftime("%2147483647c") 443 | } 444 | assert_raise(ArgumentError, Errno::ERANGE) { 445 | DateTime.new(2000,1,1).strftime("%2147483647c") 446 | } 447 | end 448 | end 449 | -------------------------------------------------------------------------------- /test/date/test_date_strptime.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require 'test/unit' 3 | require 'date' 4 | 5 | class TestDateStrptime < Test::Unit::TestCase 6 | 7 | STRFTIME_2001_02_03 = { 8 | '%A'=>['Saturday',{:wday=>6}], 9 | '%a'=>['Sat',{:wday=>6}], 10 | '%B'=>['February',{:mon=>2}], 11 | '%b'=>['Feb',{:mon=>2}], 12 | '%c'=>['Sat Feb 3 00:00:00 2001', 13 | {:wday=>6,:mon=>2,:mday=>3,:hour=>0,:min=>0,:sec=>0,:year=>2001}], 14 | '%d'=>['03',{:mday=>3}], 15 | '%e'=>[' 3',{:mday=>3}], 16 | '%H'=>['00',{:hour=>0}], 17 | '%I'=>['12',{:hour=>0}], 18 | '%j'=>['034',{:yday=>34}], 19 | '%M'=>['00',{:min=>0}], 20 | '%m'=>['02',{:mon=>2}], 21 | '%p'=>['AM',{}], 22 | '%S'=>['00',{:sec=>0}], 23 | '%U'=>['04',{:wnum0=>4}], 24 | '%W'=>['05',{:wnum1=>5}], 25 | '%X'=>['00:00:00',{:hour=>0,:min=>0,:sec=>0}], 26 | '%x'=>['02/03/01',{:mon=>2,:mday=>3,:year=>2001}], 27 | '%Y'=>['2001',{:year=>2001}], 28 | '%y'=>['01',{:year=>2001}], 29 | '%Z'=>['+00:00',{:zone=>'+00:00',:offset=>0}], 30 | '%%'=>['%',{}], 31 | '%C'=>['20',{}], 32 | '%D'=>['02/03/01',{:mon=>2,:mday=>3,:year=>2001}], 33 | '%F'=>['2001-02-03',{:year=>2001,:mon=>2,:mday=>3}], 34 | '%G'=>['2001',{:cwyear=>2001}], 35 | '%g'=>['01',{:cwyear=>2001}], 36 | '%h'=>['Feb',{:mon=>2}], 37 | '%k'=>[' 0',{:hour=>0}], 38 | '%L'=>['000',{:sec_fraction=>0}], 39 | '%l'=>['12',{:hour=>0}], 40 | '%N'=>['000000000',{:sec_fraction=>0}], 41 | '%n'=>["\n",{}], 42 | '%P'=>['am',{}], 43 | '%Q'=>['981158400000',{:seconds=>981158400.to_r}], 44 | '%R'=>['00:00',{:hour=>0,:min=>0}], 45 | '%r'=>['12:00:00 AM',{:hour=>0,:min=>0,:sec=>0}], 46 | '%s'=>['981158400',{:seconds=>981158400}], 47 | '%T'=>['00:00:00',{:hour=>0,:min=>0,:sec=>0}], 48 | '%t'=>["\t",{}], 49 | '%u'=>['6',{:cwday=>6}], 50 | '%V'=>['05',{:cweek=>5}], 51 | '%v'=>[' 3-Feb-2001',{:mday=>3,:mon=>2,:year=>2001}], 52 | '%z'=>['+0000',{:zone=>'+0000',:offset=>0}], 53 | '%+'=>['Sat Feb 3 00:00:00 +00:00 2001', 54 | {:wday=>6,:mon=>2,:mday=>3, 55 | :hour=>0,:min=>0,:sec=>0,:zone=>'+00:00',:offset=>0,:year=>2001}], 56 | } 57 | 58 | STRFTIME_2001_02_03_CVS19 = { 59 | } 60 | 61 | STRFTIME_2001_02_03_GNUext = { 62 | '%:z'=>['+00:00',{:zone=>'+00:00',:offset=>0}], 63 | '%::z'=>['+00:00:00',{:zone=>'+00:00:00',:offset=>0}], 64 | '%:::z'=>['+00',{:zone=>'+00',:offset=>0}], 65 | } 66 | 67 | STRFTIME_2001_02_03.update(STRFTIME_2001_02_03_CVS19) 68 | STRFTIME_2001_02_03.update(STRFTIME_2001_02_03_GNUext) 69 | 70 | def test__strptime 71 | STRFTIME_2001_02_03.each do |f, s| 72 | if (f == '%I' and s[0] == '12') or 73 | (f == '%l' and s[0] == '12') # hour w/o merid 74 | s[1][:hour] = 12 75 | end 76 | assert_equal(s[1], Date._strptime(s[0], f), [f, s].inspect) 77 | case f[-1,1] 78 | when 'c', 'C', 'x', 'X', 'y', 'Y' 79 | f2 = f.sub(/\A%/, '%E') 80 | assert_equal(s[1], Date._strptime(s[0], f2), [f2, s].inspect) 81 | else 82 | f2 = f.sub(/\A%/, '%E') 83 | assert_equal(nil, Date._strptime(s[0], f2), [f2, s].inspect) 84 | assert_equal({}, Date._strptime(f2, f2), [f2, s].inspect) 85 | end 86 | case f[-1,1] 87 | when 'd', 'e', 'H', 'I', 'm', 'M', 'S', 'u', 'U', 'V', 'w', 'W', 'y' 88 | f2 = f.sub(/\A%/, '%O') 89 | assert_equal(s[1], Date._strptime(s[0], f2), [f2, s].inspect) 90 | else 91 | f2 = f.sub(/\A%/, '%O') 92 | assert_equal(nil, Date._strptime(s[0], f2), [f2, s].inspect) 93 | assert_equal({}, Date._strptime(f2, f2), [f2, s].inspect) 94 | end 95 | end 96 | end 97 | 98 | def test__strptime__2 99 | h = Date._strptime('2001-02-03') 100 | assert_equal([2001,2,3], h.values_at(:year,:mon,:mday)) 101 | 102 | h = DateTime._strptime('2001-02-03T12:13:14Z') 103 | assert_equal([2001,2,3,12,13,14], 104 | h.values_at(:year,:mon,:mday,:hour,:min,:sec)) 105 | 106 | assert_equal({}, Date._strptime('', '')) 107 | assert_equal({:leftover=>"\s"*3}, Date._strptime("\s"*3, '')) 108 | assert_equal({:leftover=>'x'}, Date._strptime("\nx", "\n")) 109 | assert_equal({}, Date._strptime('', "\s"*3)) 110 | assert_equal({}, Date._strptime("\s"*3, "\s"*3)) 111 | assert_equal({}, Date._strptime("\tfoo\n\000\r", "\tfoo\n\000\r")) 112 | assert_equal({}, Date._strptime("foo\n\nbar", "foo\sbar")) 113 | assert_equal({}, Date._strptime("%\n", "%\n")) # gnu 114 | assert_equal({}, Date._strptime('%%', '%%%')) 115 | assert_equal({:wday=>6}, Date._strptime('Saturday'*1024 + ',', '%A'*1024 + ',')) 116 | assert_equal({:wday=>6}, Date._strptime('Saturday'*1024 + ',', '%a'*1024 + ',')) 117 | assert_equal({}, Date._strptime('Anton von Webern', 'Anton von Webern')) 118 | end 119 | 120 | def test__strptime__3 121 | [ 122 | # iso8601 123 | [['2001-02-03', '%Y-%m-%d'], [2001,2,3,nil,nil,nil,nil,nil,nil], __LINE__], 124 | [['2001-02-03T23:59:60', '%Y-%m-%dT%H:%M:%S'], [2001,2,3,23,59,60,nil,nil,nil], __LINE__], 125 | [['2001-02-03T23:59:60+09:00', '%Y-%m-%dT%H:%M:%S%Z'], [2001,2,3,23,59,60,'+09:00',9*3600,nil], __LINE__], 126 | [['-2001-02-03T23:59:60+09:00', '%Y-%m-%dT%H:%M:%S%Z'], [-2001,2,3,23,59,60,'+09:00',9*3600,nil], __LINE__], 127 | [['+012345-02-03T23:59:60+09:00', '%Y-%m-%dT%H:%M:%S%Z'], [12345,2,3,23,59,60,'+09:00',9*3600,nil], __LINE__], 128 | [['-012345-02-03T23:59:60+09:00', '%Y-%m-%dT%H:%M:%S%Z'], [-12345,2,3,23,59,60,'+09:00',9*3600,nil], __LINE__], 129 | 130 | # ctime(3), asctime(3) 131 | [['Thu Jul 29 14:47:19 1999', '%c'], [1999,7,29,14,47,19,nil,nil,4], __LINE__], 132 | [['Thu Jul 29 14:47:19 -1999', '%c'], [-1999,7,29,14,47,19,nil,nil,4], __LINE__], 133 | 134 | # date(1) 135 | [['Thu Jul 29 16:39:41 EST 1999', '%a %b %d %H:%M:%S %Z %Y'], [1999,7,29,16,39,41,'EST',-5*3600,4], __LINE__], 136 | [['Thu Jul 29 16:39:41 MET DST 1999', '%a %b %d %H:%M:%S %Z %Y'], [1999,7,29,16,39,41,'MET DST',2*3600,4], __LINE__], 137 | [['Thu Jul 29 16:39:41 AMT 1999', '%a %b %d %H:%M:%S %Z %Y'], [1999,7,29,16,39,41,'AMT',nil,4], __LINE__], 138 | [['Thu Jul 29 16:39:41 AMT -1999', '%a %b %d %H:%M:%S %Z %Y'], [-1999,7,29,16,39,41,'AMT',nil,4], __LINE__], 139 | [['Thu Jul 29 16:39:41 GMT+09 1999', '%a %b %d %H:%M:%S %Z %Y'], [1999,7,29,16,39,41,'GMT+09',9*3600,4], __LINE__], 140 | [['Thu Jul 29 16:39:41 GMT+0908 1999', '%a %b %d %H:%M:%S %Z %Y'], [1999,7,29,16,39,41,'GMT+0908',9*3600+8*60,4], __LINE__], 141 | [['Thu Jul 29 16:39:41 GMT+090807 1999', '%a %b %d %H:%M:%S %Z %Y'], [1999,7,29,16,39,41,'GMT+090807',9*3600+8*60+7,4], __LINE__], 142 | [['Thu Jul 29 16:39:41 GMT-09 1999', '%a %b %d %H:%M:%S %Z %Y'], [1999,7,29,16,39,41,'GMT-09',-9*3600,4], __LINE__], 143 | [['Thu Jul 29 16:39:41 GMT-09:08 1999', '%a %b %d %H:%M:%S %Z %Y'], [1999,7,29,16,39,41,'GMT-09:08',-9*3600-8*60,4], __LINE__], 144 | [['Thu Jul 29 16:39:41 GMT-09:08:07 1999', '%a %b %d %H:%M:%S %Z %Y'], [1999,7,29,16,39,41,'GMT-09:08:07',-9*3600-8*60-7,4], __LINE__], 145 | [['Thu Jul 29 16:39:41 GMT-3.5 1999', '%a %b %d %H:%M:%S %Z %Y'], [1999,7,29,16,39,41,'GMT-3.5',-3*3600-30*60,4], __LINE__], 146 | [['Thu Jul 29 16:39:41 GMT-3,5 1999', '%a %b %d %H:%M:%S %Z %Y'], [1999,7,29,16,39,41,'GMT-3,5',-3*3600-30*60,4], __LINE__], 147 | [['Thu Jul 29 16:39:41 Mountain Daylight Time 1999', '%a %b %d %H:%M:%S %Z %Y'], [1999,7,29,16,39,41,'Mountain Daylight Time',-6*3600,4], __LINE__], 148 | [['Thu Jul 29 16:39:41 E. Australia Standard Time 1999', '%a %b %d %H:%M:%S %Z %Y'], [1999,7,29,16,39,41,'E. Australia Standard Time',10*3600,4], __LINE__], 149 | 150 | # rfc822 151 | [['Thu, 29 Jul 1999 09:54:21 UT', '%a, %d %b %Y %H:%M:%S %Z'], [1999,7,29,9,54,21,'UT',0,4], __LINE__], 152 | [['Thu, 29 Jul 1999 09:54:21 GMT', '%a, %d %b %Y %H:%M:%S %Z'], [1999,7,29,9,54,21,'GMT',0,4], __LINE__], 153 | [['Thu, 29 Jul 1999 09:54:21 PDT', '%a, %d %b %Y %H:%M:%S %Z'], [1999,7,29,9,54,21,'PDT',-7*3600,4], __LINE__], 154 | [['Thu, 29 Jul 1999 09:54:21 z', '%a, %d %b %Y %H:%M:%S %Z'], [1999,7,29,9,54,21,'z',0,4], __LINE__], 155 | [['Thu, 29 Jul 1999 09:54:21 +0900', '%a, %d %b %Y %H:%M:%S %Z'], [1999,7,29,9,54,21,'+0900',9*3600,4], __LINE__], 156 | [['Thu, 29 Jul 1999 09:54:21 +0430', '%a, %d %b %Y %H:%M:%S %Z'], [1999,7,29,9,54,21,'+0430',4*3600+30*60,4], __LINE__], 157 | [['Thu, 29 Jul 1999 09:54:21 -0430', '%a, %d %b %Y %H:%M:%S %Z'], [1999,7,29,9,54,21,'-0430',-4*3600-30*60,4], __LINE__], 158 | [['Thu, 29 Jul -1999 09:54:21 -0430', '%a, %d %b %Y %H:%M:%S %Z'], [-1999,7,29,9,54,21,'-0430',-4*3600-30*60,4], __LINE__], 159 | 160 | # etc 161 | [['06-DEC-99', '%d-%b-%y'], [1999,12,6,nil,nil,nil,nil,nil,nil], __LINE__], 162 | [['sUnDay oCtoBer 31 01', '%A %B %d %y'], [2001,10,31,nil,nil,nil,nil,nil,0], __LINE__], 163 | [["October\t\n\v\f\r 15,\t\n\v\f\r99", '%B %d, %y'], [1999,10,15,nil,nil,nil,nil,nil,nil], __LINE__], 164 | [["October\t\n\v\f\r 15,\t\n\v\f\r99", '%B%t%d,%n%y'], [1999,10,15,nil,nil,nil,nil,nil,nil], __LINE__], 165 | 166 | [['09:02:11 AM', '%I:%M:%S %p'], [nil,nil,nil,9,2,11,nil,nil,nil], __LINE__], 167 | [['09:02:11 A.M.', '%I:%M:%S %p'], [nil,nil,nil,9,2,11,nil,nil,nil], __LINE__], 168 | [['09:02:11 PM', '%I:%M:%S %p'], [nil,nil,nil,21,2,11,nil,nil,nil], __LINE__], 169 | [['09:02:11 P.M.', '%I:%M:%S %p'], [nil,nil,nil,21,2,11,nil,nil,nil], __LINE__], 170 | 171 | [['12:33:44 AM', '%r'], [nil,nil,nil,0,33,44,nil,nil,nil], __LINE__], 172 | [['01:33:44 AM', '%r'], [nil,nil,nil,1,33,44,nil,nil,nil], __LINE__], 173 | [['11:33:44 AM', '%r'], [nil,nil,nil,11,33,44,nil,nil,nil], __LINE__], 174 | [['12:33:44 PM', '%r'], [nil,nil,nil,12,33,44,nil,nil,nil], __LINE__], 175 | [['01:33:44 PM', '%r'], [nil,nil,nil,13,33,44,nil,nil,nil], __LINE__], 176 | [['11:33:44 PM', '%r'], [nil,nil,nil,23,33,44,nil,nil,nil], __LINE__], 177 | 178 | [['11:33:44 PM AMT', '%I:%M:%S %p %Z'], [nil,nil,nil,23,33,44,'AMT',nil,nil], __LINE__], 179 | [['11:33:44 P.M. AMT', '%I:%M:%S %p %Z'], [nil,nil,nil,23,33,44,'AMT',nil,nil], __LINE__], 180 | 181 | [['fri1feb034pm+5', '%a%d%b%y%H%p%Z'], [2003,2,1,16,nil,nil,'+5',5*3600,5]], 182 | [['E. Australia Standard Time', '%Z'], [nil,nil,nil,nil,nil,nil,'E. Australia Standard Time',10*3600,nil], __LINE__], 183 | 184 | # out of range 185 | [['+0.9999999999999999999999', '%Z'], [nil,nil,nil,nil,nil,nil,'+0.9999999999999999999999',+1*3600,nil], __LINE__], 186 | [['+9999999999999999999999.0', '%Z'], [nil,nil,nil,nil,nil,nil,'+9999999999999999999999.0',nil,nil], __LINE__], 187 | ].each do |x, y| 188 | h = Date._strptime(*x) 189 | a = h.values_at(:year,:mon,:mday,:hour,:min,:sec,:zone,:offset,:wday) 190 | if y[1] == -1 191 | a[1] = -1 192 | a[2] = h[:yday] 193 | end 194 | assert_equal(y, a, [x, y, a].inspect) 195 | end 196 | end 197 | 198 | def test__strptime__width 199 | [ 200 | [['99', '%y'], [1999,nil,nil,nil,nil,nil,nil,nil,nil], __LINE__], 201 | [['01', '%y'], [2001,nil,nil,nil,nil,nil,nil,nil,nil], __LINE__], 202 | [['19 99', '%C %y'], [1999,nil,nil,nil,nil,nil,nil,nil,nil], __LINE__], 203 | [['20 01', '%C %y'], [2001,nil,nil,nil,nil,nil,nil,nil,nil], __LINE__], 204 | [['30 99', '%C %y'], [3099,nil,nil,nil,nil,nil,nil,nil,nil], __LINE__], 205 | [['30 01', '%C %y'], [3001,nil,nil,nil,nil,nil,nil,nil,nil], __LINE__], 206 | [['1999', '%C%y'], [1999,nil,nil,nil,nil,nil,nil,nil,nil], __LINE__], 207 | [['2001', '%C%y'], [2001,nil,nil,nil,nil,nil,nil,nil,nil], __LINE__], 208 | [['3099', '%C%y'], [3099,nil,nil,nil,nil,nil,nil,nil,nil], __LINE__], 209 | [['3001', '%C%y'], [3001,nil,nil,nil,nil,nil,nil,nil,nil], __LINE__], 210 | 211 | [['20060806', '%Y'], [20060806,nil,nil,nil,nil,nil,nil,nil,nil], __LINE__], 212 | [['20060806', "%Y\s"], [20060806,nil,nil,nil,nil,nil,nil,nil,nil], __LINE__], 213 | [['20060806', '%Y%m%d'], [2006,8,6,nil,nil,nil,nil,nil,nil], __LINE__], 214 | [['2006908906', '%Y9%m9%d'], [2006,8,6,nil,nil,nil,nil,nil,nil], __LINE__], 215 | [['12006 08 06', '%Y %m %d'], [12006,8,6,nil,nil,nil,nil,nil,nil], __LINE__], 216 | [['12006-08-06', '%Y-%m-%d'], [12006,8,6,nil,nil,nil,nil,nil,nil], __LINE__], 217 | [['200608 6', '%Y%m%e'], [2006,8,6,nil,nil,nil,nil,nil,nil], __LINE__], 218 | 219 | [['2006333', '%Y%j'], [2006,-1,333,nil,nil,nil,nil,nil,nil], __LINE__], 220 | [['20069333', '%Y9%j'], [2006,-1,333,nil,nil,nil,nil,nil,nil], __LINE__], 221 | [['12006 333', '%Y %j'], [12006,-1,333,nil,nil,nil,nil,nil,nil], __LINE__], 222 | [['12006-333', '%Y-%j'], [12006,-1,333,nil,nil,nil,nil,nil,nil], __LINE__], 223 | 224 | [['232425', '%H%M%S'], [nil,nil,nil,23,24,25,nil,nil,nil], __LINE__], 225 | [['23924925', '%H9%M9%S'], [nil,nil,nil,23,24,25,nil,nil,nil], __LINE__], 226 | [['23 24 25', '%H %M %S'], [nil,nil,nil,23,24,25,nil,nil,nil], __LINE__], 227 | [['23:24:25', '%H:%M:%S'], [nil,nil,nil,23,24,25,nil,nil,nil], __LINE__], 228 | [[' 32425', '%k%M%S'], [nil,nil,nil,3,24,25,nil,nil,nil], __LINE__], 229 | [[' 32425', '%l%M%S'], [nil,nil,nil,3,24,25,nil,nil,nil], __LINE__], 230 | 231 | [['FriAug', '%a%b'], [nil,8,nil,nil,nil,nil,nil,nil,5], __LINE__], 232 | [['FriAug', '%A%B'], [nil,8,nil,nil,nil,nil,nil,nil,5], __LINE__], 233 | [['FridayAugust', '%A%B'], [nil,8,nil,nil,nil,nil,nil,nil,5], __LINE__], 234 | [['FridayAugust', '%a%b'], [nil,8,nil,nil,nil,nil,nil,nil,5], __LINE__], 235 | ].each do |x,y,l| 236 | h = Date._strptime(*x) 237 | a = (h || {}).values_at(:year,:mon,:mday,:hour,:min,:sec,:zone,:offset,:wday) 238 | if y[1] == -1 239 | a[1] = -1 240 | a[2] = h[:yday] 241 | end 242 | assert_equal(y, a, format('', l)) 243 | end 244 | end 245 | 246 | def test__strptime__fail 247 | assert_not_nil(Date._strptime('2001.', '%Y.')) 248 | assert_not_nil(Date._strptime("2001.\s", '%Y.')) 249 | assert_not_nil(Date._strptime('2001.', "%Y.\s")) 250 | assert_not_nil(Date._strptime("2001.\s", "%Y.\s")) 251 | 252 | assert_nil(Date._strptime('2001', '%Y.')) 253 | assert_nil(Date._strptime("2001\s", '%Y.')) 254 | assert_nil(Date._strptime('2001', "%Y.\s")) 255 | assert_nil(Date._strptime("2001\s", "%Y.\s")) 256 | 257 | assert_nil(Date._strptime('2001-13-31', '%Y-%m-%d')) 258 | assert_nil(Date._strptime('2001-12-00', '%Y-%m-%d')) 259 | assert_nil(Date._strptime('2001-12-32', '%Y-%m-%d')) 260 | assert_nil(Date._strptime('2001-12-00', '%Y-%m-%e')) 261 | assert_nil(Date._strptime('2001-12-32', '%Y-%m-%e')) 262 | assert_nil(Date._strptime('2001-12-31', '%y-%m-%d')) 263 | 264 | assert_nil(Date._strptime('2004-000', '%Y-%j')) 265 | assert_nil(Date._strptime('2004-367', '%Y-%j')) 266 | assert_nil(Date._strptime('2004-366', '%y-%j')) 267 | 268 | assert_not_nil(Date._strptime('24:59:59', '%H:%M:%S')) 269 | assert_not_nil(Date._strptime('24:59:59', '%k:%M:%S')) 270 | assert_not_nil(Date._strptime('24:59:60', '%H:%M:%S')) 271 | assert_not_nil(Date._strptime('24:59:60', '%k:%M:%S')) 272 | 273 | assert_nil(Date._strptime('24:60:59', '%H:%M:%S')) 274 | assert_nil(Date._strptime('24:60:59', '%k:%M:%S')) 275 | assert_nil(Date._strptime('24:59:61', '%H:%M:%S')) 276 | assert_nil(Date._strptime('24:59:61', '%k:%M:%S')) 277 | assert_nil(Date._strptime('00:59:59', '%I:%M:%S')) 278 | assert_nil(Date._strptime('13:59:59', '%I:%M:%S')) 279 | assert_nil(Date._strptime('00:59:59', '%l:%M:%S')) 280 | assert_nil(Date._strptime('13:59:59', '%l:%M:%S')) 281 | 282 | assert_not_nil(Date._strptime('0', '%U')) 283 | assert_nil(Date._strptime('54', '%U')) 284 | assert_not_nil(Date._strptime('0', '%W')) 285 | assert_nil(Date._strptime('54', '%W')) 286 | assert_nil(Date._strptime('0', '%V')) 287 | assert_nil(Date._strptime('54', '%V')) 288 | assert_nil(Date._strptime('0', '%u')) 289 | assert_not_nil(Date._strptime('7', '%u')) 290 | assert_not_nil(Date._strptime('0', '%w')) 291 | assert_nil(Date._strptime('7', '%w')) 292 | 293 | assert_nil(Date._strptime('Sanday', '%A')) 294 | assert_nil(Date._strptime('Jenuary', '%B')) 295 | assert_not_nil(Date._strptime('Sundai', '%A')) 296 | assert_not_nil(Date._strptime('Januari', '%B')) 297 | assert_nil(Date._strptime('Sundai,', '%A,')) 298 | assert_nil(Date._strptime('Januari,', '%B,')) 299 | 300 | assert_nil(Date._strptime('+24:00', '%Z')[:offset]) 301 | assert_nil(Date._strptime('+23:60', '%Z')[:offset]) 302 | assert_nil(Date._strptime('+23:00:60', '%Z')[:offset]) 303 | assert_nil(Date._strptime('+23:00:60', '%Z')[:offset]) 304 | end 305 | 306 | def test_strptime 307 | assert_equal(Date.new, Date.strptime) 308 | d = Date.new(2002,3,14) 309 | assert_equal(d, Date.strptime(d.to_s)) 310 | assert_equal(Date.new(2002,3,14), Date.strptime('2002-03-14')) 311 | 312 | d = DateTime.new(2002,3,14,11,22,33, 0) 313 | assert_equal(d, DateTime.strptime(d.to_s)) 314 | assert_equal(DateTime.new(2002,3,14,11,22,33, 0), 315 | DateTime.strptime('2002-03-14T11:22:33Z')) 316 | assert_equal(DateTime.new(2002,3,14,11,22,33, 0), 317 | DateTime.strptime('2002-03-14T11:22:33Z', '%Y-%m-%dT%H:%M:%S%Z')) 318 | assert_equal(DateTime.new(2002,3,14,11,22,33, 9.to_r/24), 319 | DateTime.strptime('2002-03-14T11:22:33+09:00', '%Y-%m-%dT%H:%M:%S%Z')) 320 | assert_equal(DateTime.new(2002,3,14,11,22,33, -9.to_r/24), 321 | DateTime.strptime('2002-03-14T11:22:33-09:00', '%FT%T%Z')) 322 | assert_equal(DateTime.new(2002,3,14,11,22,33, -9.to_r/24) + 123456789.to_r/1000000000/86400, 323 | DateTime.strptime('2002-03-14T11:22:33.123456789-09:00', '%FT%T.%N%Z')) 324 | end 325 | 326 | def test_strptime__2 327 | (Date.new(2006,6,1)..Date.new(2007,6,1)).each do |d| 328 | [ 329 | '%Y %m %d', 330 | '%C %y %m %d', 331 | 332 | '%Y %j', 333 | '%C %y %j', 334 | 335 | '%G %V %w', 336 | '%G %V %u', 337 | '%C %g %V %w', 338 | '%C %g %V %u', 339 | 340 | '%Y %U %w', 341 | '%Y %U %u', 342 | '%Y %W %w', 343 | '%Y %W %u', 344 | '%C %y %U %w', 345 | '%C %y %U %u', 346 | '%C %y %W %w', 347 | '%C %y %W %u', 348 | ].each do |fmt| 349 | s = d.strftime(fmt) 350 | d2 = Date.strptime(s, fmt) 351 | assert_equal(d, d2, [fmt, d.to_s, d2.to_s].inspect) 352 | end 353 | 354 | [ 355 | '%Y %m %d %H %M %S', 356 | '%Y %m %d %H %M %S %N', 357 | '%C %y %m %d %H %M %S', 358 | '%C %y %m %d %H %M %S %N', 359 | 360 | '%Y %j %H %M %S', 361 | '%Y %j %H %M %S %N', 362 | '%C %y %j %H %M %S', 363 | '%C %y %j %H %M %S %N', 364 | 365 | '%s', 366 | '%s %N', 367 | '%Q', 368 | '%Q %N', 369 | ].each do |fmt| 370 | s = d.strftime(fmt) 371 | d2 = DateTime.strptime(s, fmt) 372 | assert_equal(d, d2, [fmt, d.to_s, d2.to_s].inspect) 373 | end 374 | end 375 | end 376 | 377 | def test_strptime__minus 378 | d = DateTime.strptime('-1', '%s') 379 | assert_equal([1969, 12, 31, 23, 59, 59], 380 | [d.year, d.mon, d.mday, d.hour, d.min, d.sec]) 381 | d = DateTime.strptime('-86400', '%s') 382 | assert_equal([1969, 12, 31, 0, 0, 0], 383 | [d.year, d.mon, d.mday, d.hour, d.min, d.sec]) 384 | 385 | d = DateTime.strptime('-999', '%Q') 386 | assert_equal([1969, 12, 31, 23, 59, 59, 1.to_r/10**3], 387 | [d.year, d.mon, d.mday, d.hour, d.min, d.sec, d.sec_fraction]) 388 | d = DateTime.strptime('-1000', '%Q') 389 | assert_equal([1969, 12, 31, 23, 59, 59, 0], 390 | [d.year, d.mon, d.mday, d.hour, d.min, d.sec, d.sec_fraction]) 391 | end 392 | 393 | def test_strptime__comp 394 | n = DateTime.now 395 | 396 | d = DateTime.strptime('073', '%j') 397 | assert_equal([n.year, 73, 0, 0, 0], 398 | [d.year, d.yday, d.hour, d.min, d.sec]) 399 | d = DateTime.strptime('13', '%d') 400 | assert_equal([n.year, n.mon, 13, 0, 0, 0], 401 | [d.year, d.mon, d.mday, d.hour, d.min, d.sec]) 402 | 403 | d = DateTime.strptime('Mar', '%b') 404 | assert_equal([n.year, 3, 1, 0, 0, 0], 405 | [d.year, d.mon, d.mday, d.hour, d.min, d.sec]) 406 | d = DateTime.strptime('2004', '%Y') 407 | assert_equal([2004, 1, 1, 0, 0, 0], 408 | [d.year, d.mon, d.mday, d.hour, d.min, d.sec]) 409 | 410 | d = DateTime.strptime('Mar 13', '%b %d') 411 | assert_equal([n.year, 3, 13, 0, 0, 0], 412 | [d.year, d.mon, d.mday, d.hour, d.min, d.sec]) 413 | d = DateTime.strptime('Mar 2004', '%b %Y') 414 | assert_equal([2004, 3, 1, 0, 0, 0], 415 | [d.year, d.mon, d.mday, d.hour, d.min, d.sec]) 416 | d = DateTime.strptime('23:55', '%H:%M') 417 | assert_equal([n.year, n.mon, n.mday, 23, 55, 0], 418 | [d.year, d.mon, d.mday, d.hour, d.min, d.sec]) 419 | d = DateTime.strptime('23:55:30', '%H:%M:%S') 420 | assert_equal([n.year, n.mon, n.mday, 23, 55, 30], 421 | [d.year, d.mon, d.mday, d.hour, d.min, d.sec]) 422 | 423 | d = DateTime.strptime('Sun 23:55', '%a %H:%M') 424 | d2 = d - d.wday 425 | assert_equal([d2.year, d2.mon, d2.mday, 23, 55, 0], 426 | [d.year, d.mon, d.mday, d.hour, d.min, d.sec]) 427 | d = DateTime.strptime('Aug 23:55', '%b %H:%M') 428 | assert_equal([n.year, 8, 1, 23, 55, 0], 429 | [d.year, d.mon, d.mday, d.hour, d.min, d.sec]) 430 | 431 | d = DateTime.strptime('2004', '%G') 432 | assert_equal([2004, 1, 1, 0, 0, 0], 433 | [d.cwyear, d.cweek, d.cwday, d.hour, d.min, d.sec]) 434 | d = DateTime.strptime('11', '%V') 435 | assert_equal([n.cwyear, 11, 1, 0, 0, 0], 436 | [d.cwyear, d.cweek, d.cwday, d.hour, d.min, d.sec]) 437 | d = DateTime.strptime('6', '%u') 438 | assert_equal([n.cwyear, n.cweek, 6, 0, 0, 0], 439 | [d.cwyear, d.cweek, d.cwday, d.hour, d.min, d.sec]) 440 | 441 | d = DateTime.strptime('11-6', '%V-%u') 442 | assert_equal([n.cwyear, 11, 6, 0, 0, 0], 443 | [d.cwyear, d.cweek, d.cwday, d.hour, d.min, d.sec]) 444 | d = DateTime.strptime('2004-11', '%G-%V') 445 | assert_equal([2004, 11, 1, 0, 0, 0], 446 | [d.cwyear, d.cweek, d.cwday, d.hour, d.min, d.sec]) 447 | 448 | d = DateTime.strptime('11-6', '%U-%w') 449 | assert_equal([n.year, 11, 6, 0, 0, 0], 450 | [d.year, d.strftime('%U').to_i, d.wday, d.hour, d.min, d.sec]) 451 | d = DateTime.strptime('2004-11', '%Y-%U') 452 | assert_equal([2004, 11, 0, 0, 0, 0], 453 | [d.year, d.strftime('%U').to_i, d.wday, d.hour, d.min, d.sec]) 454 | 455 | d = DateTime.strptime('11-6', '%W-%w') 456 | assert_equal([n.year, 11, 6, 0, 0, 0], 457 | [d.year, d.strftime('%W').to_i, d.wday, d.hour, d.min, d.sec]) 458 | d = DateTime.strptime('2004-11', '%Y-%W') 459 | assert_equal([2004, 11, 1, 0, 0, 0], 460 | [d.year, d.strftime('%W').to_i, d.wday, d.hour, d.min, d.sec]) 461 | end 462 | 463 | def test_strptime__d_to_s 464 | d = Date.new(2002,3,14) 465 | assert_equal(d, Date.strptime(d.to_s)) 466 | 467 | d = DateTime.new(2002,3,14,11,22,33, 9.to_r/24) 468 | assert_equal(d, DateTime.strptime(d.to_s)) 469 | end 470 | 471 | def test_strptime__ex 472 | assert_raise(Date::Error) do 473 | Date.strptime('') 474 | end 475 | assert_raise(Date::Error) do 476 | DateTime.strptime('') 477 | end 478 | assert_raise(Date::Error) do 479 | Date.strptime('2001-02-29', '%F') 480 | end 481 | assert_raise(Date::Error) do 482 | DateTime.strptime('2001-02-29T23:59:60', '%FT%T') 483 | end 484 | assert_nothing_raised(Date::Error) do 485 | DateTime.strptime('2001-03-01T23:59:60', '%FT%T') 486 | end 487 | assert_raise(Date::Error) do 488 | DateTime.strptime('2001-03-01T23:59:61', '%FT%T') 489 | end 490 | assert_raise(Date::Error) do 491 | Date.strptime('23:55', '%H:%M') 492 | end 493 | assert_raise(Date::Error) do 494 | Date.strptime('01-31-2011', '%m/%d/%Y') 495 | end 496 | end 497 | 498 | def test_given_string 499 | s = '2001-02-03T04:05:06Z' 500 | s0 = s.dup 501 | 502 | assert_not_equal({}, Date._strptime(s, '%FT%T%Z')) 503 | assert_equal(s0, s) 504 | end 505 | 506 | def test_sz 507 | d = DateTime.strptime('0 -0200', '%s %z') 508 | assert_equal([1969, 12, 31, 22, 0, 0], [d.year, d.mon, d.mday, d.hour, d.min, d.sec]) 509 | assert_equal(Rational(-2, 24), d.offset) 510 | d = DateTime.strptime('9 +0200', '%s %z') 511 | assert_equal([1970, 1, 1, 2, 0, 9], [d.year, d.mon, d.mday, d.hour, d.min, d.sec]) 512 | assert_equal(Rational(2, 24), d.offset) 513 | 514 | d = DateTime.strptime('0 -0200', '%Q %z') 515 | assert_equal([1969, 12, 31, 22, 0, 0], [d.year, d.mon, d.mday, d.hour, d.min, d.sec]) 516 | assert_equal(Rational(-2, 24), d.offset) 517 | d = DateTime.strptime('9000 +0200', '%Q %z') 518 | assert_equal([1970, 1, 1, 2, 0, 9], [d.year, d.mon, d.mday, d.hour, d.min, d.sec]) 519 | assert_equal(Rational(2, 24), d.offset) 520 | 521 | end 522 | 523 | end 524 | -------------------------------------------------------------------------------- /test/date/test_switch_hitter.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require 'test/unit' 3 | require 'date' 4 | 5 | class TestSH < Test::Unit::TestCase 6 | 7 | def test_new 8 | [Date.new, 9 | Date.civil, 10 | DateTime.new, 11 | DateTime.civil 12 | ].each do |d| 13 | assert_equal([-4712, 1, 1], [d.year, d.mon, d.mday]) 14 | end 15 | 16 | [Date.new(2001), 17 | Date.civil(2001), 18 | DateTime.new(2001), 19 | DateTime.civil(2001) 20 | ].each do |d| 21 | assert_equal([2001, 1, 1], [d.year, d.mon, d.mday]) 22 | end 23 | 24 | d = Date.new(2001, 2, 3) 25 | assert_equal([2001, 2, 3], [d.year, d.mon, d.mday]) 26 | d = Date.new(2001, 2, Rational('3.5')) 27 | assert_equal([2001, 2, 3], [d.year, d.mon, d.mday]) 28 | d = Date.new(2001,2, 3, Date::JULIAN) 29 | assert_equal([2001, 2, 3], [d.year, d.mon, d.mday]) 30 | d = Date.new(2001,2, 3, Date::GREGORIAN) 31 | assert_equal([2001, 2, 3], [d.year, d.mon, d.mday]) 32 | 33 | d = Date.new(2001,-12, -31) 34 | assert_equal([2001, 1, 1], [d.year, d.mon, d.mday]) 35 | d = Date.new(2001,-12, -31, Date::JULIAN) 36 | assert_equal([2001, 1, 1], [d.year, d.mon, d.mday]) 37 | d = Date.new(2001,-12, -31, Date::GREGORIAN) 38 | assert_equal([2001, 1, 1], [d.year, d.mon, d.mday]) 39 | 40 | d = DateTime.new(2001, 2, 3, 4, 5, 6) 41 | assert_equal([2001, 2, 3, 4, 5, 6, 0], 42 | [d.year, d.mon, d.mday, d.hour, d.min, d.sec, d.offset]) 43 | d = DateTime.new(2001, 2, 3, 4, 5, 6, 0) 44 | assert_equal([2001, 2, 3, 4, 5, 6, 0], 45 | [d.year, d.mon, d.mday, d.hour, d.min, d.sec, d.offset]) 46 | d = DateTime.new(2001, 2, 3, 4, 5, 6, Rational(9,24)) 47 | assert_equal([2001, 2, 3, 4, 5, 6, Rational(9,24)], 48 | [d.year, d.mon, d.mday, d.hour, d.min, d.sec, d.offset]) 49 | d = DateTime.new(2001, 2, 3, 4, 5, 6, 0.375) 50 | assert_equal([2001, 2, 3, 4, 5, 6, Rational(9,24)], 51 | [d.year, d.mon, d.mday, d.hour, d.min, d.sec, d.offset]) 52 | d = DateTime.new(2001, 2, 3, 4, 5, 6, '+09:00') 53 | assert_equal([2001, 2, 3, 4, 5, 6, Rational(9,24)], 54 | [d.year, d.mon, d.mday, d.hour, d.min, d.sec, d.offset]) 55 | d = DateTime.new(2001, 2, 3, 4, 5, 6, '-09:00') 56 | assert_equal([2001, 2, 3, 4, 5, 6, Rational(-9,24)], 57 | [d.year, d.mon, d.mday, d.hour, d.min, d.sec, d.offset]) 58 | d = DateTime.new(2001, -12, -31, -4, -5, -6, '-09:00') 59 | assert_equal([2001, 1, 1, 20, 55, 54, Rational(-9,24)], 60 | [d.year, d.mon, d.mday, d.hour, d.min, d.sec, d.offset]) 61 | d = DateTime.new(2001, -12, -31, -4, -5, -6, '-09:00', Date::JULIAN) 62 | assert_equal([2001, 1, 1, 20, 55, 54, Rational(-9,24)], 63 | [d.year, d.mon, d.mday, d.hour, d.min, d.sec, d.offset]) 64 | d = DateTime.new(2001, -12, -31, -4, -5, -6, '-09:00', Date::GREGORIAN) 65 | assert_equal([2001, 1, 1, 20, 55, 54, Rational(-9,24)], 66 | [d.year, d.mon, d.mday, d.hour, d.min, d.sec, d.offset]) 67 | end 68 | 69 | def test_jd 70 | d = Date.jd 71 | assert_equal([-4712, 1, 1], [d.year, d.mon, d.mday]) 72 | d = Date.jd(0) 73 | assert_equal([-4712, 1, 1], [d.year, d.mon, d.mday]) 74 | d = Date.jd(2451944) 75 | assert_equal([2001, 2, 3], [d.year, d.mon, d.mday]) 76 | 77 | d = DateTime.jd 78 | assert_equal([-4712, 1, 1, 0, 0, 0, 0], 79 | [d.year, d.mon, d.mday, d.hour, d.min, d.sec, d.offset]) 80 | d = DateTime.jd(0) 81 | assert_equal([-4712, 1, 1, 0, 0, 0, 0], 82 | [d.year, d.mon, d.mday, d.hour, d.min, d.sec, d.offset]) 83 | d = DateTime.jd(2451944) 84 | assert_equal([2001, 2, 3, 0, 0, 0, 0], 85 | [d.year, d.mon, d.mday, d.hour, d.min, d.sec, d.offset]) 86 | d = DateTime.jd(2451944, 4, 5, 6) 87 | assert_equal([2001, 2, 3, 4, 5, 6, 0], 88 | [d.year, d.mon, d.mday, d.hour, d.min, d.sec, d.offset]) 89 | d = DateTime.jd(2451944, 4, 5, 6, 0) 90 | assert_equal([2001, 2, 3, 4, 5, 6, 0], 91 | [d.year, d.mon, d.mday, d.hour, d.min, d.sec, d.offset]) 92 | d = DateTime.jd(2451944, 4, 5, 6, '+9:00') 93 | assert_equal([2001, 2, 3, 4, 5, 6, Rational(9, 24)], 94 | [d.year, d.mon, d.mday, d.hour, d.min, d.sec, d.offset]) 95 | d = DateTime.jd(2451944, -4, -5, -6, '-9:00') 96 | assert_equal([2001, 2, 3, 20, 55, 54, Rational(-9, 24)], 97 | [d.year, d.mon, d.mday, d.hour, d.min, d.sec, d.offset]) 98 | end 99 | 100 | def test_ordinal 101 | d = Date.ordinal 102 | assert_equal([-4712, 1], [d.year, d.yday]) 103 | d = Date.ordinal(-4712, 1) 104 | assert_equal([-4712, 1], [d.year, d.yday]) 105 | 106 | d = Date.ordinal(2001, 2) 107 | assert_equal([2001, 2], [d.year, d.yday]) 108 | d = Date.ordinal(2001, 2, Date::JULIAN) 109 | assert_equal([2001, 2], [d.year, d.yday]) 110 | d = Date.ordinal(2001, 2, Date::GREGORIAN) 111 | assert_equal([2001, 2], [d.year, d.yday]) 112 | 113 | d = Date.ordinal(2001, -2, Date::JULIAN) 114 | assert_equal([2001, 364], [d.year, d.yday]) 115 | d = Date.ordinal(2001, -2, Date::GREGORIAN) 116 | assert_equal([2001, 364], [d.year, d.yday]) 117 | 118 | d = DateTime.ordinal 119 | assert_equal([-4712, 1, 1, 0, 0, 0, 0], 120 | [d.year, d.mon, d.mday, d.hour, d.min, d.sec, d.offset]) 121 | d = DateTime.ordinal(-4712, 1) 122 | assert_equal([-4712, 1, 1, 0, 0, 0, 0], 123 | [d.year, d.mon, d.mday, d.hour, d.min, d.sec, d.offset]) 124 | d = DateTime.ordinal(2001, 34) 125 | assert_equal([2001, 2, 3, 0, 0, 0, 0], 126 | [d.year, d.mon, d.mday, d.hour, d.min, d.sec, d.offset]) 127 | d = DateTime.ordinal(2001, 34, 4, 5, 6) 128 | assert_equal([2001, 2, 3, 4, 5, 6, 0], 129 | [d.year, d.mon, d.mday, d.hour, d.min, d.sec, d.offset]) 130 | d = DateTime.ordinal(2001, 34, 4, 5, 6, 0) 131 | assert_equal([2001, 2, 3, 4, 5, 6, 0], 132 | [d.year, d.mon, d.mday, d.hour, d.min, d.sec, d.offset]) 133 | d = DateTime.ordinal(2001, 34, 4, 5, 6, '+9:00') 134 | assert_equal([2001, 2, 3, 4, 5, 6, Rational(9, 24)], 135 | [d.year, d.mon, d.mday, d.hour, d.min, d.sec, d.offset]) 136 | d = DateTime.ordinal(2001, 34, -4, -5, -6, '-9:00') 137 | assert_equal([2001, 2, 3, 20, 55, 54, Rational(-9, 24)], 138 | [d.year, d.mon, d.mday, d.hour, d.min, d.sec, d.offset]) 139 | end 140 | 141 | def test_commercial 142 | d = Date.commercial 143 | assert_equal([-4712, 1, 1], [d.cwyear, d.cweek, d.cwday]) 144 | d = Date.commercial(-4712, 1, 1) 145 | assert_equal([-4712, 1, 1], [d.cwyear, d.cweek, d.cwday]) 146 | 147 | d = Date.commercial(2001, 2, 3) 148 | assert_equal([2001, 2, 3], [d.cwyear, d.cweek, d.cwday]) 149 | d = Date.commercial(2001, 2, 3, Date::JULIAN) 150 | assert_equal([2001, 2, 3], [d.cwyear, d.cweek, d.cwday]) 151 | d = Date.commercial(2001, 2, 3, Date::GREGORIAN) 152 | assert_equal([2001, 2, 3], [d.cwyear, d.cweek, d.cwday]) 153 | 154 | d = Date.commercial(2001, -2, -3) 155 | assert_equal([2001, 51, 5], [d.cwyear, d.cweek, d.cwday]) 156 | d = Date.commercial(2001, -2, -3, Date::JULIAN) 157 | assert_equal([2001, 51, 5], [d.cwyear, d.cweek, d.cwday]) 158 | d = Date.commercial(2001, -2, -3, Date::GREGORIAN) 159 | assert_equal([2001, 51, 5], [d.cwyear, d.cweek, d.cwday]) 160 | 161 | d = DateTime.commercial 162 | assert_equal([-4712, 1, 1, 0, 0, 0, 0], 163 | [d.year, d.mon, d.mday, d.hour, d.min, d.sec, d.offset]) 164 | d = DateTime.commercial(-4712, 1, 1) 165 | assert_equal([-4712, 1, 1, 0, 0, 0, 0], 166 | [d.year, d.mon, d.mday, d.hour, d.min, d.sec, d.offset]) 167 | d = DateTime.commercial(2001, 5, 6) 168 | assert_equal([2001, 2, 3, 0, 0, 0, 0], 169 | [d.year, d.mon, d.mday, d.hour, d.min, d.sec, d.offset]) 170 | d = DateTime.commercial(2001, 5, 6, 4, 5, 6) 171 | assert_equal([2001, 2, 3, 4, 5, 6, 0], 172 | [d.year, d.mon, d.mday, d.hour, d.min, d.sec, d.offset]) 173 | d = DateTime.commercial(2001, 5, 6, 4, 5, 6, 0) 174 | assert_equal([2001, 2, 3, 4, 5, 6, 0], 175 | [d.year, d.mon, d.mday, d.hour, d.min, d.sec, d.offset]) 176 | d = DateTime.commercial(2001, 5, 6, 4, 5, 6, '+9:00') 177 | assert_equal([2001, 2, 3, 4, 5, 6, Rational(9, 24)], 178 | [d.year, d.mon, d.mday, d.hour, d.min, d.sec, d.offset]) 179 | d = DateTime.commercial(2001, 5, 6, -4, -5, -6, '-9:00') 180 | assert_equal([2001, 2, 3, 20, 55, 54, Rational(-9, 24)], 181 | [d.year, d.mon, d.mday, d.hour, d.min, d.sec, d.offset]) 182 | end 183 | 184 | def test_fractional 185 | d = Date.jd(2451944.0) 186 | assert_equal(2451944, d.jd) 187 | d = Date.jd(Rational(2451944)) 188 | assert_equal(2451944, d.jd) 189 | d = Date.jd(2451944.5) 190 | assert_equal(2451944, d.jd) 191 | d = Date.jd(Rational('2451944.5')) 192 | assert_equal(2451944, d.jd) 193 | 194 | d = Date.civil(2001, 2, 3.0) 195 | assert_equal([2001, 2, 3], [d.year, d.mon, d.mday]) 196 | d = Date.civil(2001, 2, Rational(3)) 197 | assert_equal([2001, 2, 3], [d.year, d.mon, d.mday]) 198 | d = Date.civil(2001, 2, 3.5) 199 | assert_equal([2001, 2, 3], [d.year, d.mon, d.mday]) 200 | d = Date.civil(2001, 2, Rational('3.5')) 201 | assert_equal([2001, 2, 3], [d.year, d.mon, d.mday]) 202 | 203 | d = Date.ordinal(2001, 2.0) 204 | assert_equal([2001, 2], [d.year, d.yday]) 205 | d = Date.ordinal(2001, Rational(2)) 206 | assert_equal([2001, 2], [d.year, d.yday]) 207 | 208 | d = Date.commercial(2001, 2, 3.0) 209 | assert_equal([2001, 2, 3], [d.cwyear, d.cweek, d.cwday]) 210 | d = Date.commercial(2001, 2, Rational(3)) 211 | assert_equal([2001, 2, 3], [d.cwyear, d.cweek, d.cwday]) 212 | 213 | d = DateTime.jd(2451944.0) 214 | assert_equal(2451944, d.jd) 215 | d = DateTime.jd(Rational(2451944)) 216 | assert_equal(2451944, d.jd) 217 | d = DateTime.jd(2451944.5) 218 | assert_equal([2451944, 12], [d.jd, d.hour]) 219 | d = DateTime.jd(Rational('2451944.5')) 220 | assert_equal([2451944, 12], [d.jd, d.hour]) 221 | 222 | d = DateTime.civil(2001, 2, 3.0) 223 | assert_equal([2001, 2, 3], [d.year, d.mon, d.mday]) 224 | d = DateTime.civil(2001, 2, Rational(3)) 225 | assert_equal([2001, 2, 3], [d.year, d.mon, d.mday]) 226 | d = DateTime.civil(2001, 2, 3.5) 227 | assert_equal([2001, 2, 3, 12], [d.year, d.mon, d.mday, d.hour]) 228 | d = DateTime.civil(2001, 2, Rational('3.5')) 229 | assert_equal([2001, 2, 3, 12], [d.year, d.mon, d.mday, d.hour]) 230 | d = DateTime.civil(2001, 2, 3, 4.5) 231 | assert_equal([2001, 2, 3, 4, 30], [d.year, d.mon, d.mday, d.hour, d.min]) 232 | d = DateTime.civil(2001, 2, 3, Rational('4.5')) 233 | assert_equal([2001, 2, 3, 4, 30], [d.year, d.mon, d.mday, d.hour, d.min]) 234 | d = DateTime.civil(2001, 2, 3, 4, 5.5) 235 | assert_equal([2001, 2, 3, 4, 5, 30], 236 | [d.year, d.mon, d.mday, d.hour, d.min, d.sec]) 237 | d = DateTime.civil(2001, 2, 3, 4, Rational('5.5')) 238 | assert_equal([2001, 2, 3, 4, 5, 30], 239 | [d.year, d.mon, d.mday, d.hour, d.min, d.sec]) 240 | 241 | d = DateTime.ordinal(2001, 2.0) 242 | assert_equal([2001, 2], [d.year, d.yday]) 243 | d = DateTime.ordinal(2001, Rational(2)) 244 | assert_equal([2001, 2], [d.year, d.yday]) 245 | 246 | d = DateTime.commercial(2001, 2, 3.0) 247 | assert_equal([2001, 2, 3], [d.cwyear, d.cweek, d.cwday]) 248 | d = DateTime.commercial(2001, 2, Rational(3)) 249 | assert_equal([2001, 2, 3], [d.cwyear, d.cweek, d.cwday]) 250 | 251 | end 252 | 253 | def test_canon24oc 254 | d = DateTime.jd(2451943,24) 255 | assert_equal([2001, 2, 3, 0, 0, 0, 0], 256 | [d.year, d.mon, d.mday, d.hour, d.min, d.sec, d.offset]) 257 | d = DateTime.ordinal(2001,33,24) 258 | assert_equal([2001, 2, 3, 0, 0, 0, 0], 259 | [d.year, d.mon, d.mday, d.hour, d.min, d.sec, d.offset]) 260 | d = DateTime.new(2001,2,2,24) 261 | assert_equal([2001, 2, 3, 0, 0, 0, 0], 262 | [d.year, d.mon, d.mday, d.hour, d.min, d.sec, d.offset]) 263 | d = DateTime.commercial(2001,5,5,24) 264 | assert_equal([2001, 2, 3, 0, 0, 0, 0], 265 | [d.year, d.mon, d.mday, d.hour, d.min, d.sec, d.offset]) 266 | end 267 | 268 | def test_zone 269 | d = DateTime.new(2001, 2, 3) 270 | assert_equal(Encoding::US_ASCII, d.zone.encoding) 271 | end 272 | 273 | def test_to_s 274 | d = Date.new(2001, 2, 3) 275 | assert_equal(Encoding::US_ASCII, d.to_s.encoding) 276 | assert_equal(Encoding::US_ASCII, d.strftime.encoding) 277 | d = DateTime.new(2001, 2, 3) 278 | assert_equal(Encoding::US_ASCII, d.to_s.encoding) 279 | assert_equal(Encoding::US_ASCII, d.strftime.encoding) 280 | end 281 | 282 | def test_inspect 283 | d = Date.new(2001, 2, 3) 284 | assert_equal(Encoding::US_ASCII, d.inspect.encoding) 285 | d = DateTime.new(2001, 2, 3) 286 | assert_equal(Encoding::US_ASCII, d.inspect.encoding) 287 | end 288 | 289 | def test_strftime 290 | assert_raise(Errno::ERANGE) do 291 | Date.today.strftime('%100000z') 292 | end 293 | assert_raise(Errno::ERANGE) do 294 | Date.new(1 << 10000).strftime('%Y') 295 | end 296 | assert_equal('-3786825600', Date.new(1850).strftime('%s')) 297 | assert_equal('-3786825600000', Date.new(1850).strftime('%Q')) 298 | end 299 | 300 | def test_cmp 301 | assert_equal(-1, Date.new(2001,2,3) <=> Date.new(2001,2,4)) 302 | assert_equal(0, Date.new(2001,2,3) <=> Date.new(2001,2,3)) 303 | assert_equal(1, Date.new(2001,2,3) <=> Date.new(2001,2,2)) 304 | 305 | assert_equal(-1, Date.new(2001,2,3) <=> 2451944.0) 306 | assert_equal(-1, Date.new(2001,2,3) <=> 2451944) 307 | assert_equal(0, Date.new(2001,2,3) <=> 2451943.5) 308 | assert_equal(1, Date.new(2001,2,3) <=> 2451943.0) 309 | assert_equal(1, Date.new(2001,2,3) <=> 2451943) 310 | 311 | assert_equal(-1, Date.new(2001,2,3) <=> Rational('4903888/2')) 312 | assert_equal(0, Date.new(2001,2,3) <=> Rational('4903887/2')) 313 | assert_equal(1, Date.new(2001,2,3) <=> Rational('4903886/2')) 314 | 315 | assert_equal(-1, Date.new(-4713,11,1,Date::GREGORIAN) <=> Date.new(-4713,12,1,Date::GREGORIAN)) 316 | end 317 | 318 | def test_eqeqeq 319 | assert_equal(false, Date.new(2001,2,3) === Date.new(2001,2,4)) 320 | assert_equal(true, Date.new(2001,2,3) === Date.new(2001,2,3)) 321 | assert_equal(false, Date.new(2001,2,3) === Date.new(2001,2,2)) 322 | 323 | assert_equal(true, Date.new(2001,2,3) === 2451944.0) 324 | assert_equal(true, Date.new(2001,2,3) === 2451944) 325 | assert_equal(false, Date.new(2001,2,3) === 2451943.5) 326 | assert_equal(false, Date.new(2001,2,3) === 2451943.0) 327 | assert_equal(false, Date.new(2001,2,3) === 2451943) 328 | 329 | assert_equal(true, Date.new(2001,2,3) === Rational('4903888/2')) 330 | assert_equal(false, Date.new(2001,2,3) === Rational('4903887/2')) 331 | assert_equal(false, Date.new(2001,2,3) === Rational('4903886/2')) 332 | end 333 | 334 | def test_period 335 | # -5000 336 | d = Date.new(-5000,1,1) 337 | assert_equal([-5000, 1, 1, 5], [d.year, d.mon, d.mday, d.wday]) 338 | d2 = d.gregorian 339 | assert_equal([-5001, 11, 22, 5], [d2.year, d2.mon, d2.mday, d.wday]) 340 | 341 | d = Date.new(-5000,1,1,Date::JULIAN) 342 | assert_equal([-5000, 1, 1, 5], [d.year, d.mon, d.mday, d.wday]) 343 | d2 = d.gregorian 344 | assert_equal([-5001, 11, 22, 5], [d2.year, d2.mon, d2.mday, d.wday]) 345 | 346 | d = Date.new(-5000,1,1,Date::GREGORIAN) 347 | assert_equal([-5000, 1, 1, 3], [d.year, d.mon, d.mday, d.wday]) 348 | d2 = d.julian 349 | assert_equal([-5000, 2, 10, 3], [d2.year, d2.mon, d2.mday, d.wday]) 350 | 351 | d = Date.jd(-105192) 352 | assert_equal([-5000, 1, 1, 5], [d.year, d.mon, d.mday, d.wday]) 353 | d2 = d.gregorian 354 | assert_equal([-5001, 11, 22, 5], [d2.year, d2.mon, d2.mday, d.wday]) 355 | 356 | d = Date.jd(-105192,Date::JULIAN) 357 | assert_equal([-5000, 1, 1, 5], [d.year, d.mon, d.mday, d.wday]) 358 | d2 = d.gregorian 359 | assert_equal([-5001, 11, 22, 5], [d2.year, d2.mon, d2.mday, d.wday]) 360 | 361 | d = Date.jd(-105152,Date::GREGORIAN) 362 | assert_equal([-5000, 1, 1, 3], [d.year, d.mon, d.mday, d.wday]) 363 | d2 = d.julian 364 | assert_equal([-5000, 2, 10, 3], [d2.year, d2.mon, d2.mday, d.wday]) 365 | 366 | # -5000000 367 | d = Date.new(-5_000_000,1,1) 368 | assert_equal([-5_000_000, 1, 1, 3], [d.year, d.mon, d.mday, d.wday]) 369 | d2 = d.gregorian 370 | assert_equal([-5_000_103, 4, 28, 3], [d2.year, d2.mon, d2.mday, d.wday]) 371 | 372 | d = Date.new(-5_000_000,1,1,Date::JULIAN) 373 | assert_equal([-5_000_000, 1, 1, 3], [d.year, d.mon, d.mday, d.wday]) 374 | d2 = d.gregorian 375 | assert_equal([-5_000_103, 4, 28, 3], [d2.year, d2.mon, d2.mday, d.wday]) 376 | 377 | d = Date.new(-5_000_000,1,1,Date::GREGORIAN) 378 | assert_equal([-5_000_000, 1, 1, 6], [d.year, d.mon, d.mday, d.wday]) 379 | d2 = d.julian 380 | assert_equal([-4_999_898, 9, 4, 6], [d2.year, d2.mon, d2.mday, d.wday]) 381 | 382 | d = Date.jd(-1824528942) 383 | assert_equal([-5_000_000, 1, 1, 3], [d.year, d.mon, d.mday, d.wday]) 384 | d2 = d.gregorian 385 | assert_equal([-5_000_103, 4, 28, 3], [d2.year, d2.mon, d2.mday, d.wday]) 386 | 387 | d = Date.jd(-1824528942,Date::JULIAN) 388 | assert_equal([-5_000_000, 1, 1, 3], [d.year, d.mon, d.mday, d.wday]) 389 | d2 = d.gregorian 390 | assert_equal([-5_000_103, 4, 28, 3], [d2.year, d2.mon, d2.mday, d.wday]) 391 | 392 | d = Date.jd(-1824491440,Date::GREGORIAN) 393 | assert_equal([-5_000_000, 1, 1, 6], [d.year, d.mon, d.mday, d.wday]) 394 | d2 = d.julian 395 | assert_equal([-4_999_898, 9, 4, 6], [d2.year, d2.mon, d2.mday, d.wday]) 396 | 397 | # 5000000 398 | d = Date.new(5_000_000,1,1) 399 | assert_equal([5_000_000, 1, 1, 6], [d.year, d.mon, d.mday, d.wday]) 400 | d2 = d.julian 401 | assert_equal([4_999_897, 5, 3, 6], [d2.year, d2.mon, d2.mday, d.wday]) 402 | 403 | d = Date.new(5_000_000,1,1,Date::JULIAN) 404 | assert_equal([5_000_000, 1, 1, 5], [d.year, d.mon, d.mday, d.wday]) 405 | d2 = d.gregorian 406 | assert_equal([5_000_102, 9, 1, 5], [d2.year, d2.mon, d2.mday, d.wday]) 407 | 408 | d = Date.new(5_000_000,1,1,Date::GREGORIAN) 409 | assert_equal([5_000_000, 1, 1, 6], [d.year, d.mon, d.mday, d.wday]) 410 | d2 = d.julian 411 | assert_equal([4_999_897, 5, 3, 6], [d2.year, d2.mon, d2.mday, d.wday]) 412 | 413 | d = Date.jd(1827933560) 414 | assert_equal([5_000_000, 1, 1, 6], [d.year, d.mon, d.mday, d.wday]) 415 | d2 = d.julian 416 | assert_equal([4_999_897, 5, 3, 6], [d2.year, d2.mon, d2.mday, d.wday]) 417 | 418 | d = Date.jd(1827971058,Date::JULIAN) 419 | assert_equal([5_000_000, 1, 1, 5], [d.year, d.mon, d.mday, d.wday]) 420 | d2 = d.gregorian 421 | assert_equal([5_000_102, 9, 1, 5], [d2.year, d2.mon, d2.mday, d.wday]) 422 | 423 | d = Date.jd(1827933560,Date::GREGORIAN) 424 | assert_equal([5_000_000, 1, 1, 6], [d.year, d.mon, d.mday, d.wday]) 425 | d2 = d.julian 426 | assert_equal([4_999_897, 5, 3, 6], [d2.year, d2.mon, d2.mday, d.wday]) 427 | 428 | # dt 429 | d = DateTime.new(-123456789,2,3,4,5,6,0) 430 | assert_equal([-123456789, 2, 3, 4, 5, 6, 1], 431 | [d.year, d.mon, d.mday, d.hour, d.min, d.sec, d.wday]) 432 | d2 = d.gregorian 433 | assert_equal([-123459325, 12, 27, 4, 5, 6, 1], 434 | [d2.year, d2.mon, d2.mday, d2.hour, d2.min, d2.sec, d.wday]) 435 | 436 | d = DateTime.new(123456789,2,3,4,5,6,0) 437 | assert_equal([123456789, 2, 3, 4, 5, 6, 5], 438 | [d.year, d.mon, d.mday, d.hour, d.min, d.sec, d.wday]) 439 | d2 = d.julian 440 | assert_equal([123454254, 1, 19, 4, 5, 6, 5], 441 | [d2.year, d2.mon, d2.mday, d2.hour, d2.min, d2.sec, d.wday]) 442 | end 443 | 444 | def period2_iter2(from, to, sg) 445 | (from..to).each do |j| 446 | d = Date.jd(j, sg) 447 | d2 = Date.new(d.year, d.mon, d.mday, sg) 448 | assert_equal(d2.jd, j) 449 | assert_equal(d2.ajd, d.ajd) 450 | assert_equal(d2.year, d.year) 451 | 452 | d = DateTime.jd(j, 12,0,0, '+12:00', sg) 453 | d2 = DateTime.new(d.year, d.mon, d.mday, 454 | d.hour, d.min, d.sec, d.offset, sg) 455 | assert_equal(d2.jd, j) 456 | assert_equal(d2.ajd, d.ajd) 457 | assert_equal(d2.year, d.year) 458 | end 459 | end 460 | 461 | def period2_iter(from, to) 462 | period2_iter2(from, to, Date::GREGORIAN) 463 | period2_iter2(from, to, Date::ITALY) 464 | period2_iter2(from, to, Date::ENGLAND) 465 | period2_iter2(from, to, Date::JULIAN) 466 | end 467 | 468 | def test_period2 469 | cm_period0 = 71149239 470 | cm_period = 0xfffffff.div(cm_period0) * cm_period0 471 | period2_iter(-cm_period * (1 << 64) - 3, -cm_period * (1 << 64) + 3) 472 | period2_iter(-cm_period - 3, -cm_period + 3) 473 | period2_iter(0 - 3, 0 + 3) 474 | period2_iter(+cm_period - 3, +cm_period + 3) 475 | period2_iter(+cm_period * (1 << 64) - 3, +cm_period * (1 << 64) + 3) 476 | end 477 | 478 | def test_different_alignments 479 | assert_equal(0, Date.jd(0) <=> Date.civil(-4713, 11, 24, Date::GREGORIAN)) 480 | assert_equal(0, Date.jd(213447717) <=> Date.civil(579687, 11, 24)) 481 | assert_equal(0, Date.jd(-213447717) <=> Date.civil(-589113, 11, 24, Date::GREGORIAN)) 482 | 483 | assert_equal(0, Date.jd(0) <=> DateTime.civil(-4713, 11, 24, 0, 0, 0, 0, Date::GREGORIAN)) 484 | assert_equal(0, Date.jd(213447717) <=> DateTime.civil(579687, 11, 24)) 485 | assert_equal(0, Date.jd(-213447717) <=> DateTime.civil(-589113, 11, 24, 0, 0, 0, 0, Date::GREGORIAN)) 486 | 487 | assert(Date.jd(0) == Date.civil(-4713, 11, 24, Date::GREGORIAN)) 488 | assert(Date.jd(213447717) == Date.civil(579687, 11, 24)) 489 | assert(Date.jd(-213447717) == Date.civil(-589113, 11, 24, Date::GREGORIAN)) 490 | 491 | assert(Date.jd(0) == DateTime.civil(-4713, 11, 24, 0, 0, 0, 0, Date::GREGORIAN)) 492 | assert(Date.jd(213447717) == DateTime.civil(579687, 11, 24)) 493 | assert(Date.jd(-213447717) == DateTime.civil(-589113, 11, 24, 0, 0, 0, 0, Date::GREGORIAN)) 494 | 495 | assert(Date.jd(0) === Date.civil(-4713, 11, 24, Date::GREGORIAN)) 496 | assert(Date.jd(213447717) === Date.civil(579687, 11, 24)) 497 | assert(Date.jd(-213447717) === Date.civil(-589113, 11, 24, Date::GREGORIAN)) 498 | 499 | assert(Date.jd(0) === DateTime.civil(-4713, 11, 24, 12, 0, 0, 0, Date::GREGORIAN)) 500 | assert(Date.jd(213447717) === DateTime.civil(579687, 11, 24, 12)) 501 | assert(Date.jd(-213447717) === DateTime.civil(-589113, 11, 24, 12, 0, 0, 0, Date::GREGORIAN)) 502 | 503 | a = Date.jd(0) 504 | b = Date.civil(-4713, 11, 24, Date::GREGORIAN) 505 | assert_equal(0, a <=> b) 506 | 507 | a = Date.civil(-4712, 1, 1, Date::JULIAN) 508 | b = Date.civil(-4713, 11, 24, Date::GREGORIAN) 509 | a.jd; b.jd 510 | assert_equal(0, a <=> b) 511 | 512 | a = Date.jd(0) 513 | b = Date.civil(-4713, 11, 24, Date::GREGORIAN) 514 | assert(a == b) 515 | 516 | a = Date.civil(-4712, 1, 1, Date::JULIAN) 517 | b = Date.civil(-4713, 11, 24, Date::GREGORIAN) 518 | a.jd; b.jd 519 | assert(a == b) 520 | 521 | a = Date.jd(0) 522 | b = Date.civil(-4713, 11, 24, Date::GREGORIAN) 523 | assert(a === b) 524 | 525 | a = Date.civil(-4712, 1, 1, Date::JULIAN) 526 | b = Date.civil(-4713, 11, 24, Date::GREGORIAN) 527 | a.jd; b.jd 528 | assert(a === b) 529 | end 530 | 531 | def test_marshal14 532 | s = "\x04\x03u:\x01\x04Date\x01\v\x04\x03[\x01\x02i\x03\xE8i%T" 533 | d = suppress_warning {Marshal.load(s)} 534 | assert_equal(Rational(4903887,2), d.ajd) 535 | assert_equal(Date::GREGORIAN, d.start) 536 | end 537 | 538 | def test_marshal16 539 | s = "\x04\x06u:\tDate\x0F\x04\x06[\ai\x03\xE8i%T" 540 | d = suppress_warning {Marshal.load(s)} 541 | assert_equal(Rational(4903887,2), d.ajd) 542 | assert_equal(Date::GREGORIAN, d.start) 543 | end 544 | 545 | def test_marshal18 546 | s = "\x04\bu:\tDateP\x04\b[\bo:\rRational\a:\x0F@numeratori\x03\xCF\xD3J:\x11@denominatori\ai\x00o:\x13Date::Infinity\x06:\a@di\xFA" 547 | d = Marshal.load(s) 548 | assert_equal(Rational(4903887,2), d.ajd) 549 | assert_equal(Date::GREGORIAN, d.start) 550 | 551 | s = "\x04\bu:\rDateTime`\x04\b[\bo:\rRational\a:\x0F@numeratorl+\b\xC9\xB0\x81\xBD\x02\x00:\x11@denominatori\x02\xC0\x12o;\x00\a;\x06i\b;\ai\ro:\x13Date::Infinity\x06:\a@di\xFA" 552 | d = Marshal.load(s) 553 | assert_equal(Rational(11769327817,4800), d.ajd) 554 | assert_equal(Rational(9,24), d.offset) 555 | assert_equal(Date::GREGORIAN, d.start) 556 | end 557 | 558 | def test_marshal192 559 | s = "\x04\bU:\tDate[\bU:\rRational[\ai\x03\xCF\xD3Ji\ai\x00o:\x13Date::Infinity\x06:\a@di\xFA" 560 | d = Marshal.load(s) 561 | assert_equal(Rational(4903887,2), d.ajd) 562 | assert_equal(Date::GREGORIAN, d.start) 563 | 564 | s = "\x04\bU:\rDateTime[\bU:\rRational[\al+\b\xC9\xB0\x81\xBD\x02\x00i\x02\xC0\x12U;\x06[\ai\bi\ro:\x13Date::Infinity\x06:\a@di\xFA" 565 | d = Marshal.load(s) 566 | assert_equal(Rational(11769327817,4800), d.ajd) 567 | assert_equal(Rational(9,24), d.offset) 568 | assert_equal(Date::GREGORIAN, d.start) 569 | end 570 | 571 | def test_enc 572 | Date::MONTHNAMES.each do |s| 573 | assert_equal(Encoding::US_ASCII, s.encoding) if s 574 | end 575 | Date::DAYNAMES.each do |s| 576 | assert_equal(Encoding::US_ASCII, s.encoding) if s 577 | end 578 | Date::ABBR_MONTHNAMES.each do |s| 579 | assert_equal(Encoding::US_ASCII, s.encoding) if s 580 | end 581 | Date::ABBR_DAYNAMES.each do |s| 582 | assert_equal(Encoding::US_ASCII, s.encoding) if s 583 | end 584 | 585 | h = Date._strptime('15:43+09:00'.dup.force_encoding('euc-jp'), '%R%z') 586 | assert_equal(Encoding::EUC_JP, h[:zone].encoding) 587 | h = Date._strptime('15:43+09:00'.dup.force_encoding('ascii-8bit'), '%R%z') 588 | assert_equal(Encoding::ASCII_8BIT, h[:zone].encoding) 589 | 590 | h = Date._strptime('1;1/0'.dup.force_encoding('euc-jp'), '%d') 591 | assert_equal(Encoding::EUC_JP, h[:leftover].encoding) 592 | h = Date._strptime('1;1/0'.dup.force_encoding('ascii-8bit'), '%d') 593 | assert_equal(Encoding::ASCII_8BIT, h[:leftover].encoding) 594 | 595 | h = Date._parse('15:43+09:00'.dup.force_encoding('euc-jp')) 596 | assert_equal(Encoding::EUC_JP, h[:zone].encoding) 597 | h = Date._parse('15:43+09:00'.dup.force_encoding('ascii-8bit')) 598 | assert_equal(Encoding::ASCII_8BIT, h[:zone].encoding) 599 | 600 | s = Date.today.strftime('new 105'.dup.force_encoding('euc-jp')) 601 | assert_equal(Encoding::EUC_JP, s.encoding) 602 | s = Date.today.strftime('new 105'.dup.force_encoding('ascii-8bit')) 603 | assert_equal(Encoding::ASCII_8BIT, s.encoding) 604 | 605 | s = DateTime.now.strftime('super $record'.dup.force_encoding('euc-jp')) 606 | assert_equal(Encoding::EUC_JP, s.encoding) 607 | s = DateTime.now.strftime('super $record'.dup.force_encoding('ascii-8bit')) 608 | assert_equal(Encoding::ASCII_8BIT, s.encoding) 609 | end 610 | 611 | def test_dup 612 | d = Date.new(2001,2,3) 613 | d2 = d.dup 614 | assert_not_equal(d.object_id, d2.object_id) 615 | assert_kind_of(Date, d2) 616 | assert_equal(d, d2) 617 | 618 | d = DateTime.new(2001,2,3) 619 | d2 = d.dup 620 | assert_not_equal(d.object_id, d2.object_id) 621 | assert_kind_of(DateTime, d2) 622 | assert_equal(d, d2) 623 | end 624 | 625 | def test_base 626 | assert_equal(true, Date.test_all) 627 | end if defined?(Date.test_all) 628 | 629 | private 630 | 631 | def suppress_warning 632 | $VERBOSE, verbose = nil, $VERBOSE 633 | yield 634 | ensure 635 | $VERBOSE = verbose 636 | end 637 | end 638 | -------------------------------------------------------------------------------- /test/lib/helper.rb: -------------------------------------------------------------------------------- 1 | require "test/unit" 2 | require "core_assertions" 3 | 4 | Test::Unit::TestCase.include Test::Unit::CoreAssertions 5 | -------------------------------------------------------------------------------- /tool/gperf.sed: -------------------------------------------------------------------------------- 1 | /^[a-zA-Z_0-9]*hash/,/^}/{ 2 | s/ hval = / hval = (unsigned int)/ 3 | s/ return / return (unsigned int)/ 4 | } 5 | --------------------------------------------------------------------------------