pax_global_header00006660000000000000000000000064143652753050014524gustar00rootroot0000000000000052 comment=d5893c99bbcd842af86023f02a84fac1659b3031 tzinfo-2.0.6/000077500000000000000000000000001436527530500130425ustar00rootroot00000000000000tzinfo-2.0.6/.editorconfig000066400000000000000000000003211436527530500155130ustar00rootroot00000000000000root = true [*] charset = utf-8 indent_style = space indent_size = 2 end_of_line = lf insert_final_newline = true trim_trailing_whitespace = true [test/tzinfo-data[12]/**/*] trim_trailing_whitespace = false tzinfo-2.0.6/.github/000077500000000000000000000000001436527530500144025ustar00rootroot00000000000000tzinfo-2.0.6/.github/workflows/000077500000000000000000000000001436527530500164375ustar00rootroot00000000000000tzinfo-2.0.6/.github/workflows/tests.yml000066400000000000000000000051451436527530500203310ustar00rootroot00000000000000name: Tests on: [push, pull_request] jobs: test: name: ${{ matrix.ruby }} on ${{ matrix.os }}${{ matrix.name_suffix }} strategy: matrix: os: [ubuntu-20.04, windows-2019] ruby: ['1.9.3', '2.0', '2.1', '2.2', '2.3', '2.4', '2.5', '2.6', '2.7', '3.0', '3.1', '3.2', jruby-1.7, jruby-9.0, jruby-9.1, jruby-9.2, jruby-9.3, jruby-9.4] architecture: [default] name_suffix: [''] experimental: [false] exclude: - os: windows-2019 ruby: jruby-1.7 include: - os: windows-2019 ruby: '2.0' architecture: x86 name_suffix: ' (x86)' experimental: false - os: ubuntu-20.04 ruby: head architecture: default name_suffix: ' (experimental)' experimental: true - os: ubuntu-20.04 ruby: jruby-head architecture: default name_suffix: ' (experimental)' experimental: true - os: windows-2019 ruby: head architecture: default name_suffix: ' (experimental)' experimental: true - os: windows-2019 ruby: jruby-head architecture: default name_suffix: ' (experimental)' experimental: true - os: ubuntu-20.04 ruby: truffleruby-21 architecture: default name_suffix: ' (experimental)' experimental: true fail-fast: false runs-on: ${{ matrix.os }} continue-on-error: ${{ matrix.experimental }} steps: - uses: actions/checkout@v3 - if: (startsWith(matrix.ruby, '1.') && startsWith(matrix.os, 'windows')) || (startsWith(matrix.ruby, '2.0') && startsWith(matrix.os, 'windows') && matrix.architecture == 'x86') || startsWith(matrix.ruby, 'jruby-1.7') || startsWith(matrix.ruby, 'jruby-9.0') uses: philr/setup-ruby@legacy-v1 with: ruby-version: ${{ matrix.ruby }} architecture: ${{ matrix.architecture }} bundler-cache: true - if: ${{ !((startsWith(matrix.ruby, '1.') && startsWith(matrix.os, 'windows')) || (startsWith(matrix.ruby, '2.0') && startsWith(matrix.os, 'windows') && matrix.architecture == 'x86') || startsWith(matrix.ruby, 'jruby-1.7') || startsWith(matrix.ruby, 'jruby-9.0')) }} uses: ruby/setup-ruby@v1 with: ruby-version: ${{ matrix.ruby }} bundler-cache: true - run: ruby --version - run: gem --version - run: bundle --version - run: bundle exec rake test env: TESTOPTS: --verbose tzinfo-2.0.6/.gitignore000066400000000000000000000000531436527530500150300ustar00rootroot00000000000000coverage doc Gemfile.lock pkg .rbx .yardoc tzinfo-2.0.6/.yardopts000066400000000000000000000001511436527530500147050ustar00rootroot00000000000000--markup markdown --no-private --protected --readme README.md lib/**/*.rb - CHANGES.md LICENSE README.md tzinfo-2.0.6/CHANGES.md000066400000000000000000001231141436527530500144360ustar00rootroot00000000000000# Changes ## Version 2.0.6 - 28-Jan-2023 * Eliminate `Object#untaint` deprecation warnings on JRuby 9.4.0.0. #145. ## Version 2.0.5 - 19-Jul-2022 * Changed `DateTime` results to always use the proleptic Gregorian calendar. This affects `DateTime` results prior to 1582-10-15 and any arithmetic performed on the results that would produce a secondary result prior to 1582-10-15. * Added support for eager loading all the time zone and country data by calling either `TZInfo::DataSource#eager_load!` or `TZInfo.eager_load!`. Compatible with Ruby On Rails' `eager_load_namespaces`. #129. * Ignore the SECURITY file from Arch Linux's tzdata package. #134. ## Version 2.0.4 - 16-Dec-2020 * Fixed an incorrect `InvalidTimezoneIdentifier` exception raised when loading a zoneinfo file that includes rules specifying an additional transition to the final defined offset (for example, Africa/Casablanca in version 2018e of the Time Zone Database). #123. ## Version 2.0.3 - 8-Nov-2020 * Added support for handling "slim" format zoneinfo files that are produced by default by zic version 2020b and later. The POSIX-style TZ string is now used calculate DST transition times after the final defined transition in the file. #120. * Fixed `TimeWithOffset#getlocal` returning a `TimeWithOffset` with the `timezone_offset` still assigned when called with an offset argument on JRuby 9.3. * Rubinius is no longer supported. ## Version 2.0.2 - 2-Apr-2020 * Fixed 'wrong number of arguments' errors when running on JRuby 9.0. #114. * Fixed warnings when running on Ruby 2.8. #113. ## Version 2.0.1 - 24-Dec-2019 * Fixed "SecurityError: Insecure operation - require" exceptions when loading data with recent Ruby releases in safe mode. #100. * Fixed warnings when running on Ruby 2.7. #109. * Added a `TZInfo::Timezone#=~` method that performs a regex match on the time zone identifier. #99. * Added a `TZInfo::Country#=~` method that performs a regex match on the country code. ## Version 2.0.0 - 26-Dec-2018 ### Added * `to_local` and `period_for` instance methods have been added to `TZInfo::Timezone`. These are similar to `utc_to_local` and `period_for_utc`, but take the UTC offset of the given time into account. * `abbreviation`, `dst?`, `base_utc_offset` and `observed_utc_offset` instance methods have been added to `TZInfo::Timezone`, returning the abbreviation, whether daylight savings time is in effect and the UTC offset of the time zone at a specified time. * A `TZInfo::Timestamp` class has been added. It can be used with `TZInfo::Timezone` in place of a `Time` or `DateTime`. * `local_time`, `local_datetime` and `local_timestamp` instance methods have been added to `TZInfo::Timezone`. These methods construct local `Time`, `DateTime` and `TZInfo::Timestamp` instances with the correct UTC offset and abbreviation for the time zone. * Support for a (yet to be released) version 2 of tzinfo-data has been added, in addition to support for version 1. The new version will remove the (no longer needed) `DateTime` parameters from transition times, reduce memory consumption and improve the efficiency of loading timezone and country indexes. * A `TZInfo::VERSION` constant has been added, indicating the TZInfo version number. ### Changed * The minimum supported Ruby versions are now Ruby MRI 1.9.3, JRuby 1.7 (in 1.9 or later mode) and Rubinius 3. * Local times are now returned using the correct UTC offset (instead of using UTC). #49 and #52. * Local times are returned as instances of `TimeWithOffset`, `DateTimeWithOffset` or `TZInfo::TimestampWithOffset`. These classes subclass `Time`, `DateTime` and `TZInfo::Timestamp` respectively. They override the default behaviour of the base classes to return information about the observed offset at the indicated time. For example, the zone abbreviation is returned when using the `%Z` directive with `strftime`. * The `transitions_up_to`, `offsets_up_to` and `strftime` instance methods of `TZInfo::Timezone` now take the UTC offsets of given times into account (instead of ignoring them as was previously the case). * The `TZInfo::TimezonePeriod` class has been split into two subclasses: `TZInfo::OffsetTimezonePeriod` and `TZInfo::TransitionsTimezonePeriod`. `TZInfo::OffsetTimezonePeriod` is returned for time zones that only have a single offset. `TZInfo::TransitionsTimezonePeriod` is returned for periods that start or end with a transition. * `TZInfo::TimezoneOffset#abbreviation`, `TZInfo::TimezonePeriod#abbreviation` and `TZInfo::TimezonePeriod#zone_identifier` now return frozen `String` instances instead of instances of `Symbol`. * The `utc_offset` and `utc_total_offset` attributes of `TZInfo::TimezonePeriod` and `TZInfo::TimezoneOffset` have been renamed `base_utc_offset` and `observed_utc_offset` respectively. The former names have been retained as aliases. * `TZInfo::Timezone.get`, `TZInfo::Timezone.get_proxy` and `TZInfo::Country.get` can now be used with strings having any encoding. Previously, only encodings that are directly comparable with UTF-8 were supported. * The requested identifier is included in `TZInfo::InvalidTimezoneIdentifier` exception messages. * The requested country code is included in `TZInfo::InvalidCountryCode` exception messages. * The full range of transitions is now loaded from zoneinfo files. Zoneinfo files produced with version 2014c of the `zic` tool contain an initial transition `2**63` seconds before the epoch. Zoneinfo files produced with version 2014d or later of `zic` contain an initial transition `2**59` seconds before the epoch. These transitions would previously have been ignored, but are now returned in methods such as `TZInfo::Timezone#transitions_up_to`. * The `TZInfo::RubyDataSource` and `TZInfo::ZoneinfoDataSource` classes have been moved into a new `TZInfo::DataSources` module. Code that is setting `TZInfo::ZoneinfoDataSource.search_path` or `TZInfo::ZoneinfoDataSource.alternate_iso3166_tab_search_path` will need to be updated accordingly. * The `TZInfo::InvalidZoneinfoDirectory` and `TZInfo::ZoneinfoDirectoryNotFound` exception classes raised by `TZInfo::DataSources::ZoneinfoDataSource` have been moved into the `TZInfo::DataSources` module. * Setting the data source to `:ruby` or instantiating `TZInfo::DataSources::RubyDataSource` will now immediately raise a `TZInfo::DataSources::TZInfoDataNotFound` exception if `require 'tzinfo/data'` fails. Previously, a failure would only occur later when accessing an index or loading a timezone or country. * The `DEFAULT_SEARCH_PATH` and `DEFAULT_ALTERNATE_ISO3166_TAB_SEARCH_PATH` constants of `TZInfo::DataSources::ZoneinfoDataSource` have been made private. * The `TZInfo::Country.data_source`, `TZInfo::DataSource.create_default_data_source`, `TZInfo::DataSources::ZoneinfoDataSource.process_search_path`, `TZInfo::Timezone.get_proxies` and `TZInfo::Timezone.data_source` methods have been made private. * The performance of loading zoneinfo files and the associated indexes has been improved. * Memory use has been decreased by deduplicating `String` instances when loading country and time zone data. * The dependency on the deprecated thread_safe gem as been removed and replaced by concurrent-ruby. * The Info classes used to return time zone and country information from `TZInfo::DataSource` implementations have been moved into the `TZInfo::DataSources` module. * The `TZInfo::TransitionDataTimezoneInfo` class has been removed and replaced with `TZInfo::DataSources::TransitionsDataTimezoneInfo` and `TZInfo::DataSources::ConstantOffsetDataTimezoneInfo`. `TZInfo::DataSources::TransitionsDataTimezoneInfo` is constructed with an `Array` of `TZInfo::TimezoneTransition` instances representing times when the offset changes. `TZInfo::DataSources::ConstantOffsetDataTimezoneInfo` is constructed with a `TZInfo::TimezoneOffset` instance representing the offset constantly observed in a time zone. * The `TZInfo::DataSource#timezone_identifiers` method should no longer be overridden in custom data source implementations. The implementation in the base class now calculates a result from `TZInfo::DataSource#data_timezone_identifiers` and `TZInfo::DataSource#linked_timezone_identifiers`. * The results of the `TZInfo::DataSources::RubyDataSource` `to_s` and `inspect` methods now include the time zone database and tzinfo-data versions. ### Removed * Methods of `TZInfo::Timezone` that accept time arguments no longer allow `Integer` timestamp values. `Time`, `DateTime` or `TZInfo::Timestamp` values or objects that respond to `to_i`, `subsec` and optionally `utc_offset` must be used instead. * The `%:::z` format directive can now only be used with `TZInfo::Timezone#strftime` if it is supported by `Time#strftime` on the runtime platform. * Using `TZInfo::Timezone.new(identifier)` and `TZInfo::Country.new(code)` to obtain a specific `TZInfo::Timezone` or `TZInfo::Country` will no longer work. `TZInfo::Timezone.get(identifier)` and `TZInfo::Country.get(code)` should be used instead. * The `TZInfo::TimeOrDateTime` class has been removed. * The `valid_for_utc?`, `utc_after_start?`, `utc_before_end?`, `valid_for_local?`, `local_after_start?` and `local_before_end?` instance methods of `TZInfo::TimezonePeriod` have been removed. Comparisons can be performed with the results of the `starts_at`, `ends_at`, `local_starts_at` and `local_ends_at` methods instead. * The `to_local` and `to_utc` instance methods of `TZInfo::TimezonePeriod` and `TZInfo::TimezoneOffset` have been removed. Conversions should be performed using the `TZInfo::Timezone` class instead. * The `TZInfo::TimezonePeriod#utc_total_offset_rational` method has been removed. Equivalent information can be obtained using the `TZInfo::TimezonePeriod#observed_utc_offset` method. * The `datetime`, `time`, `local_end`, `local_end_time`, `local_start` and `local_start_time` instance methods of `TZInfo::TimezoneTransition` have been removed. The `at`, `local_end_at` and `local_start_at` methods should be used instead and the result (a `TZInfo::TimestampWithOffset`) converted to either a `DateTime` or `Time` by calling `to_datetime` or `to_time` on the result. * The `us_zones` and `us_zone_identifiers` class methods of `TZInfo::Timezone` have been removed. `TZInfo::Country.get('US').zones` and `TZInfo::Country.get('US').zone_identifiers` should be used instead. ## Version 1.2.11 - 28-Jan-2023 * Eliminate `Object#untaint` deprecation warnings on JRuby 9.4.0.0. #145. ## Version 1.2.10 - 19-Jul-2022 * Fixed a relative path traversal bug that could cause arbitrary files to be loaded with `require` when used with `RubyDataSource`. Please refer to for details. CVE-2022-31163. * Ignore the SECURITY file from Arch Linux's tzdata package. #134. ## Version 1.2.9 - 16-Dec-2020 * Fixed an incorrect `InvalidTimezoneIdentifier` exception raised when loading a zoneinfo file that includes rules specifying an additional transition to the final defined offset (for example, Africa/Casablanca in version 2018e of the Time Zone Database). #123. ## Version 1.2.8 - 8-Nov-2020 * Added support for handling "slim" format zoneinfo files that are produced by default by zic version 2020b and later. The POSIX-style TZ string is now used calculate DST transition times after the final defined transition in the file. The 64-bit section is now always used regardless of whether Time has support for 64-bit times. #120. * Rubinius is no longer supported. ## Version 1.2.7 - 2-Apr-2020 * Fixed 'wrong number of arguments' errors when running on JRuby 9.0. #114. * Fixed warnings when running on Ruby 2.8. #112. ## Version 1.2.6 - 24-Dec-2019 * `Timezone#strftime('%s', time)` will now return the correct number of seconds since the epoch. #91. * Removed the unused `TZInfo::RubyDataSource::REQUIRE_PATH` constant. * Fixed "SecurityError: Insecure operation - require" exceptions when loading data with recent Ruby releases in safe mode. * Fixed warnings when running on Ruby 2.7. #106 and #111. ## Version 1.2.5 - 4-Feb-2018 * Support recursively (deep) freezing `Country` and `Timezone` instances. #80. * Allow negative daylight savings time offsets to be derived when reading from zoneinfo files. The utc_offset and std_offset are now derived correctly for Europe/Dublin in the 2018a and 2018b releases of the Time Zone Database. ## Version 1.2.4 - 26-Oct-2017 * Ignore the leapseconds file that is included in zoneinfo directories installed with version 2017c and later of the Time Zone Database. ## Version 1.2.3 - 25-Mar-2017 * Reduce the number of `String` objects allocated when loading zoneinfo files. #54. * Make `Timezone#friendly_identifier` compatible with frozen string literals. * Improve the algorithm for deriving the `utc_offset` from zoneinfo files. This now correctly handles Pacific/Apia switching from one side of the International Date Line to the other whilst observing daylight savings time. #66. * Fix an `UnknownTimezone` exception when calling transitions_up_to or offsets_up_to on a `TimezoneProxy` instance obtained from `Timezone.get_proxy`. * Allow the Factory zone to be obtained from the Zoneinfo data source. * Ignore the /usr/share/zoneinfo/timeconfig symlink included in Slackware distributions. #64. * Fix `Timezone#strftime` handling of `%Z` expansion when `%Z` is prefixed with more than one percent. #31. * Support expansion of `%z`, `%:z`, `%::z` and `%:::z` to the UTC offset of the time zone in `Timezone#strftime`. #31 and #67. ## Version 1.2.2 - 8-Aug-2014 * Fix an error with duplicates being returned by `Timezone#all_country_zones` and `Timezone#all_country_zone_identifiers` when used with tzinfo-data v1.2014.6 or later. * Use the zone1970.tab file for country timezone data if it is found in the zoneinfo directory (and fallback to zone.tab if not). zone1970.tab was added in tzdata 2014f. zone.tab is now deprecated. ## Version 1.2.1 - 1-Jun-2014 * Support zoneinfo files generated with zic version 2014c and later. * On platforms that only support positive 32-bit timestamps, ensure that conversions are accurate from the epoch instead of just from the first transition after the epoch. * Minor documentation improvements. ## Version 1.2.0 - 26-May-2014 * Raise the minimum supported Ruby version to 1.8.7. * Support loading system zoneinfo data on FreeBSD, OpenBSD and Solaris. Resolves #15. * Add `canonical_identifier` and `canonical_zone` methods to `Timezone`. Resolves #16. * Add a link to a `DataSourceNotFound` help page in the `TZInfo::DataSourceNotFound` exception message. * Load iso3166.tab and zone.tab files as UTF-8. * Fix `Timezone#local_to_utc` returning local `Time` instances on systems using UTC as the local time zone. Resolves #13. * Fix `==` methods raising an exception when passed an instance of a different class by making `<=>` return `nil` if passed a non-comparable argument. * Eliminate `require 'rational'` warnings. Resolves #10. * Eliminate "assigned but unused variable - info" warnings. Resolves #11. * Switch to minitest v5 for unit tests. Resolves #18. ## Version 1.1.0 - 25-Sep-2013 * TZInfo is now thread safe. `ThreadSafe::Cache` is now used instead of `Hash` to cache `Timezone` and `Country` instances returned by `Timezone.get` and `Country.get`. The tzinfo gem now depends on thread_safe ~> 0.1. * Added a `transitions_up_to` method to `Timezone` that returns a list of the times where the UTC offset of the timezone changes. * Added an `offsets_up_to` method to `Timezone` that returns the set of offsets that have been observed in a defined timezone. * Fixed a "can't modify frozen String" error when loading a `Timezone` from a zoneinfo file using an identifier `String` that is both tainted and frozen. Resolves #3. * Support TZif3 format zoneinfo files (now produced by zic from tzcode version 2013e onwards). * Support using YARD to generate documentation (added a .yardopts file). * Ignore the +VERSION file included in the zoneinfo directory on Mac OS X. * Added a note to the documentation concerning 32-bit zoneinfo files (as included with Mac OS X). ## Version 1.0.1 - 22-Jun-2013 * Fix a test case failure when tests are run from a directory that contains a dot in the path (issue #29751). ## Version 1.0.0 - 2-Jun-2013 * Allow TZInfo to be used with different data sources instead of just the built-in Ruby module data files. * Include a data source that allows TZInfo to load data from the binary zoneinfo files produced by zic and included with many Linux and Unix-like distributions. * Remove the definition and index Ruby modules from TZInfo and move them into a separate TZInfo::Data library (available as the tzinfo-data gem). * Default to using the TZInfo::Data library as the data source if it is installed, otherwise use zoneinfo files instead. * Preserve the nanoseconds of local timezone Time objects when performing conversions (issue #29705). * Don't add the tzinfo lib directory to the search path when requiring 'tzinfo'. The tzinfo lib directory must now be in the search path before 'tzinfo' is required. * Add `utc_start_time`, `utc_end_time`, `local_start_time` and `local_end_time` instance methods to `TimezonePeriod`. These return an identical value as the existing `utc_start`, `utc_end`, `local_start` and `local_end` methods, but return `Time` instances instead of `DateTime`. * Make the `start_transition`, `end_transition` and `offset` properties of `TimezonePeriod` protected. To access properties of the period, callers should use other `TimezonePeriod` instance methods instead (issue #7655). ## Version 0.3.61 (tzdata v2022a) - 19-Jul-2022 * Fixed a relative path traversal bug that could cause arbitrary files to be loaded with `require` from the Ruby load path. Please refer to for details. CVE-2022-31163. * Updated to tzdata version 2022a (). ## Version 0.3.60 (tzdata v2021a) - 6-Feb-2021 * Updated to tzdata version 2021a (). ## Version 0.3.59 (tzdata v2020e) - 24-Dec-2020 * Updated to tzdata version 2020e (). ## Version 0.3.58 (tzdata v2020d) - 8-Nov-2020 * Updated to tzdata version 2020d (). ## Version 0.3.57 (tzdata v2020a) - 17-May-2020 * Updated to tzdata version 2020a (). ## Version 0.3.56 (tzdata v2019c) - 1-Nov-2019 * Updated to tzdata version 2019c (). ## Version 0.3.55 (tzdata v2018g) - 27-Oct-2018 * Updated to tzdata version 2018g (). ## Version 0.3.54 (tzdata v2018d) - 25-Mar-2018 * Updated to tzdata version 2018d (). ## Version 0.3.53 (tzdata v2017b) - 23-Mar-2017 * Updated to tzdata version 2017b (). ## Version 0.3.52 (tzdata v2016h) - 28-Oct-2016 * Updated to tzdata version 2016h (). ## Version 0.3.51 (tzdata v2016f) - 5-Jul-2016 * Updated to tzdata version 2016f (). ## Version 0.3.50 (tzdata v2016e) - 14-Jun-2016 * Updated to tzdata version 2016e (). ## Version 0.3.49 (tzdata v2016d) - 18-Apr-2016 * Updated to tzdata version 2016d (). ## Version 0.3.48 (tzdata v2016c) - 23-Mar-2016 * Updated to tzdata version 2016c (). ## Version 0.3.47 (tzdata v2016b) - 15-Mar-2016 * Updated to tzdata version 2016b (). ## Version 0.3.46 (tzdata v2015g) - 2-Dec-2015 * From version 2015e, the IANA time zone database uses non-ASCII characters in country names. Backport the encoding handling from TZInfo::Data to allow TZInfo 0.3.x to support Ruby 1.9 (which would otherwise fail with an invalid byte sequence error when loading the countries index). Resolves #41. ## Version 0.3.45 (tzdata v2015g) - 3-Oct-2015 * Updated to tzdata version 2015g (). ## Version 0.3.44 (tzdata v2015d) - 24-Apr-2015 * Updated to tzdata version 2015d (). ## Version 0.3.43 (tzdata v2015a) - 31-Jan-2015 * Updated to tzdata version 2015a (). ## Version 0.3.42 (tzdata v2014i) - 23-Oct-2014 * Updated to tzdata version 2014i (). ## Version 0.3.41 (tzdata v2014f) - 8-Aug-2014 * Updated to tzdata version 2014f (). ## Version 0.3.40 (tzdata v2014e) - 10-Jul-2014 * Updated to tzdata version 2014e (). ## Version 0.3.39 (tzdata v2014a) - 9-Mar-2014 * Updated to tzdata version 2014a (). ## Version 0.3.38 (tzdata v2013g) - 8-Oct-2013 * Updated to tzdata version 2013g (). ## Version 0.3.37 (tzdata v2013b) - 11-Mar-2013 * Updated to tzdata version 2013b (). ## Version 0.3.36 (tzdata v2013a) - 3-Mar-2013 * Updated to tzdata version 2013a (). * Fix `TimezoneTransitionInfo#eql?` incorrectly returning false when running on Ruby 2.0. * Change `eql?` and `==` implementations to test the class of the passed in object instead of checking individual properties with `respond_to?`. ## Version 0.3.35 (tzdata v2012i) - 4-Nov-2012 * Updated to tzdata version 2012i (). ## Version 0.3.34 (tzdata v2012h) - 27-Oct-2012 * Updated to tzdata version 2012h (). ## Version 0.3.33 (tzdata v2012c) - 8-Apr-2012 * Updated to tzdata version 2012c (). ## Version 0.3.32 (tzdata v2012b) - 4-Mar-2012 * Updated to tzdata version 2012b (). ## Version 0.3.31 (tzdata v2011n) - 6-Nov-2011 * Updated to tzdata version 2011n (). ## Version 0.3.30 (tzdata v2011k) - 29-Sep-2011 * Updated to tzdata version 2011k (). ## Version 0.3.29 (tzdata v2011h) - 27-Jun-2011 * Updated to tzdata version 2011h (). * Allow the default value of the `local_to_utc` and `period_for_local` `dst` parameter to be specified globally with a `Timezone.default_dst` attribute. Thanks to Kurt Werle for the suggestion and patch. ## Version 0.3.28 (tzdata v2011g) - 13-Jun-2011 * Add support for Ruby 1.9.3 (trunk revision 31668 and later). Thanks to Aaron Patterson for reporting the problems running on the new version. Closes #29233. ## Version 0.3.27 (tzdata v2011g) - 26-Apr-2011 * Updated to tzdata version 2011g (). ## Version 0.3.26 (tzdata v2011e) - 2-Apr-2011 * Updated to tzdata version 2011e (). ## Version 0.3.25 (tzdata v2011d) - 14-Mar-2011 * Updated to tzdata version 2011d (). ## Version 0.3.24 (tzdata v2010o) - 15-Jan-2011 * Updated to tzdata version 2010o (). ## Version 0.3.23 (tzdata v2010l) - 19-Aug-2010 * Updated to tzdata version 2010l (). ## Version 0.3.22 (tzdata v2010j) - 29-May-2010 * Corrected file permissions issue with 0.3.21 release. ## Version 0.3.21 (tzdata v2010j) - 28-May-2010 * Updated to tzdata version 2010j (). * Change invalid timezone check to exclude characters not used in timezone identifiers and avoid 'character class has duplicated range' warnings with Ruby 1.9.2. * Ruby 1.9.2 has deprecated `require 'rational'`, but older versions of Ruby need rational to be required. Require rational only when the Rational module has not already been loaded. * Remove circular requires (now a warning in Ruby 1.9.2). Instead of using requires in each file for dependencies, `tzinfo.rb` now requires all tzinfo files. If you were previously requiring files within the tzinfo directory (e.g. `require 'tzinfo/timezone'`), then you will now have to `require 'tzinfo'` instead. ## Version 0.3.20 (tzdata v2010i) - 19-Apr-2010 * Updated to tzdata version 2010i (). ## Version 0.3.19 (tzdata v2010h) - 5-Apr-2010 * Updated to tzdata version 2010h (). ## Version 0.3.18 (tzdata v2010g) - 29-Mar-2010 * Updated to tzdata version 2010g (). ## Version 0.3.17 (tzdata v2010e) - 8-Mar-2010 * Updated to tzdata version 2010e (). ## Version 0.3.16 (tzdata v2009u) - 5-Jan-2010 * Support the use of '-' to denote '0' as an offset in the tz data files. Used for the first time in the SAVE field in tzdata v2009u. * Updated to tzdata version 2009u (). ## Version 0.3.15 (tzdata v2009p) - 26-Oct-2009 * Updated to tzdata version 2009p (). * Added a description to the gem spec. * List test files in test_files instead of files in the gem spec. ## Version 0.3.14 (tzdata v2009l) - 19-Aug-2009 * Updated to tzdata version 2009l (). * Include current directory in load path to allow running tests on Ruby 1.9.2, which doesn't include it by default any more. ## Version 0.3.13 (tzdata v2009f) - 15-Apr-2009 * Updated to tzdata version 2009f (). * Untaint the timezone module filename after validation to allow use with `$SAFE == 1` (e.g. under mod_ruby). Thanks to Dmitry Borodaenko for the suggestion. Closes #25349. ## Version 0.3.12 (tzdata v2008i) - 12-Nov-2008 * Updated to tzdata version 2008i (). ## Version 0.3.11 (tzdata v2008g) - 7-Oct-2008 * Updated to tzdata version 2008g (). * Support Ruby 1.9.0-5. `Rational.new!` has now been removed in Ruby 1.9. Only use `Rational.new!` if it is available (it is preferable in Ruby 1.8 for performance reasons). Thanks to Jeremy Kemper and Pratik Naik for reporting this. Closes #22312. * Apply a patch from Pratik Naik to replace assert calls that have been deprecated in the Ruby svn trunk. Closes #22308. ## Version 0.3.10 (tzdata v2008f) - 16-Sep-2008 * Updated to tzdata version 2008f (). ## Version 0.3.9 (tzdata v2008c) - 27-May-2008 * Updated to tzdata version 2008c (). * Support loading timezone data in the latest trunk versions of Ruby 1.9. `Rational.new!` is now private, so call it using `Rational.send :new!` instead. Thanks to Jeremy Kemper and Pratik Naik for spotting this. Closes #19184. * Prevent warnings from being output when running Ruby with the -v or -w command line options. Thanks to Paul McMahon for the patch. Closes #19719. ## Version 0.3.8 (tzdata v2008b) - 24-Mar-2008 * Updated to tzdata version 2008b (). * Support loading timezone data in Ruby 1.9.0. Use `DateTime.new!` if it is available instead of `DateTime.new0` when constructing transition times. `DateTime.new!` was added in Ruby 1.8.6. `DateTime.new0` was removed in Ruby 1.9.0. Thanks to Joshua Peek for reporting this. Closes #17606. * Modify some of the equality test cases to cope with the differences between Ruby 1.8.6 and Ruby 1.9.0. ## Version 0.3.7 (tzdata v2008a) - 10-Mar-2008 * Updated to tzdata version 2008a (). ## Version 0.3.6 (tzdata v2007k) - 1-Jan-2008 * Updated to tzdata version 2007k (). * Removed deprecated RubyGems autorequire option. ## Version 0.3.5 (tzdata v2007h) - 1-Oct-2007 * Updated to tzdata version 2007h (). ## Version 0.3.4 (tzdata v2007g) - 21-Aug-2007 * Updated to tzdata version 2007g (). ## Version 0.3.3 (tzdata v2006p) - 27-Nov-2006 * Updated to tzdata version 2006p (). ## Version 0.3.2 (tzdata v2006n) - 11-Oct-2006 * Updated to tzdata version 2006n (). Note that this release of tzdata removes the country Serbia and Montenegro (CS) and replaces it with separate Serbia (RS) and Montenegro (ME) entries. ## Version 0.3.1 (tzdata v2006j) - 21-Aug-2006 * Remove colon from case statements to avoid warning in Ruby 1.8.5. #5198. * Use temporary variable to avoid dynamic string warning from rdoc. * Updated to tzdata version 2006j (). ## Version 0.3.0 (tzdata v2006g) - 17-Jul-2006 * New timezone data format. Timezone data now occupies less space on disk and takes less memory once loaded. #4142, #4144. * Timezone data is defined in modules rather than classes. `Timezone` instances returned by `Timezone.get` are no longer instances of data classes, but are instead instances of new `DataTimezone` and `LinkedTimezone` classes. * `Timezone` instances can now be used with `Marshal.dump` and `Marshal.load`. #4240. * Added a `Timezone.get_proxy` method that returns a `TimezoneProxy` object for a given identifier. * Country index data is now defined in a single module that is independent of the `Country` class implementation. * `Country` instances can now be used with `Marshal.dump` and `Marshal.load`. #4240. * `Country` has a new `zone_info` method that returns `CountryTimezone` objects containing additional information (latitude, longitude and a description) relating to each `Timezone`. #4140. * Time zones within a `Country` are now returned in an order that makes geographic sense. * The zdumptest utility now checks local to utc conversions in addition to utc to local conversions. * `eql?` method defined on `Country` and `Timezone` that is equivalent to `==`. * The `==` method of `Timezone` no longer raises an exception when passed an object with no identifier method. * The `==` method of `Country` no longer raises an exception when passed an object with no code method. * `hash` method defined on `Country` that returns the hash of the code. * `hash` method defined on `Timezone` that returns the hash of the identifier. * Miscellaneous API documentation corrections and improvements. * Timezone definition and indexes are now excluded from rdoc (the contents were previously ignored with `#:nodoc:` anyway). * Removed no longer needed `#:nodoc:` directives from timezone data files (which are now excluded from the rdoc build). * Installation of the gem now causes rdoc API documentation to be generated. #4905. * When optimizing transitions to generate zone definitions, check the UTC and standard offsets separately rather than just the total offset to UTC. Fixes an incorrect abbreviation issue with Europe/London, Europe/Dublin and Pacific/Auckland. * Eliminated unnecessary `.nil?` calls to give a minor performance gain. * `Timezone.all` and `Timezone.all_identifiers` now return all the `Timezone` instances/identifiers rather than just those associated with countries. #4146. * Added `all_data_zones`, `all_data_zone_identifiers`, `all_linked_zones` and `all_linked_zone_identifiers` class methods to `Timezone`. * Added a `strftime` method to `Timezone` that converts a time in UTC to local time and then returns it formatted. `%Z` is replaced with the timezone abbreviation for the given time (for example, EST or EDT). #4143. * Fix escaping of quotes in `TZDataParser`. This affected country names and descriptions of time zones within countries. ## Version 0.2.2 (tzdata v2006g) - 17-May-2006 * Use class-scoped instance variables to store the Timezone identifier and singleton instance. Loading a linked zone no longer causes the parent zone's identifier to be changed. The instance method of a linked zone class also now returns an instance of the linked zone class rather than the parent class. #4502. * The zdumptest utility now compares the TZInfo zone identifier with the zdump zone identifier. * The zdumptestall utility now exits if not supplied with enough parameters. * Updated to tzdata version 2006g (). ## Version 0.2.1 (tzdata v2006d) - 17-Apr-2006 * Fix a performance issue caused in 0.2.0 with `Timezone.local_to_utc`. Conversions performed on `TimeOrDateTime` instances passed to `<=>` are now cached as originally intended. Thanks to Michael Smedberg for spotting this. * Fix a performance issue with the `local_to_utc` period search algorithm originally implemented in 0.1.0. The condition that was supposed to cause the search to terminate when enough periods had been found was only being evaluated in a small subset of cases. Thanks to Michael Smedberg and Jamis Buck for reporting this. * Added abbreviation as an alias for `TimezonePeriod.zone_identifier`. * Updated to tzdata version 2006d (). * Ignore any offset in `DateTime` instances passed in (as is already done for `Time` instances). All of the following now refer to the same UTC time (15:40 on 17 April 2006). Previously, the `DateTime` in the second line would have been interpreted as 20:40. ```ruby tz.utc_to_local(DateTime.new(2006, 4, 17, 15, 40, 0)) tz.utc_to_local(DateTime.new(2006, 4, 17, 15, 40, 0).new_offset(Rational(5, 24))) tz.utc_to_local(Time.utc(2006, 4, 17, 15, 40, 0)) tz.utc_to_local(Time.local(2006, 4, 17, 15, 40, 0)) ``` ## Version 0.2.0 (tzdata v2006c) - 3-Apr-2006 * Use timestamps rather than `DateTime` objects in zone files for times between 1970 and 2037 (the range of `Time`). * Don't convert passed in `Time` objects to `DateTime` in most cases (provides a substantial performance improvement). * Allow integer timestamps (time in seconds since 1970-1-1) to be used as well as `Time` and `DateTime` objects in all public methods that take times as parameters. * Tool to compare TZInfo conversions with output from zdump. * `TZDataParser` zone generation algorithm rewritten. Now based on the zic code. TZInfo is now 100% compatible with zic/zdump output. * Riyadh Solar Time zones now included again (generation time has been reduced with `TZDataParser` changes). * Use binary mode when writing zone and country files to get Unix (\n) new lines. * Omit unnecessary quotes in zone identifier symbols. * Omit the final transition to DST if there is a prior transition in the last year processed to standard time. * Updated to tzdata version 2006c (). ## Version 0.1.2 (tzdata v2006a) - 5-Feb-2006 * Add lib directory to the load path when tzinfo is required. Makes it easier to use tzinfo gem when unpacked to vendor directory in rails. * Updated to tzdata version 2006a (). * `build_tz_classes` rake task now handles running svn add and svn delete as new time zones and countries are added and old ones are removed. * Return a better error when attempting to use a `Timezone` instance that was constructed with `Timezone.new(nil)`. This will occur when using Rails' `composed_of`. When the timezone identifier in the database is null, attempting to use the `Timezone` will now result in an `UnknownTimezone` exception rather than a `NameError`. ## Version 0.1.1 (tzdata v2005q) - 18-Dec-2005 * Time zones that are defined by a single unbounded period (e.g. UTC) now work again. * Updated to tzdata version 2005q. ## Version 0.1.0 (tzdata v2005n) - 27-Nov-2005 * `period_for_local` and `local_to_utc` now allow resolution of ambiguous times (e.g. when switching from daylight savings to standard time). The behaviour of these methods when faced with an ambiguous local time has now changed. If you are using these methods you should check the documentation. Thanks to Cliff Matthews for suggesting this change. * Added `require 'date'` to `timezone.rb` (date isn't loaded by default in all environments). * Use rake to build packages and documentation. * License file is now included in gem distribution. * Dates in definitions stored as Astronomical Julian Day numbers rather than as civil dates (improves performance creating `DateTime` instances). * Added options to `TZDataParser` to allow generation of specific zones and countries. * Moved `TimezonePeriod` class to `timezone_period.rb`. * New `TimezonePeriodList` class to store `TimezonePeriod` instances for a timezone and perform searches for periods. * Time zones are now defined using blocks. `TimezonePeriod` instances are only created when they are needed. Thanks to Jamis Buck for the suggestion. * Add options to `TZDataParser` to allow exclusion of specific zones and countries. * Exclude the Riyadh Solar Time zones. The rules are only for 1987 to 1989 and take a long time to generate and process. Riyadh Solar Time is no longer observed. * The last `TimezonePeriod` for each `Timezone` is now written out with an unbounded rather than arbitrary end time. * Construct the `Rational` offset in `TimezonePeriod` once when the `TimezonePeriod` is constructed rather than each time it is needed. * `Timezone` and `Country` now keep a cache of loaded instances to avoid running `require` which can be slow on some platforms. * Updated to tzdata version 2005n. ## Version 0.0.4 (tzdata v2005m) - 18-Sep-2005 * Removed debug output accidentally included in the previous release. * Fixed a bug in the generation of friendly zone identifiers (was inserting apostrophes into UTC, GMT, etc). * Fixed `Country` `<=>` operator (was comparing non-existent attribute) * Fixed `Timezone.period_for_local` error when period not found. * Added test cases for `Timezone`, `TimezoneProxy`, `TimezonePeriod`, `Country` and some selected time zones. ## Version 0.0.3 (tzdata v2005m) - 17-Sep-2005 * Reduced visibility of some methods added in `Timezone#setup` and `Country#setup`. * Added `name` method to `Timezone` (returns the identifier). * Added `friendly_identifier` method to `Timezone`. Returns a more friendly version of the identifier. * Added `to_s` method to `Timezone`. Returns the friendly identifier. * Added `==` and `<=>` operators to `Timezone` (compares identifiers). * `Timezone` now includes `Comparable`. * Added `to_s` method to `Country`. * Added `==` and `<=>` operators to `Country` (compares ISO 3166 country codes). * `Country` now includes `Comparable`. * New `TimezoneProxy` class that behaves the same as a `Timezone` but doesn't actually load in its definition until it is actually required. * Modified `Timezone` and `Country` methods that return `Timezone` instances to return `TimezoneProxy` instances instead. This makes these methods much quicker. In Ruby on Rails, you can now show a drop-down list of all time zones using the Rails `time_zone_select` helper method: ```ruby <%= time_zone_select 'user', 'time_zone', TZInfo::Timezone.all.sort, :model => TZInfo::Timezone %> ``` ## Version 0.0.2 (tzdata v2005m) - 13-Sep-2005 * `Country` and `Timezone` data is now loaded into class rather than instance variables. This makes `Timezone` links more efficient and saves memory if creating specific `Timezone` and `Country` classes directly. * `TimezonePeriod` `zone_identifier` is now defined as a symbol to save memory (was previously a string). * `TimezonePeriod` `zone_identifier`s that were previously `''` are now `:Unknown`. * `Timezone` and `Country` instances can now be returned using `Timezone.new(identifier)` and `Country.new(identifier)`. When passed an identifier, the `new` method calls `get` to return an instance of the specified timezone or country. * Added new class methods to `Timezone` to return sets of zones and identifiers. Thanks to Scott Barron of Lunchbox Software for the suggestions in his article about using TZInfo with Rails () ## Version 0.0.1 (tzdata v2005m) - 29-Aug-2005 * First release. tzinfo-2.0.6/Gemfile000066400000000000000000000016361436527530500143430ustar00rootroot00000000000000source "https://rubygems.org" gemspec group :test do gem 'rake', ['>= 12.2.1', '< 14'] gem 'minitest', '~> 5.0' gem 'simplecov', '~> 0.15.1', require: false # json is a dependency of simplecov. Version 2.3.0 is declared as compatible # with Ruby >= 1.9, but actually fails with a syntax error: # https://travis-ci.org/tzinfo/tzinfo/jobs/625092293#L605 # # 2.5.1 is declared as compatible with Ruby >= 2.0, but actually fails to # compile with an undefined reference to `rb_funcallv` on Windows: # https://github.com/tzinfo/tzinfo/runs/1664656059#step:3:757 # # 2.3.0 also fails to build the native extension with Rubinius: # https://travis-ci.org/tzinfo/tzinfo/jobs/625092305#L1310 # # Limit to earlier compatible versions. if RUBY_VERSION < '2.0' || RUBY_ENGINE == 'rbx' gem 'json', '< 2.3.0' elsif RUBY_VERSION < '2.1' && RUBY_PLATFORM =~ /mingw/ gem 'json', '< 2.5.0' end end tzinfo-2.0.6/LICENSE000066400000000000000000000020441436527530500140470ustar00rootroot00000000000000Copyright (c) 2005-2023 Philip Ross Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. tzinfo-2.0.6/README.md000066400000000000000000000331121436527530500143210ustar00rootroot00000000000000# TZInfo - Ruby Time Zone Library [![RubyGems](https://img.shields.io/gem/v/tzinfo?logo=rubygems&label=Gem)](https://rubygems.org/gems/tzinfo) [![Tests](https://github.com/tzinfo/tzinfo/workflows/Tests/badge.svg?branch=master&event=push)](https://github.com/tzinfo/tzinfo/actions?query=workflow%3ATests+branch%3Amaster+event%3Apush) [TZInfo](https://tzinfo.github.io) is a Ruby library that provides access to time zone data and allows times to be converted using time zone rules. ## Data Sources TZInfo requires a source of time zone data. There are two options: 1. A zoneinfo directory containing timezone definition files. These files are generated from the [IANA Time Zone Database](https://www.iana.org/time-zones) using the `zic` utility. Most Unix-like systems include a zoneinfo directory. 2. The TZInfo::Data library (the tzinfo-data gem). TZInfo::Data contains a set of Ruby modules that are also generated from the IANA Time Zone Database. By default, TZInfo will attempt to use TZInfo::Data. If TZInfo::Data is not available (i.e. if `require 'tzinfo/data'` fails), then TZInfo will search for a zoneinfo directory instead (using the search path specified by `TZInfo::ZoneinfoDataSource::DEFAULT_SEARCH_PATH`). If no data source can be found, a `TZInfo::DataSourceNotFound` exception will be raised when TZInfo is used. Further information is available [in the wiki](https://tzinfo.github.io/datasourcenotfound) to help resolve `TZInfo::DataSourceNotFound` errors. The default data source selection can be overridden by calling `TZInfo::DataSource.set`. Custom data sources can also be used. See the `TZInfo::DataSource.set` documentation for further details. ## Installation The TZInfo gem can be installed by running `gem install tzinfo` or by adding `gem 'tzinfo'` to your `Gemfile` and running `bundle install`. To use the Ruby modules as the data source, TZInfo::Data will also need to be installed by running `gem install tzinfo-data` or by adding `gem 'tzinfo-data'` to your `Gemfile`. ## IANA Time Zone Database The data returned and used by TZInfo is sourced from the [IANA Time Zone Database](http://www.iana.org/time-zones). The [Theory and pragmatics of the tz code and data](https://data.iana.org/time-zones/theory.html) document gives details of how the data is organized and managed. ## Example Usage To use TZInfo, it must first be required with: ```ruby require 'tzinfo' ``` The `TZInfo::Timezone` class provides access to time zone data and methods for converting times. The `all_identifiers` method returns a list of valid time zone identifiers: ```ruby identifiers = TZInfo::Timezone.all_identifiers # => ["Africa/Adibdjan", "Africa/Accra", ..., "Zulu"] ``` A `TZInfo::Timezone` instance representing an individual time zone can be obtained with `TZInfo::Timezone.get`: ```ruby tz = TZInfo::Timezone.get('America/New_York') # => # ``` A time can be converted to the local time of the time zone with `to_local`: ```ruby tz.to_local(Time.utc(2018, 2, 1, 12, 30, 0)) # => 2018-02-01 07:30:00 -0500 tz.to_local(Time.utc(2018, 7, 1, 12, 30, 0)) # => 2018-07-01 08:30:00 -0400 tz.to_local(Time.new(2018, 7, 1, 13, 30, 0, '+01:00')) # => 2018-07-01 08:30:00 -0400 ``` Local times with the appropriate offset for the time zone can be constructed with `local_time`: ```ruby tz.local_time(2018, 2, 1, 7, 30, 0) # => 2018-02-01 07:30:00 -0500 tz.local_time(2018, 7, 1, 8, 30, 0) # => 2018-07-01 08:30:00 -0400 ``` Local times can be converted to UTC by using `local_time` and calling `utc` on the result: ```ruby tz.local_time(2018, 2, 1, 7, 30, 0).utc # => 2018-02-01 12:30:00 UTC tz.local_time(2018, 7, 1, 8, 30, 0).utc # => 2018-07-01 12:30:00 UTC ``` The `local_to_utc` method can also be used to convert a time object to UTC. The offset of the time is ignored - it is treated as if it were a local time for the time zone: ```ruby tz.local_to_utc(Time.utc(2018, 2, 1, 7, 30, 0)) # => 2018-02-01 12:30:00 UTC tz.local_to_utc(Time.new(2018, 2, 1, 7, 30, 0, '+01:00')) # => 2018-02-01 12:30:00 UTC ``` Information about the time zone can be obtained from returned local times: ```ruby local_time = tz.to_local(Time.utc(2018, 2, 1, 12, 30, 0)) local_time.utc_offset # => -18000 local_time.dst? # => false local_time.zone # => "EST" local_time = tz.to_local(Time.utc(2018, 7, 1, 12, 30, 0)) local_time.utc_offset # => -14400 local_time.dst? # => true local_time.zone # => "EDT" ``` Time zone information can be included when formatting times with `strftime` using the `%z` and `%Z` directives: ```ruby tz.to_local(Time.utc(2018, 2, 1, 12, 30, 0)).strftime('%Y-%m-%d %H:%M:%S %z %Z') # => "2018-02-01 07:30:00 -0500 EST" tz.to_local(Time.utc(2018, 7, 1, 12, 30, 0)).strftime('%Y-%m-%d %H:%M:%S %z %Z') # => "2018-07-01 08:30:00 -0400 EDT" ``` The `period_for` method can be used to obtain information about the observed time zone information at a particular time as a `TZInfo::TimezonePeriod` object: ```ruby period = tz.period_for(Time.utc(2018, 7, 1, 12, 30, 0)) period.base_utc_offset # => -18000 period.std_offset # => 3600 period.observed_utc_offset # => -14400 period.abbreviation # => "EDT" period.dst? # => true period.local_starts_at.to_time # => 2018-03-11 03:00:00 -0400 period.local_ends_at.to_time # => 2018-11-04 02:00:00 -0400 ``` A list of transitions between periods where different rules are observed can be obtained with the `transitions_up_to` method. The result is returned as an `Array` of `TZInfo::TimezoneTransition` objects: ```ruby transitions = tz.transitions_up_to(Time.utc(2019, 1, 1), Time.utc(2017, 1, 1)) transitions.map do |t| [t.local_end_at.to_time, t.offset.observed_utc_offset, t.offset.abbreviation] end # => [[2017-03-12 02:00:00 -0500, -14400, "EDT"], # [2017-11-05 02:00:00 -0400, -18000, "EST"], # [2018-03-11 02:00:00 -0500, -14400, "EDT"], # [2018-11-04 02:00:00 -0400, -18000, "EST"]] ``` A list of the unique offsets used by a time zone can be obtained with the `offsets_up_to` method. The result is returned as an `Array` of `TZInfo::TimezoneOffset` objects: ```ruby offsets = tz.offsets_up_to(Time.utc(2019, 1, 1)) offsets.map {|o| [o.observed_utc_offset, o.abbreviation] } # => [[-17762, "LMT"], # [-18000, "EST"], # [-14400, "EDT"], # [-14400, "EWT"], # [-14400, "EPT"]] ``` All `TZInfo::Timezone` methods that accept a time as a parameter can be used with either instances of `Time`, `DateTime` or `TZInfo::Timestamp`. Arbitrary `Time`-like objects that respond to both `to_i` and `subsec` and optionally `utc_offset` will be treated as if they are instances of `Time`. `TZInfo::Timezone` methods that both accept and return times will return an object with a type matching that of the parameter (actually a `TZInfo::TimeWithOffset`, `TZInfo::DateTimeWithOffset` or `TZInfo::TimestampWithOffset` subclass when returning a local time): ```ruby tz.to_local(Time.utc(2018, 7, 1, 12, 30, 0)) # => 2018-07-01 08:30:00 -0400 tz.to_local(DateTime.new(2018, 7, 1, 12, 30, 0)) # => # tz.to_local(TZInfo::Timestamp.create(2018, 7, 1, 12, 30, 0, 0, :utc)) # => # ``` In addition to `local_time`, which returns `Time` instances, the `local_datetime` and `local_timestamp` methods can be used to construct local `DateTime` and `TZInfo::Timestamp` instances with the appropriate offset: ```ruby tz.local_time(2018, 2, 1, 7, 30, 0) # => 2018-02-01 07:30:00 -0500 tz.local_datetime(2018, 2, 1, 7, 30, 0) # => # tz.local_timestamp(2018, 2, 1, 7, 30, 0) # => # ``` The `local_to_utc`, `local_time`, `local_datetime` and `local_timestamp` methods may raise a `TZInfo::PeriodNotFound` or a `TZInfo::AmbiguousTime` exception. `TZInfo::PeriodNotFound` signals that there is no equivalent UTC time (for example, during the transition from standard time to daylight savings time when the clocks are moved forward and an hour is skipped). `TZInfo::AmbiguousTime` signals that there is more than one equivalent UTC time (for example, during the transition from daylight savings time to standard time where the clocks are moved back and an hour is repeated): ```ruby tz.local_time(2018, 3, 11, 2, 30, 0, 0) # raises TZInfo::PeriodNotFound (2018-03-11 02:30:00 is an invalid local time.) tz.local_time(2018, 11, 4, 1, 30, 0, 0) # raises TZInfo::AmbiguousTime (2018-11-04 01:30:00 is an ambiguous local time.) ``` `TZInfo::PeriodNotFound` exceptions can only be resolved by adjusting the time, for example, by advancing an hour: ```ruby tz.local_time(2018, 3, 11, 3, 30, 0, 0) # => 2018-03-11 03:30:00 -0400 ``` `TZInfo::AmbiguousTime` exceptions can be resolved by setting the `dst` parameter and/or specifying a block to choose one of the interpretations: ```ruby tz.local_time(2018, 11, 4, 1, 30, 0, 0, true) # => 2018-11-04 01:30:00 -0400 tz.local_time(2018, 11, 4, 1, 30, 0, 0, false) # => 2018-11-04 01:30:00 -0500 tz.local_time(2018, 11, 4, 1, 30, 0, 0) {|p| p.first } # => 2018-11-04 01:30:00 -0400 tz.local_time(2018, 11, 4, 1, 30, 0, 0) {|p| p.last } # => 2018-11-04 01:30:00 -0500 ``` The default value of the `dst` parameter can also be set globally: ```ruby TZInfo::Timezone.default_dst = true tz.local_time(2018, 11, 4, 1, 30, 0, 0) # => 2018-11-04 01:30:00 -0400 TZInfo::Timezone.default_dst = false tz.local_time(2018, 11, 4, 1, 30, 0, 0) # => 2018-11-04 01:30:00 -0500 ``` TZInfo also provides information about [ISO 3166-1](https://www.iso.org/iso-3166-country-codes.html) countries and their associated time zones via the `TZInfo::Country` class. A list of valid ISO 3166-1 (alpha-2) country codes can be obtained by calling `TZInfo::Country.all_codes`: ```ruby TZInfo::Country.all_codes # => ["AD", "AE", ..., "ZW"] ``` A `TZInfo::Country` instance representing an individual time zone can be obtained with `TZInfo::Country.get`: ```ruby c = TZInfo::Country.get('US') # => # c.name # => "United States" ``` The `zone_identifiers` method returns a list of the time zone identifiers used in a country: ```ruby c.zone_identifiers # => ["America/New_York", "America/Detroit", ..., "Pacific/Honolulu"] ``` The `zone_info` method returns further information about the time zones used in a country as an `Array` of `TZInfo::CountryTimezone` instances: ```ruby zi = c.zone_info.first zi.identifier # => "America/New_York" zi.latitude.to_f.round(5) # => 40.71417 zi.longitude.to_f.round(5) # => -74.00639 zi.description # => "Eastern (most areas)" ``` The `zones` method returns an `Array` of `TZInfo::Timezone` instances for a country. A `TZInfo::Timezone` instance can be obtained from a `TZInfo::CountryTimezone` using the `timezone` method: ```ruby zi.timezone.to_local(Time.utc(2018, 2, 1, 12, 30, 0)) # => 2018-02-01 07:30:00 -0500 ``` For further detail, please refer to the API documentation for the `TZInfo::Timezone` and `TZInfo::Country` classes. ## Time Zone Selection The Time Zone Database maintainers recommend that time zone identifiers are not made visible to end-users (see [Names of timezones](https://data.iana.org/time-zones/theory.html#naming)). Instead of displaying a list of time zone identifiers, time zones can be selected by the user's country. Call `TZInfo::Country.all` to obtain a list of `TZInfo::Country` objects, each with a unique `code` and a `name` that can be used for display purposes. Most countries have a single time zone. When choosing such a country, the time zone can be inferred and selected automatically. ```ruby croatia = TZInfo::Country.get('HR') # => # croatia.zone_info.length # => 1 croatia.zone_info[0].identifier # => "Europe/Belgrade" ``` Some countries have multiple time zones. The `zone_info` method can be used to obtain a list of user-friendly descriptions of the available options: ```ruby australia = TZInfo::Country.get('AU') # => # australia.zone_info.length # => 13 australia.zone_info.map {|i| [i.identifier, i.description] } # => [["Australia/Lord_Howe", "Lord Howe Island"], # ["Antarctica/Macquarie", "Macquarie Island"], # ... # ["Australia/Eucla", "Western Australia (Eucla)"]] ``` Please note that country information available through TZInfo is intended as an aid to help users select a time zone data appropriate for their practical needs. It is not intended to take or endorse any position on legal or territorial claims. ## Compatibility TZInfo v2.0.0 requires a minimum of Ruby MRI 1.9.3 or JRuby 1.7 (in 1.9 mode or later). ## Thread-Safety The `TZInfo::Country` and `TZInfo::Timezone` classes are thread-safe. It is safe to use class and instance methods of `TZInfo::Country` and `TZInfo::Timezone` in concurrently executing threads. Instances of both classes can be shared across thread boundaries. ## Documentation API documentation for TZInfo is available on [RubyDoc.info](https://www.rubydoc.info/gems/tzinfo/). ## License TZInfo is released under the MIT license, see LICENSE for details. ## Source Code Source code for TZInfo is available on [GitHub](https://github.com/tzinfo/tzinfo). ## Issue Tracker Please post any bugs, issues, feature requests or questions about TZInfo to the [GitHub issue tracker](https://github.com/tzinfo/tzinfo/issues). Issues with the underlying time zone data should be raised on the [Time Zone Database Discussion mailing list](https://mm.icann.org/mailman/listinfo/tz). tzinfo-2.0.6/Rakefile000066400000000000000000000063701436527530500145150ustar00rootroot00000000000000require 'rubygems' require 'rubygems/package_task' require 'fileutils' require 'rake/testtask' # Ignore errors loading rdoc/task (the rdoc tasks will be excluded if # rdoc is unavailable). begin require 'rdoc/task' rescue LoadError, RuntimeError end BASE_DIR = File.expand_path(File.dirname(__FILE__)) task default: [:test] spec = eval(File.read('tzinfo.gemspec')) class TZInfoPackageTask < Gem::PackageTask alias_method :orig_sh, :sh private :orig_sh def sh(*cmd, &block) if cmd[0] == '__tar_with_owner__' && cmd[1] =~ /\A-?[zjcvf]+\z/ opts = cmd[1] cmd = ['tar', 'c', '--owner', '0', '--group', '0', "#{opts.start_with?('-') ? '' : '-'}#{opts.gsub('c', '')}"] + cmd.drop(2) elsif cmd.first =~ /\A__tar_with_owner__ -?([zjcvf]+)(.*)\z/ opts = $1 args = $2 cmd[0] = "tar c --owner 0 --group 0 -#{opts.gsub('c', '')}#{args}" end orig_sh(*cmd, &block) end end def add_signing_key(spec) # Attempt to find the private key and add options to sign the gem if found. private_key_path = File.expand_path(File.join(BASE_DIR, '..', 'key', 'gem-private_key.pem')) if File.exist?(private_key_path) spec = spec.clone spec.signing_key = private_key_path spec.cert_chain = [File.join(BASE_DIR, 'gem-public_cert.pem')] else puts 'WARNING: Private key not found. Not signing gem file.' end spec end package_task = TZInfoPackageTask.new(add_signing_key(spec)) do |pkg| pkg.need_zip = true pkg.need_tar_gz = true pkg.tar_command = '__tar_with_owner__' end # Skip the rdoc task if RDoc::Task is unavailable if defined?(RDoc) && defined?(RDoc::Task) RDoc::Task.new do |rdoc| rdoc.rdoc_dir = 'doc' rdoc.options.concat spec.rdoc_options rdoc.rdoc_files.include(spec.extra_rdoc_files) rdoc.rdoc_files.include('lib') end end Rake::Task[package_task.package_dir_path].enhance do recurse_chmod(package_task.package_dir_path) end Rake::Task[:package].enhance do FileUtils.rm_rf(package_task.package_dir_path) end def recurse_chmod(dir) File.chmod(0755, dir) Dir.entries(dir).each do |entry| if entry != '.' && entry != '..' path = File.join(dir, entry) if File.directory?(path) recurse_chmod(path) else File.chmod(0644, path) end end end end # Only run coverage tests on MRI. SimpleCov is supported on JRuby 9.1, but # generates warnings. It is not supported on Rubinius. TEST_COVERAGE = RUBY_ENGINE == 'ruby' ENV['TEST_COVERAGE'] = TEST_COVERAGE ? '1' : '0' desc 'Run tests using RubyDataSource with a format 1 version of TZInfo::Data, RubyDataSource with a format 2 version of TZInfo::Data and ZoneinfoDataSource' task test: [:clean_coverage, :test_ruby_format1, :test_ruby_format2, :test_zoneinfo] do end desc 'Remove coverage results' task :clean_coverage do FileUtils.rm_f(File.join(BASE_DIR, 'coverage', '.resultset.json')) end def setup_tests(test_task, type) test_task.libs = [File.join(BASE_DIR, 'lib')] test_task.pattern = File.join(BASE_DIR, 'test', "ts_all_#{type}.rb") test_task.warning = true end Rake::TestTask.new(:test_ruby_format1) do |t| setup_tests(t, :ruby_format1) end Rake::TestTask.new(:test_ruby_format2) do |t| setup_tests(t, :ruby_format2) end Rake::TestTask.new(:test_zoneinfo) do |t| setup_tests(t, :zoneinfo) end tzinfo-2.0.6/gem-public_cert.pem000066400000000000000000000022401436527530500166040ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIDPDCCAiSgAwIBAgIBATANBgkqhkiG9w0BAQsFADAkMSIwIAYDVQQDDBlwaGls LnJvc3MvREM9Z21haWwvREM9Y29tMB4XDTE5MTIyNDE0NTU0N1oXDTM5MTIyNDE0 NTU0N1owJDEiMCAGA1UEAwwZcGhpbC5yb3NzL0RDPWdtYWlsL0RDPWNvbTCCASIw DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJGcwfqn4ZsmPl0b1Lt9dCzExrE5 EeP/CRQjBdGHkF+mSpi69XysxdwLdfg5SPr9LfxthUug4nNFd5fDCiXM8hYe9jQD TmkIQKNBh4fFpGngn9gyy+SumCXi6b5L6d/aMc59NAOM6LJ88TOdH1648dh5rq3C ULq82n3gg4+u0HHGjRPuR/pnCFQCZbANYdX+UBWd0qkOJn/EreNKROmEeHr/xKuh 2/GlKFKt9KLcW3hwBB4fHHVYUzRau7D1m9KbEERdg//qNDC4B7fD2BFJuPbM5S7J 41VwDAh1O8B/Qpg0f+S83K4Kodw4MiPGsug55UkNtd3mGR/zZJ9WM03DSwkCAwEA AaN5MHcwCQYDVR0TBAIwADALBgNVHQ8EBAMCBLAwHQYDVR0OBBYEFA+Z8zvfzBuA esoHIfz7+jxfUOcfMB4GA1UdEQQXMBWBE3BoaWwucm9zc0BnbWFpbC5jb20wHgYD VR0SBBcwFYETcGhpbC5yb3NzQGdtYWlsLmNvbTANBgkqhkiG9w0BAQsFAAOCAQEA J80xgZ3gGdQVA8N+8NJANU5HLuZIU9jOaAlziU9ImoTgPiOHKGZC4as1TwT4kBt1 Qcnu7YSANYRrxP5tpOHsWPF/MQYgerAFCZS5+PzOTudwZ+7OsMW4/EMHy6aCVHEd c7HzQRC4mSrDRpWxzyBnZ5nX5OAmIkKA8NgeKybT/4Ku6iFPPUQwlyxQaO+Wlxdo FqHwpjRyoiVSpe4RUTNK3d3qesWPYi7Lxn6k6ZZeEdvG6ya33AXktE3jmmF+jPR1 J3Zn/kSTjTekiaspyGbczC3PUaeJNxr+yCvR4sk71Xmk/GaKKGOHedJ1uj/LAXrA MR0mpl7b8zCg0PFC1J73uw== -----END CERTIFICATE----- tzinfo-2.0.6/lib/000077500000000000000000000000001436527530500136105ustar00rootroot00000000000000tzinfo-2.0.6/lib/tzinfo.rb000066400000000000000000000055701436527530500154550ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true # The top level module for TZInfo. module TZInfo class << self # Instructs the current {DataSource} to load all timezone and country data # into memory (initializing the {DataSource} first if not previously # accessed or set). # # This may be desirable in production environments to improve copy-on-write # performance and to avoid flushing the constant cache every time a new # timezone or country is loaded from {DataSources::RubyDataSource}. def eager_load! DataSource.get.eager_load! end end end require_relative 'tzinfo/ruby_core_support' require_relative 'tzinfo/version' require_relative 'tzinfo/string_deduper' require_relative 'tzinfo/timestamp' require_relative 'tzinfo/with_offset' require_relative 'tzinfo/datetime_with_offset' require_relative 'tzinfo/time_with_offset' require_relative 'tzinfo/timestamp_with_offset' require_relative 'tzinfo/timezone_offset' require_relative 'tzinfo/timezone_transition' require_relative 'tzinfo/transition_rule' require_relative 'tzinfo/annual_rules' require_relative 'tzinfo/data_sources' require_relative 'tzinfo/data_sources/timezone_info' require_relative 'tzinfo/data_sources/data_timezone_info' require_relative 'tzinfo/data_sources/linked_timezone_info' require_relative 'tzinfo/data_sources/constant_offset_data_timezone_info' require_relative 'tzinfo/data_sources/transitions_data_timezone_info' require_relative 'tzinfo/data_sources/country_info' require_relative 'tzinfo/data_sources/posix_time_zone_parser' require_relative 'tzinfo/data_sources/zoneinfo_reader' require_relative 'tzinfo/data_source' require_relative 'tzinfo/data_sources/ruby_data_source' require_relative 'tzinfo/data_sources/zoneinfo_data_source' require_relative 'tzinfo/timezone_period' require_relative 'tzinfo/offset_timezone_period' require_relative 'tzinfo/transitions_timezone_period' require_relative 'tzinfo/timezone' require_relative 'tzinfo/info_timezone' require_relative 'tzinfo/data_timezone' require_relative 'tzinfo/linked_timezone' require_relative 'tzinfo/timezone_proxy' require_relative 'tzinfo/country' require_relative 'tzinfo/country_timezone' require_relative 'tzinfo/format2' require_relative 'tzinfo/format2/country_definer' require_relative 'tzinfo/format2/country_index_definer' require_relative 'tzinfo/format2/country_index_definition' require_relative 'tzinfo/format2/timezone_definer' require_relative 'tzinfo/format2/timezone_definition' require_relative 'tzinfo/format2/timezone_index_definer' require_relative 'tzinfo/format2/timezone_index_definition' require_relative 'tzinfo/format1' require_relative 'tzinfo/format1/country_definer' require_relative 'tzinfo/format1/country_index_definition' require_relative 'tzinfo/format1/timezone_definer' require_relative 'tzinfo/format1/timezone_definition' require_relative 'tzinfo/format1/timezone_index_definition' tzinfo-2.0.6/lib/tzinfo/000077500000000000000000000000001436527530500151215ustar00rootroot00000000000000tzinfo-2.0.6/lib/tzinfo/annual_rules.rb000066400000000000000000000052561436527530500201460ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true module TZInfo # A set of rules that define when transitions occur in time zones with # annually occurring daylight savings time. # # @private class AnnualRules #:nodoc: # @return [TimezoneOffset] the standard offset that applies when daylight # savings time is not in force. attr_reader :std_offset # @return [TimezoneOffset] the offset that applies when daylight savings # time is in force. attr_reader :dst_offset # @return [TransitionRule] the rule that determines when daylight savings # time starts. attr_reader :dst_start_rule # @return [TransitionRule] the rule that determines when daylight savings # time ends. attr_reader :dst_end_rule # Initializes a new {AnnualRules} instance. # # @param std_offset [TimezoneOffset] the standard offset that applies when # daylight savings time is not in force. # @param dst_offset [TimezoneOffset] the offset that applies when daylight # savings time is in force. # @param dst_start_rule [TransitionRule] the rule that determines when # daylight savings time starts. # @param dst_end_rule [TransitionRule] the rule that determines when daylight # savings time ends. def initialize(std_offset, dst_offset, dst_start_rule, dst_end_rule) @std_offset = std_offset @dst_offset = dst_offset @dst_start_rule = dst_start_rule @dst_end_rule = dst_end_rule end # Returns the transitions between standard and daylight savings time for a # given year. The results are ordered by time of occurrence (earliest to # latest). # # @param year [Integer] the year to calculate transitions for. # @return [Array] the transitions for the year. def transitions(year) start_dst = apply_rule(@dst_start_rule, @std_offset, @dst_offset, year) end_dst = apply_rule(@dst_end_rule, @dst_offset, @std_offset, year) end_dst.timestamp_value < start_dst.timestamp_value ? [end_dst, start_dst] : [start_dst, end_dst] end private # Applies a given rule between offsets on a year. # # @param rule [TransitionRule] the rule to apply. # @param from_offset [TimezoneOffset] the offset the rule transitions from. # @param to_offset [TimezoneOffset] the offset the rule transitions to. # @param year [Integer] the year when the transition occurs. # @return [TimezoneTransition] the transition determined by the rule. def apply_rule(rule, from_offset, to_offset, year) at = rule.at(from_offset, year) TimezoneTransition.new(to_offset, from_offset, at.value) end end private_constant :AnnualRules end tzinfo-2.0.6/lib/tzinfo/country.rb000066400000000000000000000163421436527530500171570ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true module TZInfo # {InvalidCountryCode} is raised by {Country#get} if the code given is not a # valid ISO 3166-1 alpha-2 code. class InvalidCountryCode < StandardError end # The {Country} class represents an ISO 3166-1 country. It can be used to # obtain a list of time zones observed by a country. For example: # # united_states = Country.get('US') # united_states.zone_identifiers # united_states.zones # united_states.zone_info # # The {Country} class is thread-safe. It is safe to use class and instance # methods of {Country} in concurrently executing threads. Instances of # {Country} can be shared across thread boundaries. # # Country information available through TZInfo is intended as an aid for # users, to help them select time zone data appropriate for their practical # needs. It is not intended to take or endorse any position on legal or # territorial claims. class Country include Comparable class << self # Gets a {Country} by its ISO 3166-1 alpha-2 code. # # The {Country.all_codes} method can be used to obtain a list of valid ISO # 3166-1 alpha-2 codes. # # @param code [String] An ISO 3166-1 alpha-2 code. # @return [Country] a {Country} instance representing the ISO-3166-1 # country identified by the `code` parameter. # @raise [InvalidCountryCode] If {code} is not a valid ISO 3166-1 alpha-2 # code it couldn't be found. def get(code) Country.new(data_source.get_country_info(code)) end # @return [Array] an `Array` containing all the valid ISO 3166-1 # alpha-2 country codes. def all_codes data_source.country_codes end # @return [Array] an `Array` containing one {Country} instance # for each defined country. def all data_source.country_codes.collect {|code| get(code)} end private # @return [DataSource] the current DataSource. def data_source DataSource.get end end # Initializes a new {Country} based upon a {DataSources::CountryInfo} # instance. # # {Country} instances should not normally be constructed directly. Use # the {Country.get} method to obtain instances instead. # # @param info [DataSources::CountryInfo] the data to base the new {Country} # instance upon. def initialize(info) @info = info end # @return [String] the ISO 3166-1 alpha-2 country code. def code @info.code end # @return [String] the name of the country. def name @info.name end # @return [String] a `String` representation of this {Country} (the name of # the country). def to_s name end # @return [String] the internal object state as a programmer-readable # `String`. def inspect "#<#{self.class}: #{@info.code}>" end # Returns an `Array` containing the identifier for each time zone observed # by the country. These are in an order that # # 1. makes some geographical sense, and # 2. puts the most populous zones first, where that does not contradict 1. # # Returned zone identifiers may refer to cities and regions outside of the # country. This will occur if the zone covers multiple countries. Any zones # referring to a city or region in a different country will be listed after # those relating to this country. # # @return [Array] an `Array` containing the identifier for each time # zone observed by the country def zone_identifiers zone_info.map(&:identifier) end alias zone_names zone_identifiers # Returns An `Array` containing a {Timezone} instance for each time zone # observed by the country. These are in an order that # # 1. makes some geographical sense, and # 2. puts the most populous zones first, where that does not contradict 1. # # The identifiers of the time zones returned may refer to cities and regions # outside of the country. This will occur if the time zone covers multiple # countries. Any zones referring to a city or region in a different country # will be listed after those relating to this country. # # The results are actually instances of {TimezoneProxy} in order to defer # loading of the time zone transition data until it is first needed. # # @return [Array] an `Array` containing a {Timezone} instance for # each time zone observed by the country. def zones zone_info.map(&:timezone) end # Returns a frozen `Array` containing a {CountryTimezone} instance for each # time zone observed by the country. These are in an order that # # 1. makes some geographical sense, and # 2. puts the most populous zones first, where that does not contradict 1. # # The {CountryTimezone} instances can be used to obtain the location and # descriptions of the observed time zones. # # Identifiers and descriptions of the time zones returned may refer to # cities and regions outside of the country. This will occur if the time # zone covers multiple countries. Any zones referring to a city or region in # a different country will be listed after those relating to this country. # # @return [Array] a frozen `Array` containing a # {CountryTimezone} instance for each time zone observed by the country. def zone_info @info.zones end # Compares this {Country} with another based on their {code}. # # @param c [Object] an `Object` to compare this {Country} with. # @return [Integer] -1 if `c` is less than `self`, 0 if `c` is equal to # `self` and +1 if `c` is greater than `self`, or `nil` if `c` is not an # instance of {Country}. def <=>(c) return nil unless c.is_a?(Country) code <=> c.code end # @param c [Object] an `Object` to compare this {Country} with. # @return [Boolean] `true` if `c` is an instance of {Country} and has the # same code as `self`, otherwise `false`. def eql?(c) self == c end # @return [Integer] a hash based on the {code}. def hash code.hash end # Matches `regexp` against the {code} of this {Country}. # # @param regexp [Regexp] a `Regexp` to match against the {code} of # this {Country}. # @return [Integer] the position the match starts, or `nil` if there is no # match. def =~(regexp) regexp =~ code end # Returns a serialized representation of this {Country}. This method is # called when using `Marshal.dump` with an instance of {Country}. # # @param limit [Integer] the maximum depth to dump - ignored. # @return [String] a serialized representation of this {Country}. def _dump(limit) code end # Loads a {Country} from the serialized representation returned by {_dump}. # This is method is called when using `Marshal.load` or `Marshal.restore` # to restore a serialized {Country}. # # @param data [String] a serialized representation of a {Country}. # @return [Country] the result of converting `data` back into a {Country}. def self._load(data) Country.get(data) end end end tzinfo-2.0.6/lib/tzinfo/country_timezone.rb000066400000000000000000000066321436527530500210720ustar00rootroot00000000000000# encoding: UTF-8 module TZInfo # Information about a time zone used by a {Country}. class CountryTimezone # @return [String] the identifier of the {Timezone} being described. attr_reader :identifier # The latitude of this time zone in degrees. Positive numbers are degrees # north and negative numbers are degrees south. # # Note that depending on the data source, the position given by {#latitude} # and {#longitude} may not be within the country. # # @return [Rational] the latitude in degrees. attr_reader :latitude # The longitude of this time zone in degrees. Positive numbers are degrees # east and negative numbers are degrees west. # # Note that depending on the data source, the position given by {#latitude} # and {#longitude} may not be within the country. # # @return [Rational] the longitude in degrees. attr_reader :longitude # A description of this time zone in relation to the country, e.g. "Eastern # Time". This is usually `nil` for countries that have a single time zone. # # @return [String] an optional description of the time zone. attr_reader :description # Creates a new {CountryTimezone}. # # The passed in identifier and description instances will be frozen. # # {CountryTimezone} instances should normally only be constructed # by implementations of {DataSource}. # # @param identifier [String] the {Timezone} identifier. # @param latitude [Rational] the latitude of the time zone. # @param longitude [Rational] the longitude of the time zone. # @param description [String] an optional description of the time zone. def initialize(identifier, latitude, longitude, description = nil) @identifier = identifier.freeze @latitude = latitude @longitude = longitude @description = description && description.freeze end # Returns the associated {Timezone}. # # The result is actually an instance of {TimezoneProxy} in order to defer # loading of the time zone transition data until it is first needed. # # @return [Timezone] the associated {Timezone}. def timezone Timezone.get_proxy(@identifier) end # @return [String] the {description} if present, otherwise a human-readable # representation of the identifier (using {Timezone#friendly_identifier}). def description_or_friendly_identifier description || timezone.friendly_identifier(true) end # Tests if the given object is equal to the current instance (has the same # identifier, latitude, longitude and description). # # @param ct [Object] the object to be compared. # @return [TrueClass] `true` if `ct` is equal to the current instance. def ==(ct) ct.kind_of?(CountryTimezone) && identifier == ct.identifier && latitude == ct.latitude && longitude == ct.longitude && description == ct.description end # Tests if the given object is equal to the current instance (has the same # identifier, latitude, longitude and description). # # @param ct [Object] the object to be compared. # @return [Boolean] `true` if `ct` is equal to the current instance. def eql?(ct) self == ct end # @return [Integer] a hash based on the {identifier}, {latitude}, # {longitude} and {description}. def hash [@identifier, @latitude, @longitude, @description].hash end end end tzinfo-2.0.6/lib/tzinfo/data_source.rb000066400000000000000000000437061436527530500177510ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true require 'concurrent' require 'thread' module TZInfo # {InvalidDataSource} is raised if the selected {DataSource} doesn't implement # one of the required methods. class InvalidDataSource < StandardError end # {DataSourceNotFound} is raised if no data source could be found (i.e. if # `'tzinfo/data'` cannot be found on the load path and no valid zoneinfo # directory can be found on the system). class DataSourceNotFound < StandardError end # TZInfo can be used with different data sources for time zone and country # data. Each source of data is implemented as a subclass of {DataSource}. # # To choose a data source and override the default selection, use the # {DataSource.set} method. # # @abstract To create a custom data source, create a subclass of {DataSource} # and implement the {load_timezone_info}, {data_timezone_identifiers}, # {linked_timezone_identifiers}, {load_country_info} and {country_codes} # methods. class DataSource # The currently selected data source. # # @private @@instance = nil # A `Mutex` used to ensure the default data source is only created once. # # @private @@default_mutex = Mutex.new class << self # @return [DataSource] the currently selected source of data. def get # If a DataSource hasn't been manually set when the first request is # made to obtain a DataSource, then a default data source is created. # # This is done at the first request rather than when TZInfo is loaded to # avoid unnecessary attempts to find a suitable DataSource. # # A `Mutex` is used to ensure that only a single default instance is # created (this avoiding the possibility of retaining two copies of the # same data in memory). unless @@instance @@default_mutex.synchronize do set(create_default_data_source) unless @@instance end end @@instance end # Sets the currently selected data source for time zone and country data. # # This should usually be set to one of the two standard data source types: # # * `:ruby` - read data from the Ruby modules included in the TZInfo::Data # library (tzinfo-data gem). # * `:zoneinfo` - read data from the zoneinfo files included with most # Unix-like operating systems (e.g. in /usr/share/zoneinfo). # # To set TZInfo to use one of the standard data source types, call # `TZInfo::DataSource.set`` in one of the following ways: # # TZInfo::DataSource.set(:ruby) # TZInfo::DataSource.set(:zoneinfo) # TZInfo::DataSource.set(:zoneinfo, zoneinfo_dir) # TZInfo::DataSource.set(:zoneinfo, zoneinfo_dir, iso3166_tab_file) # # `DataSource.set(:zoneinfo)` will automatically search for the zoneinfo # directory by checking the paths specified in # {DataSources::ZoneinfoDataSource.search_path}. # {DataSources::ZoneinfoDirectoryNotFound} will be raised if no valid # zoneinfo directory could be found. # # `DataSource.set(:zoneinfo, zoneinfo_dir)` uses the specified # `zoneinfo_dir` directory as the data source. If the directory is not a # valid zoneinfo directory, a {DataSources::InvalidZoneinfoDirectory} # exception will be raised. # # `DataSource.set(:zoneinfo, zoneinfo_dir, iso3166_tab_file)` uses the # specified `zoneinfo_dir` directory as the data source, but loads the # `iso3166.tab` file from the path given by `iso3166_tab_file`. If the # directory is not a valid zoneinfo directory, a # {DataSources::InvalidZoneinfoDirectory} exception will be raised. # # Custom data sources can be created by subclassing TZInfo::DataSource and # implementing the following methods: # # * {load_timezone_info} # * {data_timezone_identifiers} # * {linked_timezone_identifiers} # * {load_country_info} # * {country_codes} # # To have TZInfo use the custom data source, call {DataSource.set}, # passing an instance of the custom data source implementation as follows: # # TZInfo::DataSource.set(CustomDataSource.new) # # Calling {DataSource.set} will only affect instances of {Timezone} and # {Country} obtained with {Timezone.get} and {Country.get} subsequent to # the {DataSource.set} call. Existing {Timezone} and {Country} instances # will be unaffected. # # If {DataSource.set} is not called, TZInfo will by default attempt to use # TZInfo::Data as the data source. If TZInfo::Data is not available (i.e. # if `require 'tzinfo/data'` fails), then TZInfo will search for a # zoneinfo directory instead (using the search path specified by # {DataSources::ZoneinfoDataSource.search_path}). # # @param data_source_or_type [Object] either `:ruby`, `:zoneinfo` or an # instance of a {DataSource}. # @param args [Array] when `data_source_or_type` is a symbol, # optional arguments to use when initializing the data source. # @raise [ArgumentError] if `data_source_or_type` is not `:ruby`, # `:zoneinfo` or an instance of {DataSource}. def set(data_source_or_type, *args) if data_source_or_type.kind_of?(DataSource) @@instance = data_source_or_type elsif data_source_or_type == :ruby @@instance = DataSources::RubyDataSource.new elsif data_source_or_type == :zoneinfo @@instance = DataSources::ZoneinfoDataSource.new(*args) else raise ArgumentError, 'data_source_or_type must be a DataSource instance or a data source type (:ruby or :zoneinfo)' end end private # Creates a {DataSource} instance for use as the default. Used if no # preference has been specified manually. # # @return [DataSource] the newly created default {DataSource} instance. def create_default_data_source has_tzinfo_data = false begin require 'tzinfo/data' has_tzinfo_data = true rescue LoadError end return DataSources::RubyDataSource.new if has_tzinfo_data begin return DataSources::ZoneinfoDataSource.new rescue DataSources::ZoneinfoDirectoryNotFound raise DataSourceNotFound, "No source of timezone data could be found.\nPlease refer to https://tzinfo.github.io/datasourcenotfound for help resolving this error." end end end # Initializes a new {DataSource} instance. Typically only called via # subclasses of {DataSource}. def initialize @timezones = Concurrent::Map.new end # Returns a {DataSources::TimezoneInfo} instance for the given identifier. # The result will derive from either {DataSources::DataTimezoneInfo} for # time zones that define their own data or {DataSources::LinkedTimezoneInfo} # for links or aliases to other time zones. # # {get_timezone_info} calls {load_timezone_info} to create the # {DataSources::TimezoneInfo} instance. The returned instance is cached and # returned in subsequent calls to {get_timezone_info} for the identifier. # # @param identifier [String] A time zone identifier. # @return [DataSources::TimezoneInfo] a {DataSources::TimezoneInfo} instance # for a given identifier. # @raise [InvalidTimezoneIdentifier] if the time zone is not found or the # identifier is invalid. def get_timezone_info(identifier) result = @timezones[identifier] unless result # Thread-safety: It is possible that multiple equivalent TimezoneInfo # instances could be created here in concurrently executing threads. The # consequences of this are that the data may be loaded more than once # (depending on the data source). The performance benefit of ensuring # that only a single instance is created is unlikely to be worth the # overhead of only allowing one TimezoneInfo to be loaded at a time. result = load_timezone_info(identifier) @timezones[result.identifier] = result end result end # @return [Array] a frozen `Array`` of all the available time zone # identifiers. The identifiers are sorted according to `String#<=>`. def timezone_identifiers # Thread-safety: It is possible that the value of @timezone_identifiers # may be calculated multiple times in concurrently executing threads. It # is not worth the overhead of locking to ensure that # @timezone_identifiers is only calculated once. @timezone_identifiers ||= build_timezone_identifiers end # Returns a frozen `Array` of all the available time zone identifiers for # data time zones (i.e. those that actually contain definitions). The # identifiers are sorted according to `String#<=>`. # # @return [Array] a frozen `Array` of all the available time zone # identifiers for data time zones. def data_timezone_identifiers raise_invalid_data_source('data_timezone_identifiers') end # Returns a frozen `Array` of all the available time zone identifiers that # are links to other time zones. The identifiers are sorted according to # `String#<=>`. # # @return [Array] a frozen `Array` of all the available time zone # identifiers that are links to other time zones. def linked_timezone_identifiers raise_invalid_data_source('linked_timezone_identifiers') end # @param code [String] an ISO 3166-1 alpha-2 country code. # @return [DataSources::CountryInfo] a {DataSources::CountryInfo} instance # for the given ISO 3166-1 alpha-2 country code. # @raise [InvalidCountryCode] if the country could not be found or the code # is invalid. def get_country_info(code) load_country_info(code) end # Returns a frozen `Array` of all the available ISO 3166-1 alpha-2 country # codes. The identifiers are sorted according to `String#<=>`. # # @return [Array] a frozen `Array` of all the available ISO 3166-1 # alpha-2 country codes. def country_codes raise_invalid_data_source('country_codes') end # Loads all timezone and country data into memory. # # This may be desirable in production environments to improve copy-on-write # performance and to avoid flushing the constant cache every time a new # timezone or country is loaded from {DataSources::RubyDataSource}. def eager_load! timezone_identifiers.each {|identifier| load_timezone_info(identifier) } country_codes.each {|code| load_country_info(code) } nil end # @return [String] a description of the {DataSource}. def to_s "Default DataSource" end # @return [String] the internal object state as a programmer-readable # `String`. def inspect "#<#{self.class}>" end protected # Returns a {DataSources::TimezoneInfo} instance for the given time zone # identifier. The result should derive from either # {DataSources::DataTimezoneInfo} for time zones that define their own data # or {DataSources::LinkedTimezoneInfo} for links to or aliases for other # time zones. # # @param identifier [String] A time zone identifier. # @return [DataSources::TimezoneInfo] a {DataSources::TimezoneInfo} instance # for the given time zone identifier. # @raise [InvalidTimezoneIdentifier] if the time zone is not found or the # identifier is invalid. def load_timezone_info(identifier) raise_invalid_data_source('load_timezone_info') end # @param code [String] an ISO 3166-1 alpha-2 country code. # @return [DataSources::CountryInfo] a {DataSources::CountryInfo} instance # for the given ISO 3166-1 alpha-2 country code. # @raise [InvalidCountryCode] if the country could not be found or the code # is invalid. def load_country_info(code) raise_invalid_data_source('load_country_info') end # @return [Encoding] the `Encoding` used by the `String` instances returned # by {data_timezone_identifiers} and {linked_timezone_identifiers}. def timezone_identifier_encoding Encoding::UTF_8 end # Checks that the given identifier is a valid time zone identifier (can be # found in the {timezone_identifiers} `Array`). If the identifier is valid, # the `String` instance representing that identifier from # `timezone_identifiers` is returned. Otherwise an # {InvalidTimezoneIdentifier} exception is raised. # # @param identifier [String] a time zone identifier to be validated. # @return [String] the `String` instance equivalent to `identifier` from # {timezone_identifiers}. # @raise [InvalidTimezoneIdentifier] if `identifier` was not found in # {timezone_identifiers}. def validate_timezone_identifier(identifier) raise InvalidTimezoneIdentifier, "Invalid identifier: #{identifier.nil? ? 'nil' : identifier}" unless identifier.kind_of?(String) valid_identifier = try_with_encoding(identifier, timezone_identifier_encoding) {|id| find_timezone_identifier(id) } return valid_identifier if valid_identifier raise InvalidTimezoneIdentifier, "Invalid identifier: #{identifier.encode(Encoding::UTF_8)}" end # Looks up a given code in the given hash of code to # {DataSources::CountryInfo} mappings. If the code is found the # {DataSources::CountryInfo} is returned. Otherwise an {InvalidCountryCode} # exception is raised. # # @param hash [String, DataSources::CountryInfo] a mapping from ISO 3166-1 # alpha-2 country codes to {DataSources::CountryInfo} instances. # @param code [String] a country code to lookup. # @param encoding [Encoding] the encoding used for the country codes in # `hash`. # @return [DataSources::CountryInfo] the {DataSources::CountryInfo} instance # corresponding to `code`. # @raise [InvalidCountryCode] if `code` was not found in `hash`. def lookup_country_info(hash, code, encoding = Encoding::UTF_8) raise InvalidCountryCode, "Invalid country code: #{code.nil? ? 'nil' : code}" unless code.kind_of?(String) info = try_with_encoding(code, encoding) {|c| hash[c] } return info if info raise InvalidCountryCode, "Invalid country code: #{code.encode(Encoding::UTF_8)}" end private # Raises {InvalidDataSource} to indicate that a method has not been # overridden by a particular data source implementation. # # @raise [InvalidDataSource] always. def raise_invalid_data_source(method_name) raise InvalidDataSource, "#{method_name} not defined" end # Combines {data_timezone_identifiers} and {linked_timezone_identifiers} # to create an `Array` containing all valid time zone identifiers. If # {linked_timezone_identifiers} is empty, the {data_timezone_identifiers} # instance is returned. # # The returned `Array` is frozen. The identifiers are sorted according to # `String#<=>`. # # @return [Array] an `Array` containing all valid time zone # identifiers. def build_timezone_identifiers data = data_timezone_identifiers linked = linked_timezone_identifiers linked.empty? ? data : (data + linked).sort!.freeze end if [].respond_to?(:bsearch) # If the given `identifier` is contained within the {timezone_identifiers} # `Array`, the `String` instance representing that identifier from # {timezone_identifiers} is returned. Otherwise, `nil` is returned. # # @param identifier [String] A time zone identifier to search for. # @return [String] the `String` instance representing `identifier` from # {timezone_identifiers} if found, or `nil` if not found. # # :nocov_no_array_bsearch: def find_timezone_identifier(identifier) result = timezone_identifiers.bsearch {|i| i >= identifier } result == identifier ? result : nil end # :nocov_no_array_bsearch: else # If the given `identifier` is contained within the {timezone_identifiers} # `Array`, the `String` instance representing that identifier from # {timezone_identifiers} is returned. Otherwise, `nil` is returned. # # @param identifier [String] A time zone identifier to search for. # @return [String] the `String` instance representing `identifier` from # {timezone_identifiers} if found, or `nil` if not found. # # :nocov_array_bsearch: def find_timezone_identifier(identifier) identifiers = timezone_identifiers low = 0 high = identifiers.length while low < high do mid = (low + high).div(2) mid_identifier = identifiers[mid] cmp = mid_identifier <=> identifier return mid_identifier if cmp == 0 if cmp > 0 high = mid else low = mid + 1 end end nil end # :nocov_array_bsearch: end # Tries an operation using `string` directly. If the operation fails, the # string is copied and encoded with `encoding` and the operation is tried # again. # # @param string [String] The `String` to perform the operation on. # @param encoding [Encoding] The `Encoding` to use if the initial attempt # fails. # @yield [s] the caller will be yielded to once or twice to attempt the # operation. # @yieldparam s [String] either `string` or an encoded copy of `string`. # @yieldreturn [Object] The result of the operation. Must be truthy if # successful. # @return [Object] the result of the operation or `nil` if the first attempt # fails and `string` is already encoded with `encoding`. def try_with_encoding(string, encoding) result = yield string return result if result unless encoding == string.encoding string = string.encode(encoding) yield string end end end end tzinfo-2.0.6/lib/tzinfo/data_sources.rb000066400000000000000000000002271436527530500201230ustar00rootroot00000000000000# encoding: UTF-8 module TZInfo # {DataSource} implementations and classes used by {DataSource} # implementations. module DataSources end end tzinfo-2.0.6/lib/tzinfo/data_sources/000077500000000000000000000000001436527530500175755ustar00rootroot00000000000000tzinfo-2.0.6/lib/tzinfo/data_sources/constant_offset_data_timezone_info.rb000066400000000000000000000040071436527530500272400ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true module TZInfo module DataSources # Represents a data time zone defined by a constantly observed offset. class ConstantOffsetDataTimezoneInfo < DataTimezoneInfo # @return [TimezoneOffset] the offset that is constantly observed. attr_reader :constant_offset # Initializes a new {ConstantOffsetDataTimezoneInfo}. # # The passed in `identifier` instance will be frozen. A reference to the # passed in {TimezoneOffset} will be retained. # # @param identifier [String] the identifier of the time zone. # @param constant_offset [TimezoneOffset] the constantly observed offset. # @raise [ArgumentError] if `identifier` or `constant_offset` is `nil`. def initialize(identifier, constant_offset) super(identifier) raise ArgumentError, 'constant_offset must be specified' unless constant_offset @constant_offset = constant_offset end # @param timestamp [Timestamp] ignored. # @return [TimezonePeriod] an unbounded {TimezonePeriod} for the time # zone's constantly observed offset. def period_for(timestamp) constant_period end # @param local_timestamp [Timestamp] ignored. # @return [Array] an `Array` containing a single unbounded # {TimezonePeriod} for the time zone's constantly observed offset. def periods_for_local(local_timestamp) [constant_period] end # @param to_timestamp [Timestamp] ignored. # @param from_timestamp [Timestamp] ignored. # @return [Array] an empty `Array`, since there are no transitions in time # zones that observe a constant offset. def transitions_up_to(to_timestamp, from_timestamp = nil) [] end private # @return [TimezonePeriod] an unbounded {TimezonePeriod} with the constant # offset of this timezone. def constant_period OffsetTimezonePeriod.new(@constant_offset) end end end end tzinfo-2.0.6/lib/tzinfo/data_sources/country_info.rb000066400000000000000000000025631436527530500226460ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true module TZInfo module DataSources # Represents a country and references to its time zones as returned by a # {DataSource}. class CountryInfo # @return [String] the ISO 3166-1 alpha-2 country code. attr_reader :code # @return [String] the name of the country. attr_reader :name # @return [Array] the time zones observed in the country. attr_reader :zones # Initializes a new {CountryInfo}. The passed in `code`, `name` and # `zones` instances will be frozen. # # @param code [String] an ISO 3166-1 alpha-2 country code. # @param name [String] the name of the country. # @param zones [Array] the time zones observed in the # country. # @raise [ArgumentError] if `code`, `name` or `zones` is `nil`. def initialize(code, name, zones) raise ArgumentError, 'code must be specified' unless code raise ArgumentError, 'name must be specified' unless name raise ArgumentError, 'zones must be specified' unless zones @code = code.freeze @name = name.freeze @zones = zones.freeze end # @return [String] the internal object state as a programmer-readable # `String`. def inspect "#<#{self.class}: #@code>" end end end end tzinfo-2.0.6/lib/tzinfo/data_sources/data_timezone_info.rb000066400000000000000000000102401436527530500237550ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true module TZInfo module DataSources # The base class for time zones defined as either a series of transitions # ({TransitionsDataTimezoneInfo}) or a constantly observed offset # ({ConstantOffsetDataTimezoneInfo}). # # @abstract Data sources return instances of {DataTimezoneInfo} subclasses. class DataTimezoneInfo < TimezoneInfo # @param timestamp [Timestamp] a {Timestamp} with a specified # {Timestamp#utc_offset utc_offset}. # @return [TimezonePeriod] the {TimezonePeriod} observed at the time # specified by `timestamp`. # @raise [ArgumentError] may be raised if `timestamp` is `nil` or does not # have a specified {Timestamp#utc_offset utc_offset}. def period_for(timestamp) raise_not_implemented('period_for') end # Returns an `Array` containing the {TimezonePeriod TimezonePeriods} that # could be observed at the local time specified by `local_timestamp`. The # results are are ordered by increasing UTC start date. An empty `Array` # is returned if no periods are found for the given local time. # # @param local_timestamp [Timestamp] a {Timestamp} representing a local # time - must have an unspecified {Timestamp#utc_offset utc_offset}. # @return [Array] an `Array` containing the # {TimezonePeriod TimezonePeriods} that could be observed at the local # time specified by `local_timestamp`. # @raise [ArgumentError] may be raised if `local_timestamp` is `nil`, or # has a specified {Timestamp#utc_offset utc_offset}. def periods_for_local(local_timestamp) raise_not_implemented('periods_for_local') end # Returns an `Array` of {TimezoneTransition} instances representing the # times where the UTC offset of the time zone changes. # # Transitions are returned up to a given {Timestamp} (`to_timestamp`). # # A from {Timestamp} may also be supplied using the `from_timestamp` # parameter. If `from_timestamp` is specified, only transitions from that # time onwards will be returned. # # Comparisons with `to_timestamp` are exclusive. Comparisons with # `from_timestamp` are inclusive. If a transition falls precisely on # `to_timestamp`, it will be excluded. If a transition falls on # `from_timestamp`, it will be included. # # Transitions returned are ordered by when they occur, from earliest to # latest. # # @param to_timestamp [Timestamp] a {Timestamp} with a specified # {Timestamp#utc_offset utc_offset}. Transitions are returned if they # occur before this time. # @param from_timestamp [Timestamp] an optional {Timestamp} with a # specified {Timestamp#utc_offset utc_offset}. If specified, transitions # are returned if they occur at or after this time. # @return [Array] an `Array` of {TimezoneTransition} # instances representing the times where the UTC offset of the time zone # changes. # @raise [ArgumentError] may be raised if `to_timestamp` is `nil` or does # not have a specified {Timestamp#utc_offset utc_offset}. # @raise [ArgumentError] may be raised if `from_timestamp` is specified # but does not have a specified {Timestamp#utc_offset utc_offset}. # @raise [ArgumentError] may be raised if `from_timestamp` is specified # but is not earlier than or at the same time as `to_timestamp`. def transitions_up_to(to_timestamp, from_timestamp = nil) raise_not_implemented('transitions_up_to') end # @return [DataTimezone] a new {DataTimezone} instance for the time zone # represented by this {DataTimezoneInfo}. def create_timezone DataTimezone.new(self) end private # Raises a {NotImplementedError} to indicate that the base class is # incorrectly being used directly. # # raise [NotImplementedError] always. def raise_not_implemented(method_name) raise NotImplementedError, "Subclasses must override #{method_name}" end end end end tzinfo-2.0.6/lib/tzinfo/data_sources/linked_timezone_info.rb000066400000000000000000000023201436527530500243120ustar00rootroot00000000000000# encoding: UTF-8 module TZInfo module DataSources # Represents a time zone that is defined as a link to or alias of another # zone. class LinkedTimezoneInfo < TimezoneInfo # @return [String] the identifier of the time zone that provides the data # (that this zone links to or is an alias for). attr_reader :link_to_identifier # Initializes a new {LinkedTimezoneInfo}. The passed in `identifier` and # `link_to_identifier` instances will be frozen. # # @param identifier [String] the identifier of the time zone. # @param link_to_identifier [String] the identifier of the time zone that # this zone link to. # @raise [ArgumentError] if `identifier` or `link_to_identifier` are # `nil`. def initialize(identifier, link_to_identifier) super(identifier) raise ArgumentError, 'link_to_identifier must be specified' unless link_to_identifier @link_to_identifier = link_to_identifier.freeze end # @return [LinkedTimezone] a new {LinkedTimezone} instance for the time # zone represented by this {LinkedTimezoneInfo}. def create_timezone LinkedTimezone.new(self) end end end end tzinfo-2.0.6/lib/tzinfo/data_sources/posix_time_zone_parser.rb000066400000000000000000000156031436527530500247160ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true require 'strscan' module TZInfo module DataSources # An {InvalidPosixTimeZone} exception is raised if an invalid POSIX-style # time zone string is encountered. # # @private class InvalidPosixTimeZone < StandardError #:nodoc: end private_constant :InvalidPosixTimeZone # A parser for POSIX-style TZ strings used in zoneinfo files and specified # by tzfile.5 and tzset.3. # # @private class PosixTimeZoneParser #:nodoc: # Initializes a new {PosixTimeZoneParser}. # # @param string_deduper [StringDeduper] a {StringDeduper} instance to use # to dedupe abbreviations. def initialize(string_deduper) @string_deduper = string_deduper end # Parses a POSIX-style TZ string. # # @param tz_string [String] the string to parse. # @return [Object] either a {TimezoneOffset} for a constantly applied # offset or an {AnnualRules} instance representing the rules. # @raise [InvalidPosixTimeZone] if `tz_string` is not a `String`. # @raise [InvalidPosixTimeZone] if `tz_string` is is not valid. def parse(tz_string) raise InvalidPosixTimeZone unless tz_string.kind_of?(String) return nil if tz_string.empty? s = StringScanner.new(tz_string) check_scan(s, /([^-+,\d<][^-+,\d]*) | <([^>]+)>/x) std_abbrev = @string_deduper.dedupe(RubyCoreSupport.untaint(s[1] || s[2])) check_scan(s, /([-+]?\d+)(?::(\d+)(?::(\d+))?)?/) std_offset = get_offset_from_hms(s[1], s[2], s[3]) if s.scan(/([^-+,\d<][^-+,\d]*) | <([^>]+)>/x) dst_abbrev = @string_deduper.dedupe(RubyCoreSupport.untaint(s[1] || s[2])) if s.scan(/([-+]?\d+)(?::(\d+)(?::(\d+))?)?/) dst_offset = get_offset_from_hms(s[1], s[2], s[3]) else # POSIX is negative for ahead of UTC. dst_offset = std_offset - 3600 end dst_difference = std_offset - dst_offset start_rule = parse_rule(s, 'start') end_rule = parse_rule(s, 'end') raise InvalidPosixTimeZone, "Expected the end of a POSIX-style time zone string but found '#{s.rest}'." if s.rest? if start_rule.is_always_first_day_of_year? && start_rule.transition_at == 0 && end_rule.is_always_last_day_of_year? && end_rule.transition_at == 86400 + dst_difference # Constant daylight savings time. # POSIX is negative for ahead of UTC. TimezoneOffset.new(-std_offset, dst_difference, dst_abbrev) else AnnualRules.new( TimezoneOffset.new(-std_offset, 0, std_abbrev), TimezoneOffset.new(-std_offset, dst_difference, dst_abbrev), start_rule, end_rule) end elsif !s.rest? # Constant standard time. # POSIX is negative for ahead of UTC. TimezoneOffset.new(-std_offset, 0, std_abbrev) else raise InvalidPosixTimeZone, "Expected the end of a POSIX-style time zone string but found '#{s.rest}'." end end private # Parses a rule. # # @param s [StringScanner] the `StringScanner` to read the rule from. # @param type [String] the type of rule (either `'start'` or `'end'`). # @raise [InvalidPosixTimeZone] if the rule is not valid. # @return [TransitionRule] the parsed rule. def parse_rule(s, type) check_scan(s, /,(?: (?: J(\d+) ) | (\d+) | (?: M(\d+)\.(\d)\.(\d) ) )/x) julian_day_of_year = s[1] absolute_day_of_year = s[2] month = s[3] week = s[4] day_of_week = s[5] if s.scan(/\//) check_scan(s, /([-+]?\d+)(?::(\d+)(?::(\d+))?)?/) transition_at = get_seconds_after_midnight_from_hms(s[1], s[2], s[3]) else transition_at = 7200 end begin if julian_day_of_year JulianDayOfYearTransitionRule.new(julian_day_of_year.to_i, transition_at) elsif absolute_day_of_year AbsoluteDayOfYearTransitionRule.new(absolute_day_of_year.to_i, transition_at) elsif week == '5' LastDayOfMonthTransitionRule.new(month.to_i, day_of_week.to_i, transition_at) else DayOfMonthTransitionRule.new(month.to_i, week.to_i, day_of_week.to_i, transition_at) end rescue ArgumentError => e raise InvalidPosixTimeZone, "Invalid #{type} rule in POSIX-style time zone string: #{e}" end end # Returns an offset in seconds from hh:mm:ss values. The value can be # negative. -02:33:12 would represent 2 hours, 33 minutes and 12 seconds # ahead of UTC. # # @param h [String] the hours. # @param m [String] the minutes. # @param s [String] the seconds. # @return [Integer] the offset. # @raise [InvalidPosixTimeZone] if the mm and ss values are greater than # 59. def get_offset_from_hms(h, m, s) h = h.to_i m = m.to_i s = s.to_i raise InvalidPosixTimeZone, "Invalid minute #{m} in offset for POSIX-style time zone string." if m > 59 raise InvalidPosixTimeZone, "Invalid second #{s} in offset for POSIX-style time zone string." if s > 59 magnitude = (h.abs * 60 + m) * 60 + s h < 0 ? -magnitude : magnitude end # Returns the seconds from midnight from hh:mm:ss values. Hours can exceed # 24 for a time on the following day. Hours can be negative to subtract # hours from midnight on the given day. -02:33:12 represents 22:33:12 on # the prior day. # # @param h [String] the hour. # @param m [String] the minutes past the hour. # @param s [String] the seconds past the minute. # @return [Integer] the number of seconds after midnight. # @raise [InvalidPosixTimeZone] if the mm and ss values are greater than # 59. def get_seconds_after_midnight_from_hms(h, m, s) h = h.to_i m = m.to_i s = s.to_i raise InvalidPosixTimeZone, "Invalid minute #{m} in time for POSIX-style time zone string." if m > 59 raise InvalidPosixTimeZone, "Invalid second #{s} in time for POSIX-style time zone string." if s > 59 (h * 3600) + m * 60 + s end # Scans for a pattern and raises an exception if the pattern does not # match the input. # # @param s [StringScanner] the `StringScanner` to scan. # @param pattern [Regexp] the pattern to match. # @return [String] the result of the scan. # @raise [InvalidPosixTimeZone] if the pattern does not match the input. def check_scan(s, pattern) result = s.scan(pattern) raise InvalidPosixTimeZone, "Expected '#{s.rest}' to match #{pattern} in POSIX-style time zone string." unless result result end end private_constant :PosixTimeZoneParser end end tzinfo-2.0.6/lib/tzinfo/data_sources/ruby_data_source.rb000066400000000000000000000113741436527530500234620ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true module TZInfo module DataSources # A {TZInfoDataNotFound} exception is raised if the tzinfo-data gem could # not be found (i.e. `require 'tzinfo/data'` failed) when selecting the Ruby # data source. class TZInfoDataNotFound < StandardError end # A DataSource implementation that loads data from the set of Ruby modules # included in the tzinfo-data gem. # # TZInfo will use {RubyDataSource} by default if the tzinfo-data gem # is available on the load path. It can also be selected by calling # {DataSource.set} as follows: # # TZInfo::DataSource.set(:ruby) class RubyDataSource < DataSource # (see DataSource#data_timezone_identifiers) attr_reader :data_timezone_identifiers # (see DataSource#linked_timezone_identifiers) attr_reader :linked_timezone_identifiers # (see DataSource#country_codes) attr_reader :country_codes # Initializes a new {RubyDataSource} instance. # # @raise [TZInfoDataNotFound] if the tzinfo-data gem could not be found # (i.e. `require 'tzinfo/data'` failed). def initialize super begin require('tzinfo/data') rescue LoadError raise TZInfoDataNotFound, "The tzinfo-data gem could not be found (require 'tzinfo/data' failed)." end if TZInfo::Data.const_defined?(:LOCATION) # Format 2 @base_path = File.join(TZInfo::Data::LOCATION, 'tzinfo', 'data') else # Format 1 data_file = File.join('', 'tzinfo', 'data.rb') path = $".reverse_each.detect {|p| p.end_with?(data_file) } if path @base_path = RubyCoreSupport.untaint(File.join(File.dirname(path), 'data')) else @base_path = 'tzinfo/data' end end require_index('timezones') require_index('countries') @data_timezone_identifiers = Data::Indexes::Timezones.data_timezones @linked_timezone_identifiers = Data::Indexes::Timezones.linked_timezones @countries = Data::Indexes::Countries.countries @country_codes = @countries.keys.sort!.freeze end # (see DataSource#to_s) def to_s "Ruby DataSource: #{version_info}" end # (see DataSource#inspect) def inspect "#" end protected # Returns a {TimezoneInfo} instance for the given time zone identifier. # The result will either be a {ConstantOffsetDataTimezoneInfo}, a # {TransitionsDataTimezoneInfo} or a {LinkedTimezoneInfo} depending on the # type of time zone. # # @param identifier [String] A time zone identifier. # @return [TimezoneInfo] a {TimezoneInfo} instance for the given time zone # identifier. # @raise [InvalidTimezoneIdentifier] if the time zone is not found or the # identifier is invalid. def load_timezone_info(identifier) valid_identifier = validate_timezone_identifier(identifier) split_identifier = valid_identifier.gsub(/-/, '__m__').gsub(/\+/, '__p__').split('/') begin require_definition(split_identifier) m = Data::Definitions split_identifier.each {|part| m = m.const_get(part) } m.get rescue LoadError, NameError => e raise InvalidTimezoneIdentifier, "#{e.message.encode(Encoding::UTF_8)} (loading #{valid_identifier})" end end # (see DataSource#load_country_info) def load_country_info(code) lookup_country_info(@countries, code) end private # Requires a zone definition by its identifier (split on /). # # @param identifier [Array] the component parts of a time zone # identifier (split on /). This must have already been validated. def require_definition(identifier) require_data('definitions', *identifier) end # Requires an index by its name. # # @param name [String] an index name. def require_index(name) require_data('indexes', name) end # Requires a file from tzinfo/data. # # @param file [Array] a relative path to a file to be required. def require_data(*file) require(File.join(@base_path, *file)) end # @return [String] a `String` containing TZInfo::Data version infomation # for inclusion in the #to_s and #inspect output. def version_info # The TZInfo::Data::VERSION constant is only available from v1.2014.8 # onwards. "tzdb v#{TZInfo::Data::Version::TZDATA}#{TZInfo::Data.const_defined?(:VERSION) ? ", tzinfo-data v#{TZInfo::Data::VERSION}" : ''}" end end end end tzinfo-2.0.6/lib/tzinfo/data_sources/timezone_info.rb000066400000000000000000000026471436527530500230000ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true module TZInfo module DataSources # Represents a time zone defined by a data source. # # @abstract Data sources return instances of {TimezoneInfo} subclasses. class TimezoneInfo # @return [String] the identifier of the time zone. attr_reader :identifier # Initializes a new TimezoneInfo. The passed in `identifier` instance will # be frozen. # # @param identifier [String] the identifier of the time zone. # @raise [ArgumentError] if `identifier` is `nil`. def initialize(identifier) raise ArgumentError, 'identifier must be specified' unless identifier @identifier = identifier.freeze end # @return [String] the internal object state as a programmer-readable # `String`. def inspect "#<#{self.class}: #@identifier>" end # @return [Timezone] a new {Timezone} instance for the time zone # represented by this {TimezoneInfo}. def create_timezone raise_not_implemented('create_timezone') end private # Raises a {NotImplementedError}. # # @param method_name [String] the name of the method that must be # overridden. # @raise NotImplementedError always. def raise_not_implemented(method_name) raise NotImplementedError, "Subclasses must override #{method_name}" end end end end tzinfo-2.0.6/lib/tzinfo/data_sources/transitions_data_timezone_info.rb000066400000000000000000000217401436527530500264210ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true module TZInfo module DataSources # Represents a data time zone defined by a list of transitions that change # the locally observed time. class TransitionsDataTimezoneInfo < DataTimezoneInfo # @return [Array] the transitions that define this # time zone in order of ascending timestamp. attr_reader :transitions # Initializes a new {TransitionsDataTimezoneInfo}. # # The passed in `identifier` instance will be frozen. A reference to the # passed in `Array` will be retained. # # The `transitions` `Array` must be sorted in order of ascending # timestamp. Each transition must have a # {TimezoneTransition#timestamp_value timestamp_value} that is greater # than the {TimezoneTransition#timestamp_value timestamp_value} of the # prior transition. # # @param identifier [String] the identifier of the time zone. # @param transitions [Array] an `Array` of # transitions that each indicate when a change occurs in the locally # observed time. # @raise [ArgumentError] if `identifier` is `nil`. # @raise [ArgumentError] if `transitions` is `nil`. # @raise [ArgumentError] if `transitions` is an empty `Array`. def initialize(identifier, transitions) super(identifier) raise ArgumentError, 'transitions must be specified' unless transitions raise ArgumentError, 'transitions must not be an empty Array' if transitions.empty? @transitions = transitions.freeze end # (see DataTimezoneInfo#period_for) def period_for(timestamp) raise ArgumentError, 'timestamp must be specified' unless timestamp raise ArgumentError, 'timestamp must have a specified utc_offset' unless timestamp.utc_offset timestamp_value = timestamp.value index = find_minimum_transition {|t| t.timestamp_value >= timestamp_value } if index transition = @transitions[index] if transition.timestamp_value == timestamp_value # timestamp occurs within the second of the found transition, so is # the transition that starts the period. start_transition = transition end_transition = @transitions[index + 1] else # timestamp occurs before the second of the found transition, so is # the transition that ends the period. start_transition = index == 0 ? nil : @transitions[index - 1] end_transition = transition end else start_transition = @transitions.last end_transition = nil end TransitionsTimezonePeriod.new(start_transition, end_transition) end # (see DataTimezoneInfo#periods_for_local) def periods_for_local(local_timestamp) raise ArgumentError, 'local_timestamp must be specified' unless local_timestamp raise ArgumentError, 'local_timestamp must have an unspecified utc_offset' if local_timestamp.utc_offset local_timestamp_value = local_timestamp.value latest_possible_utc_value = local_timestamp_value + 86400 earliest_possible_utc_value = local_timestamp_value - 86400 # Find the index of the first transition that occurs after a latest # possible UTC representation of the local timestamp and then search # backwards until an earliest possible UTC representation. index = find_minimum_transition {|t| t.timestamp_value >= latest_possible_utc_value } # No transitions after latest_possible_utc_value, set to max index + 1 # to search backwards including the period after the last transition index = @transitions.length unless index result = [] index.downto(0) do |i| start_transition = i > 0 ? @transitions[i - 1] : nil end_transition = @transitions[i] offset = start_transition ? start_transition.offset : end_transition.previous_offset utc_timestamp_value = local_timestamp_value - offset.observed_utc_offset # It is not necessary to compare the sub-seconds because a timestamp # is in the period if is >= the start transition (sub-seconds would # make == become >) and if it is < the end transition (which # sub-seconds cannot affect). if (!start_transition || utc_timestamp_value >= start_transition.timestamp_value) && (!end_transition || utc_timestamp_value < end_transition.timestamp_value) result << TransitionsTimezonePeriod.new(start_transition, end_transition) elsif end_transition && end_transition.timestamp_value < earliest_possible_utc_value break end end result.reverse! end # (see DataTimezoneInfo#transitions_up_to) def transitions_up_to(to_timestamp, from_timestamp = nil) raise ArgumentError, 'to_timestamp must be specified' unless to_timestamp raise ArgumentError, 'to_timestamp must have a specified utc_offset' unless to_timestamp.utc_offset if from_timestamp raise ArgumentError, 'from_timestamp must have a specified utc_offset' unless from_timestamp.utc_offset raise ArgumentError, 'to_timestamp must be greater than from_timestamp' if to_timestamp <= from_timestamp end if from_timestamp from_index = find_minimum_transition {|t| transition_on_or_after_timestamp?(t, from_timestamp) } return [] unless from_index else from_index = 0 end to_index = find_minimum_transition {|t| transition_on_or_after_timestamp?(t, to_timestamp) } if to_index return [] if to_index < 1 to_index -= 1 else to_index = -1 end @transitions[from_index..to_index] end private # Array#bsearch_index was added in Ruby 2.3.0. Use bsearch_index to find # transitions if it is available, otherwise use a Ruby implementation. if [].respond_to?(:bsearch_index) # Performs a binary search on {transitions} to find the index of the # earliest transition satisfying a condition. # # @yield [transition] the caller will be yielded to to test the search # condition. # @yieldparam transition [TimezoneTransition] a {TimezoneTransition} # instance from {transitions}. # @yieldreturn [Boolean] `true` for the earliest transition that # satisfies the condition and return `true` for all subsequent # transitions. In all other cases, the result of the block must be # `false`. # @return [Integer] the index of the earliest transition safisfying # the condition or `nil` if there are no such transitions. # # :nocov_no_array_bsearch_index: def find_minimum_transition(&block) @transitions.bsearch_index(&block) end # :nocov_no_array_bsearch_index: else # Performs a binary search on {transitions} to find the index of the # earliest transition satisfying a condition. # # @yield [transition] the caller will be yielded to to test the search # condition. # @yieldparam transition [TimezoneTransition] a {TimezoneTransition} # instance from {transitions}. # @yieldreturn [Boolean] `true` for the earliest transition that # satisfies the condition and return `true` for all subsequent # transitions. In all other cases, the result of the block must be # `false`. # @return [Integer] the index of the earliest transition safisfying # the condition or `nil` if there are no such transitions. # # :nocov_array_bsearch_index: def find_minimum_transition # A Ruby implementation of the find-minimum mode of Array#bsearch_index. low = 0 high = @transitions.length satisfied = false while low < high do mid = (low + high).div(2) if yield @transitions[mid] satisfied = true high = mid else low = mid + 1 end end satisfied ? low : nil end # :nocov_array_bsearch_index: end # Determines if a transition occurs at or after a given {Timestamp}, # taking the {Timestamp#sub_second sub_second} into consideration. # # @param transition [TimezoneTransition] the transition to compare. # @param timestamp [Timestamp] the timestamp to compare. # @return [Boolean] `true` if `transition` occurs at or after `timestamp`, # otherwise `false`. def transition_on_or_after_timestamp?(transition, timestamp) transition_timestamp_value = transition.timestamp_value timestamp_value = timestamp.value transition_timestamp_value > timestamp_value || transition_timestamp_value == timestamp_value && timestamp.sub_second == 0 end end end end tzinfo-2.0.6/lib/tzinfo/data_sources/zoneinfo_data_source.rb000066400000000000000000000570661436527530500243400ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true module TZInfo module DataSources # An {InvalidZoneinfoDirectory} exception is raised if {ZoneinfoDataSource} # is initialized with a specific zoneinfo path that is not a valid zoneinfo # directory. A valid zoneinfo directory is one that contains time zone # files, a country code index file named iso3166.tab and a time zone index # file named zone1970.tab or zone.tab. class InvalidZoneinfoDirectory < StandardError end # A {ZoneinfoDirectoryNotFound} exception is raised if no valid zoneinfo # directory could be found when checking the paths listed in # {ZoneinfoDataSource.search_path}. A valid zoneinfo directory is one that # contains time zone files, a country code index file named iso3166.tab and # a time zone index file named zone1970.tab or zone.tab. class ZoneinfoDirectoryNotFound < StandardError end # A DataSource implementation that loads data from a 'zoneinfo' directory # containing compiled "TZif" version 3 (or earlier) files in addition to # iso3166.tab and zone1970.tab or zone.tab index files. # # To have TZInfo load the system zoneinfo files, call # {TZInfo::DataSource.set} as follows: # # TZInfo::DataSource.set(:zoneinfo) # # To load zoneinfo files from a particular directory, pass the directory to # {TZInfo::DataSource.set}: # # TZInfo::DataSource.set(:zoneinfo, directory) # # To load zoneinfo files from a particular directory, but load the # iso3166.tab index file from a separate location, pass the directory and # path to the iso3166.tab file to {TZInfo::DataSource.set}: # # TZInfo::DataSource.set(:zoneinfo, directory, iso3166_path) # # Please note that versions of the 'zic' tool (used to build zoneinfo files) # that were released prior to February 2006 created zoneinfo files that used # 32-bit integers for transition timestamps. Later versions of zic produce # zoneinfo files that use 64-bit integers. If you have 32-bit zoneinfo files # on your system, then any queries falling outside of the range 1901-12-13 # 20:45:52 to 2038-01-19 03:14:07 may be inaccurate. # # Most modern platforms include 64-bit zoneinfo files. However, Mac OS X (up # to at least 10.8.4) still uses 32-bit zoneinfo files. # # To check whether your zoneinfo files contain 32-bit or 64-bit transition # data, you can run the following code (substituting the identifier of the # zone you want to test for `zone_identifier`): # # TZInfo::DataSource.set(:zoneinfo) # dir = TZInfo::DataSource.get.zoneinfo_dir # File.open(File.join(dir, zone_identifier), 'r') {|f| f.read(5) } # # If the last line returns `"TZif\\x00"`, then you have a 32-bit zoneinfo # file. If it returns `"TZif2"` or `"TZif3"` then you have a 64-bit zoneinfo # file. # # It is also worth noting that as of the 2017c release of the IANA Time Zone # Database, 64-bit zoneinfo files only include future transitions up to # 2038-01-19 03:14:07. Any queries falling after this time may be # inaccurate. class ZoneinfoDataSource < DataSource # The default value of {ZoneinfoDataSource.search_path}. DEFAULT_SEARCH_PATH = ['/usr/share/zoneinfo', '/usr/share/lib/zoneinfo', '/etc/zoneinfo'].freeze private_constant :DEFAULT_SEARCH_PATH # The default value of {ZoneinfoDataSource.alternate_iso3166_tab_search_path}. DEFAULT_ALTERNATE_ISO3166_TAB_SEARCH_PATH = ['/usr/share/misc/iso3166.tab', '/usr/share/misc/iso3166'].freeze private_constant :DEFAULT_ALTERNATE_ISO3166_TAB_SEARCH_PATH # Files and directories in the top level zoneinfo directory that will be # excluded from the list of available time zones: # # - +VERSION is included on Mac OS X. # - leapseconds is a list of leap seconds. # - localtime is the current local timezone (may be a link). # - posix, posixrules and right are directories containing other # versions of the zoneinfo files. # - SECURITY is included in the Arch Linux tzdata package. # - src is a directory containing the tzdata source included on Solaris. # - timeconfig is a symlink included on Slackware. EXCLUDED_FILENAMES = [ '+VERSION', 'leapseconds', 'localtime', 'posix', 'posixrules', 'right', 'SECURITY', 'src', 'timeconfig' ].freeze private_constant :EXCLUDED_FILENAMES # Paths to be checked to find the system zoneinfo directory. # # @private @@search_path = DEFAULT_SEARCH_PATH.dup # Paths to possible alternate iso3166.tab files (used to locate the # system-wide iso3166.tab files on FreeBSD and OpenBSD). # # @private @@alternate_iso3166_tab_search_path = DEFAULT_ALTERNATE_ISO3166_TAB_SEARCH_PATH.dup class << self # An `Array` of directories that will be checked to find the system # zoneinfo directory. # # Directories are checked in the order they appear in the `Array`. # # The default value is `['/usr/share/zoneinfo', # '/usr/share/lib/zoneinfo', '/etc/zoneinfo']`. # # @return [Array] an `Array` of directories to check in order to # find the system zoneinfo directory. def search_path @@search_path end # Sets the directories to be checked when locating the system zoneinfo # directory. # # Can be set to an `Array` of directories or a `String` containing # directories separated with `File::PATH_SEPARATOR`. # # Directories are checked in the order they appear in the `Array` or # `String`. # # Set to `nil` to revert to the default paths. # # @param search_path [Object] either `nil` or a list of directories to # check as either an `Array` of `String` or a `File::PATH_SEPARATOR` # separated `String`. def search_path=(search_path) @@search_path = process_search_path(search_path, DEFAULT_SEARCH_PATH) end # An `Array` of paths that will be checked to find an alternate # iso3166.tab file if one was not included in the zoneinfo directory # (for example, on FreeBSD and OpenBSD systems). # # Paths are checked in the order they appear in the `Array`. # # The default value is `['/usr/share/misc/iso3166.tab', # '/usr/share/misc/iso3166']`. # # @return [Array] an `Array` of paths to check in order to # locate an iso3166.tab file. def alternate_iso3166_tab_search_path @@alternate_iso3166_tab_search_path end # Sets the paths to check to locate an alternate iso3166.tab file if one # was not included in the zoneinfo directory. # # Can be set to an `Array` of paths or a `String` containing paths # separated with `File::PATH_SEPARATOR`. # # Paths are checked in the order they appear in the array. # # Set to `nil` to revert to the default paths. # # @param alternate_iso3166_tab_search_path [Object] either `nil` or a # list of paths to check as either an `Array` of `String` or a # `File::PATH_SEPARATOR` separated `String`. def alternate_iso3166_tab_search_path=(alternate_iso3166_tab_search_path) @@alternate_iso3166_tab_search_path = process_search_path(alternate_iso3166_tab_search_path, DEFAULT_ALTERNATE_ISO3166_TAB_SEARCH_PATH) end private # Processes a path for use as the {search_path} or # {alternate_iso3166_tab_search_path}. # # @param path [Object] either `nil` or a list of paths to check as # either an `Array` of `String` or a `File::PATH_SEPARATOR` separated # `String`. # @param default [Array] the default value. # @return [Array] the processed path. def process_search_path(path, default) if path if path.kind_of?(String) path.split(File::PATH_SEPARATOR) else path.collect(&:to_s) end else default.dup end end end # @return [String] the zoneinfo directory being used. attr_reader :zoneinfo_dir # (see DataSource#country_codes) attr_reader :country_codes # Initializes a new {ZoneinfoDataSource}. # # If `zoneinfo_dir` is specified, it will be checked and used as the # source of zoneinfo files. # # The directory must contain a file named iso3166.tab and a file named # either zone1970.tab or zone.tab. These may either be included in the # root of the directory or in a 'tab' sub-directory and named country.tab # and zone_sun.tab respectively (as is the case on Solaris). # # Additionally, the path to iso3166.tab can be overridden using the # `alternate_iso3166_tab_path` parameter. # # If `zoneinfo_dir` is not specified or `nil`, the paths referenced in # {search_path} are searched in order to find a valid zoneinfo directory # (one that contains zone1970.tab or zone.tab and iso3166.tab files as # above). # # The paths referenced in {alternate_iso3166_tab_search_path} are also # searched to find an iso3166.tab file if one of the searched zoneinfo # directories doesn't contain an iso3166.tab file. # # @param zoneinfo_dir [String] an optional path to a directory to use as # the source of zoneinfo files. # @param alternate_iso3166_tab_path [String] an optional path to the # iso3166.tab file. # @raise [InvalidZoneinfoDirectory] if the iso3166.tab and zone1970.tab or # zone.tab files cannot be found using the `zoneinfo_dir` and # `alternate_iso3166_tab_path` parameters. # @raise [ZoneinfoDirectoryNotFound] if no valid directory can be found # by searching. def initialize(zoneinfo_dir = nil, alternate_iso3166_tab_path = nil) super() if zoneinfo_dir iso3166_tab_path, zone_tab_path = validate_zoneinfo_dir(zoneinfo_dir, alternate_iso3166_tab_path) unless iso3166_tab_path && zone_tab_path raise InvalidZoneinfoDirectory, "#{zoneinfo_dir} is not a directory or doesn't contain a iso3166.tab file and a zone1970.tab or zone.tab file." end @zoneinfo_dir = zoneinfo_dir else @zoneinfo_dir, iso3166_tab_path, zone_tab_path = find_zoneinfo_dir unless @zoneinfo_dir && iso3166_tab_path && zone_tab_path raise ZoneinfoDirectoryNotFound, "None of the paths included in #{self.class.name}.search_path are valid zoneinfo directories." end end @zoneinfo_dir = File.expand_path(@zoneinfo_dir).freeze @timezone_identifiers = load_timezone_identifiers.freeze @countries = load_countries(iso3166_tab_path, zone_tab_path).freeze @country_codes = @countries.keys.sort!.freeze string_deduper = ConcurrentStringDeduper.new posix_tz_parser = PosixTimeZoneParser.new(string_deduper) @zoneinfo_reader = ZoneinfoReader.new(posix_tz_parser, string_deduper) end # Returns a frozen `Array` of all the available time zone identifiers. The # identifiers are sorted according to `String#<=>`. # # @return [Array] a frozen `Array` of all the available time zone # identifiers. def data_timezone_identifiers @timezone_identifiers end # Returns an empty `Array`. There is no information about linked/aliased # time zones in the zoneinfo files. When using {ZoneinfoDataSource}, every # time zone will be returned as a {DataTimezone}. # # @return [Array] an empty `Array`. def linked_timezone_identifiers [].freeze end # (see DataSource#to_s) def to_s "Zoneinfo DataSource: #{@zoneinfo_dir}" end # (see DataSource#inspect) def inspect "#<#{self.class}: #{@zoneinfo_dir}>" end protected # Returns a {TimezoneInfo} instance for the given time zone identifier. # The result will either be a {ConstantOffsetDataTimezoneInfo} or a # {TransitionsDataTimezoneInfo}. # # @param identifier [String] A time zone identifier. # @return [TimezoneInfo] a {TimezoneInfo} instance for the given time zone # identifier. # @raise [InvalidTimezoneIdentifier] if the time zone is not found, the # identifier is invalid, the zoneinfo file cannot be opened or the # zoneinfo file is not valid. def load_timezone_info(identifier) valid_identifier = validate_timezone_identifier(identifier) path = File.join(@zoneinfo_dir, valid_identifier) zoneinfo = begin @zoneinfo_reader.read(path) rescue Errno::EACCES, InvalidZoneinfoFile => e raise InvalidTimezoneIdentifier, "#{e.message.encode(Encoding::UTF_8)} (loading #{valid_identifier})" rescue Errno::EISDIR, Errno::ENAMETOOLONG, Errno::ENOENT, Errno::ENOTDIR raise InvalidTimezoneIdentifier, "Invalid identifier: #{valid_identifier}" end if zoneinfo.kind_of?(TimezoneOffset) ConstantOffsetDataTimezoneInfo.new(valid_identifier, zoneinfo) else TransitionsDataTimezoneInfo.new(valid_identifier, zoneinfo) end end # (see DataSource#load_country_info) def load_country_info(code) lookup_country_info(@countries, code) end private # Validates a zoneinfo directory and returns the paths to the iso3166.tab # and zone1970.tab or zone.tab files if valid. If the directory is not # valid, returns `nil`. # # The path to the iso3166.tab file may be overridden by passing in a path. # This is treated as either absolute or relative to the current working # directory. # # @param path [String] the path to a possible zoneinfo directory. # @param iso3166_tab_path [String] an optional path to an external # iso3166.tab file. # @return [Array] an `Array` containing the iso3166.tab and # zone.tab paths if the directory is valid, otherwise `nil`. def validate_zoneinfo_dir(path, iso3166_tab_path = nil) if File.directory?(path) if iso3166_tab_path return nil unless File.file?(iso3166_tab_path) else iso3166_tab_path = resolve_tab_path(path, ['iso3166.tab'], 'country.tab') return nil unless iso3166_tab_path end zone_tab_path = resolve_tab_path(path, ['zone1970.tab', 'zone.tab'], 'zone_sun.tab') return nil unless zone_tab_path [iso3166_tab_path, zone_tab_path] else nil end end # Attempts to resolve the path to a tab file given its standard names and # tab sub-directory name (as used on Solaris). # # @param zoneinfo_path [String] the path to a zoneinfo directory. # @param standard_names [Array] the standard names for the tab # file. # @param tab_name [String] the alternate name for the tab file to check in # the tab sub-directory. # @return [String] the path to the tab file. def resolve_tab_path(zoneinfo_path, standard_names, tab_name) standard_names.each do |standard_name| path = File.join(zoneinfo_path, standard_name) return path if File.file?(path) end path = File.join(zoneinfo_path, 'tab', tab_name) return path if File.file?(path) nil end # Finds a zoneinfo directory using {search_path} and # {alternate_iso3166_tab_search_path}. # # @return [Array] an `Array` containing the iso3166.tab and # zone.tab paths if a zoneinfo directory was found, otherwise `nil`. def find_zoneinfo_dir alternate_iso3166_tab_path = self.class.alternate_iso3166_tab_search_path.detect do |path| File.file?(path) end self.class.search_path.each do |path| # Try without the alternate_iso3166_tab_path first. iso3166_tab_path, zone_tab_path = validate_zoneinfo_dir(path) return path, iso3166_tab_path, zone_tab_path if iso3166_tab_path && zone_tab_path if alternate_iso3166_tab_path iso3166_tab_path, zone_tab_path = validate_zoneinfo_dir(path, alternate_iso3166_tab_path) return path, iso3166_tab_path, zone_tab_path if iso3166_tab_path && zone_tab_path end end # Not found. nil end # Scans @zoneinfo_dir and returns an `Array` of available time zone # identifiers. The result is sorted according to `String#<=>`. # # @return [Array] an `Array` containing all the time zone # identifiers found. def load_timezone_identifiers index = [] enum_timezones([], EXCLUDED_FILENAMES) do |identifier| index << identifier.join('/').freeze end index.sort! end # Recursively enumerate a directory of time zones. # # @param dir [Array] the directory to enumerate as an `Array` of # path components. # @param exclude [Array] file names to exclude when scanning # `dir`. # @yield [path] the path of each time zone file found is passed to # the block. # @yieldparam path [Array] the path of a time zone file as an # `Array` of path components. def enum_timezones(dir, exclude = [], &block) Dir.foreach(File.join(@zoneinfo_dir, *dir)) do |entry| begin entry.encode!(Encoding::UTF_8) rescue EncodingError next end unless entry =~ /\./ || exclude.include?(entry) RubyCoreSupport.untaint(entry) path = dir + [entry] full_path = File.join(@zoneinfo_dir, *path) if File.directory?(full_path) enum_timezones(path, [], &block) elsif File.file?(full_path) yield path end end end end # Uses the iso3166.tab and zone1970.tab or zone.tab files to return a Hash # mapping country codes to CountryInfo instances. # # @param iso3166_tab_path [String] the path to the iso3166.tab file. # @param zone_tab_path [String] the path to the zone.tab file. # @return [Hash] a mapping from ISO 3166-1 alpha-2 # country codes to {CountryInfo} instances. def load_countries(iso3166_tab_path, zone_tab_path) # Handle standard 3 to 4 column zone.tab files as well as the 4 to 5 # column format used by Solaris. # # On Solaris, an extra column before the comment gives an optional # linked/alternate timezone identifier (or '-' if not set). # # Additionally, there is a section at the end of the file for timezones # covering regions. These are given lower-case "country" codes. The timezone # identifier column refers to a continent instead of an identifier. These # lines will be ignored by TZInfo. # # Since the last column is optional in both formats, testing for the # Solaris format is done in two passes. The first pass identifies if there # are any lines using 5 columns. # The first column is allowed to be a comma separated list of country # codes, as used in zone1970.tab (introduced in tzdata 2014f). # # The first country code in the comma-separated list is the country that # contains the city the zone identifier is based on. The first country # code on each line is considered to be primary with the others # secondary. # # The zones for each country are ordered primary first, then secondary. # Within the primary and secondary groups, the zones are ordered by their # order in the file. file_is_5_column = false zone_tab = [] file = File.read(zone_tab_path, external_encoding: Encoding::UTF_8, internal_encoding: Encoding::UTF_8) file.each_line do |line| line.chomp! if line =~ /\A([A-Z]{2}(?:,[A-Z]{2})*)\t(?:([+\-])(\d{2})(\d{2})([+\-])(\d{3})(\d{2})|([+\-])(\d{2})(\d{2})(\d{2})([+\-])(\d{3})(\d{2})(\d{2}))\t([^\t]+)(?:\t([^\t]+))?(?:\t([^\t]+))?\z/ codes = $1 if $2 latitude = dms_to_rational($2, $3, $4) longitude = dms_to_rational($5, $6, $7) else latitude = dms_to_rational($8, $9, $10, $11) longitude = dms_to_rational($12, $13, $14, $15) end zone_identifier = $16 column4 = $17 column5 = $18 file_is_5_column = true if column5 zone_tab << [codes.split(','.freeze), zone_identifier, latitude, longitude, column4, column5] end end string_deduper = StringDeduper.new primary_zones = {} secondary_zones = {} zone_tab.each do |codes, zone_identifier, latitude, longitude, column4, column5| description = file_is_5_column ? column5 : column4 description = string_deduper.dedupe(description) if description # Lookup the identifier in the timezone index, so that the same # String instance can be used (saving memory). begin zone_identifier = validate_timezone_identifier(zone_identifier) rescue InvalidTimezoneIdentifier # zone_identifier is not valid, dedupe and allow anyway. zone_identifier = string_deduper.dedupe(zone_identifier) end country_timezone = CountryTimezone.new(zone_identifier, latitude, longitude, description) # codes will always have at least one element (primary_zones[codes.first.freeze] ||= []) << country_timezone codes[1..-1].each do |code| (secondary_zones[code.freeze] ||= []) << country_timezone end end countries = {} file = File.read(iso3166_tab_path, external_encoding: Encoding::UTF_8, internal_encoding: Encoding::UTF_8) file.each_line do |line| line.chomp! # Handle both the two column alpha-2 and name format used in the tz # database as well as the 4 column alpha-2, alpha-3, numeric-3 and # name format used by FreeBSD and OpenBSD. if line =~ /\A([A-Z]{2})(?:\t[A-Z]{3}\t[0-9]{3})?\t(.+)\z/ code = $1 name = $2 zones = (primary_zones[code] || []) + (secondary_zones[code] || []) countries[code] = CountryInfo.new(code, name, zones) end end countries end # Converts degrees, minutes and seconds to a Rational. # # @param sign [String] `'-'` or `'+'`. # @param degrees [String] the number of degrees. # @param minutes [String] the number of minutes. # @param seconds [String] the number of seconds (optional). # @return [Rational] the result of converting from degrees, minutes and # seconds to a `Rational`. def dms_to_rational(sign, degrees, minutes, seconds = nil) degrees = degrees.to_i minutes = minutes.to_i sign = sign == '-'.freeze ? -1 : 1 if seconds Rational(sign * (degrees * 3600 + minutes * 60 + seconds.to_i), 3600) else Rational(sign * (degrees * 60 + minutes), 60) end end end end end tzinfo-2.0.6/lib/tzinfo/data_sources/zoneinfo_reader.rb000066400000000000000000000513321436527530500232770ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true module TZInfo module DataSources # An {InvalidZoneinfoFile} exception is raised if an attempt is made to load # an invalid zoneinfo file. class InvalidZoneinfoFile < StandardError end # Reads compiled zoneinfo TZif (\0, 2 or 3) files. class ZoneinfoReader #:nodoc: # The year to generate transitions up to. # # @private GENERATE_UP_TO = Time.now.utc.year + 100 private_constant :GENERATE_UP_TO # Initializes a new {ZoneinfoReader}. # # @param posix_tz_parser [PosixTimeZoneParser] a {PosixTimeZoneParser} # instance to use to parse POSIX-style TZ strings. # @param string_deduper [StringDeduper] a {StringDeduper} instance to use # to dedupe abbreviations. def initialize(posix_tz_parser, string_deduper) @posix_tz_parser = posix_tz_parser @string_deduper = string_deduper end # Reads a zoneinfo structure from the given path. Returns either a # {TimezoneOffset} that is constantly observed or an `Array` # {TimezoneTransition}s. # # @param file_path [String] the path of a zoneinfo file. # @return [Object] either a {TimezoneOffset} or an `Array` of # {TimezoneTransition}s. # @raise [SecurityError] if safe mode is enabled and `file_path` is # tainted. # @raise [InvalidZoneinfoFile] if `file_path`` does not refer to a valid # zoneinfo file. def read(file_path) File.open(file_path, 'rb') { |file| parse(file) } end private # Translates an unsigned 32-bit integer (as returned by unpack) to signed # 32-bit. # # @param long [Integer] an unsigned 32-bit integer. # @return [Integer] {long} translated to signed 32-bit. def make_signed_int32(long) long >= 0x80000000 ? long - 0x100000000 : long end # Translates a pair of unsigned 32-bit integers (as returned by unpack, # most significant first) to a signed 64-bit integer. # # @param high [Integer] the most significant 32-bits. # @param low [Integer] the least significant 32-bits. # @return [Integer] {high} and {low} combined and translated to signed # 64-bit. def make_signed_int64(high, low) unsigned = (high << 32) | low unsigned >= 0x8000000000000000 ? unsigned - 0x10000000000000000 : unsigned end # Reads the given number of bytes from the given file and checks that the # correct number of bytes could be read. # # @param file [IO] the file to read from. # @param bytes [Integer] the number of bytes to read. # @return [String] the bytes that were read. # @raise [InvalidZoneinfoFile] if the number of bytes available didn't # match the number requested. def check_read(file, bytes) result = file.read(bytes) unless result && result.length == bytes raise InvalidZoneinfoFile, "Expected #{bytes} bytes reading '#{file.path}', but got #{result ? result.length : 0} bytes" end result end # Zoneinfo files don't include the offset from standard time (std_offset) # for DST periods. Derive the base offset (base_utc_offset) where DST is # observed from either the previous or next non-DST period. # # @param transitions [Array] an `Array` of transition hashes. # @param offsets [Array] an `Array` of offset hashes. # @return [Integer] the index of the offset to be used prior to the first # transition. def derive_offsets(transitions, offsets) # The first non-DST offset (if there is one) is the offset observed # before the first transition. Fall back to the first DST offset if # there are no non-DST offsets. first_non_dst_offset_index = offsets.index {|o| !o[:is_dst] } first_offset_index = first_non_dst_offset_index || 0 return first_offset_index if transitions.empty? # Determine the base_utc_offset of the next non-dst offset at each transition. base_utc_offset_from_next = nil transitions.reverse_each do |transition| offset = offsets[transition[:offset]] if offset[:is_dst] transition[:base_utc_offset_from_next] = base_utc_offset_from_next if base_utc_offset_from_next else base_utc_offset_from_next = offset[:observed_utc_offset] end end base_utc_offset_from_previous = first_non_dst_offset_index ? offsets[first_non_dst_offset_index][:observed_utc_offset] : nil defined_offsets = {} transitions.each do |transition| offset_index = transition[:offset] offset = offsets[offset_index] observed_utc_offset = offset[:observed_utc_offset] if offset[:is_dst] base_utc_offset_from_next = transition[:base_utc_offset_from_next] difference_to_previous = (observed_utc_offset - (base_utc_offset_from_previous || observed_utc_offset)).abs difference_to_next = (observed_utc_offset - (base_utc_offset_from_next || observed_utc_offset)).abs base_utc_offset = if difference_to_previous == 3600 base_utc_offset_from_previous elsif difference_to_next == 3600 base_utc_offset_from_next elsif difference_to_previous > 0 && difference_to_next > 0 difference_to_previous < difference_to_next ? base_utc_offset_from_previous : base_utc_offset_from_next elsif difference_to_previous > 0 base_utc_offset_from_previous elsif difference_to_next > 0 base_utc_offset_from_next else # No difference, assume a 1 hour offset from standard time. observed_utc_offset - 3600 end if !offset[:base_utc_offset] offset[:base_utc_offset] = base_utc_offset defined_offsets[offset] = offset_index elsif offset[:base_utc_offset] != base_utc_offset # An earlier transition has already derived a different # base_utc_offset. Define a new offset or reuse an existing identically # defined offset. new_offset = offset.dup new_offset[:base_utc_offset] = base_utc_offset offset_index = defined_offsets[new_offset] unless offset_index offsets << new_offset offset_index = offsets.length - 1 defined_offsets[new_offset] = offset_index end transition[:offset] = offset_index end else base_utc_offset_from_previous = observed_utc_offset end end first_offset_index end # Determines if the offset from a transition matches the offset from a # rule. This is a looser match than equality, not requiring that the # base_utc_offset and std_offset both match (which have to be derived for # transitions, but are known for rules. # # @param offset [TimezoneOffset] an offset from a transition. # @param rule_offset [TimezoneOffset] an offset from a rule. # @return [Boolean] whether the offsets match. def offset_matches_rule?(offset, rule_offset) offset.observed_utc_offset == rule_offset.observed_utc_offset && offset.dst? == rule_offset.dst? && offset.abbreviation == rule_offset.abbreviation end # Apply the rules from the TZ string when there were no defined # transitions. Checks for a matching offset. Returns the rules-based # constant offset or generates transitions from 1970 until 100 years into # the future (at the time of loading zoneinfo_reader.rb). # # @param file [IO] the file being processed. # @param first_offset [TimezoneOffset] the first offset included in the # file that would normally apply without the rules. # @param rules [Object] a {TimezoneOffset} specifying a constant offset or # {AnnualRules} instance specfying transitions. # @return [Object] either a {TimezoneOffset} or an `Array` of # {TimezoneTransition}s. # @raise [InvalidZoneinfoFile] if the first offset does not match the # rules. def apply_rules_without_transitions(file, first_offset, rules) if rules.kind_of?(TimezoneOffset) unless offset_matches_rule?(first_offset, rules) raise InvalidZoneinfoFile, "Constant offset POSIX-style TZ string does not match constant offset in file '#{file.path}'." end rules else transitions = 1970.upto(GENERATE_UP_TO).flat_map {|y| rules.transitions(y) } first_transition = transitions[0] unless offset_matches_rule?(first_offset, first_transition.previous_offset) # Not transitioning from the designated first offset. if offset_matches_rule?(first_offset, first_transition.offset) # Skip an unnecessary transition to the first offset. transitions.shift else # The initial offset doesn't match the ongoing rules. Replace the # previous offset of the first transition. transitions[0] = TimezoneTransition.new(first_transition.offset, first_offset, first_transition.timestamp_value) end end transitions end end # Finds an offset that is equivalent to the one specified in the given # `Array`. Matching is performed with {TimezoneOffset#==}. # # @param offsets [Array] an `Array` to search. # @param offset [TimezoneOffset] the offset to search for. # @return [TimezoneOffset] the matching offset from `offsets` or `nil` # if not found. def find_existing_offset(offsets, offset) offsets.find {|o| o == offset } end # Returns a new AnnualRules instance with standard and daylight savings # offsets replaced with equivalents from an array. This reduces the memory # requirement for loaded time zones by reusing offsets for rule-generated # transitions. # # @param offsets [Array] an `Array` to search for # equivalent offsets. # @param annual_rules [AnnualRules] the {AnnualRules} instance to check. # @return [AnnualRules] either a new {AnnualRules} instance with either # the {AnnualRules#std_offset std_offset} or {AnnualRules#dst_offset # dst_offset} replaced, or the original instance if no equivalent for # either {AnnualRules#std_offset std_offset} or {AnnualRules#dst_offset # dst_offset} could be found. def replace_with_existing_offsets(offsets, annual_rules) existing_std_offset = find_existing_offset(offsets, annual_rules.std_offset) existing_dst_offset = find_existing_offset(offsets, annual_rules.dst_offset) if existing_std_offset || existing_dst_offset AnnualRules.new(existing_std_offset || annual_rules.std_offset, existing_dst_offset || annual_rules.dst_offset, annual_rules.dst_start_rule, annual_rules.dst_end_rule) else annual_rules end end # Validates the offset indicated to be observed by the rules before the # first generated transition against the offset of the last defined # transition. # # Fix the last defined transition if it differ on just base/std offsets # (which are derived). Raise an error if the observed UTC offset or # abbreviations differ. # # @param file [IO] the file being processed. # @param last_defined [TimezoneTransition] the last defined transition in # the file. # @param first_rule_offset [TimezoneOffset] the offset the rules indicate # is observed prior to the first rules generated transition. # @return [TimezoneTransition] the last defined transition (either the # original instance or a replacement). # @raise [InvalidZoneinfoFile] if the offset of {last_defined} and # {first_rule_offset} do not match. def validate_and_fix_last_defined_transition_offset(file, last_defined, first_rule_offset) offset_of_last_defined = last_defined.offset if offset_of_last_defined == first_rule_offset last_defined else if offset_matches_rule?(offset_of_last_defined, first_rule_offset) # The same overall offset, but differing in the base or std # offset (which are derived). Correct by using the rule. TimezoneTransition.new(first_rule_offset, last_defined.previous_offset, last_defined.timestamp_value) else raise InvalidZoneinfoFile, "The first offset indicated by the POSIX-style TZ string did not match the final defined offset in file '#{file.path}'." end end end # Apply the rules from the TZ string when there were defined # transitions. Checks for a matching offset with the last transition. # Redefines the last transition if required and if the rules don't # specific a constant offset, generates transitions until 100 years into # the future (at the time of loading zoneinfo_reader.rb). # # @param file [IO] the file being processed. # @param transitions [Array] the defined transitions. # @param offsets [Array] the offsets used by the defined # transitions. # @param rules [Object] a {TimezoneOffset} specifying a constant offset or # {AnnualRules} instance specfying transitions. # @raise [InvalidZoneinfoFile] if the first offset does not match the # rules. # @raise [InvalidZoneinfoFile] if the previous offset of the first # generated transition does not match the offset of the last defined # transition. def apply_rules_with_transitions(file, transitions, offsets, rules) last_defined = transitions[-1] if rules.kind_of?(TimezoneOffset) transitions[-1] = validate_and_fix_last_defined_transition_offset(file, last_defined, rules) else last_year = last_defined.local_end_at.to_time.year if last_year <= GENERATE_UP_TO rules = replace_with_existing_offsets(offsets, rules) generated = rules.transitions(last_year).find_all do |t| t.timestamp_value > last_defined.timestamp_value && !offset_matches_rule?(last_defined.offset, t.offset) end generated += (last_year + 1).upto(GENERATE_UP_TO).flat_map {|y| rules.transitions(y) } unless generated.empty? transitions[-1] = validate_and_fix_last_defined_transition_offset(file, last_defined, generated[0].previous_offset) transitions.concat(generated) end end end end # Parses a zoneinfo file and returns either a {TimezoneOffset} that is # constantly observed or an `Array` of {TimezoneTransition}s. # # @param file [IO] the file to be read. # @return [Object] either a {TimezoneOffset} or an `Array` of # {TimezoneTransition}s. # @raise [InvalidZoneinfoFile] if the file is not a valid zoneinfo file. def parse(file) magic, version, ttisutccnt, ttisstdcnt, leapcnt, timecnt, typecnt, charcnt = check_read(file, 44).unpack('a4 a x15 NNNNNN') if magic != 'TZif' raise InvalidZoneinfoFile, "The file '#{file.path}' does not start with the expected header." end if version == '2' || version == '3' # Skip the first 32-bit section and read the header of the second 64-bit section file.seek(timecnt * 5 + typecnt * 6 + charcnt + leapcnt * 8 + ttisstdcnt + ttisutccnt, IO::SEEK_CUR) prev_version = version magic, version, ttisutccnt, ttisstdcnt, leapcnt, timecnt, typecnt, charcnt = check_read(file, 44).unpack('a4 a x15 NNNNNN') unless magic == 'TZif' && (version == prev_version) raise InvalidZoneinfoFile, "The file '#{file.path}' contains an invalid 64-bit section header." end using_64bit = true elsif version != '3' && version != '2' && version != "\0" raise InvalidZoneinfoFile, "The file '#{file.path}' contains a version of the zoneinfo format that is not currently supported." else using_64bit = false end unless leapcnt == 0 raise InvalidZoneinfoFile, "The file '#{file.path}' contains leap second data. TZInfo requires zoneinfo files that omit leap seconds." end transitions = if using_64bit timecnt.times.map do |i| high, low = check_read(file, 8).unpack('NN'.freeze) transition_time = make_signed_int64(high, low) {at: transition_time} end else timecnt.times.map do |i| transition_time = make_signed_int32(check_read(file, 4).unpack('N'.freeze)[0]) {at: transition_time} end end check_read(file, timecnt).unpack('C*'.freeze).each_with_index do |localtime_type, i| raise InvalidZoneinfoFile, "Invalid offset referenced by transition in file '#{file.path}'." if localtime_type >= typecnt transitions[i][:offset] = localtime_type end offsets = typecnt.times.map do |i| gmtoff, isdst, abbrind = check_read(file, 6).unpack('NCC'.freeze) gmtoff = make_signed_int32(gmtoff) isdst = isdst == 1 {observed_utc_offset: gmtoff, is_dst: isdst, abbr_index: abbrind} end abbrev = check_read(file, charcnt) if using_64bit # Skip to the POSIX-style TZ string. file.seek(ttisstdcnt + ttisutccnt, IO::SEEK_CUR) # + leapcnt * 8, but leapcnt is checked above and guaranteed to be 0. tz_string_start = check_read(file, 1) raise InvalidZoneinfoFile, "Expected newline starting POSIX-style TZ string in file '#{file.path}'." unless tz_string_start == "\n" tz_string = file.readline("\n").force_encoding(Encoding::UTF_8) raise InvalidZoneinfoFile, "Expected newline ending POSIX-style TZ string in file '#{file.path}'." unless tz_string.chomp!("\n") begin rules = @posix_tz_parser.parse(tz_string) rescue InvalidPosixTimeZone => e raise InvalidZoneinfoFile, "Failed to parse POSIX-style TZ string in file '#{file.path}': #{e}" end else rules = nil end # Derive the offsets from standard time (std_offset). first_offset_index = derive_offsets(transitions, offsets) offsets = offsets.map do |o| observed_utc_offset = o[:observed_utc_offset] base_utc_offset = o[:base_utc_offset] if base_utc_offset # DST offset with base_utc_offset derived by derive_offsets. std_offset = observed_utc_offset - base_utc_offset elsif o[:is_dst] # DST offset unreferenced by a transition (offset in use before the # first transition). No derived base UTC offset, so assume 1 hour # DST. base_utc_offset = observed_utc_offset - 3600 std_offset = 3600 else # Non-DST offset. base_utc_offset = observed_utc_offset std_offset = 0 end abbrev_start = o[:abbr_index] raise InvalidZoneinfoFile, "Abbreviation index is out of range in file '#{file.path}'." unless abbrev_start < abbrev.length abbrev_end = abbrev.index("\0", abbrev_start) raise InvalidZoneinfoFile, "Missing abbreviation null terminator in file '#{file.path}'." unless abbrev_end abbr = @string_deduper.dedupe(RubyCoreSupport.untaint(abbrev[abbrev_start...abbrev_end].force_encoding(Encoding::UTF_8))) TimezoneOffset.new(base_utc_offset, std_offset, abbr) end first_offset = offsets[first_offset_index] if transitions.empty? if rules apply_rules_without_transitions(file, first_offset, rules) else first_offset end else previous_offset = first_offset previous_at = nil transitions = transitions.map do |t| offset = offsets[t[:offset]] at = t[:at] raise InvalidZoneinfoFile, "Transition at #{at} is not later than the previous transition at #{previous_at} in file '#{file.path}'." if previous_at && previous_at >= at tt = TimezoneTransition.new(offset, previous_offset, at) previous_offset = offset previous_at = at tt end apply_rules_with_transitions(file, transitions, offsets, rules) if rules transitions end end end private_constant :ZoneinfoReader end end tzinfo-2.0.6/lib/tzinfo/data_timezone.rb000066400000000000000000000025121436527530500202710ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true module TZInfo # Represents time zones that are defined by rules that set out when # transitions occur. class DataTimezone < InfoTimezone # (see Timezone#period_for) def period_for(time) raise ArgumentError, 'time must be specified' unless time timestamp = Timestamp.for(time) raise ArgumentError, 'time must have a specified utc_offset' unless timestamp.utc_offset info.period_for(timestamp) end # (see Timezone#periods_for_local) def periods_for_local(local_time) raise ArgumentError, 'local_time must be specified' unless local_time info.periods_for_local(Timestamp.for(local_time, :ignore)) end # (see Timezone#transitions_up_to) def transitions_up_to(to, from = nil) raise ArgumentError, 'to must be specified' unless to to_timestamp = Timestamp.for(to) from_timestamp = from && Timestamp.for(from) begin info.transitions_up_to(to_timestamp, from_timestamp) rescue ArgumentError => e raise ArgumentError, e.message.gsub('_timestamp', '') end end # Returns the canonical {Timezone} instance for this {DataTimezone}. # # For a {DataTimezone}, this is always `self`. # # @return [Timezone] `self`. def canonical_zone self end end end tzinfo-2.0.6/lib/tzinfo/datetime_with_offset.rb000066400000000000000000000124571436527530500216540ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true require 'date' module TZInfo # A subclass of `DateTime` used to represent local times. {DateTimeWithOffset} # holds a reference to the related {TimezoneOffset} and overrides various # methods to return results appropriate for the {TimezoneOffset}. Certain # operations will clear the associated {TimezoneOffset} (if the # {TimezoneOffset} would not necessarily be valid for the result). Once the # {TimezoneOffset} has been cleared, {DateTimeWithOffset} behaves identically # to `DateTime`. # # Arithmetic performed on {DateTimeWithOffset} instances is _not_ time # zone-aware. Regardless of whether transitions in the time zone are crossed, # results of arithmetic operations will always maintain the same offset from # UTC (`offset`). The associated {TimezoneOffset} will aways be cleared. class DateTimeWithOffset < DateTime include WithOffset # @return [TimezoneOffset] the {TimezoneOffset} associated with this # instance. attr_reader :timezone_offset # Sets the associated {TimezoneOffset}. # # @param timezone_offset [TimezoneOffset] a {TimezoneOffset} valid at the # time and for the offset of this {DateTimeWithOffset}. # @return [DateTimeWithOffset] `self`. # @raise [ArgumentError] if `timezone_offset` is `nil`. # @raise [ArgumentError] if `timezone_offset.observed_utc_offset` does not # equal `self.offset * 86400`. def set_timezone_offset(timezone_offset) raise ArgumentError, 'timezone_offset must be specified' unless timezone_offset raise ArgumentError, 'timezone_offset.observed_utc_offset does not match self.utc_offset' if offset * 86400 != timezone_offset.observed_utc_offset @timezone_offset = timezone_offset self end # An overridden version of `DateTime#to_time` that, if there is an # associated {TimezoneOffset}, returns a {DateTimeWithOffset} with that # offset. # # @return [Time] if there is an associated {TimezoneOffset}, a # {TimeWithOffset} representation of this {DateTimeWithOffset}, otherwise # a `Time` representation. def to_time if_timezone_offset(super) do |o,t| # Ruby 2.4.0 changed the behaviour of to_time so that it preserves the # offset instead of converting to the system local timezone. # # When self has an associated TimezonePeriod, this implementation will # preserve the offset on all versions of Ruby. TimeWithOffset.at(t.to_i, t.subsec * 1_000_000).set_timezone_offset(o) end end # An overridden version of `DateTime#downto` that clears the associated # {TimezoneOffset} of the returned or yielded instances. def downto(min) if block_given? super {|dt| yield dt.clear_timezone_offset } else enum = super enum.each {|dt| dt.clear_timezone_offset } enum end end # An overridden version of `DateTime#england` that preserves the associated # {TimezoneOffset}. # # @return [DateTime] def england # super doesn't call #new_start on MRI, so each method has to be # individually overridden. if_timezone_offset(super) {|o,dt| dt.set_timezone_offset(o) } end # An overridden version of `DateTime#gregorian` that preserves the # associated {TimezoneOffset}. # # @return [DateTime] def gregorian # super doesn't call #new_start on MRI, so each method has to be # individually overridden. if_timezone_offset(super) {|o,dt| dt.set_timezone_offset(o) } end # An overridden version of `DateTime#italy` that preserves the associated # {TimezoneOffset}. # # @return [DateTime] def italy # super doesn't call #new_start on MRI, so each method has to be # individually overridden. if_timezone_offset(super) {|o,dt| dt.set_timezone_offset(o) } end # An overridden version of `DateTime#julian` that preserves the associated # {TimezoneOffset}. # # @return [DateTime] def julian # super doesn't call #new_start on MRI, so each method has to be # individually overridden. if_timezone_offset(super) {|o,dt| dt.set_timezone_offset(o) } end # An overridden version of `DateTime#new_start` that preserves the # associated {TimezoneOffset}. # # @return [DateTime] def new_start(start = Date::ITALY) if_timezone_offset(super) {|o,dt| dt.set_timezone_offset(o) } end # An overridden version of `DateTime#step` that clears the associated # {TimezoneOffset} of the returned or yielded instances. def step(limit, step = 1) if block_given? super {|dt| yield dt.clear_timezone_offset } else enum = super enum.each {|dt| dt.clear_timezone_offset } enum end end # An overridden version of `DateTime#upto` that clears the associated # {TimezoneOffset} of the returned or yielded instances. def upto(max) if block_given? super {|dt| yield dt.clear_timezone_offset } else enum = super enum.each {|dt| dt.clear_timezone_offset } enum end end protected # Clears the associated {TimezoneOffset}. # # @return [DateTimeWithOffset] `self`. def clear_timezone_offset @timezone_offset = nil self end end end tzinfo-2.0.6/lib/tzinfo/format1.rb000066400000000000000000000002701436527530500170160ustar00rootroot00000000000000# encoding: UTF-8 module TZInfo # Modules and classes used by the format 1 version of TZInfo::Data. # # @private module Format1 #:nodoc: end private_constant :Format1 end tzinfo-2.0.6/lib/tzinfo/format1/000077500000000000000000000000001436527530500164725ustar00rootroot00000000000000tzinfo-2.0.6/lib/tzinfo/format1/country_definer.rb000066400000000000000000000010251436527530500222140ustar00rootroot00000000000000# encoding: UTF-8 module TZInfo module Format1 # Instances of {Format1::CountryDefiner} are yielded to the format 1 version # of `TZInfo::Data::Indexes::Countries` by {CountryIndexDefinition} to allow # the zones of a country to be specified. # # @private class CountryDefiner < Format2::CountryDefiner #:nodoc: # Initializes a new {CountryDefiner}. def initialize(identifier_deduper, description_deduper) super(nil, identifier_deduper, description_deduper) end end end end tzinfo-2.0.6/lib/tzinfo/format1/country_index_definition.rb000066400000000000000000000037231436527530500241260ustar00rootroot00000000000000# encoding: UTF-8 module TZInfo module Format1 # The format 1 TZInfo::Data country index file includes # {Format1::CountryIndexDefinition}, which provides a # {CountryIndexDefinition::ClassMethods#country country} method used to # define each country in the index. # # @private module CountryIndexDefinition #:nodoc: # Adds class methods to the includee and initializes class instance # variables. # # @param base [Module] the includee. def self.append_features(base) super base.extend(ClassMethods) base.instance_eval { @countries = {} } end # Class methods for inclusion. # # @private module ClassMethods #:nodoc: # @return [Hash] a frozen `Hash` # of all the countries that have been defined in the index keyed by # their codes. def countries @description_deduper = nil @countries.freeze end private # Defines a country with an ISO 3166-1 alpha-2 country code and name. # # @param code [String] the ISO 3166-1 alpha-2 country code. # @param name [String] the name of the country. # @yield [definer] (optional) to obtain the time zones for the country. # @yieldparam definer [CountryDefiner] a {CountryDefiner} instance. def country(code, name) @description_deduper ||= StringDeduper.new zones = if block_given? definer = CountryDefiner.new(StringDeduper.global, @description_deduper) yield definer definer.timezones else [] end @countries[code.freeze] = DataSources::CountryInfo.new(code, name, zones) end end end end # Alias used by TZInfo::Data format1 releases. # # @private CountryIndexDefinition = Format1::CountryIndexDefinition #:nodoc: private_constant :CountryIndexDefinition end tzinfo-2.0.6/lib/tzinfo/format1/timezone_definer.rb000066400000000000000000000063171436527530500223540ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true module TZInfo module Format1 # Instances of {Format1::TimezoneDefiner} are yielded to TZInfo::Data # format 1 modules by {TimezoneDefinition} to allow the offsets and # transitions of the time zone to be specified. # # @private class TimezoneDefiner < Format2::TimezoneDefiner #:nodoc: undef_method :subsequent_rules # Defines an offset. # # @param id [Symbol] an arbitrary value used identify the offset in # subsequent calls to transition. It must be unique. # @param utc_offset [Integer] the base offset from UTC of the zone in # seconds. This does not include daylight savings time. # @param std_offset [Integer] the daylight savings offset from the base # offset in seconds. Typically either 0 or 3600. # @param abbreviation [Symbol] an abbreviation for the offset, for # example, `:EST` or `:EDT`. # @raise [ArgumentError] if another offset has already been defined with # the given id. def offset(id, utc_offset, std_offset, abbreviation) super(id, utc_offset, std_offset, abbreviation.to_s) end # Defines a transition to a given offset. # # Transitions must be defined in increasing time order. # # @param year [Integer] the UTC year in which the transition occurs. Used # in earlier versions of TZInfo, but now ignored. # @param month [Integer] the UTC month in which the transition occurs. # Used in earlier versions of TZInfo, but now ignored. # @param offset_id [Symbol] references the id of a previously defined # offset (see #offset). # @param timestamp_value [Integer] the time the transition occurs as an # Integer number of seconds since 1970-01-01 00:00:00 UTC ignoring leap # seconds (i.e. each day is treated as if it were 86,400 seconds long). # @param datetime_numerator [Integer] the time of the transition as the # numerator of the `Rational` returned by `DateTime#ajd`. Used in # earlier versions of TZInfo, but now ignored. # @param datetime_denominator [Integer] the time of the transition as the # denominator of the `Rational` returned by `DateTime#ajd`. Used in # earlier versions of TZInfo, but now ignored. # @raise [ArgumentError] if `offset_id` does not reference a defined # offset. # @raise [ArgumentError] if `timestamp_value` is not greater than the # `timestamp_value` of the previously defined transition. # @raise [ArgumentError] if `datetime_numerator` is specified, but # `datetime_denominator` is not. In older versions of TZInfo, it was # possible to define a transition with the `DateTime` numerator as the # 4th parameter and the denominator as the 5th parameter. This style of # definition is not used in released versions of TZInfo::Data. def transition(year, month, offset_id, timestamp_value, datetime_numerator = nil, datetime_denominator = nil) raise ArgumentError, 'DateTime-only transitions are not supported' if datetime_numerator && !datetime_denominator super(offset_id, timestamp_value) end end end end tzinfo-2.0.6/lib/tzinfo/format1/timezone_definition.rb000066400000000000000000000017721436527530500230700ustar00rootroot00000000000000# encoding: UTF-8 module TZInfo module Format1 # {Format1::TimezoneDefinition} is included into format 1 time zone # definition modules and provides the methods for defining time zones. # # @private module TimezoneDefinition #:nodoc: # Adds class methods to the includee. # # @param base [Module] the includee. def self.append_features(base) super base.extend(Format2::TimezoneDefinition::ClassMethods) base.extend(ClassMethods) end # Class methods for inclusion. # # @private module ClassMethods #:nodoc: private # @return the class to be instantiated and yielded by # {Format2::TimezoneDefinition::ClassMethods#timezone}. def timezone_definer_class TimezoneDefiner end end end end # Alias used by TZInfo::Data format1 releases. # # @private TimezoneDefinition = Format1::TimezoneDefinition #:nodoc: private_constant :TimezoneDefinition end tzinfo-2.0.6/lib/tzinfo/format1/timezone_index_definition.rb000066400000000000000000000044221436527530500242520ustar00rootroot00000000000000# encoding: UTF-8 module TZInfo module Format1 # The format 1 TZInfo::Data time zone index file includes # {Format1::TimezoneIndexDefinition}, which provides methods used to define # time zones in the index. # # @private module TimezoneIndexDefinition #:nodoc: # Adds class methods to the includee and initializes class instance # variables. # # @param base [Module] the includee. def self.append_features(base) super base.extend(ClassMethods) base.instance_eval do @timezones = [] @data_timezones = [] @linked_timezones = [] end end # Class methods for inclusion. # # @private module ClassMethods #:nodoc: # @return [Array] a frozen `Array` containing the identifiers of # all data time zones. Identifiers are sorted according to # `String#<=>`. def data_timezones unless @data_timezones.frozen? @data_timezones = @data_timezones.sort.freeze end @data_timezones end # @return [Array] a frozen `Array` containing the identifiers of # all linked time zones. Identifiers are sorted according to # `String#<=>`. def linked_timezones unless @linked_timezones.frozen? @linked_timezones = @linked_timezones.sort.freeze end @linked_timezones end private # Adds a data time zone to the index. # # @param identifier [String] the time zone identifier. def timezone(identifier) identifier = StringDeduper.global.dedupe(identifier) @timezones << identifier @data_timezones << identifier end # Adds a linked time zone to the index. # # @param identifier [String] the time zone identifier. def linked_timezone(identifier) identifier = StringDeduper.global.dedupe(identifier) @timezones << identifier @linked_timezones << identifier end end end end # Alias used by TZInfo::Data format 1 releases. # # @private TimezoneIndexDefinition = Format1::TimezoneIndexDefinition #:nodoc: private_constant :TimezoneIndexDefinition end tzinfo-2.0.6/lib/tzinfo/format2.rb000066400000000000000000000002701436527530500170170ustar00rootroot00000000000000# encoding: UTF-8 module TZInfo # Modules and classes used by the format 2 version of TZInfo::Data. # # @private module Format2 #:nodoc: end private_constant :Format2 end tzinfo-2.0.6/lib/tzinfo/format2/000077500000000000000000000000001436527530500164735ustar00rootroot00000000000000tzinfo-2.0.6/lib/tzinfo/format2/country_definer.rb000066400000000000000000000065131436527530500222240ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true module TZInfo module Format2 # Instances of {Format2::CountryDefiner} are yielded to the format 2 version # of `TZInfo::Data::Indexes::Countries` by {CountryIndexDefiner} to allow # the zones of a country to be specified. # # @private class CountryDefiner #:nodoc: # @return [Array] the time zones observed in the country. attr_reader :timezones # Initializes a new {CountryDefiner}. # # @param shared_timezones [Hash] a `Hash` # containing time zones shared by more than one country, keyed by a # unique reference. # @param identifier_deduper [StringDeduper] a {StringDeduper} instance to # use when deduping time zone identifiers. # @param description_deduper [StringDeduper] a {StringDeduper} instance to # use when deduping time zone descriptions. def initialize(shared_timezones, identifier_deduper, description_deduper) @shared_timezones = shared_timezones @identifier_deduper = identifier_deduper @description_deduper = description_deduper @timezones = [] end # @overload timezone(reference) # Defines a time zone of a country as a reference to a pre-defined # shared time zone. # @param reference [Symbol] a reference for a pre-defined shared time # zone. # @overload timezone(identifier, latitude_numerator, latitude_denominator, longitude_numerator, longitude_denominator, description) # Defines a (non-shared) time zone of a country. The latitude and # longitude are given as the numerator and denominator of a `Rational`. # @param identifier [String] the time zone identifier. # @param latitude_numerator [Integer] the numerator of the latitude. # @param latitude_denominator [Integer] the denominator of the latitude. # @param longitude_numerator [Integer] the numerator of the longitude. # @param longitude_denominator [Integer] the denominator of the # longitude. # @param description [String] an optional description for the time zone. def timezone(identifier_or_reference, latitude_numerator = nil, latitude_denominator = nil, longitude_numerator = nil, longitude_denominator = nil, description = nil) if latitude_numerator unless latitude_denominator && longitude_numerator && longitude_denominator raise ArgumentError, 'Either just a reference should be supplied, or the identifier, latitude and longitude must all be specified' end # Dedupe non-frozen literals from format 1 on all Ruby versions and # format 2 on Ruby < 2.3 (without frozen_string_literal support). @timezones << CountryTimezone.new(@identifier_deduper.dedupe(identifier_or_reference), Rational(latitude_numerator, latitude_denominator), Rational(longitude_numerator, longitude_denominator), description && @description_deduper.dedupe(description)) else shared_timezone = @shared_timezones[identifier_or_reference] raise ArgumentError, "Unknown shared timezone: #{identifier_or_reference}" unless shared_timezone @timezones << shared_timezone end end end end end tzinfo-2.0.6/lib/tzinfo/format2/country_index_definer.rb000066400000000000000000000061631436527530500234140ustar00rootroot00000000000000# encoding: UTF-8 module TZInfo module Format2 # Instances of {Format2::CountryIndexDefiner} are yielded to the format 2 # version of `TZInfo::Data::Indexes::Countries` by {CountryIndexDefinition} # to allow countries and their time zones to be specified. # # @private class CountryIndexDefiner #:nodoc: # @return [Hash] a `Hash` of all the countries that # have been defined in the index keyed by their codes. attr_reader :countries # Initializes a new {CountryIndexDefiner}. # # @param identifier_deduper [StringDeduper] a {StringDeduper} instance to # use when deduping time zone identifiers. # @param description_deduper [StringDeduper] a {StringDeduper} instance to # use when deduping time zone descriptions. def initialize(identifier_deduper, description_deduper) @identifier_deduper = identifier_deduper @description_deduper = description_deduper @shared_timezones = {} @countries = {} end # Defines a time zone shared by many countries with an reference for # subsequent use in country definitions. The latitude and longitude are # given as the numerator and denominator of a `Rational`. # # @param reference [Symbol] a unique reference for the time zone. # @param identifier [String] the time zone identifier. # @param latitude_numerator [Integer] the numerator of the latitude. # @param latitude_denominator [Integer] the denominator of the latitude. # @param longitude_numerator [Integer] the numerator of the longitude. # @param longitude_denominator [Integer] the denominator of the longitude. # @param description [String] an optional description for the time zone. def timezone(reference, identifier, latitude_numerator, latitude_denominator, longitude_numerator, longitude_denominator, description = nil) # Dedupe non-frozen literals from format 1 on all Ruby versions and # format 2 on Ruby < 2.3 (without frozen_string_literal support). @shared_timezones[reference] = CountryTimezone.new(@identifier_deduper.dedupe(identifier), Rational(latitude_numerator, latitude_denominator), Rational(longitude_numerator, longitude_denominator), description && @description_deduper.dedupe(description)) end # Defines a country. # # @param code [String] The ISO 3166-1 alpha-2 code of the country. # @param name [String] Then name of the country. # @yield [definer] yields (optional) to obtain the time zones for the # country. # @yieldparam definer [CountryDefiner] a {CountryDefiner} # instance that should be used to specify the time zones of the country. def country(code, name) timezones = if block_given? definer = CountryDefiner.new(@shared_timezones, @identifier_deduper, @description_deduper) yield definer definer.timezones else [] end @countries[code.freeze] = DataSources::CountryInfo.new(code, name, timezones) end end end end tzinfo-2.0.6/lib/tzinfo/format2/country_index_definition.rb000066400000000000000000000026211436527530500241230ustar00rootroot00000000000000# encoding: UTF-8 module TZInfo module Format2 # The format 2 country index file includes # {Format2::CountryIndexDefinition}, which provides a # {CountryIndexDefinition::ClassMethods#country_index country_index} method # used to define the country index. # # @private module CountryIndexDefinition #:nodoc: # Adds class methods to the includee and initializes class instance # variables. # # @param base [Module] the includee. def self.append_features(base) super base.extend(ClassMethods) base.instance_eval { @countries = {}.freeze } end # Class methods for inclusion. # # @private module ClassMethods #:nodoc: # @return [Hash] a frozen `Hash` # of all the countries that have been defined in the index keyed by # their codes. attr_reader :countries private # Defines the index. # # @yield [definer] yields to allow the index to be defined. # @yieldparam definer [CountryIndexDefiner] a {CountryIndexDefiner} # instance that should be used to define the index. def country_index definer = CountryIndexDefiner.new(StringDeduper.global, StringDeduper.new) yield definer @countries = definer.countries.freeze end end end end end tzinfo-2.0.6/lib/tzinfo/format2/timezone_definer.rb000066400000000000000000000076221436527530500223550ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true module TZInfo module Format2 # Instances of {TimezoneDefiner} are yielded to TZInfo::Data modules by # {TimezoneDefinition} to allow the offsets and transitions of the time zone # to be specified. # # @private class TimezoneDefiner #:nodoc: # @return [Array] the defined transitions of the time # zone. attr_reader :transitions # Initializes a new TimezoneDefiner. # # @param string_deduper [StringDeduper] a {StringDeduper} instance to use # when deduping abbreviations. def initialize(string_deduper) @string_deduper = string_deduper @offsets = {} @transitions = [] end # Returns the first offset to be defined or `nil` if no offsets have been # defined. The first offset is observed before the time of the first # transition. # # @return [TimezoneOffset] the first offset to be defined or `nil` if no # offsets have been defined. def first_offset first = @offsets.first first && first.last end # Defines an offset. # # @param id [Symbol] an arbitrary value used identify the offset in # subsequent calls to transition. It must be unique. # @param base_utc_offset [Integer] the base offset from UTC of the zone in # seconds. This does not include daylight savings time. # @param std_offset [Integer] the daylight savings offset from the base # offset in seconds. Typically either 0 or 3600. # @param abbreviation [String] an abbreviation for the offset, for # example, EST or EDT. # @raise [ArgumentError] if another offset has already been defined with # the given id. def offset(id, base_utc_offset, std_offset, abbreviation) raise ArgumentError, 'An offset has already been defined with the given id' if @offsets.has_key?(id) # Dedupe non-frozen literals from format 1 on all Ruby versions and # format 2 on Ruby < 2.3 (without frozen_string_literal support). abbreviation = @string_deduper.dedupe(abbreviation) offset = TimezoneOffset.new(base_utc_offset, std_offset, abbreviation) @offsets[id] = offset @previous_offset ||= offset end # Defines a transition to a given offset. # # Transitions must be defined in increasing time order. # # @param offset_id [Symbol] references the id of a previously defined # offset. # @param timestamp_value [Integer] the time the transition occurs as a # number of seconds since 1970-01-01 00:00:00 UTC ignoring leap seconds # (i.e. each day is treated as if it were 86,400 seconds long). # @raise [ArgumentError] if `offset_id` does not reference a defined # offset. # @raise [ArgumentError] if `timestamp_value` is not greater than the # `timestamp_value` of the previously defined transition. def transition(offset_id, timestamp_value) offset = @offsets[offset_id] raise ArgumentError, 'offset_id has not been defined' unless offset raise ArgumentError, 'timestamp is not greater than the timestamp of the previously defined transition' if !@transitions.empty? && @transitions.last.timestamp_value >= timestamp_value @transitions << TimezoneTransition.new(offset, @previous_offset, timestamp_value) @previous_offset = offset end # Defines the rules that will be used for handling instants after the last # transition. # # This method is currently just a placeholder for forward compatibility # that accepts and ignores any arguments passed. # # Support for subsequent rules will be added in a future version of TZInfo # and the rules will be included in format 2 releases of TZInfo::Data. def subsequent_rules(*args) end end end end tzinfo-2.0.6/lib/tzinfo/format2/timezone_definition.rb000066400000000000000000000050031436527530500230600ustar00rootroot00000000000000# encoding: UTF-8 module TZInfo module Format2 # {Format2::TimezoneDefinition} is included into format 2 time zone # definition modules and provides methods for defining time zones. # # @private module TimezoneDefinition #:nodoc: # Adds class methods to the includee. # # @param base [Module] the includee. def self.append_features(base) super base.extend(ClassMethods) end # Class methods for inclusion. # # @private module ClassMethods #:nodoc: # @return [TimezoneInfo] the last time zone to be defined. def get @timezone end private # @return [Class] the class to be instantiated and yielded by # {#timezone}. def timezone_definer_class TimezoneDefiner end # Defines a data time zone. # # @param identifier [String] the identifier of the time zone. # @yield [definer] yields to the caller to define the time zone. # @yieldparam definer [Object] an instance of the class returned by # {#timezone_definer_class}, typically {TimezoneDefiner}. def timezone(identifier) # Dedupe non-frozen literals from format 1 on all Ruby versions and # format 2 on Ruby < 2.3 (without frozen_string_literal support). string_deduper = StringDeduper.global identifier = string_deduper.dedupe(identifier) definer = timezone_definer_class.new(string_deduper) yield definer transitions = definer.transitions @timezone = if transitions.empty? DataSources::ConstantOffsetDataTimezoneInfo.new(identifier, definer.first_offset) else DataSources::TransitionsDataTimezoneInfo.new(identifier, transitions) end end # Defines a linked time zone. # # @param identifier [String] the identifier of the time zone being # defined. # @param link_to_identifier [String] the identifier the new time zone # links to (is an alias for). def linked_timezone(identifier, link_to_identifier) # Dedupe non-frozen literals from format 1 on all Ruby versions and # format 2 on Ruby < 2.3 (without frozen_string_literal support). string_deduper = StringDeduper.global @timezone = DataSources::LinkedTimezoneInfo.new(string_deduper.dedupe(identifier), string_deduper.dedupe(link_to_identifier)) end end end end end tzinfo-2.0.6/lib/tzinfo/format2/timezone_index_definer.rb000066400000000000000000000030121436527530500235310ustar00rootroot00000000000000# encoding: UTF-8 module TZInfo module Format2 # Instances of {TimezoneIndexDefiner} are yielded by # {TimezoneIndexDefinition} to allow the time zone index to be defined. # # @private class TimezoneIndexDefiner #:nodoc: # @return [Array] the identifiers of all data time zones. attr_reader :data_timezones # @return [Array] the identifiers of all linked time zones. attr_reader :linked_timezones # Initializes a new TimezoneDefiner. # # @param string_deduper [StringDeduper] a {StringDeduper} instance to use # when deduping identifiers. def initialize(string_deduper) @string_deduper = string_deduper @data_timezones = [] @linked_timezones = [] end # Adds a data time zone to the index. # # @param identifier [String] the time zone identifier. def data_timezone(identifier) # Dedupe non-frozen literals from format 1 on all Ruby versions and # format 2 on Ruby < 2.3 (without frozen_string_literal support). @data_timezones << @string_deduper.dedupe(identifier) end # Adds a linked time zone to the index. # # @param identifier [String] the time zone identifier. def linked_timezone(identifier) # Dedupe non-frozen literals from format 1 on all Ruby versions and # format 2 on Ruby < 2.3 (without frozen_string_literal support). @linked_timezones << @string_deduper.dedupe(identifier) end end end end tzinfo-2.0.6/lib/tzinfo/format2/timezone_index_definition.rb000066400000000000000000000034401436527530500242520ustar00rootroot00000000000000# encoding: UTF-8 module TZInfo module Format2 # The format 2 time zone index file includes {TimezoneIndexDefinition}, # which provides the {TimezoneIndexDefinition::ClassMethods#timezone_index # timezone_index} method used to define the index. # # @private module TimezoneIndexDefinition #:nodoc: # Adds class methods to the includee and initializes class instance # variables. # # @param base [Module] the includee. def self.append_features(base) super base.extend(ClassMethods) base.instance_eval do empty = [].freeze @timezones = empty @data_timezones = empty @linked_timezones = empty end end # Class methods for inclusion. # # @private module ClassMethods #:nodoc: # @return [Array] a frozen `Array` containing the identifiers of # all data time zones. Identifiers are sorted according to # `String#<=>`. attr_reader :data_timezones # @return [Array] a frozen `Array` containing the identifiers of # all linked time zones. Identifiers are sorted according to # `String#<=>`. attr_reader :linked_timezones # Defines the index. # # @yield [definer] yields to the caller to allow the index to be # defined. # @yieldparam definer [TimezoneIndexDefiner] a {TimezoneIndexDefiner} # instance that should be used to define the index. def timezone_index definer = TimezoneIndexDefiner.new(StringDeduper.global) yield definer @data_timezones = definer.data_timezones.sort!.freeze @linked_timezones = definer.linked_timezones.sort!.freeze end end end end end tzinfo-2.0.6/lib/tzinfo/info_timezone.rb000066400000000000000000000015211436527530500203120ustar00rootroot00000000000000# encoding: UTF-8 module TZInfo # A {Timezone} based on a {DataSources::TimezoneInfo}. # # @abstract class InfoTimezone < Timezone # Initializes a new {InfoTimezone}. # # {InfoTimezone} instances should not normally be created directly. Use # the {Timezone.get} method to obtain {Timezone} instances. # # @param info [DataSources::TimezoneInfo] a {DataSources::TimezoneInfo} # instance supplied by a {DataSource} that will be used as the source of # data for this {InfoTimezone}. def initialize(info) super() @info = info end # (see Timezone#identifier) def identifier @info.identifier end protected # @return [DataSources::TimezoneInfo] the {DataSources::TimezoneInfo} this # {InfoTimezone} is based on. def info @info end end end tzinfo-2.0.6/lib/tzinfo/linked_timezone.rb000066400000000000000000000025501436527530500206300ustar00rootroot00000000000000# encoding: UTF-8 module TZInfo # Represents time zones that are defined as a link to or alias for another # time zone. class LinkedTimezone < InfoTimezone # Initializes a new {LinkedTimezone}. # # {LinkedTimezone} instances should not normally be created directly. Use # the {Timezone.get} method to obtain {Timezone} instances. # # @param info [DataSources::LinkedTimezoneInfo] a # {DataSources::LinkedTimezoneInfo} instance supplied by a {DataSource} # that will be used as the source of data for this {LinkedTimezone}. def initialize(info) super @linked_timezone = Timezone.get(info.link_to_identifier) end # (see Timezone#period_for) def period_for(time) @linked_timezone.period_for(time) end # (see Timezone#periods_for_local) def periods_for_local(local_time) @linked_timezone.periods_for_local(local_time) end # (see Timezone#transitions_up_to) def transitions_up_to(to, from = nil) @linked_timezone.transitions_up_to(to, from) end # Returns the canonical {Timezone} instance for this {LinkedTimezone}. # # For a {LinkedTimezone}, this is the canonical zone of the link target. # # @return [Timezone] the canonical {Timezone} instance for this {Timezone}. def canonical_zone @linked_timezone.canonical_zone end end end tzinfo-2.0.6/lib/tzinfo/offset_timezone_period.rb000066400000000000000000000024151436527530500222120ustar00rootroot00000000000000# encoding: UTF-8 module TZInfo # Represents the infinite period of time in a time zone that constantly # observes the same offset from UTC (has an unbounded start and end). class OffsetTimezonePeriod < TimezonePeriod # Initializes an {OffsetTimezonePeriod}. # # @param offset [TimezoneOffset] the offset that is constantly observed. # @raise [ArgumentError] if `offset` is `nil`. def initialize(offset) super end # @return [TimezoneTransition] the transition that defines the start of this # {TimezonePeriod}, always `nil` for {OffsetTimezonePeriod}. def start_transition nil end # @return [TimezoneTransition] the transition that defines the end of this # {TimezonePeriod}, always `nil` for {OffsetTimezonePeriod}. def end_transition nil end # Determines if this {OffsetTimezonePeriod} is equal to another instance. # # @param p [Object] the instance to test for equality. # @return [Boolean] `true` if `p` is a {OffsetTimezonePeriod} with the same # {offset}, otherwise `false`. def ==(p) p.kind_of?(OffsetTimezonePeriod) && offset == p.offset end alias eql? == # @return [Integer] a hash based on {offset}. def hash offset.hash end end end tzinfo-2.0.6/lib/tzinfo/ruby_core_support.rb000066400000000000000000000017551436527530500212430ustar00rootroot00000000000000module TZInfo # Methods to support different versions of Ruby. # # @private module RubyCoreSupport #:nodoc: class << self # Object#untaint is deprecated and becomes a no-op in Ruby >= 2.7. It has # been removed from Ruby 3.2. if !Object.new.respond_to?(:untaint) || RUBY_VERSION =~ /\A(\d+)\.(\d+)(?:\.|\z)/ && ($1 == '2' && $2.to_i >= 7 || $1.to_i >= 3) # :nocov_functional_untaint: # Returns the supplied `Object` # # @param o [Object] the `Object` to untaint. # @return [Object] `o`. def untaint(o) o end # :nocov_functional_untaint: else # :nocov_no_functional_untaint: # Untaints and returns the supplied `Object`. # # @param o [Object] the `Object` to untaint. # @return [Object] `o`. def untaint(o) o.untaint end # :nocov_no_functional_untaint: end end end private_constant :RubyCoreSupport end tzinfo-2.0.6/lib/tzinfo/string_deduper.rb000066400000000000000000000073711436527530500204740ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true require 'concurrent' module TZInfo # Maintains a pool of `String` instances. The {#dedupe} method will return # either a pooled copy of a given `String` or add the instance to the pool. # # @private class StringDeduper #:nodoc: class << self # @return [StringDeduper] a globally available singleton instance of # {StringDeduper}. This instance is safe for use in concurrently # executing threads. attr_reader :global end # Initializes a new {StringDeduper}. def initialize @strings = create_hash do |h, k| v = k.dup.freeze h[v] = v end end # @param string [String] the string to deduplicate. # @return [bool] `string` if it is frozen, otherwise a frozen, possibly # pre-existing copy of `string`. def dedupe(string) return string if string.frozen? @strings[string] end protected # Creates a `Hash` to store pooled `String` instances. # # @param block [Proc] Default value block to be passed to `Hash.new`. # @return [Hash] a `Hash` to store pooled `String` instances. def create_hash(&block) Hash.new(&block) end end private_constant :StringDeduper # A thread-safe version of {StringDeduper}. # # @private class ConcurrentStringDeduper < StringDeduper #:nodoc: protected def create_hash(&block) Concurrent::Map.new(&block) end end private_constant :ConcurrentStringDeduper string_unary_minus_does_dedupe = if '0'.respond_to?(:-@) # :nocov_no_string_-@: s1 = -('0'.dup) s2 = -('0'.dup) s1.object_id == s2.object_id # :nocov_no_string_-@: else # :nocov_string_-@: false # :nocov_string_-@: end if string_unary_minus_does_dedupe # :nocov_no_deduping_string_unary_minus: # An implementation of {StringDeduper} using the `String#-@` method where # that method performs deduplication (Ruby 2.5 and later). # # Note that this is slightly different to the plain {StringDeduper} # implementation. In this implementation, frozen literal strings are already # in the pool and are candidates for being returned, even when passed # another equal frozen non-literal string. {StringDeduper} will always # return frozen strings. # # There are also differences in encoding handling. This implementation will # treat strings with different encodings as different strings. # {StringDeduper} will treat strings with the compatible encodings as the # same string. # # @private class UnaryMinusGlobalStringDeduper #:nodoc: # @param string [String] the string to deduplicate. # @return [bool] `string` if it is frozen, otherwise a frozen, possibly # pre-existing copy of `string`. def dedupe(string) # String#-@ on Ruby 2.6 will dedupe a frozen non-literal String. Ruby # 2.5 will just return frozen strings. # # The pooled implementation can't tell the difference between frozen # literals and frozen non-literals, so must always return frozen String # instances to avoid doing unncessary work when loading format 2 # TZInfo::Data modules. # # For compatibility with the pooled implementation, just return frozen # string instances (acting like Ruby 2.5). return string if string.frozen? -string end end private_constant :UnaryMinusGlobalStringDeduper StringDeduper.instance_variable_set(:@global, UnaryMinusGlobalStringDeduper.new) # :nocov_no_deduping_string_unary_minus: else # :nocov_deduping_string_unary_minus: StringDeduper.instance_variable_set(:@global, ConcurrentStringDeduper.new) # :nocov_deduping_string_unary_minus: end end tzinfo-2.0.6/lib/tzinfo/time_with_offset.rb000066400000000000000000000123261436527530500210110ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true module TZInfo # A subclass of `Time` used to represent local times. {TimeWithOffset} holds a # reference to the related {TimezoneOffset} and overrides various methods to # return results appropriate for the {TimezoneOffset}. Certain operations will # clear the associated {TimezoneOffset} (if the {TimezoneOffset} would not # necessarily be valid for the result). Once the {TimezoneOffset} has been # cleared, {TimeWithOffset} behaves identically to `Time`. # # Arithmetic performed on {TimeWithOffset} instances is _not_ time zone-aware. # Regardless of whether transitions in the time zone are crossed, results of # arithmetic operations will always maintain the same offset from UTC # (`utc_offset`). The associated {TimezoneOffset} will aways be cleared. class TimeWithOffset < Time include WithOffset # @return [TimezoneOffset] the {TimezoneOffset} associated with this # instance. attr_reader :timezone_offset # Marks this {TimeWithOffset} as a local time with the UTC offset of a given # {TimezoneOffset} and sets the associated {TimezoneOffset}. # # @param timezone_offset [TimezoneOffset] the {TimezoneOffset} to use to set # the offset of this {TimeWithOffset}. # @return [TimeWithOffset] `self`. # @raise [ArgumentError] if `timezone_offset` is `nil`. def set_timezone_offset(timezone_offset) raise ArgumentError, 'timezone_offset must be specified' unless timezone_offset localtime(timezone_offset.observed_utc_offset) @timezone_offset = timezone_offset self end # An overridden version of `Time#dst?` that, if there is an associated # {TimezoneOffset}, returns the result of calling {TimezoneOffset#dst? dst?} # on that offset. # # @return [Boolean] `true` if daylight savings time is being observed, # otherwise `false`. def dst? to = timezone_offset to ? to.dst? : super end alias isdst dst? # An overridden version of `Time#getlocal` that clears the associated # {TimezoneOffset} if the base implementation of `getlocal` returns a # {TimeWithOffset}. # # @return [Time] a representation of the {TimeWithOffset} using either the # local time zone or the given offset. def getlocal(*args) # JRuby < 9.3 returns a Time in all cases. # JRuby >= 9.3 returns a Time when called with no arguments and a # TimeWithOffset with a timezone_offset assigned when called with an # offset argument. result = super result.clear_timezone_offset if result.kind_of?(TimeWithOffset) result end # An overridden version of `Time#gmtime` that clears the associated # {TimezoneOffset}. # # @return [TimeWithOffset] `self`. def gmtime super @timezone_offset = nil self end # An overridden version of `Time#localtime` that clears the associated # {TimezoneOffset}. # # @return [TimeWithOffset] `self`. def localtime(*args) super @timezone_offset = nil self end # An overridden version of `Time#round` that, if there is an associated # {TimezoneOffset}, returns a {TimeWithOffset} preserving that offset. # # @return [Time] the rounded time. def round(ndigits = 0) if_timezone_offset(super) {|o,t| self.class.at(t.to_i, t.subsec * 1_000_000).set_timezone_offset(o) } end # An overridden version of `Time#to_a`. The `isdst` (index 8) and `zone` # (index 9) elements of the array are set according to the associated # {TimezoneOffset}. # # @return [Array] an `Array` representation of the {TimeWithOffset}. def to_a if_timezone_offset(super) do |o,a| a[8] = o.dst? a[9] = o.abbreviation a end end # An overridden version of `Time#utc` that clears the associated # {TimezoneOffset}. # # @return [TimeWithOffset] `self`. def utc super @timezone_offset = nil self end # An overridden version of `Time#zone` that, if there is an associated # {TimezoneOffset}, returns the {TimezoneOffset#abbreviation abbreviation} # of that offset. # # @return [String] the {TimezoneOffset#abbreviation abbreviation} of the # associated {TimezoneOffset}, or the result from `Time#zone` if there is # no such offset. def zone to = timezone_offset to ? to.abbreviation : super end # An overridden version of `Time#to_datetime` that, if there is an # associated {TimezoneOffset}, returns a {DateTimeWithOffset} with that # offset. # # @return [DateTime] if there is an associated {TimezoneOffset}, a # {DateTimeWithOffset} representation of this {TimeWithOffset}, otherwise # a `Time` representation. def to_datetime if_timezone_offset(super) do |o,dt| offset = dt.offset result = DateTimeWithOffset.jd(dt.jd + dt.day_fraction - offset) result = result.new_offset(offset) unless offset == 0 result.set_timezone_offset(o) end end protected # Clears the associated {TimezoneOffset}. # # @return [TimeWithOffset] `self`. def clear_timezone_offset @timezone_offset = nil self end end end tzinfo-2.0.6/lib/tzinfo/timestamp.rb000066400000000000000000000564621436527530500174660ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true module TZInfo # A time represented as an `Integer` number of seconds since 1970-01-01 # 00:00:00 UTC (ignoring leap seconds and using the proleptic Gregorian # calendar), the fraction through the second (sub_second as a `Rational`) and # an optional UTC offset. Like Ruby's `Time` class, {Timestamp} can # distinguish between a local time with a zero offset and a time specified # explicitly as UTC. class Timestamp include Comparable # The Unix epoch (1970-01-01 00:00:00 UTC) as a chronological Julian day # number. JD_EPOCH = 2440588 private_constant :JD_EPOCH class << self # Returns a new {Timestamp} representing the (proleptic Gregorian # calendar) date and time specified by the supplied parameters. # # If `utc_offset` is `nil`, `:utc` or 0, the date and time parameters will # be interpreted as representing a UTC date and time. Otherwise the date # and time parameters will be interpreted as a local date and time with # the given offset. # # @param year [Integer] the year. # @param month [Integer] the month (1-12). # @param day [Integer] the day of the month (1-31). # @param hour [Integer] the hour (0-23). # @param minute [Integer] the minute (0-59). # @param second [Integer] the second (0-59). # @param sub_second [Numeric] the fractional part of the second as either # a `Rational` that is greater than or equal to 0 and less than 1, or # the `Integer` 0. # @param utc_offset [Object] either `nil` for a {Timestamp} without a # specified offset, an offset from UTC specified as an `Integer` number # of seconds or the `Symbol` `:utc`). # @return [Timestamp] a new {Timestamp} representing the specified # (proleptic Gregorian calendar) date and time. # @raise [ArgumentError] if either of `year`, `month`, `day`, `hour`, # `minute`, or `second` is not an `Integer`. # @raise [ArgumentError] if `sub_second` is not a `Rational`, or the # `Integer` 0. # @raise [ArgumentError] if `utc_offset` is not `nil`, not an `Integer` # and not the `Symbol` `:utc`. # @raise [RangeError] if `month` is not between 1 and 12. # @raise [RangeError] if `day` is not between 1 and 31. # @raise [RangeError] if `hour` is not between 0 and 23. # @raise [RangeError] if `minute` is not between 0 and 59. # @raise [RangeError] if `second` is not between 0 and 59. # @raise [RangeError] if `sub_second` is a `Rational` but that is less # than 0 or greater than or equal to 1. def create(year, month = 1, day = 1, hour = 0, minute = 0, second = 0, sub_second = 0, utc_offset = nil) raise ArgumentError, 'year must be an Integer' unless year.kind_of?(Integer) raise ArgumentError, 'month must be an Integer' unless month.kind_of?(Integer) raise ArgumentError, 'day must be an Integer' unless day.kind_of?(Integer) raise ArgumentError, 'hour must be an Integer' unless hour.kind_of?(Integer) raise ArgumentError, 'minute must be an Integer' unless minute.kind_of?(Integer) raise ArgumentError, 'second must be an Integer' unless second.kind_of?(Integer) raise RangeError, 'month must be between 1 and 12' if month < 1 || month > 12 raise RangeError, 'day must be between 1 and 31' if day < 1 || day > 31 raise RangeError, 'hour must be between 0 and 23' if hour < 0 || hour > 23 raise RangeError, 'minute must be between 0 and 59' if minute < 0 || minute > 59 raise RangeError, 'second must be between 0 and 59' if second < 0 || second > 59 # Based on days_from_civil from https://howardhinnant.github.io/date_algorithms.html#days_from_civil after_february = month > 2 year -= 1 unless after_february era = year / 400 year_of_era = year - era * 400 day_of_year = (153 * (month + (after_february ? -3 : 9)) + 2) / 5 + day - 1 day_of_era = year_of_era * 365 + year_of_era / 4 - year_of_era / 100 + day_of_year days_since_epoch = era * 146097 + day_of_era - 719468 value = ((days_since_epoch * 24 + hour) * 60 + minute) * 60 + second value -= utc_offset if utc_offset.kind_of?(Integer) new(value, sub_second, utc_offset) end # When used without a block, returns a {Timestamp} representation of a # given `Time`, `DateTime` or {Timestamp}. # # When called with a block, the {Timestamp} representation of `value` is # passed to the block. The block must then return a {Timestamp}, which # will be converted back to the type of the initial value. If the initial # value was a {Timestamp}, the block result will be returned. If the # initial value was a `DateTime`, a Gregorian `DateTime` will be returned. # # The UTC offset of `value` can either be preserved (the {Timestamp} # representation will have the same UTC offset as `value`), ignored (the # {Timestamp} representation will have no defined UTC offset), or treated # as though it were UTC (the {Timestamp} representation will have a # {utc_offset} of 0 and {utc?} will return `true`). # # @param value [Object] a `Time`, `DateTime` or {Timestamp}. # @param offset [Symbol] either `:preserve` to preserve the offset of # `value`, `:ignore` to ignore the offset of `value` and create a # {Timestamp} with an unspecified offset, or `:treat_as_utc` to treat # the offset of `value` as though it were UTC and create a UTC # {Timestamp}. # @yield [timestamp] if a block is provided, the {Timestamp} # representation is passed to the block. # @yieldparam timestamp [Timestamp] the {Timestamp} representation of # `value`. # @yieldreturn [Timestamp] a {Timestamp} to be converted back to the type # of `value`. # @return [Object] if called without a block, the {Timestamp} # representation of `value`, otherwise the result of the block, # converted back to the type of `value`. def for(value, offset = :preserve) raise ArgumentError, 'value must be specified' unless value case offset when :ignore ignore_offset = true target_utc_offset = nil when :treat_as_utc ignore_offset = true target_utc_offset = :utc when :preserve ignore_offset = false target_utc_offset = nil else raise ArgumentError, 'offset must be :preserve, :ignore or :treat_as_utc' end time_like = false timestamp = case value when Time for_time(value, ignore_offset, target_utc_offset) when DateTime for_datetime(value, ignore_offset, target_utc_offset) when Timestamp for_timestamp(value, ignore_offset, target_utc_offset) else raise ArgumentError, "#{value.class} values are not supported" unless is_time_like?(value) time_like = true for_time_like(value, ignore_offset, target_utc_offset) end if block_given? result = yield timestamp raise ArgumentError, 'block must return a Timestamp' unless result.kind_of?(Timestamp) case value when Time result.to_time when DateTime result.to_datetime else # A Time-like value or a Timestamp time_like ? result.to_time : result end else timestamp end end # Creates a new UTC {Timestamp}. # # @param value [Integer] the number of seconds since 1970-01-01 00:00:00 # UTC ignoring leap seconds. # @param sub_second [Numeric] the fractional part of the second as either # a `Rational` that is greater than or equal to 0 and less than 1, or # the `Integer` 0. # @raise [ArgumentError] if `value` is not an `Integer`. # @raise [ArgumentError] if `sub_second` is not a `Rational`, or the # `Integer` 0. # @raise [RangeError] if `sub_second` is a `Rational` but that is less # than 0 or greater than or equal to 1. def utc(value, sub_second = 0) new(value, sub_second, :utc) end private # Constructs a new instance of `self` (i.e. {Timestamp} or a subclass of # {Timestamp}) without validating the parameters. This method is used # internally within {Timestamp} to avoid the overhead of checking # parameters. # # @param value [Integer] the number of seconds since 1970-01-01 00:00:00 # UTC ignoring leap seconds. # @param sub_second [Numeric] the fractional part of the second as either # a `Rational` that is greater than or equal to 0 and less than 1, or # the `Integer` 0. # @param utc_offset [Object] either `nil` for a {Timestamp} without a # specified offset, an offset from UTC specified as an `Integer` number # of seconds or the `Symbol` `:utc`). # @return [Timestamp] a new instance of `self`. def new!(value, sub_second = 0, utc_offset = nil) result = allocate result.send(:initialize!, value, sub_second, utc_offset) result end # Creates a {Timestamp} that represents a given `Time`, optionally # ignoring the offset. # # @param time [Time] a `Time`. # @param ignore_offset [Boolean] whether to ignore the offset of `time`. # @param target_utc_offset [Object] if `ignore_offset` is `true`, the UTC # offset of the result (`:utc`, `nil` or an `Integer`). # @return [Timestamp] the {Timestamp} representation of `time`. def for_time(time, ignore_offset, target_utc_offset) value = time.to_i sub_second = time.subsec if ignore_offset utc_offset = target_utc_offset value += time.utc_offset elsif time.utc? utc_offset = :utc else utc_offset = time.utc_offset end new!(value, sub_second, utc_offset) end # Creates a {Timestamp} that represents a given `DateTime`, optionally # ignoring the offset. # # @param datetime [DateTime] a `DateTime`. # @param ignore_offset [Boolean] whether to ignore the offset of # `datetime`. # @param target_utc_offset [Object] if `ignore_offset` is `true`, the UTC # offset of the result (`:utc`, `nil` or an `Integer`). # @return [Timestamp] the {Timestamp} representation of `datetime`. def for_datetime(datetime, ignore_offset, target_utc_offset) value = (datetime.jd - JD_EPOCH) * 86400 + datetime.sec + datetime.min * 60 + datetime.hour * 3600 sub_second = datetime.sec_fraction if ignore_offset utc_offset = target_utc_offset else utc_offset = (datetime.offset * 86400).to_i value -= utc_offset end new!(value, sub_second, utc_offset) end # Returns a {Timestamp} that represents another {Timestamp}, optionally # ignoring the offset. If the result would be identical to `value`, the # same instance is returned. If the passed in value is an instance of a # subclass of {Timestamp}, then a new {Timestamp} will always be returned. # # @param timestamp [Timestamp] a {Timestamp}. # @param ignore_offset [Boolean] whether to ignore the offset of # `timestamp`. # @param target_utc_offset [Object] if `ignore_offset` is `true`, the UTC # offset of the result (`:utc`, `nil` or an `Integer`). # @return [Timestamp] a [Timestamp] representation of `timestamp`. def for_timestamp(timestamp, ignore_offset, target_utc_offset) if ignore_offset if target_utc_offset unless target_utc_offset == :utc && timestamp.utc? || timestamp.utc_offset == target_utc_offset return new!(timestamp.value + (timestamp.utc_offset || 0), timestamp.sub_second, target_utc_offset) end elsif timestamp.utc_offset return new!(timestamp.value + timestamp.utc_offset, timestamp.sub_second) end end unless timestamp.instance_of?(Timestamp) # timestamp is identical in value, sub_second and utc_offset but is a # subclass (i.e. TimestampWithOffset). Return a new Timestamp # instance. return new!(timestamp.value, timestamp.sub_second, timestamp.utc? ? :utc : timestamp.utc_offset) end timestamp end # Determines if an object is like a `Time` (for the purposes of converting # to a {Timestamp} with {for}), responding to `to_i` and `subsec`. # # @param value [Object] an object to test. # @return [Boolean] `true` if the object is `Time`-like, otherwise # `false`. def is_time_like?(value) value.respond_to?(:to_i) && value.respond_to?(:subsec) end # Creates a {Timestamp} that represents a given `Time`-like object, # optionally ignoring the offset (if the `time_like` responds to # `utc_offset`). # # @param time_like [Object] a `Time`-like object. # @param ignore_offset [Boolean] whether to ignore the offset of `time`. # @param target_utc_offset [Object] if `ignore_offset` is `true`, the UTC # offset of the result (`:utc`, `nil` or an `Integer`). # @return [Timestamp] the {Timestamp} representation of `time_like`. def for_time_like(time_like, ignore_offset, target_utc_offset) value = time_like.to_i sub_second = time_like.subsec.to_r if ignore_offset utc_offset = target_utc_offset value += time_like.utc_offset.to_i if time_like.respond_to?(:utc_offset) elsif time_like.respond_to?(:utc_offset) utc_offset = time_like.utc_offset.to_i else utc_offset = 0 end new(value, sub_second, utc_offset) end end # @return [Integer] the number of seconds since 1970-01-01 00:00:00 UTC # ignoring leap seconds (i.e. each day is treated as if it were 86,400 # seconds long). attr_reader :value # @return [Numeric] the fraction of a second elapsed since timestamp as # either a `Rational` or the `Integer` 0. Always greater than or equal to # 0 and less than 1. attr_reader :sub_second # @return [Integer] the offset from UTC in seconds or `nil` if the # {Timestamp} doesn't have a specified offset. attr_reader :utc_offset # Initializes a new {Timestamp}. # # @param value [Integer] the number of seconds since 1970-01-01 00:00:00 UTC # ignoring leap seconds. # @param sub_second [Numeric] the fractional part of the second as either a # `Rational` that is greater than or equal to 0 and less than 1, or # the `Integer` 0. # @param utc_offset [Object] either `nil` for a {Timestamp} without a # specified offset, an offset from UTC specified as an `Integer` number of # seconds or the `Symbol` `:utc`). # @raise [ArgumentError] if `value` is not an `Integer`. # @raise [ArgumentError] if `sub_second` is not a `Rational`, or the # `Integer` 0. # @raise [RangeError] if `sub_second` is a `Rational` but that is less # than 0 or greater than or equal to 1. # @raise [ArgumentError] if `utc_offset` is not `nil`, not an `Integer` and # not the `Symbol` `:utc`. def initialize(value, sub_second = 0, utc_offset = nil) raise ArgumentError, 'value must be an Integer' unless value.kind_of?(Integer) raise ArgumentError, 'sub_second must be a Rational or the Integer 0' unless (sub_second.kind_of?(Integer) && sub_second == 0) || sub_second.kind_of?(Rational) raise RangeError, 'sub_second must be >= 0 and < 1' if sub_second < 0 || sub_second >= 1 raise ArgumentError, 'utc_offset must be an Integer, :utc or nil' if utc_offset && utc_offset != :utc && !utc_offset.kind_of?(Integer) initialize!(value, sub_second, utc_offset) end # @return [Boolean] `true` if this {Timestamp} represents UTC, `false` if # the {Timestamp} wasn't specified as UTC or `nil` if the {Timestamp} has # no specified offset. def utc? @utc end # Adds a number of seconds to the {Timestamp} value, setting the UTC offset # of the result. # # @param seconds [Integer] the number of seconds to be added. # @param utc_offset [Object] either `nil` for a {Timestamp} without a # specified offset, an offset from UTC specified as an `Integer` number of # seconds or the `Symbol` `:utc`). # @return [Timestamp] the result of adding `seconds` to the # {Timestamp} value as a new {Timestamp} instance with the chosen # `utc_offset`. # @raise [ArgumentError] if `seconds` is not an `Integer`. # @raise [ArgumentError] if `utc_offset` is not `nil`, not an `Integer` and # not the `Symbol` `:utc`. def add_and_set_utc_offset(seconds, utc_offset) raise ArgumentError, 'seconds must be an Integer' unless seconds.kind_of?(Integer) raise ArgumentError, 'utc_offset must be an Integer, :utc or nil' if utc_offset && utc_offset != :utc && !utc_offset.kind_of?(Integer) return self if seconds == 0 && utc_offset == (@utc ? :utc : @utc_offset) Timestamp.send(:new!, @value + seconds, @sub_second, utc_offset) end # @return [Timestamp] a UTC {Timestamp} equivalent to this instance. Returns # `self` if {#utc? self.utc?} is `true`. def utc return self if @utc Timestamp.send(:new!, @value, @sub_second, :utc) end # Converts this {Timestamp} to a `Time`. # # @return [Time] a `Time` representation of this {Timestamp}. If the UTC # offset of this {Timestamp} is not specified, a UTC `Time` will be # returned. def to_time time = new_time if @utc_offset && !@utc time.localtime(@utc_offset) else time.utc end end # Converts this {Timestamp} to a Gregorian `DateTime`. # # @return [DateTime] a Gregorian `DateTime` representation of this # {Timestamp}. If the UTC offset of this {Timestamp} is not specified, a # UTC `DateTime` will be returned. def to_datetime new_datetime end # Converts this {Timestamp} to an `Integer` number of seconds since # 1970-01-01 00:00:00 UTC (ignoring leap seconds). # # @return [Integer] an `Integer` representation of this {Timestamp} (the # number of seconds since 1970-01-01 00:00:00 UTC ignoring leap seconds). def to_i value end # Formats this {Timestamp} according to the directives in the given format # string. # # @param format [String] the format string. Please refer to `Time#strftime` # for a list of supported format directives. # @return [String] the formatted {Timestamp}. # @raise [ArgumentError] if `format` is not specified. def strftime(format) raise ArgumentError, 'format must be specified' unless format to_time.strftime(format) end # @return [String] a `String` representation of this {Timestamp}. def to_s return value_and_sub_second_to_s unless @utc_offset return "#{value_and_sub_second_to_s} UTC" if @utc sign = @utc_offset >= 0 ? '+' : '-' min, sec = @utc_offset.abs.divmod(60) hour, min = min.divmod(60) "#{value_and_sub_second_to_s(@utc_offset)} #{sign}#{'%02d' % hour}:#{'%02d' % min}#{sec > 0 ? ':%02d' % sec : nil}#{@utc_offset != 0 ? " (#{value_and_sub_second_to_s} UTC)" : nil}" end # Compares this {Timestamp} with another. # # {Timestamp} instances without a defined UTC offset are not comparable with # {Timestamp} instances that have a defined UTC offset. # # @param t [Timestamp] the {Timestamp} to compare this instance with. # @return [Integer] -1, 0 or 1 depending if this instance is earlier, equal # or later than `t` respectively. Returns `nil` when comparing a # {Timestamp} that does not have a defined UTC offset with a {Timestamp} # that does have a defined UTC offset. Returns `nil` if `t` is not a # {Timestamp}. def <=>(t) return nil unless t.kind_of?(Timestamp) return nil if utc_offset && !t.utc_offset return nil if !utc_offset && t.utc_offset result = value <=> t.value result = sub_second <=> t.sub_second if result == 0 result end alias eql? == # @return [Integer] a hash based on the value, sub-second and whether there # is a defined UTC offset. def hash [@value, @sub_second, !!@utc_offset].hash end # @return [String] the internal object state as a programmer-readable # `String`. def inspect "#<#{self.class}: @value=#{@value}, @sub_second=#{@sub_second}, @utc_offset=#{@utc_offset.inspect}, @utc=#{@utc.inspect}>" end protected # Creates a new instance of a `Time` or `Time`-like class matching the # {value} and {sub_second} of this {Timestamp}, but not setting the offset. # # @param klass [Class] the class to instantiate. # # @private def new_time(klass = Time) klass.at(@value, @sub_second * 1_000_000) end # Constructs a new instance of a `DateTime` or `DateTime`-like class with # the same {value}, {sub_second} and {utc_offset} as this {Timestamp}. # # @param klass [Class] the class to instantiate. # # @private def new_datetime(klass = DateTime) # Can't specify the start parameter unless the jd parameter is an exact number of days. # Use #gregorian instead. datetime = klass.jd(JD_EPOCH + ((@value.to_r + @sub_second) / 86400)).gregorian @utc_offset && @utc_offset != 0 ? datetime.new_offset(Rational(@utc_offset, 86400)) : datetime end private # Converts the value and sub-seconds to a `String`, adding on the given # offset. # # @param offset [Integer] the offset to add to the value. # @return [String] the value and sub-seconds. def value_and_sub_second_to_s(offset = 0) "#{@value + offset}#{sub_second_to_s}" end # Converts the {sub_second} value to a `String` suitable for appending to # the `String` representation of a {Timestamp}. # # @return [String] a `String` representation of {sub_second}. def sub_second_to_s if @sub_second == 0 '' else " #{@sub_second.numerator}/#{@sub_second.denominator}" end end # Initializes a new {Timestamp} without validating the parameters. This # method is used internally within {Timestamp} to avoid the overhead of # checking parameters. # # @param value [Integer] the number of seconds since 1970-01-01 00:00:00 UTC # ignoring leap seconds. # @param sub_second [Numeric] the fractional part of the second as either a # `Rational` that is greater than or equal to 0 and less than 1, or the # `Integer` 0. # @param utc_offset [Object] either `nil` for a {Timestamp} without a # specified offset, an offset from UTC specified as an `Integer` number of # seconds or the `Symbol` `:utc`). def initialize!(value, sub_second = 0, utc_offset = nil) @value = value # Convert Rational(0,1) to 0. @sub_second = sub_second == 0 ? 0 : sub_second if utc_offset @utc = utc_offset == :utc @utc_offset = @utc ? 0 : utc_offset else @utc = @utc_offset = nil end end end end tzinfo-2.0.6/lib/tzinfo/timestamp_with_offset.rb000066400000000000000000000071561436527530500220630ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true module TZInfo # A subclass of {Timestamp} used to represent local times. # {TimestampWithOffset} holds a reference to the related {TimezoneOffset} and # overrides various methods to return results appropriate for the # {TimezoneOffset}. Certain operations will clear the associated # {TimezoneOffset} (if the {TimezoneOffset} would not necessarily be valid for # the result). Once the {TimezoneOffset} has been cleared, # {TimestampWithOffset} behaves identically to {Timestamp}. class TimestampWithOffset < Timestamp include WithOffset # @return [TimezoneOffset] the {TimezoneOffset} associated with this # instance. attr_reader :timezone_offset # Creates a new {TimestampWithOffset} from a given {Timestamp} and # {TimezoneOffset}. # # @param timestamp [Timestamp] a {Timestamp}. # @param timezone_offset [TimezoneOffset] a {TimezoneOffset} valid at the # time of `timestamp`. # @return [TimestampWithOffset] a {TimestampWithOffset} that has the same # {value value} and {sub_second sub_second} as the `timestamp` parameter, # a {utc_offset utc_offset} equal to the # {TimezoneOffset#observed_utc_offset observed_utc_offset} of the # `timezone_offset` parameter and {timezone_offset timezone_offset} set to # the `timezone_offset` parameter. # @raise [ArgumentError] if `timestamp` or `timezone_offset` is `nil`. def self.set_timezone_offset(timestamp, timezone_offset) raise ArgumentError, 'timestamp must be specified' unless timestamp raise ArgumentError, 'timezone_offset must be specified' unless timezone_offset new!(timestamp.value, timestamp.sub_second, timezone_offset.observed_utc_offset).set_timezone_offset(timezone_offset) end # Sets the associated {TimezoneOffset} of this {TimestampWithOffset}. # # @param timezone_offset [TimezoneOffset] a {TimezoneOffset} valid at the time # and for the offset of this {TimestampWithOffset}. # @return [TimestampWithOffset] `self`. # @raise [ArgumentError] if `timezone_offset` is `nil`. # @raise [ArgumentError] if {utc? self.utc?} is `true`. # @raise [ArgumentError] if `timezone_offset.observed_utc_offset` does not equal # `self.utc_offset`. def set_timezone_offset(timezone_offset) raise ArgumentError, 'timezone_offset must be specified' unless timezone_offset raise ArgumentError, 'timezone_offset.observed_utc_offset does not match self.utc_offset' if utc? || utc_offset != timezone_offset.observed_utc_offset @timezone_offset = timezone_offset self end # An overridden version of {Timestamp#to_time} that, if there is an # associated {TimezoneOffset}, returns a {TimeWithOffset} with that offset. # # @return [Time] if there is an associated {TimezoneOffset}, a # {TimeWithOffset} representation of this {TimestampWithOffset}, otherwise # a `Time` representation. def to_time to = timezone_offset if to new_time(TimeWithOffset).set_timezone_offset(to) else super end end # An overridden version of {Timestamp#to_datetime}, if there is an # associated {TimezoneOffset}, returns a {DateTimeWithOffset} with that # offset. # # @return [DateTime] if there is an associated {TimezoneOffset}, a # {DateTimeWithOffset} representation of this {TimestampWithOffset}, # otherwise a `DateTime` representation. def to_datetime to = timezone_offset if to new_datetime(DateTimeWithOffset).set_timezone_offset(to) else super end end end end tzinfo-2.0.6/lib/tzinfo/timezone.rb000066400000000000000000001502431436527530500173050ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true require 'set' module TZInfo # {AmbiguousTime} is raised to indicate that a specified local time has more # than one possible equivalent UTC time. Such ambiguities arise when the # clocks are set back in a time zone, most commonly during the repeated hour # when transitioning from daylight savings time to standard time. # # {AmbiguousTime} is raised by {Timezone#local_datetime}, # {Timezone#local_time}, {Timezone#local_timestamp}, {Timezone#local_to_utc} # and {Timezone#period_for_local} when using an ambiguous time and not # specifying how to resolve the ambiguity. class AmbiguousTime < StandardError end # {PeriodNotFound} is raised to indicate that no {TimezonePeriod} matching a # given time could be found. class PeriodNotFound < StandardError end # {InvalidTimezoneIdentifier} is raised by {Timezone.get} if the identifier # given is not valid. class InvalidTimezoneIdentifier < StandardError end # {UnknownTimezone} is raised when calling methods on an instance of # {Timezone} that was created directly. To obtain {Timezone} instances the # {Timezone.get} method should be used instead. class UnknownTimezone < StandardError end # The {Timezone} class represents a time zone. It provides a factory method, # {get}, to retrieve {Timezone} instances by their identifier. # # The {Timezone#to_local} method can be used to convert `Time` and `DateTime` # instances to the local time for the zone. For example: # # tz = TZInfo::Timezone.get('America/New_York') # local_time = tz.to_local(Time.utc(2005,8,29,15,35,0)) # local_datetime = tz.to_local(DateTime.new(2005,8,29,15,35,0)) # # Local `Time` and `DateTime` instances returned by `Timezone` have the # correct local offset. # # The {Timezone#local_to_utc} method can by used to convert local `Time` and # `DateTime` instances to UTC. {Timezone#local_to_utc} ignores the UTC offset # of the supplied value and treats if it is a local time for the zone. For # example: # # tz = TZInfo::Timezone.get('America/New_York') # utc_time = tz.local_to_utc(Time.new(2005,8,29,11,35,0)) # utc_datetime = tz.local_to_utc(DateTime.new(2005,8,29,11,35,0)) # # Each time zone is treated as sequence of periods of time ({TimezonePeriod}) # that observe the same offset ({TimezoneOffset}). Transitions # ({TimezoneTransition}) denote the end of one period and the start of the # next. The {Timezone} class has methods that allow the periods, offsets and # transitions of a time zone to be interrogated. # # All methods that take `Time` objects as parameters can be used with # arbitrary `Time`-like objects that respond to both `to_i` and `subsec` and # optionally `utc_offset`. # # The {Timezone} class is thread-safe. It is safe to use class and instance # methods of {Timezone} in concurrently executing threads. Instances of # {Timezone} can be shared across thread boundaries. # # The IANA Time Zone Database maintainers recommend that time zone identifiers # are not made visible to end-users (see [Names of # timezones](https://data.iana.org/time-zones/theory.html#naming)). The # {Country} class can be used to obtain lists of time zones by country, # including user-friendly descriptions and approximate locations. # # @abstract The {get} method returns an instance of either {DataTimezone} or # {LinkedTimezone}. The {get_proxy} method and other methods returning # collections of time zones return instances of {TimezoneProxy}. class Timezone include Comparable # The default value of the dst parameter of the {local_datetime}, # {local_time}, {local_timestamp}, {local_to_utc} and {period_for_local} # methods. # # @!visibility private @@default_dst = nil class << self # Sets the default value of the optional `dst` parameter of the # {local_datetime}, {local_time}, {local_timestamp}, {local_to_utc} and # {period_for_local} methods. Can be set to `nil`, `true` or `false`. # # @param value [Boolean] `nil`, `true` or `false`. def default_dst=(value) @@default_dst = value.nil? ? nil : !!value end # Returns the default value of the optional `dst` parameter of the # {local_time}, {local_datetime} and {local_timestamp}, {local_to_utc} # and {period_for_local} methods (`nil`, `true` or `false`). # # {default_dst} defaults to `nil` unless changed with {default_dst=}. # # @return [Boolean] the default value of the optional `dst` parameter of # the {local_time}, {local_datetime} and {local_timestamp}, # {local_to_utc} and {period_for_local} methods (`nil`, `true` or # `false`). def default_dst @@default_dst end # Returns a time zone by its IANA Time Zone Database identifier (e.g. # `"Europe/London"` or `"America/Chicago"`). Call {all_identifiers} for a # list of all the valid identifiers. # # The {get} method will return a subclass of {Timezone}, either a # {DataTimezone} (for a time zone defined by rules that set out when # transitions occur) or a {LinkedTimezone} (for a time zone that is just a # link to or alias for a another time zone). # # @param identifier [String] an IANA Time Zone Database time zone # identifier. # @return [Timezone] the {Timezone} with the given `identifier`. # @raise [InvalidTimezoneIdentifier] if the `identifier` is not valid. def get(identifier) data_source.get_timezone_info(identifier).create_timezone end # Returns a proxy for the time zone with the given identifier. This allows # loading of the time zone data to be deferred until it is first needed. # # The identifier will not be validated. If an invalid identifier is # specified, no exception will be raised until the proxy is used. # # @param identifier [String] an IANA Time Zone Database time zone # identifier. # @return [TimezoneProxy] a proxy for the time zone with the given # `identifier`. def get_proxy(identifier) TimezoneProxy.new(identifier) end # Returns an `Array` of all the available time zones. # # {TimezoneProxy} instances are returned to avoid the overhead of loading # time zone data until it is first needed. # # @return [Array] all available time zones. def all get_proxies(all_identifiers) end # @return [Array] an `Array` containing the identifiers of all the # available time zones. def all_identifiers data_source.timezone_identifiers end # Returns an `Array` of all the available time zones that are # defined by offsets and transitions. # # {TimezoneProxy} instances are returned to avoid the overhead of loading # time zone data until it is first needed. # # @return [Array] an `Array` of all the available time zones # that are defined by offsets and transitions. def all_data_zones get_proxies(all_data_zone_identifiers) end # @return [Array] an `Array` of the identifiers of all available # time zones that are defined by offsets and transitions. def all_data_zone_identifiers data_source.data_timezone_identifiers end # Returns an `Array` of all the available time zones that are # defined as links to / aliases for other time zones. # # {TimezoneProxy} instances are returned to avoid the overhead of loading # time zone data until it is first needed. # # @return [Array] an `Array` of all the available time zones # that are defined as links to / aliases for other time zones. def all_linked_zones get_proxies(all_linked_zone_identifiers) end # @return [Array] an `Array` of the identifiers of all available # time zones that are defined as links to / aliases for other time zones. def all_linked_zone_identifiers data_source.linked_timezone_identifiers end # Returns an `Array` of all the time zones that are observed by at least # one {Country}. This is not the complete set of time zones as some are # not country specific (e.g. `'Etc/GMT'`). # # {TimezoneProxy} instances are returned to avoid the overhead of loading # time zone data until it is first needed. # # @return [Array] an `Array` of all the time zones that are # observed by at least one {Country}. def all_country_zones Country.all.map(&:zones).flatten.uniq end # Returns an `Array` of the identifiers of all the time zones that are # observed by at least one {Country}. This is not the complete set of time # zone identifiers as some are not country specific (e.g. `'Etc/GMT'`). # # {TimezoneProxy} instances are returned to avoid the overhead of loading # time zone data until it is first needed. # # @return [Array] an `Array` of the identifiers of all the time # zones that are observed by at least one {Country}. def all_country_zone_identifiers Country.all.map(&:zone_identifiers).flatten.uniq end private # @param [Enumerable] identifiers an `Enumerable` of time zone # identifiers. # @return [Array] an `Array` of {TimezoneProxy} # instances corresponding to the given identifiers. def get_proxies(identifiers) identifiers.collect {|identifier| get_proxy(identifier)} end # @return [DataSource] the current DataSource. def data_source DataSource.get end end # @return [String] the identifier of the time zone, for example, # `"Europe/Paris"`. def identifier raise_unknown_timezone end # @return [String] the identifier of the time zone, for example, # `"Europe/Paris"`. def name # Don't use alias, as identifier gets overridden. identifier end # @return [String] {identifier}, modified to make it more readable. def to_s friendly_identifier end # @return [String] the internal object state as a programmer-readable # `String`. def inspect "#<#{self.class}: #{identifier}>" end # Returns {identifier}, modified to make it more readable. Set # `skip_first_part` to omit the first part of the identifier (typically a # region name) where there is more than one part. # # For example: # # TZInfo::Timezone.get('Europe/Paris').friendly_identifier(false) #=> "Europe - Paris" # TZInfo::Timezone.get('Europe/Paris').friendly_identifier(true) #=> "Paris" # TZInfo::Timezone.get('America/Indiana/Knox').friendly_identifier(false) #=> "America - Knox, Indiana" # TZInfo::Timezone.get('America/Indiana/Knox').friendly_identifier(true) #=> "Knox, Indiana" # # @param skip_first_part [Boolean] whether the first part of the identifier # (typically a region name) should be omitted. # @return [String] the modified identifier. def friendly_identifier(skip_first_part = false) id = identifier id = id.encode(Encoding::UTF_8) unless id.encoding.ascii_compatible? parts = id.split('/') if parts.empty? # shouldn't happen identifier elsif parts.length == 1 parts[0] else prefix = skip_first_part ? nil : "#{parts[0]} - " parts = parts.drop(1).map do |part| part.gsub!(/_/, ' ') if part.index(/[a-z]/) # Missing a space if a lower case followed by an upper case and the # name isn't McXxxx. part.gsub!(/([^M][a-z])([A-Z])/, '\1 \2') part.gsub!(/([M][a-bd-z])([A-Z])/, '\1 \2') # Missing an apostrophe if two consecutive upper case characters. part.gsub!(/([A-Z])([A-Z])/, '\1\'\2') end part end "#{prefix}#{parts.reverse.join(', ')}" end end # Returns the {TimezonePeriod} that is valid at a given time. # # Unlike {period_for_local} and {period_for_utc}, the UTC offset of the # `time` parameter is taken into consideration. # # @param time [Object] a `Time`, `DateTime` or {Timestamp}. # @return [TimezonePeriod] the {TimezonePeriod} that is valid at `time`. # @raise [ArgumentError] if `time` is `nil`. # @raise [ArgumentError] if `time` is a {Timestamp} with an unspecified # offset. def period_for(time) raise_unknown_timezone end # Returns the set of {TimezonePeriod}s that are valid for the given # local time as an `Array`. # # The UTC offset of the `local_time` parameter is ignored (it is treated as # a time in the time zone represented by `self`). # # This will typically return an `Array` containing a single # {TimezonePeriod}. More than one {TimezonePeriod} will be returned when the # local time is ambiguous (for example, when daylight savings time ends). An # empty `Array` will be returned when the local time is not valid (for # example, when daylight savings time begins). # # To obtain just a single {TimezonePeriod} in all cases, use # {period_for_local} instead and specify how ambiguities should be resolved. # # @param local_time [Object] a `Time`, `DateTime` or {Timestamp}. # @return [Array] the set of {TimezonePeriod}s that are # valid at `local_time`. # @raise [ArgumentError] if `local_time` is `nil`. def periods_for_local(local_time) raise_unknown_timezone end # Returns an `Array` of {TimezoneTransition} instances representing the # times where the UTC offset of the timezone changes. # # Transitions are returned up to a given time (`to`). # # A from time may also be supplied using the `from` parameter. If from is # not `nil`, only transitions from that time onwards will be returned. # # Comparisons with `to` are exclusive. Comparisons with `from` are # inclusive. If a transition falls precisely on `to`, it will be excluded. # If a transition falls on `from`, it will be included. # # @param to [Object] a `Time`, `DateTime` or {Timestamp} specifying the # latest (exclusive) transition to return. # @param from [Object] an optional `Time`, `DateTime` or {Timestamp} # specifying the earliest (inclusive) transition to return. # @return [Array] the transitions that are earlier than # `to` and, if specified, at or later than `from`. Transitions are ordered # by when they occur, from earliest to latest. # @raise [ArgumentError] if `from` is specified and `to` is not greater than # `from`. # @raise [ArgumentError] is raised if `to` is `nil`. # @raise [ArgumentError] if either `to` or `from` is a {Timestamp} with an # unspecified offset. def transitions_up_to(to, from = nil) raise_unknown_timezone end # Returns the canonical {Timezone} instance for this {Timezone}. # # The IANA Time Zone database contains two types of definition: Zones and # Links. Zones are defined by rules that set out when transitions occur. # Links are just references to fully defined Zone, creating an alias for # that Zone. # # Links are commonly used where a time zone has been renamed in a release of # the Time Zone database. For example, the US/Eastern Zone was renamed as # America/New_York. A US/Eastern Link was added in its place, linking to # (and creating an alias for) America/New_York. # # Links are also used for time zones that are currently identical to a full # Zone, but that are administered separately. For example, Europe/Vatican is # a Link to (and alias for) Europe/Rome. # # For a full Zone (implemented by {DataTimezone}), {canonical_zone} returns # self. # # For a Link (implemented by {LinkedTimezone}), {canonical_zone} returns a # {Timezone} instance representing the full Zone that the link targets. # # TZInfo can be used with different data sources (see the documentation for # {TZInfo::DataSource}). Some DataSource implementations may not support # distinguishing between full Zones and Links and will treat all time zones # as full Zones. In this case, {canonical_zone} will always return `self`. # # There are two built-in DataSource implementations. # {DataSources::RubyDataSource} (which will be used if the tzinfo-data gem # is available) supports Link zones. {DataSources::ZoneinfoDataSource} # returns Link zones as if they were full Zones. If the {canonical_zone} or # {canonical_identifier} methods are needed, the tzinfo-data gem should be # installed. # # The {TZInfo::DataSource.get} method can be used to check which DataSource # implementation is being used. # # @return [Timezone] the canonical {Timezone} instance for this {Timezone}. def canonical_zone raise_unknown_timezone end # Returns the {TimezonePeriod} that is valid at a given time. # # The UTC offset of the `utc_time` parameter is ignored (it is treated as a # UTC time). Use the {period_for} method instead if the UTC offset of the # time needs to be taken into consideration. # # @param utc_time [Object] a `Time`, `DateTime` or {Timestamp}. # @return [TimezonePeriod] the {TimezonePeriod} that is valid at `utc_time`. # @raise [ArgumentError] if `utc_time` is `nil`. def period_for_utc(utc_time) raise ArgumentError, 'utc_time must be specified' unless utc_time period_for(Timestamp.for(utc_time, :treat_as_utc)) end # Returns the {TimezonePeriod} that is valid at the given local time. # # The UTC offset of the `local_time` parameter is ignored (it is treated as # a time in the time zone represented by `self`). Use the {period_for} # method instead if the the UTC offset of the time needs to be taken into # consideration. # # _Warning:_ There are local times that have no equivalent UTC times (for # example, during the transition from standard time to daylight savings # time). There are also local times that have more than one UTC equivalent # (for example, during the transition from daylight savings time to standard # time). # # In the first case (no equivalent UTC time), a {PeriodNotFound} exception # will be raised. # # In the second case (more than one equivalent UTC time), an {AmbiguousTime} # exception will be raised unless the optional `dst` parameter or block # handles the ambiguity. # # If the ambiguity is due to a transition from daylight savings time to # standard time, the `dst` parameter can be used to select whether the # daylight savings time or local time is used. For example, the following # code would raise an {AmbiguousTime} exception: # # tz = TZInfo::Timezone.get('America/New_York') # tz.period_for_local(Time.new(2004,10,31,1,30,0)) # # Specifying `dst = true` would select the daylight savings period from # April to October 2004. Specifying `dst = false` would return the # standard time period from October 2004 to April 2005. # # The `dst` parameter will not be able to resolve an ambiguity resulting # from the clocks being set back without changing from daylight savings time # to standard time. In this case, if a block is specified, it will be called # to resolve the ambiguity. The block must take a single parameter - an # `Array` of {TimezonePeriod}s that need to be resolved. The block can # select and return a single {TimezonePeriod} or return `nil` or an empty # `Array` to cause an {AmbiguousTime} exception to be raised. # # The default value of the `dst` parameter can be specified using # {Timezone.default_dst=}. # # @param local_time [Object] a `Time`, `DateTime` or {Timestamp}. # @param dst [Boolean] whether to resolve ambiguous local times by always # selecting the period observing daylight savings time (`true`), always # selecting the period observing standard time (`false`), or leaving the # ambiguity unresolved (`nil`). # @yield [periods] if the `dst` parameter did not resolve an ambiguity, an # optional block is yielded to. # @yieldparam periods [Array] an `Array` containing all # the {TimezonePeriod}s that still match `local_time` after applying the # `dst` parameter. # @yieldreturn [Object] to resolve the ambiguity: a chosen {TimezonePeriod} # or an `Array` containing a chosen {TimezonePeriod}; to leave the # ambiguity unresolved: an empty `Array`, an `Array` containing more than # one {TimezonePeriod}, or `nil`. # @return [TimezonePeriod] the {TimezonePeriod} that is valid at # `local_time`. # @raise [ArgumentError] if `local_time` is `nil`. # @raise [PeriodNotFound] if `local_time` is not valid for the time zone # (there is no equivalent UTC time). # @raise [AmbiguousTime] if `local_time` was ambiguous for the time zone and # the `dst` parameter or block did not resolve the ambiguity. def period_for_local(local_time, dst = Timezone.default_dst) raise ArgumentError, 'local_time must be specified' unless local_time local_time = Timestamp.for(local_time, :ignore) results = periods_for_local(local_time) if results.empty? raise PeriodNotFound, "#{local_time.strftime('%Y-%m-%d %H:%M:%S')} is an invalid local time." elsif results.size < 2 results.first else # ambiguous result try to resolve if !dst.nil? matches = results.find_all {|period| period.dst? == dst} results = matches if !matches.empty? end if results.size < 2 results.first else # still ambiguous, try the block if block_given? results = yield results end if results.is_a?(TimezonePeriod) results elsif results && results.size == 1 results.first else raise AmbiguousTime, "#{local_time.strftime('%Y-%m-%d %H:%M:%S')} is an ambiguous local time." end end end end # Converts a time to the local time for the time zone. # # The result will be of type {TimeWithOffset} (if passed a `Time`), # {DateTimeWithOffset} (if passed a `DateTime`) or {TimestampWithOffset} (if # passed a {Timestamp}). {TimeWithOffset}, {DateTimeWithOffset} and # {TimestampWithOffset} are subclasses of `Time`, `DateTime` and {Timestamp} # that provide additional information about the local result. # # Unlike {utc_to_local}, {to_local} takes the UTC offset of the given time # into consideration. # # @param time [Object] a `Time`, `DateTime` or {Timestamp}. # @return [Object] the local equivalent of `time` as a {TimeWithOffset}, # {DateTimeWithOffset} or {TimestampWithOffset}. # @raise [ArgumentError] if `time` is `nil`. # @raise [ArgumentError] if `time` is a {Timestamp} that does not have a # specified UTC offset. def to_local(time) raise ArgumentError, 'time must be specified' unless time Timestamp.for(time) do |ts| TimestampWithOffset.set_timezone_offset(ts, period_for(ts).offset) end end # Converts a time in UTC to the local time for the time zone. # # The result will be of type {TimeWithOffset} (if passed a `Time`), # {DateTimeWithOffset} (if passed a `DateTime`) or {TimestampWithOffset} (if # passed a {Timestamp}). {TimeWithOffset}, {DateTimeWithOffset} and # {TimestampWithOffset} are subclasses of `Time`, `DateTime` and {Timestamp} # that provide additional information about the local result. # # The UTC offset of the `utc_time` parameter is ignored (it is treated as a # UTC time). Use the {to_local} method instead if the the UTC offset of the # time needs to be taken into consideration. # # @param utc_time [Object] a `Time`, `DateTime` or {Timestamp}. # @return [Object] the local equivalent of `utc_time` as a {TimeWithOffset}, # {DateTimeWithOffset} or {TimestampWithOffset}. # @raise [ArgumentError] if `utc_time` is `nil`. def utc_to_local(utc_time) raise ArgumentError, 'utc_time must be specified' unless utc_time Timestamp.for(utc_time, :treat_as_utc) do |ts| to_local(ts) end end # Converts a local time for the time zone to UTC. # # The result will either be a `Time`, `DateTime` or {Timestamp} according to # the type of the `local_time` parameter. # # The UTC offset of the `local_time` parameter is ignored (it is treated as # a time in the time zone represented by `self`). # # _Warning:_ There are local times that have no equivalent UTC times (for # example, during the transition from standard time to daylight savings # time). There are also local times that have more than one UTC equivalent # (for example, during the transition from daylight savings time to standard # time). # # In the first case (no equivalent UTC time), a {PeriodNotFound} exception # will be raised. # # In the second case (more than one equivalent UTC time), an {AmbiguousTime} # exception will be raised unless the optional `dst` parameter or block # handles the ambiguity. # # If the ambiguity is due to a transition from daylight savings time to # standard time, the `dst` parameter can be used to select whether the # daylight savings time or local time is used. For example, the following # code would raise an {AmbiguousTime} exception: # # tz = TZInfo::Timezone.get('America/New_York') # tz.period_for_local(Time.new(2004,10,31,1,30,0)) # # Specifying `dst = true` would select the daylight savings period from # April to October 2004. Specifying `dst = false` would return the # standard time period from October 2004 to April 2005. # # The `dst` parameter will not be able to resolve an ambiguity resulting # from the clocks being set back without changing from daylight savings time # to standard time. In this case, if a block is specified, it will be called # to resolve the ambiguity. The block must take a single parameter - an # `Array` of {TimezonePeriod}s that need to be resolved. The block can # select and return a single {TimezonePeriod} or return `nil` or an empty # `Array` to cause an {AmbiguousTime} exception to be raised. # # The default value of the `dst` parameter can be specified using # {Timezone.default_dst=}. # # @param local_time [Object] a `Time`, `DateTime` or {Timestamp}. # @param dst [Boolean] whether to resolve ambiguous local times by always # selecting the period observing daylight savings time (`true`), always # selecting the period observing standard time (`false`), or leaving the # ambiguity unresolved (`nil`). # @yield [periods] if the `dst` parameter did not resolve an ambiguity, an # optional block is yielded to. # @yieldparam periods [Array] an `Array` containing all # the {TimezonePeriod}s that still match `local_time` after applying the # `dst` parameter. # @yieldreturn [Object] to resolve the ambiguity: a chosen {TimezonePeriod} # or an `Array` containing a chosen {TimezonePeriod}; to leave the # ambiguity unresolved: an empty `Array`, an `Array` containing more than # one {TimezonePeriod}, or `nil`. # @return [Object] the UTC equivalent of `local_time` as a `Time`, # `DateTime` or {Timestamp}. # @raise [ArgumentError] if `local_time` is `nil`. # @raise [PeriodNotFound] if `local_time` is not valid for the time zone # (there is no equivalent UTC time). # @raise [AmbiguousTime] if `local_time` was ambiguous for the time zone and # the `dst` parameter or block did not resolve the ambiguity. def local_to_utc(local_time, dst = Timezone.default_dst) raise ArgumentError, 'local_time must be specified' unless local_time Timestamp.for(local_time, :ignore) do |ts| period = if block_given? period_for_local(ts, dst) {|periods| yield periods } else period_for_local(ts, dst) end ts.add_and_set_utc_offset(-period.observed_utc_offset, :utc) end end # Creates a `Time` object based on the given (Gregorian calendar) date and # time parameters. The parameters are interpreted as a local time in the # time zone. The result has the appropriate `utc_offset`, `zone` and # {TimeWithOffset#timezone_offset timezone_offset}. # # _Warning:_ There are time values that are not valid as local times in a # time zone (for example, during the transition from standard time to # daylight savings time). There are also time values that are ambiguous, # occurring more than once with different offsets to UTC (for example, # during the transition from daylight savings time to standard time). # # In the first case (an invalid local time), a {PeriodNotFound} exception # will be raised. # # In the second case (more than one occurrence), an {AmbiguousTime} # exception will be raised unless the optional `dst` parameter or block # handles the ambiguity. # # If the ambiguity is due to a transition from daylight savings time to # standard time, the `dst` parameter can be used to select whether the # daylight savings time or local time is used. For example, the following # code would raise an {AmbiguousTime} exception: # # tz = TZInfo::Timezone.get('America/New_York') # tz.local_time(2004,10,31,1,30,0,0) # # Specifying `dst = true` would return a `Time` with a UTC offset of -4 # hours and abbreviation EDT (Eastern Daylight Time). Specifying `dst = # false` would return a `Time` with a UTC offset of -5 hours and # abbreviation EST (Eastern Standard Time). # # The `dst` parameter will not be able to resolve an ambiguity resulting # from the clocks being set back without changing from daylight savings time # to standard time. In this case, if a block is specified, it will be called # to resolve the ambiguity. The block must take a single parameter - an # `Array` of {TimezonePeriod}s that need to be resolved. The block can # select and return a single {TimezonePeriod} or return `nil` or an empty # `Array` to cause an {AmbiguousTime} exception to be raised. # # The default value of the `dst` parameter can be specified using # {Timezone.default_dst=}. # # @param year [Integer] the year. # @param month [Integer] the month (1-12). # @param day [Integer] the day of the month (1-31). # @param hour [Integer] the hour (0-23). # @param minute [Integer] the minute (0-59). # @param second [Integer] the second (0-59). # @param sub_second [Numeric] the fractional part of the second as either # a `Rational` that is greater than or equal to 0 and less than 1, or # the `Integer` 0. # @param dst [Boolean] whether to resolve ambiguous local times by always # selecting the period observing daylight savings time (`true`), always # selecting the period observing standard time (`false`), or leaving the # ambiguity unresolved (`nil`). # @yield [periods] if the `dst` parameter did not resolve an ambiguity, an # optional block is yielded to. # @yieldparam periods [Array] an `Array` containing all # the {TimezonePeriod}s that still match `local_time` after applying the # `dst` parameter. # @yieldreturn [Object] to resolve the ambiguity: a chosen {TimezonePeriod} # or an `Array` containing a chosen {TimezonePeriod}; to leave the # ambiguity unresolved: an empty `Array`, an `Array` containing more than # one {TimezonePeriod}, or `nil`. # @return [TimeWithOffset] a new `Time` object based on the given values, # interpreted as a local time in the time zone. # @raise [ArgumentError] if either of `year`, `month`, `day`, `hour`, # `minute`, or `second` is not an `Integer`. # @raise [ArgumentError] if `sub_second` is not a `Rational`, or the # `Integer` 0. # @raise [ArgumentError] if `utc_offset` is not `nil`, not an `Integer` # and not the `Symbol` `:utc`. # @raise [RangeError] if `month` is not between 1 and 12. # @raise [RangeError] if `day` is not between 1 and 31. # @raise [RangeError] if `hour` is not between 0 and 23. # @raise [RangeError] if `minute` is not between 0 and 59. # @raise [RangeError] if `second` is not between 0 and 59. # @raise [RangeError] if `sub_second` is a `Rational` but that is less # than 0 or greater than or equal to 1. # @raise [PeriodNotFound] if the date and time parameters do not specify a # valid local time in the time zone. # @raise [AmbiguousTime] if the date and time parameters are ambiguous for # the time zone and the `dst` parameter or block did not resolve the # ambiguity. def local_time(year, month = 1, day = 1, hour = 0, minute = 0, second = 0, sub_second = 0, dst = Timezone.default_dst, &block) local_timestamp(year, month, day, hour, minute, second, sub_second, dst, &block).to_time end # Creates a `DateTime` object based on the given (Gregorian calendar) date # and time parameters. The parameters are interpreted as a local time in the # time zone. The result has the appropriate `offset` and # {DateTimeWithOffset#timezone_offset timezone_offset}. # # _Warning:_ There are time values that are not valid as local times in a # time zone (for example, during the transition from standard time to # daylight savings time). There are also time values that are ambiguous, # occurring more than once with different offsets to UTC (for example, # during the transition from daylight savings time to standard time). # # In the first case (an invalid local time), a {PeriodNotFound} exception # will be raised. # # In the second case (more than one occurrence), an {AmbiguousTime} # exception will be raised unless the optional `dst` parameter or block # handles the ambiguity. # # If the ambiguity is due to a transition from daylight savings time to # standard time, the `dst` parameter can be used to select whether the # daylight savings time or local time is used. For example, the following # code would raise an {AmbiguousTime} exception: # # tz = TZInfo::Timezone.get('America/New_York') # tz.local_datetime(2004,10,31,1,30,0,0) # # Specifying `dst = true` would return a `Time` with a UTC offset of -4 # hours and abbreviation EDT (Eastern Daylight Time). Specifying `dst = # false` would return a `Time` with a UTC offset of -5 hours and # abbreviation EST (Eastern Standard Time). # # The `dst` parameter will not be able to resolve an ambiguity resulting # from the clocks being set back without changing from daylight savings time # to standard time. In this case, if a block is specified, it will be called # to resolve the ambiguity. The block must take a single parameter - an # `Array` of {TimezonePeriod}s that need to be resolved. The block can # select and return a single {TimezonePeriod} or return `nil` or an empty # `Array` to cause an {AmbiguousTime} exception to be raised. # # The default value of the `dst` parameter can be specified using # {Timezone.default_dst=}. # # @param year [Integer] the year. # @param month [Integer] the month (1-12). # @param day [Integer] the day of the month (1-31). # @param hour [Integer] the hour (0-23). # @param minute [Integer] the minute (0-59). # @param second [Integer] the second (0-59). # @param sub_second [Numeric] the fractional part of the second as either # a `Rational` that is greater than or equal to 0 and less than 1, or # the `Integer` 0. # @param dst [Boolean] whether to resolve ambiguous local times by always # selecting the period observing daylight savings time (`true`), always # selecting the period observing standard time (`false`), or leaving the # ambiguity unresolved (`nil`). # @yield [periods] if the `dst` parameter did not resolve an ambiguity, an # optional block is yielded to. # @yieldparam periods [Array] an `Array` containing all # the {TimezonePeriod}s that still match `local_time` after applying the # `dst` parameter. # @yieldreturn [Object] to resolve the ambiguity: a chosen {TimezonePeriod} # or an `Array` containing a chosen {TimezonePeriod}; to leave the # ambiguity unresolved: an empty `Array`, an `Array` containing more than # one {TimezonePeriod}, or `nil`. # @return [DateTimeWithOffset] a new `DateTime` object based on the given # values, interpreted as a local time in the time zone. # @raise [ArgumentError] if either of `year`, `month`, `day`, `hour`, # `minute`, or `second` is not an `Integer`. # @raise [ArgumentError] if `sub_second` is not a `Rational`, or the # `Integer` 0. # @raise [ArgumentError] if `utc_offset` is not `nil`, not an `Integer` # and not the `Symbol` `:utc`. # @raise [RangeError] if `month` is not between 1 and 12. # @raise [RangeError] if `day` is not between 1 and 31. # @raise [RangeError] if `hour` is not between 0 and 23. # @raise [RangeError] if `minute` is not between 0 and 59. # @raise [RangeError] if `second` is not between 0 and 59. # @raise [RangeError] if `sub_second` is a `Rational` but that is less # than 0 or greater than or equal to 1. # @raise [PeriodNotFound] if the date and time parameters do not specify a # valid local time in the time zone. # @raise [AmbiguousTime] if the date and time parameters are ambiguous for # the time zone and the `dst` parameter or block did not resolve the # ambiguity. def local_datetime(year, month = 1, day = 1, hour = 0, minute = 0, second = 0, sub_second = 0, dst = Timezone.default_dst, &block) local_timestamp(year, month, day, hour, minute, second, sub_second, dst, &block).to_datetime end # Creates a {Timestamp} object based on the given (Gregorian calendar) date # and time parameters. The parameters are interpreted as a local time in the # time zone. The result has the appropriate {Timestamp#utc_offset # utc_offset} and {TimestampWithOffset#timezone_offset timezone_offset}. # # _Warning:_ There are time values that are not valid as local times in a # time zone (for example, during the transition from standard time to # daylight savings time). There are also time values that are ambiguous, # occurring more than once with different offsets to UTC (for example, # during the transition from daylight savings time to standard time). # # In the first case (an invalid local time), a {PeriodNotFound} exception # will be raised. # # In the second case (more than one occurrence), an {AmbiguousTime} # exception will be raised unless the optional `dst` parameter or block # handles the ambiguity. # # If the ambiguity is due to a transition from daylight savings time to # standard time, the `dst` parameter can be used to select whether the # daylight savings time or local time is used. For example, the following # code would raise an {AmbiguousTime} exception: # # tz = TZInfo::Timezone.get('America/New_York') # tz.local_timestamp(2004,10,31,1,30,0,0) # # Specifying `dst = true` would return a `Time` with a UTC offset of -4 # hours and abbreviation EDT (Eastern Daylight Time). Specifying `dst = # false` would return a `Time` with a UTC offset of -5 hours and # abbreviation EST (Eastern Standard Time). # # The `dst` parameter will not be able to resolve an ambiguity resulting # from the clocks being set back without changing from daylight savings time # to standard time. In this case, if a block is specified, it will be called # to resolve the ambiguity. The block must take a single parameter - an # `Array` of {TimezonePeriod}s that need to be resolved. The block can # select and return a single {TimezonePeriod} or return `nil` or an empty # `Array` to cause an {AmbiguousTime} exception to be raised. # # The default value of the `dst` parameter can be specified using # {Timezone.default_dst=}. # # @param year [Integer] the year. # @param month [Integer] the month (1-12). # @param day [Integer] the day of the month (1-31). # @param hour [Integer] the hour (0-23). # @param minute [Integer] the minute (0-59). # @param second [Integer] the second (0-59). # @param sub_second [Numeric] the fractional part of the second as either # a `Rational` that is greater than or equal to 0 and less than 1, or # the `Integer` 0. # @param dst [Boolean] whether to resolve ambiguous local times by always # selecting the period observing daylight savings time (`true`), always # selecting the period observing standard time (`false`), or leaving the # ambiguity unresolved (`nil`). # @yield [periods] if the `dst` parameter did not resolve an ambiguity, an # optional block is yielded to. # @yieldparam periods [Array] an `Array` containing all # the {TimezonePeriod}s that still match `local_time` after applying the # `dst` parameter. # @yieldreturn [Object] to resolve the ambiguity: a chosen {TimezonePeriod} # or an `Array` containing a chosen {TimezonePeriod}; to leave the # ambiguity unresolved: an empty `Array`, an `Array` containing more than # one {TimezonePeriod}, or `nil`. # @return [TimestampWithOffset] a new {Timestamp} object based on the given # values, interpreted as a local time in the time zone. # @raise [ArgumentError] if either of `year`, `month`, `day`, `hour`, # `minute`, or `second` is not an `Integer`. # @raise [ArgumentError] if `sub_second` is not a `Rational`, or the # `Integer` 0. # @raise [ArgumentError] if `utc_offset` is not `nil`, not an `Integer` # and not the `Symbol` `:utc`. # @raise [RangeError] if `month` is not between 1 and 12. # @raise [RangeError] if `day` is not between 1 and 31. # @raise [RangeError] if `hour` is not between 0 and 23. # @raise [RangeError] if `minute` is not between 0 and 59. # @raise [RangeError] if `second` is not between 0 and 59. # @raise [RangeError] if `sub_second` is a `Rational` but that is less # than 0 or greater than or equal to 1. # @raise [PeriodNotFound] if the date and time parameters do not specify a # valid local time in the time zone. # @raise [AmbiguousTime] if the date and time parameters are ambiguous for # the time zone and the `dst` parameter or block did not resolve the # ambiguity. def local_timestamp(year, month = 1, day = 1, hour = 0, minute = 0, second = 0, sub_second = 0, dst = Timezone.default_dst, &block) ts = Timestamp.create(year, month, day, hour, minute, second, sub_second) timezone_offset = period_for_local(ts, dst, &block).offset utc_offset = timezone_offset.observed_utc_offset TimestampWithOffset.new(ts.value - utc_offset, sub_second, utc_offset).set_timezone_offset(timezone_offset) end # Returns the unique offsets used by the time zone up to a given time (`to`) # as an `Array` of {TimezoneOffset} instances. # # A from time may also be supplied using the `from` parameter. If from is # not `nil`, only offsets used from that time onwards will be returned. # # Comparisons with `to` are exclusive. Comparisons with `from` are # inclusive. # # @param to [Object] a `Time`, `DateTime` or {Timestamp} specifying the # latest (exclusive) offset to return. # @param from [Object] an optional `Time`, `DateTime` or {Timestamp} # specifying the earliest (inclusive) offset to return. # @return [Array] the offsets that are used earlier than # `to` and, if specified, at or later than `from`. Offsets may be returned # in any order. # @raise [ArgumentError] if `from` is specified and `to` is not greater than # `from`. # @raise [ArgumentError] is raised if `to` is `nil`. # @raise [ArgumentError] if either `to` or `from` is a {Timestamp} with an # unspecified offset. def offsets_up_to(to, from = nil) raise ArgumentError, 'to must be specified' unless to to_timestamp = Timestamp.for(to) from_timestamp = from && Timestamp.for(from) transitions = transitions_up_to(to_timestamp, from_timestamp) if transitions.empty? # No transitions in the range, find the period that covers it. if from_timestamp # Use the from date as it is inclusive. period = period_for(from_timestamp) else # to is exclusive, so this can't be used with period_for. However, any # time earlier than to can be used. Subtract 1 hour. period = period_for(to_timestamp.add_and_set_utc_offset(-3600, :utc)) end [period.offset] else result = Set.new first = transitions.first result << first.previous_offset unless from_timestamp && first.at == from_timestamp transitions.each do |t| result << t.offset end result.to_a end end # Returns the canonical identifier of this time zone. # # This is a shortcut for calling `canonical_zone.identifier`. Please refer # to the {canonical_zone} documentation for further information. # # @return [String] the canonical identifier of this time zone. def canonical_identifier canonical_zone.identifier end # @return [TimeWithOffset] the current local time in the time zone. def now to_local(Time.now) end # @return [TimezonePeriod] the current {TimezonePeriod} for the time zone. def current_period period_for(Time.now) end # Returns the current local time and {TimezonePeriod} for the time zone as # an `Array`. The first element is the time as a {TimeWithOffset}. The # second element is the period. # # @return [Array] an `Array` containing the current {TimeWithOffset} for the # time zone as the first element and the current {TimezonePeriod} for the # time zone as the second element. def current_time_and_period period = nil local_time = Timestamp.for(Time.now) do |ts| period = period_for(ts) TimestampWithOffset.set_timezone_offset(ts, period.offset) end [local_time, period] end alias current_period_and_time current_time_and_period # Converts a time to local time for the time zone and returns a `String` # representation of the local time according to the given format. # # `Timezone#strftime` first expands any occurrences of `%Z` in the format # string to the time zone abbreviation for the local time (for example, EST # or EDT). Depending on the type of `time` parameter, the result of the # expansion is then passed to either `Time#strftime`, `DateTime#strftime` or # `Timestamp#strftime` to handle any other format directives. # # This method is equivalent to the following: # # time_zone.to_local(time).strftime(format) # # @param format [String] the format string. # @param time [Object] a `Time`, `DateTime` or `Timestamp`. # @return [String] the formatted local time. # @raise [ArgumentError] if `format` or `time` is `nil`. # @raise [ArgumentError] if `time` is a {Timestamp} with an unspecified UTC # offset. def strftime(format, time = Time.now) to_local(time).strftime(format) end # @param time [Object] a `Time`, `DateTime` or `Timestamp`. # @return [String] the abbreviation of this {Timezone} at the given time. # @raise [ArgumentError] if `time` is `nil`. # @raise [ArgumentError] if `time` is a {Timestamp} with an unspecified UTC # offset. def abbreviation(time = Time.now) period_for(time).abbreviation end alias abbr abbreviation # @param time [Object] a `Time`, `DateTime` or `Timestamp`. # @return [Boolean] whether daylight savings time is in effect at the given # time. # @raise [ArgumentError] if `time` is `nil`. # @raise [ArgumentError] if `time` is a {Timestamp} with an unspecified UTC # offset. def dst?(time = Time.now) period_for(time).dst? end # Returns the base offset from UTC in seconds at the given time. This does # not include any adjustment made for daylight savings time and will # typically remain constant throughout the year. # # To obtain the observed offset from UTC, including the effect of daylight # savings time, use {observed_utc_offset} instead. # # If you require accurate {base_utc_offset} values, you should install the # tzinfo-data gem and set {DataSources::RubyDataSource} as the {DataSource}. # When using {DataSources::ZoneinfoDataSource}, the value of # {base_utc_offset} has to be derived from changes to the observed UTC # offset and DST status since it is not included in zoneinfo files. # # @param time [Object] a `Time`, `DateTime` or `Timestamp`. # @return [Integer] the base offset from UTC in seconds at the given time. # @raise [ArgumentError] if `time` is `nil`. # @raise [ArgumentError] if `time` is a {Timestamp} with an unspecified UTC # offset. def base_utc_offset(time = Time.now) period_for(time).base_utc_offset end # Returns the observed offset from UTC in seconds at the given time. This # includes adjustments made for daylight savings time. # # @param time [Object] a `Time`, `DateTime` or `Timestamp`. # @return [Integer] the observed offset from UTC in seconds at the given # time. # @raise [ArgumentError] if `time` is `nil`. # @raise [ArgumentError] if `time` is a {Timestamp} with an unspecified UTC # offset. def observed_utc_offset(time = Time.now) period_for(time).observed_utc_offset end alias utc_offset observed_utc_offset # Compares this {Timezone} with another based on the {identifier}. # # @param tz [Object] an `Object` to compare this {Timezone} with. # @return [Integer] -1 if `tz` is less than `self`, 0 if `tz` is equal to # `self` and +1 if `tz` is greater than `self`, or `nil` if `tz` is not an # instance of {Timezone}. def <=>(tz) return nil unless tz.is_a?(Timezone) identifier <=> tz.identifier end # @param tz [Object] an `Object` to compare this {Timezone} with. # @return [Boolean] `true` if `tz` is an instance of {Timezone} and has the # same {identifier} as `self`, otherwise `false`. def eql?(tz) self == tz end # @return [Integer] a hash based on the {identifier}. def hash identifier.hash end # Matches `regexp` against the {identifier} of this {Timezone}. # # @param regexp [Regexp] a `Regexp` to match against the {identifier} of # this {Timezone}. # @return [Integer] the position the match starts, or `nil` if there is no # match. def =~(regexp) regexp =~ identifier end # Returns a serialized representation of this {Timezone}. This method is # called when using `Marshal.dump` with an instance of {Timezone}. # # @param limit [Integer] the maximum depth to dump - ignored. # @return [String] a serialized representation of this {Timezone}. def _dump(limit) identifier end # Loads a {Timezone} from the serialized representation returned by {_dump}. # This is method is called when using `Marshal.load` or `Marshal.restore` # to restore a serialized {Timezone}. # # @param data [String] a serialized representation of a {Timezone}. # @return [Timezone] the result of converting `data` back into a {Timezone}. def self._load(data) Timezone.get(data) end private # Raises an {UnknownTimezone} exception. # # @raise [UnknownTimezone] always. def raise_unknown_timezone raise UnknownTimezone, 'TZInfo::Timezone should not be constructed directly (use TZInfo::Timezone.get instead)' end end end tzinfo-2.0.6/lib/tzinfo/timezone_offset.rb000066400000000000000000000107111436527530500206460ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true module TZInfo # Represents an offset from UTC observed by a time zone. class TimezoneOffset # Returns the base offset from UTC in seconds (`observed_utc_offset - # std_offset`). This does not include any adjustment made for daylight # savings time and will typically remain constant throughout the year. # # To obtain the currently observed offset from UTC, including the effect of # daylight savings time, use {observed_utc_offset} instead. # # If you require accurate {base_utc_offset} values, you should install the # tzinfo-data gem and set {DataSources::RubyDataSource} as the {DataSource}. # When using {DataSources::ZoneinfoDataSource}, the value of # {base_utc_offset} has to be derived from changes to the observed UTC # offset and DST status since it is not included in zoneinfo files. # # @return [Integer] the base offset from UTC in seconds. attr_reader :base_utc_offset alias utc_offset base_utc_offset # Returns the offset from the time zone's standard time in seconds # (`observed_utc_offset - base_utc_offset`). Zero when daylight savings time # is not in effect. Non-zero (usually 3600 = 1 hour) if daylight savings is # being observed. # # If you require accurate {std_offset} values, you should install the # tzinfo-data gem and set {DataSources::RubyDataSource} as the {DataSource}. # When using {DataSources::ZoneinfoDataSource}, the value of {std_offset} # has to be derived from changes to the observed UTC offset and DST status # since it is not included in zoneinfo files. # # @return [Integer] the offset from the time zone's standard time in # seconds. attr_reader :std_offset # Returns the observed offset from UTC in seconds (`base_utc_offset + # std_offset`). This includes adjustments made for daylight savings time. # # @return [Integer] the observed offset from UTC in seconds. attr_reader :observed_utc_offset alias utc_total_offset observed_utc_offset # The abbreviation that identifies this offset. For example GMT # (Greenwich Mean Time) or BST (British Summer Time) for Europe/London. # # @return [String] the abbreviation that identifies this offset. attr_reader :abbreviation alias abbr abbreviation # Initializes a new {TimezoneOffset}. # # {TimezoneOffset} instances should not normally be constructed manually. # # The passed in `abbreviation` instance will be frozen. # # @param base_utc_offset [Integer] the base offset from UTC in seconds. # @param std_offset [Integer] the offset from standard time in seconds. # @param abbreviation [String] the abbreviation identifying the offset. def initialize(base_utc_offset, std_offset, abbreviation) @base_utc_offset = base_utc_offset @std_offset = std_offset @abbreviation = abbreviation.freeze @observed_utc_offset = @base_utc_offset + @std_offset end # Determines if daylight savings is in effect (i.e. if {std_offset} is # non-zero). # # @return [Boolean] `true` if {std_offset} is non-zero, otherwise `false`. def dst? @std_offset != 0 end # Determines if this {TimezoneOffset} is equal to another instance. # # @param toi [Object] the instance to test for equality. # @return [Boolean] `true` if `toi` is a {TimezoneOffset} with the same # {utc_offset}, {std_offset} and {abbreviation} as this {TimezoneOffset}, # otherwise `false`. def ==(toi) toi.kind_of?(TimezoneOffset) && base_utc_offset == toi.base_utc_offset && std_offset == toi.std_offset && abbreviation == toi.abbreviation end # Determines if this {TimezoneOffset} is equal to another instance. # # @param toi [Object] the instance to test for equality. # @return [Boolean] `true` if `toi` is a {TimezoneOffset} with the same # {utc_offset}, {std_offset} and {abbreviation} as this {TimezoneOffset}, # otherwise `false`. def eql?(toi) self == toi end # @return [Integer] a hash based on {utc_offset}, {std_offset} and # {abbreviation}. def hash [@base_utc_offset, @std_offset, @abbreviation].hash end # @return [String] the internal object state as a programmer-readable # `String`. def inspect "#<#{self.class}: @base_utc_offset=#{@base_utc_offset}, @std_offset=#{@std_offset}, @abbreviation=#{@abbreviation}>" end end end tzinfo-2.0.6/lib/tzinfo/timezone_period.rb000066400000000000000000000155011436527530500206440ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true module TZInfo # {TimezonePeriod} represents a period of time for a time zone where the same # offset from UTC applies. It provides access to the observed offset, time # zone abbreviation, start time and end time. # # The period of time can be unbounded at the start, end, or both the start # and end. # # @abstract Time zone period data will returned as an instance of one of the # subclasses of {TimezonePeriod}. class TimezonePeriod # @return [TimezoneOffset] the offset that applies in the period of time. attr_reader :offset # Initializes a {TimezonePeriod}. # # @param offset [TimezoneOffset] the offset that is observed for the period # of time. # @raise [ArgumentError] if `offset` is `nil`. def initialize(offset) raise ArgumentError, 'offset must be specified' unless offset @offset = offset end # @return [TimezoneTransition] the transition that defines the start of this # {TimezonePeriod} (`nil` if the start is unbounded). def start_transition raise_not_implemented(:start_transition) end # @return [TimezoneTransition] the transition that defines the end of this # {TimezonePeriod} (`nil` if the end is unbounded). def end_transition raise_not_implemented(:end_transition) end # Returns the base offset from UTC in seconds (`observed_utc_offset - # std_offset`). This does not include any adjustment made for daylight # savings time and will typically remain constant throughout the year. # # To obtain the currently observed offset from UTC, including the effect of # daylight savings time, use {observed_utc_offset} instead. # # If you require accurate {base_utc_offset} values, you should install the # tzinfo-data gem and set {DataSources::RubyDataSource} as the {DataSource}. # When using {DataSources::ZoneinfoDataSource}, the value of # {base_utc_offset} has to be derived from changes to the observed UTC # offset and DST status since it is not included in zoneinfo files. # # @return [Integer] the base offset from UTC in seconds. def base_utc_offset @offset.base_utc_offset end alias utc_offset base_utc_offset # Returns the offset from the time zone's standard time in seconds # (`observed_utc_offset - base_utc_offset`). Zero when daylight savings time # is not in effect. Non-zero (usually 3600 = 1 hour) if daylight savings is # being observed. # # If you require accurate {std_offset} values, you should install the # tzinfo-data gem and set {DataSources::RubyDataSource} as the {DataSource}. # When using {DataSources::ZoneinfoDataSource}, the value of {std_offset} # has to be derived from changes to the observed UTC offset and DST status # since it is not included in zoneinfo files. # # @return [Integer] the offset from the time zone's standard time in # seconds. def std_offset @offset.std_offset end # The abbreviation that identifies this offset. For example GMT # (Greenwich Mean Time) or BST (British Summer Time) for Europe/London. # # @return [String] the abbreviation that identifies this offset. def abbreviation @offset.abbreviation end alias abbr abbreviation alias zone_identifier abbreviation # Returns the observed offset from UTC in seconds (`base_utc_offset + # std_offset`). This includes adjustments made for daylight savings time. # # @return [Integer] the observed offset from UTC in seconds. def observed_utc_offset @offset.observed_utc_offset end alias utc_total_offset observed_utc_offset # Determines if daylight savings is in effect (i.e. if {std_offset} is # non-zero). # # @return [Boolean] `true` if {std_offset} is non-zero, otherwise `false`. def dst? @offset.dst? end # Returns the UTC start time of the period or `nil` if the start of the # period is unbounded. # # The result is returned as a {Timestamp}. To obtain the start time as a # `Time` or `DateTime`, call either {Timestamp#to_time to_time} or # {Timestamp#to_datetime to_datetime} on the result. # # @return [Timestamp] the UTC start time of the period or `nil` if the start # of the period is unbounded. def starts_at timestamp(start_transition) end # Returns the UTC end time of the period or `nil` if the end of the period # is unbounded. # # The result is returned as a {Timestamp}. To obtain the end time as a # `Time` or `DateTime`, call either {Timestamp#to_time to_time} or # {Timestamp#to_datetime to_datetime} on the result. # # @return [Timestamp] the UTC end time of the period or `nil` if the end of # the period is unbounded. def ends_at timestamp(end_transition) end # Returns the local start time of the period or `nil` if the start of the # period is unbounded. # # The result is returned as a {TimestampWithOffset}. To obtain the start # time as a `Time` or `DateTime`, call either {TimestampWithOffset#to_time # to_time} or {TimestampWithOffset#to_datetime to_datetime} on the result. # # @return [TimestampWithOffset] the local start time of the period or `nil` # if the start of the period is unbounded. def local_starts_at timestamp_with_offset(start_transition) end # Returns the local end time of the period or `nil` if the end of the period # is unbounded. # # The result is returned as a {TimestampWithOffset}. To obtain the end time # as a `Time` or `DateTime`, call either {TimestampWithOffset#to_time # to_time} or {TimestampWithOffset#to_datetime to_datetime} on the result. # # @return [TimestampWithOffset] the local end time of the period or `nil` if # the end of the period is unbounded. def local_ends_at timestamp_with_offset(end_transition) end private # Raises a {NotImplementedError} to indicate that subclasses should override # a method. # # @raise [NotImplementedError] always. def raise_not_implemented(method_name) raise NotImplementedError, "Subclasses must override #{method_name}" end # @param transition [TimezoneTransition] a transition or `nil`. # @return [Timestamp] the {Timestamp} representing when a transition occurs, # or `nil` if `transition` is `nil`. def timestamp(transition) transition ? transition.at : nil end # @param transition [TimezoneTransition] a transition or `nil`. # @return [TimestampWithOffset] a {Timestamp} representing when a transition # occurs with offset set to {#offset}, or `nil` if `transition` is `nil`. def timestamp_with_offset(transition) transition ? TimestampWithOffset.set_timezone_offset(transition.at, offset) : nil end end end tzinfo-2.0.6/lib/tzinfo/timezone_proxy.rb000066400000000000000000000062441436527530500205470ustar00rootroot00000000000000# encoding: UTF-8 module TZInfo # A proxy class standing in for a {Timezone} with a given identifier. # {TimezoneProxy} inherits from {Timezone} and can be treated identically to # {Timezone} instances loaded with {Timezone.get}. # # {TimezoneProxy} instances are used to avoid the performance overhead of # loading time zone data into memory, for example, by {Timezone.all}. # # The first time an attempt is made to access the data for the time zone, the # real {Timezone} will be loaded is loaded. If the proxy's identifier was not # valid, then an exception will be raised at this point. class TimezoneProxy < Timezone # Initializes a new {TimezoneProxy}. # # The `identifier` parameter is not checked when initializing the proxy. It # will be validated when the real {Timezone} instance is loaded. # # @param identifier [String] an IANA Time Zone Database time zone # identifier. def initialize(identifier) super() @identifier = identifier @real_timezone = nil end # (see Timezone#identifier) def identifier @real_timezone ? @real_timezone.identifier : @identifier end # (see Timezone#period_for) def period_for(time) real_timezone.period_for_utc(time) end # (see Timezone#periods_for_local) def periods_for_local(local_time) real_timezone.periods_for_local(local_time) end # (see Timezone#transitions_up_to) def transitions_up_to(to, from = nil) real_timezone.transitions_up_to(to, from) end # (see Timezone#canonical_zone) def canonical_zone real_timezone.canonical_zone end # Returns a serialized representation of this {TimezoneProxy}. This method # is called when using `Marshal.dump` with an instance of {TimezoneProxy}. # # @param limit [Integer] the maximum depth to dump - ignored. @return # [String] a serialized representation of this {TimezoneProxy}. # @return [String] a serialized representation of this {TimezoneProxy}. def _dump(limit) identifier end # Loads a {TimezoneProxy} from the serialized representation returned by # {_dump}. This is method is called when using `Marshal.load` or # `Marshal.restore` to restore a serialized {Timezone}. # # @param data [String] a serialized representation of a {TimezoneProxy}. # @return [TimezoneProxy] the result of converting `data` back into a # {TimezoneProxy}. def self._load(data) TimezoneProxy.new(data) end private # Returns the real {Timezone} instance being proxied. # # The real {Timezone} is loaded using {Timezone.get} on the first access. # # @return [Timezone] the real {Timezone} instance being proxied. def real_timezone # Thread-safety: It is possible that the value of @real_timezone may be # calculated multiple times in concurrently executing threads. It is not # worth the overhead of locking to ensure that @real_timezone is only # calculated once. unless @real_timezone result = Timezone.get(@identifier) return result if frozen? @real_timezone = result end @real_timezone end end end tzinfo-2.0.6/lib/tzinfo/timezone_transition.rb000066400000000000000000000100261436527530500215510ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true module TZInfo # Represents a transition from one observed UTC offset ({TimezoneOffset} to # another for a time zone. class TimezoneTransition # @return [TimezoneOffset] the offset this transition changes to. attr_reader :offset # @return [TimezoneOffset] the offset this transition changes from. attr_reader :previous_offset # When this transition occurs as an `Integer` number of seconds since # 1970-01-01 00:00:00 UTC ignoring leap seconds (i.e. each day is treated as # if it were 86,400 seconds long). Equivalent to the result of calling the # {Timestamp#value value} method on the {Timestamp} returned by {at}. # # @return [Integer] when this transition occurs as a number of seconds since # 1970-01-01 00:00:00 UTC ignoring leap seconds. attr_reader :timestamp_value # Initializes a new {TimezoneTransition}. # # {TimezoneTransition} instances should not normally be constructed # manually. # # @param offset [TimezoneOffset] the offset the transition changes to. # @param previous_offset [TimezoneOffset] the offset the transition changes # from. # @param timestamp_value [Integer] when the transition occurs as a # number of seconds since 1970-01-01 00:00:00 UTC ignoring leap seconds # (i.e. each day is treated as if it were 86,400 seconds long). def initialize(offset, previous_offset, timestamp_value) @offset = offset @previous_offset = previous_offset @timestamp_value = timestamp_value end # Returns a {Timestamp} instance representing the UTC time when this # transition occurs. # # To obtain the result as a `Time` or `DateTime`, call either # {Timestamp#to_time to_time} or {Timestamp#to_datetime to_datetime} on the # {Timestamp} instance that is returned. # # @return [Timestamp] the UTC time when this transition occurs. def at Timestamp.utc(@timestamp_value) end # Returns a {TimestampWithOffset} instance representing the local time when # this transition causes the previous observance to end (calculated from # {at} using {previous_offset}). # # To obtain the result as a `Time` or `DateTime`, call either # {TimestampWithOffset#to_time to_time} or {TimestampWithOffset#to_datetime # to_datetime} on the {TimestampWithOffset} instance that is returned. # # @return [TimestampWithOffset] the local time when this transition causes # the previous observance to end. def local_end_at TimestampWithOffset.new(@timestamp_value, 0, @previous_offset.observed_utc_offset).set_timezone_offset(@previous_offset) end # Returns a {TimestampWithOffset} instance representing the local time when # this transition causes the next observance to start (calculated from {at} # using {offset}). # # To obtain the result as a `Time` or `DateTime`, call either # {TimestampWithOffset#to_time to_time} or {TimestampWithOffset#to_datetime # to_datetime} on the {TimestampWithOffset} instance that is returned. # # @return [TimestampWithOffset] the local time when this transition causes # the next observance to start. def local_start_at TimestampWithOffset.new(@timestamp_value, 0, @offset.observed_utc_offset).set_timezone_offset(@offset) end # Determines if this {TimezoneTransition} is equal to another instance. # # @param tti [Object] the instance to test for equality. # @return [Boolean] `true` if `tti` is a {TimezoneTransition} with the same # {offset}, {previous_offset} and {timestamp_value} as this # {TimezoneTransition}, otherwise `false`. def ==(tti) tti.kind_of?(TimezoneTransition) && offset == tti.offset && previous_offset == tti.previous_offset && timestamp_value == tti.timestamp_value end alias eql? == # @return [Integer] a hash based on {offset}, {previous_offset} and # {timestamp_value}. def hash [@offset, @previous_offset, @timestamp_value].hash end end end tzinfo-2.0.6/lib/tzinfo/transition_rule.rb000066400000000000000000000406301436527530500206720ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true module TZInfo # Base class for rules definining the transition between standard and daylight # savings time. # # @abstract # @private class TransitionRule #:nodoc: # Returns the number of seconds after midnight local time on the day # identified by the rule at which the transition occurs. Can be negative to # denote a time on the prior day. Can be greater than or equal to 86,400 to # denote a time of the following day. # # @return [Integer] the time in seconds after midnight local time at which # the transition occurs. attr_reader :transition_at # Initializes a new {TransitionRule}. # # @param transition_at [Integer] the time in seconds after midnight local # time at which the transition occurs. # @raise [ArgumentError] if `transition_at` is not an `Integer`. def initialize(transition_at) raise ArgumentError, 'Invalid transition_at' unless transition_at.kind_of?(Integer) @transition_at = transition_at end # Calculates the time of the transition from a given offset on a given year. # # @param offset [TimezoneOffset] the current offset at the time the rule # will transition. # @param year [Integer] the year in which the transition occurs (local # time). # @return [TimestampWithOffset] the time at which the transition occurs. def at(offset, year) day = get_day(offset, year) TimestampWithOffset.set_timezone_offset(Timestamp.for(day + @transition_at), offset) end # Determines if this {TransitionRule} is equal to another instance. # # @param r [Object] the instance to test for equality. # @return [Boolean] `true` if `r` is a {TransitionRule} with the same # {transition_at} as this {TransitionRule}, otherwise `false`. def ==(r) r.kind_of?(TransitionRule) && @transition_at == r.transition_at end alias eql? == # @return [Integer] a hash based on {hash_args} (defaulting to # {transition_at}). def hash hash_args.hash end protected # @return [Array] an `Array` of parameters that will influence the output of # {hash}. def hash_args [@transition_at] end end private_constant :TransitionRule # A base class for transition rules that activate based on an integer day of # the year. # # @abstract # @private class DayOfYearTransitionRule < TransitionRule #:nodoc: # Initializes a new {DayOfYearTransitionRule}. # # @param day [Integer] the day of the year on which the transition occurs. # The precise meaning is defined by subclasses. # @param transition_at [Integer] the time in seconds after midnight local # time at which the transition occurs. # @raise [ArgumentError] if `transition_at` is not an `Integer`. # @raise [ArgumentError] if `day` is not an `Integer`. def initialize(day, transition_at) super(transition_at) raise ArgumentError, 'Invalid day' unless day.kind_of?(Integer) @seconds = day * 86400 end # Determines if this {DayOfYearTransitionRule} is equal to another instance. # # @param r [Object] the instance to test for equality. # @return [Boolean] `true` if `r` is a {DayOfYearTransitionRule} with the # same {transition_at} and day as this {DayOfYearTransitionRule}, # otherwise `false`. def ==(r) super(r) && r.kind_of?(DayOfYearTransitionRule) && @seconds == r.seconds end alias eql? == protected # @return [Integer] the day multipled by the number of seconds in a day. attr_reader :seconds # (see TransitionRule#hash_args) def hash_args [@seconds] + super end end private_constant :DayOfYearTransitionRule # Defines transitions that occur on the zero-based nth day of the year. # # Day 0 is 1 January. # # Leap days are counted. Day 59 will be 29 February on a leap year and 1 March # on a non-leap year. Day 365 will be 31 December on a leap year and 1 January # the following year on a non-leap year. # # @private class AbsoluteDayOfYearTransitionRule < DayOfYearTransitionRule #:nodoc: # Initializes a new {AbsoluteDayOfYearTransitionRule}. # # @param day [Integer] the zero-based day of the year on which the # transition occurs (0 to 365 inclusive). # @param transition_at [Integer] the time in seconds after midnight local # time at which the transition occurs. # @raise [ArgumentError] if `transition_at` is not an `Integer`. # @raise [ArgumentError] if `day` is not an `Integer`. # @raise [ArgumentError] if `day` is less than 0 or greater than 365. def initialize(day, transition_at = 0) super(day, transition_at) raise ArgumentError, 'Invalid day' unless day >= 0 && day <= 365 end # @return [Boolean] `true` if the day specified by this transition is the # first in the year (a day number of 0), otherwise `false`. def is_always_first_day_of_year? seconds == 0 end # @return [Boolean] `false`. def is_always_last_day_of_year? false end # Determines if this {AbsoluteDayOfYearTransitionRule} is equal to another # instance. # # @param r [Object] the instance to test for equality. # @return [Boolean] `true` if `r` is a {AbsoluteDayOfYearTransitionRule} # with the same {transition_at} and day as this # {AbsoluteDayOfYearTransitionRule}, otherwise `false`. def ==(r) super(r) && r.kind_of?(AbsoluteDayOfYearTransitionRule) end alias eql? == protected # Returns a `Time` representing midnight local time on the day specified by # the rule for the given offset and year. # # @param offset [TimezoneOffset] the current offset at the time of the # transition. # @param year [Integer] the year in which the transition occurs. # @return [Time] midnight local time on the day specified by the rule for # the given offset and year. def get_day(offset, year) Time.new(year, 1, 1, 0, 0, 0, offset.observed_utc_offset) + seconds end # (see TransitionRule#hash_args) def hash_args [AbsoluteDayOfYearTransitionRule] + super end end # Defines transitions that occur on the one-based nth Julian day of the year. # # Leap days are not counted. Day 1 is 1 January. Day 60 is always 1 March. # Day 365 is always 31 December. # # @private class JulianDayOfYearTransitionRule < DayOfYearTransitionRule #:nodoc: # The 60 days in seconds. LEAP = 60 * 86400 private_constant :LEAP # The length of a non-leap year in seconds. YEAR = 365 * 86400 private_constant :YEAR # Initializes a new {JulianDayOfYearTransitionRule}. # # @param day [Integer] the one-based Julian day of the year on which the # transition occurs (1 to 365 inclusive). # @param transition_at [Integer] the time in seconds after midnight local # time at which the transition occurs. # @raise [ArgumentError] if `transition_at` is not an `Integer`. # @raise [ArgumentError] if `day` is not an `Integer`. # @raise [ArgumentError] if `day` is less than 1 or greater than 365. def initialize(day, transition_at = 0) super(day, transition_at) raise ArgumentError, 'Invalid day' unless day >= 1 && day <= 365 end # @return [Boolean] `true` if the day specified by this transition is the # first in the year (a day number of 1), otherwise `false`. def is_always_first_day_of_year? seconds == 86400 end # @return [Boolean] `true` if the day specified by this transition is the # last in the year (a day number of 365), otherwise `false`. def is_always_last_day_of_year? seconds == YEAR end # Determines if this {JulianDayOfYearTransitionRule} is equal to another # instance. # # @param r [Object] the instance to test for equality. # @return [Boolean] `true` if `r` is a {JulianDayOfYearTransitionRule} with # the same {transition_at} and day as this # {JulianDayOfYearTransitionRule}, otherwise `false`. def ==(r) super(r) && r.kind_of?(JulianDayOfYearTransitionRule) end alias eql? == protected # Returns a `Time` representing midnight local time on the day specified by # the rule for the given offset and year. # # @param offset [TimezoneOffset] the current offset at the time of the # transition. # @param year [Integer] the year in which the transition occurs. # @return [Time] midnight local time on the day specified by the rule for # the given offset and year. def get_day(offset, year) # Returns 1 March on non-leap years. leap = Time.new(year, 2, 29, 0, 0, 0, offset.observed_utc_offset) diff = seconds - LEAP diff += 86400 if diff >= 0 && leap.mday == 29 leap + diff end # (see TransitionRule#hash_args) def hash_args [JulianDayOfYearTransitionRule] + super end end private_constant :JulianDayOfYearTransitionRule # A base class for rules that transition on a particular day of week of a # given week (subclasses specify which week of the month). # # @abstract # @private class DayOfWeekTransitionRule < TransitionRule #:nodoc: # Initializes a new {DayOfWeekTransitionRule}. # # @param month [Integer] the month of the year when the transition occurs. # @param day_of_week [Integer] the day of the week when the transition # occurs. 0 is Sunday, 6 is Saturday. # @param transition_at [Integer] the time in seconds after midnight local # time at which the transition occurs. # @raise [ArgumentError] if `transition_at` is not an `Integer`. # @raise [ArgumentError] if `month` is not an `Integer`. # @raise [ArgumentError] if `month` is less than 1 or greater than 12. # @raise [ArgumentError] if `day_of_week` is not an `Integer`. # @raise [ArgumentError] if `day_of_week` is less than 0 or greater than 6. def initialize(month, day_of_week, transition_at) super(transition_at) raise ArgumentError, 'Invalid month' unless month.kind_of?(Integer) && month >= 1 && month <= 12 raise ArgumentError, 'Invalid day_of_week' unless day_of_week.kind_of?(Integer) && day_of_week >= 0 && day_of_week <= 6 @month = month @day_of_week = day_of_week end # @return [Boolean] `false`. def is_always_first_day_of_year? false end # @return [Boolean] `false`. def is_always_last_day_of_year? false end # Determines if this {DayOfWeekTransitionRule} is equal to another # instance. # # @param r [Object] the instance to test for equality. # @return [Boolean] `true` if `r` is a {DayOfWeekTransitionRule} with the # same {transition_at}, month and day of week as this # {DayOfWeekTransitionRule}, otherwise `false`. def ==(r) super(r) && r.kind_of?(DayOfWeekTransitionRule) && @month == r.month && @day_of_week == r.day_of_week end alias eql? == protected # @return [Integer] the month of the year (1 to 12). attr_reader :month # @return [Integer] the day of the week (0 to 6 for Sunday to Monday). attr_reader :day_of_week # (see TransitionRule#hash_args) def hash_args [@month, @day_of_week] + super end end private_constant :DayOfWeekTransitionRule # A rule that transitions on the nth occurrence of a particular day of week # of a calendar month. # # @private class DayOfMonthTransitionRule < DayOfWeekTransitionRule #:nodoc: # Initializes a new {DayOfMonthTransitionRule}. # # @param month [Integer] the month of the year when the transition occurs. # @param week [Integer] the week of the month when the transition occurs (1 # to 4). # @param day_of_week [Integer] the day of the week when the transition # occurs. 0 is Sunday, 6 is Saturday. # @param transition_at [Integer] the time in seconds after midnight local # time at which the transition occurs. # @raise [ArgumentError] if `transition_at` is not an `Integer`. # @raise [ArgumentError] if `month` is not an `Integer`. # @raise [ArgumentError] if `month` is less than 1 or greater than 12. # @raise [ArgumentError] if `week` is not an `Integer`. # @raise [ArgumentError] if `week` is less than 1 or greater than 4. # @raise [ArgumentError] if `day_of_week` is not an `Integer`. # @raise [ArgumentError] if `day_of_week` is less than 0 or greater than 6. def initialize(month, week, day_of_week, transition_at = 0) super(month, day_of_week, transition_at) raise ArgumentError, 'Invalid week' unless week.kind_of?(Integer) && week >= 1 && week <= 4 @offset_start = (week - 1) * 7 + 1 end # Determines if this {DayOfMonthTransitionRule} is equal to another # instance. # # @param r [Object] the instance to test for equality. # @return [Boolean] `true` if `r` is a {DayOfMonthTransitionRule} with the # same {transition_at}, month, week and day of week as this # {DayOfMonthTransitionRule}, otherwise `false`. def ==(r) super(r) && r.kind_of?(DayOfMonthTransitionRule) && @offset_start == r.offset_start end alias eql? == protected # @return [Integer] the day the week starts on for a month starting on a # Sunday. attr_reader :offset_start # Returns a `Time` representing midnight local time on the day specified by # the rule for the given offset and year. # # @param offset [TimezoneOffset] the current offset at the time of the # transition. # @param year [Integer] the year in which the transition occurs. # @return [Time] midnight local time on the day specified by the rule for # the given offset and year. def get_day(offset, year) candidate = Time.new(year, month, @offset_start, 0, 0, 0, offset.observed_utc_offset) diff = day_of_week - candidate.wday if diff < 0 candidate + (7 + diff) * 86400 elsif diff > 0 candidate + diff * 86400 else candidate end end # (see TransitionRule#hash_args) def hash_args [@offset_start] + super end end private_constant :DayOfMonthTransitionRule # A rule that transitions on the last occurrence of a particular day of week # of a calendar month. # # @private class LastDayOfMonthTransitionRule < DayOfWeekTransitionRule #:nodoc: # Initializes a new {LastDayOfMonthTransitionRule}. # # @param month [Integer] the month of the year when the transition occurs. # @param day_of_week [Integer] the day of the week when the transition # occurs. 0 is Sunday, 6 is Saturday. # @param transition_at [Integer] the time in seconds after midnight local # time at which the transition occurs. # @raise [ArgumentError] if `transition_at` is not an `Integer`. # @raise [ArgumentError] if `month` is not an `Integer`. # @raise [ArgumentError] if `month` is less than 1 or greater than 12. # @raise [ArgumentError] if `day_of_week` is not an `Integer`. # @raise [ArgumentError] if `day_of_week` is less than 0 or greater than 6. def initialize(month, day_of_week, transition_at = 0) super(month, day_of_week, transition_at) end # Determines if this {LastDayOfMonthTransitionRule} is equal to another # instance. # # @param r [Object] the instance to test for equality. # @return [Boolean] `true` if `r` is a {LastDayOfMonthTransitionRule} with # the same {transition_at}, month and day of week as this # {LastDayOfMonthTransitionRule}, otherwise `false`. def ==(r) super(r) && r.kind_of?(LastDayOfMonthTransitionRule) end alias eql? == protected # Returns a `Time` representing midnight local time on the day specified by # the rule for the given offset and year. # # @param offset [TimezoneOffset] the current offset at the time of the # transition. # @param year [Integer] the year in which the transition occurs. # @return [Time] midnight local time on the day specified by the rule for # the given offset and year. def get_day(offset, year) next_month = month + 1 if next_month == 13 year += 1 next_month = 1 end candidate = Time.new(year, next_month, 1, 0, 0, 0, offset.observed_utc_offset) - 86400 diff = candidate.wday - day_of_week if diff < 0 candidate - (diff + 7) * 86400 elsif diff > 0 candidate - diff * 86400 else candidate end end end private_constant :LastDayOfMonthTransitionRule end tzinfo-2.0.6/lib/tzinfo/transitions_timezone_period.rb000066400000000000000000000047131436527530500233040ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true module TZInfo # Represents a period of time in a time zone where the same offset from UTC # applies. The period of time is bounded at at least one end, either having a # start transition, end transition or both start and end transitions. class TransitionsTimezonePeriod < TimezonePeriod # @return [TimezoneTransition] the transition that defines the start of this # {TimezonePeriod} (`nil` if the start is unbounded). attr_reader :start_transition # @return [TimezoneTransition] the transition that defines the end of this # {TimezonePeriod} (`nil` if the end is unbounded). attr_reader :end_transition # Initializes a {TransitionsTimezonePeriod}. # # At least one of `start_transition` and `end_transition` must be specified. # # @param start_transition [TimezoneTransition] the transition that defines # the start of the period, or `nil` if the start is unbounded. # @param end_transition [TimezoneTransition] the transition that defines the # end of the period, or `nil` if the end is unbounded. # @raise [ArgumentError] if both `start_transition` and `end_transition` are # `nil`. def initialize(start_transition, end_transition) if start_transition super(start_transition.offset) elsif end_transition super(end_transition.previous_offset) else raise ArgumentError, 'At least one of start_transition and end_transition must be specified' end @start_transition = start_transition @end_transition = end_transition end # Determines if this {TransitionsTimezonePeriod} is equal to another # instance. # # @param p [Object] the instance to test for equality. # @return [Boolean] `true` if `p` is a {TransitionsTimezonePeriod} with the # same {offset}, {start_transition} and {end_transition}, otherwise # `false`. def ==(p) p.kind_of?(TransitionsTimezonePeriod) && start_transition == p.start_transition && end_transition == p.end_transition end alias eql? == # @return [Integer] a hash based on {start_transition} and {end_transition}. def hash [@start_transition, @end_transition].hash end # @return [String] the internal object state as a programmer-readable # `String`. def inspect "#<#{self.class}: @start_transition=#{@start_transition.inspect}, @end_transition=#{@end_transition.inspect}>" end end end tzinfo-2.0.6/lib/tzinfo/version.rb000066400000000000000000000001661436527530500171360ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true module TZInfo # The TZInfo version number. VERSION = '2.0.6' end tzinfo-2.0.6/lib/tzinfo/with_offset.rb000066400000000000000000000043651436527530500177770ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true module TZInfo # The {WithOffset} module is included in {TimeWithOffset}, # {DateTimeWithOffset} and {TimestampWithOffset}. It provides an override for # the {strftime} method that handles expanding the `%Z` directive according to # the {TimezoneOffset#abbreviation abbreviation} of the {TimezoneOffset} # associated with a local time. module WithOffset # Overrides the `Time`, `DateTime` or {Timestamp} version of `strftime`, # replacing `%Z` with the {TimezoneOffset#abbreviation abbreviation} of the # associated {TimezoneOffset}. If there is no associated offset, `%Z` is # expanded by the base class instead. # # All the format directives handled by the base class are supported. # # @param format [String] the format string. # @return [String] the formatted time. # @raise [ArgumentError] if `format` is `nil`. def strftime(format) raise ArgumentError, 'format must be specified' unless format if_timezone_offset do |o| abbreviation = nil format = format.gsub(/%(%*)Z/) do if $1.length.odd? # Return %%Z so the real strftime treats it as a literal %Z too. "#$1%Z" else "#$1#{abbreviation ||= o.abbreviation.gsub(/%/, '%%')}" end end end super end protected # Performs a calculation if there is an associated {TimezoneOffset}. # # @param result [Object] a result value that can be manipulated by the block # if there is an associated {TimezoneOffset}. # @yield [period, result] if there is an associated {TimezoneOffset}, the # block is yielded to in order to calculate the method result. # @yieldparam period [TimezoneOffset] the associated {TimezoneOffset}. # @yieldparam result [Object] the `result` parameter. # @yieldreturn [Object] the result of the calculation performed if there is # an associated {TimezoneOffset}. # @return [Object] the result of the block if there is an associated # {TimezoneOffset}, otherwise the `result` parameter. # # @private def if_timezone_offset(result = nil) #:nodoc: to = timezone_offset to ? yield(to, result) : result end end end tzinfo-2.0.6/test/000077500000000000000000000000001436527530500140215ustar00rootroot00000000000000tzinfo-2.0.6/test/data_sources/000077500000000000000000000000001436527530500164755ustar00rootroot00000000000000tzinfo-2.0.6/test/data_sources/tc_constant_offset_data_timezone_info.rb000066400000000000000000000042311436527530500266250ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true require_relative '../test_utils' module DataSources class TCConstantOffsetDataTimezoneInfo < Minitest::Test include TZInfo include TZInfo::DataSources def test_initialize offset = TimezoneOffset.new(-17900, 0, 'TESTLMT') identifier = 'Test/Zone'.dup refute(identifier.frozen?) i = ConstantOffsetDataTimezoneInfo.new(identifier, offset) assert_same(identifier, i.identifier) assert_same(offset, i.constant_offset) assert(identifier.frozen?) end def test_initialize_nil_identifier o = TimezoneOffset.new(-17900, 0, 'TESTLMT') error = assert_raises(ArgumentError) { ConstantOffsetDataTimezoneInfo.new(nil, o) } assert_match(/\bidentifier\b/, error.message) end def test_initialize_nil_constant_offset error = assert_raises(ArgumentError) { ConstantOffsetDataTimezoneInfo.new('Test/Zone', nil) } assert_match(/\bconstant_offset\b/, error.message) end def test_period_for o = TimezoneOffset.new(-17900, 0, 'TESTLMT') i = ConstantOffsetDataTimezoneInfo.new('Test/Zone', o) assert_equal(OffsetTimezonePeriod.new(o), i.period_for(Timestamp.for(Time.utc(2017,1,1,0,0,0)))) assert_equal(OffsetTimezonePeriod.new(o), i.period_for(Timestamp.for(Time.new(2017,1,1,0,0,0,0)))) assert_equal(OffsetTimezonePeriod.new(o), i.period_for(Timestamp.for(Time.new(2017,1,1,1,0,0,3600)))) end def test_periods_for_local o = TimezoneOffset.new(-17900, 0, 'TESTLMT') i = ConstantOffsetDataTimezoneInfo.new('Test/Zone', o) assert_equal([OffsetTimezonePeriod.new(o)], i.periods_for_local(Timestamp.for(Time.utc(2017,1,1,0,0,0), :ignore))) end def test_transitions_up_to i = ConstantOffsetDataTimezoneInfo.new('Test/Zone', TimezoneOffset.new(-17900, 0, 'TESTLMT')) assert_equal([], i.transitions_up_to(Timestamp.for(Time.utc(2017,1,1,0,0,0)))) end def test_inspect i = ConstantOffsetDataTimezoneInfo.new('Test/Zone', TimezoneOffset.new(0, 0, 'TEST')) assert_equal('#', i.inspect) end end end tzinfo-2.0.6/test/data_sources/tc_country_info.rb000066400000000000000000000050051436527530500222260ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true require_relative '../test_utils' module DataSources class TCCountryInfo < Minitest::Test include TZInfo include TZInfo::DataSources def test_initialize_nil_code error = assert_raises(ArgumentError) { CountryInfo.new(nil, 'Zzz', []) } assert_match(/\bcode\b/, error.message) end def test_initialize_nil_name error = assert_raises(ArgumentError) { CountryInfo.new('ZZ', nil, []) } assert_match(/\bname\b/, error.message) end def test_initialize_nil_zones error = assert_raises(ArgumentError) { CountryInfo.new('ZZ', 'Zzz', nil) } assert_match(/\bzones\b/, error.message) end def test_code ci = CountryInfo.new('ZZ', 'Zzz', []) assert_equal('ZZ', ci.code) end def test_code_frozen code = 'ZZ'.dup refute(code.frozen?) ci = CountryInfo.new(code, 'Zzz', []) assert_same(code, ci.code) assert(ci.code.frozen?) end def test_name ci = CountryInfo.new('ZZ', 'Zzz', []) assert_equal('Zzz', ci.name) end def test_name_frozen name = 'Zzz'.dup refute(name.frozen?) ci = CountryInfo.new('ZZ', name, []) assert_same(name, ci.name) assert(ci.name.frozen?) end def test_zones_empty zones = [] ci = CountryInfo.new('ZZ', 'Zzz', zones) value = ci.zones assert_equal([], value) assert_same(zones, value) assert(value.frozen?) end def test_zones zones = [ CountryTimezone.new('ZZ/TimezoneB', Rational(1, 2), Rational(1, 2), 'Timezone B'), CountryTimezone.new('ZZ/TimezoneA', Rational(1, 4), Rational(1, 4), 'Timezone A'), CountryTimezone.new('ZZ/TimezoneC', Rational(-10, 3), Rational(-20, 7), 'C'), CountryTimezone.new('ZZ/TimezoneD', Rational(-10, 3), Rational(-20, 7)) ] ci = CountryInfo.new('ZZ', 'Zzz', zones) value = ci.zones assert_equal([CountryTimezone.new('ZZ/TimezoneB', Rational(1, 2), Rational(1, 2), 'Timezone B'), CountryTimezone.new('ZZ/TimezoneA', Rational(1, 4), Rational(1, 4), 'Timezone A'), CountryTimezone.new('ZZ/TimezoneC', Rational(-10, 3), Rational(-20, 7), 'C'), CountryTimezone.new('ZZ/TimezoneD', Rational(-10, 3), Rational(-20, 7))], value) assert_same(zones, value) assert(value.frozen?) end def test_inspect ci = CountryInfo.new('ZZ', 'Zzz', []) assert_equal('#', ci.inspect) end end end tzinfo-2.0.6/test/data_sources/tc_data_timezone_info.rb000066400000000000000000000036031436527530500233500ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true require_relative '../test_utils' module DataSources class TCDataTimezoneInfo < Minitest::Test include TZInfo include TZInfo::DataSources def test_initialize_nil_identifier error = assert_raises(ArgumentError) { DataTimezoneInfo.new(nil) } assert_match(/\bidentifier\b/, error.message) end def test_identifier ti = DataTimezoneInfo.new('Test/Zone') assert_equal('Test/Zone', ti.identifier) end def test_identifier_frozen identifier = 'Test/Zone'.dup refute(identifier.frozen?) lti = DataTimezoneInfo.new(identifier) assert_same(identifier, lti.identifier) assert(lti.identifier.frozen?) end def test_construct_timezone ti = DataTimezoneInfo.new('Test/Zone') tz = ti.create_timezone assert_kind_of(DataTimezone, tz) assert_equal('Test/Zone', tz.identifier) end def test_period_for ti = DataTimezoneInfo.new('Test/Zone') ts = Timestamp.utc(1480291200) error = assert_raises(NotImplementedError) { ti.period_for(ts) } assert_equal('Subclasses must override period_for', error.message) end def test_periods_for_local ti = DataTimezoneInfo.new('Test/Zone') ts = Timestamp.new(1480291200) error = assert_raises(NotImplementedError) { ti.periods_for_local(ts) } assert_equal('Subclasses must override periods_for_local', error.message) end def test_transitions_up_to ti = DataTimezoneInfo.new('Test/Zone') ts = Timestamp.utc(1480291200) error = assert_raises(NotImplementedError) { ti.transitions_up_to(ts) } assert_equal('Subclasses must override transitions_up_to', error.message) end def test_inspect ti = DataTimezoneInfo.new('Test/Zone') assert_equal('#', ti.inspect) end end end tzinfo-2.0.6/test/data_sources/tc_linked_timezone_info.rb000066400000000000000000000036051436527530500237070ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true require_relative '../test_utils' module DataSources class TCLinkedTimezoneInfo < Minitest::Test include TZInfo include TZInfo::DataSources def test_initialize_nil_identifier error = assert_raises(ArgumentError) { LinkedTimezoneInfo.new(nil, 'Test/Linked') } assert_match(/\bidentifier\b/, error.message) end def test_initialize_nil_link_to_identifier error = assert_raises(ArgumentError) { LinkedTimezoneInfo.new('Test/Zone', nil) } assert_match(/\blink_to_identifier\b/, error.message) end def test_identifier lti = LinkedTimezoneInfo.new('Test/Zone', 'Test/Linked') assert_equal('Test/Zone', lti.identifier) end def test_identifier_frozen identifier = 'Test/Zone'.dup refute(identifier.frozen?) lti = LinkedTimezoneInfo.new(identifier, 'Test/Linked') assert_same(identifier, lti.identifier) assert(lti.identifier.frozen?) end def test_link_to_identifier lti = LinkedTimezoneInfo.new('Test/Zone', 'Test/Linked') assert_equal('Test/Linked', lti.link_to_identifier) assert(lti.link_to_identifier.frozen?) end def test_link_to_identifier_frozen link_to_identifier = 'Test/Linked'.dup refute(link_to_identifier.frozen?) lti = LinkedTimezoneInfo.new('Test/Zone', link_to_identifier) assert_same(link_to_identifier, lti.link_to_identifier) assert(lti.link_to_identifier.frozen?) end def test_construct_timezone lti = LinkedTimezoneInfo.new('Test/Zone', 'Europe/London') tz = lti.create_timezone assert_kind_of(LinkedTimezone, tz) assert_equal('Test/Zone', tz.identifier) end def test_inspect lti = LinkedTimezoneInfo.new('Test/Zone', 'Europe/London') assert_equal('#', lti.inspect) end end end tzinfo-2.0.6/test/data_sources/tc_posix_time_zone_parser.rb000066400000000000000000000260521436527530500243040ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true require_relative '../test_utils' module DataSources class TCPosixTimeZoneParser < Minitest::Test include TZInfo include TZInfo::DataSources HOUR = 3600 MINUTE = 60 class << self include TZInfo::DataSources private def append_time_to_rule(day_rule, time) time ? "#{day_rule}/#{time}" : day_rule end def define_invalid_dst_rule_tests(type, rule) define_method "test_#{type}_dst_start_rule_for_invalid_#{rule}" do tz_string = "STD-1DST,#{rule},300" assert_raises(InvalidPosixTimeZone) { @parser.parse(tz_string) } end define_method "test_#{type}_dst_end_rule_for_invalid_#{rule}" do tz_string = "STD-1DST,60,#{rule}" assert_raises(InvalidPosixTimeZone) { @parser.parse(tz_string) } end end end def setup @string_deduper = StringDeduper.new @parser = PosixTimeZoneParser.new(@string_deduper) end def test_empty_rule_returns_nil result = @parser.parse('') assert_nil(result) end ABBREVIATIONS_WITH_OFFSETS = [ ['UTC0', 'UTC', 0], ['U0', 'U', 0], ['West1', 'West', -HOUR], ['East-1', 'East', HOUR], ['<-05>5', '-05', -5 * HOUR], ['<+12>-12', '+12', 12 * HOUR], ['HMM2:30', 'HMM', -(2 * HOUR + 30 * MINUTE)], ['HHMM02:30', 'HHMM', -(2 * HOUR + 30 * MINUTE)], ['HHMM+02:30', 'HHMM', -(2 * HOUR + 30 * MINUTE)], ['HHMSS-12:5:50', 'HHMSS', 12 * HOUR + 5 * MINUTE + 50], ['HHMMSS-12:05:50', 'HHMMSS', 12 * HOUR + 5 * MINUTE + 50], ['HHMMS-12:05:7', 'HHMMS', 12 * HOUR + 5 * MINUTE + 7] ] ABBREVIATIONS_WITH_OFFSETS.each do |(tz_string, expected_abbrev, expected_base_offset)| define_method "test_std_only_returns_std_offset_#{tz_string}" do result = @parser.parse(tz_string) expected = TimezoneOffset.new(expected_base_offset, 0, expected_abbrev) assert_equal(expected, result) end end ABBREVIATIONS_WITH_OFFSETS.each do |(abbrev_and_offset, expected_abbrev, expected_base_offset)| define_method "test_std_offset_#{abbrev_and_offset}" do result = @parser.parse(abbrev_and_offset + 'DST,60,300') expected_std_offset = TimezoneOffset.new(expected_base_offset, 0, expected_abbrev) assert_equal(expected_std_offset, result.std_offset) end end [ ['Zero0One-1', 'One', 0, HOUR], ['Zero0One', 'One', 0, HOUR], ['Z0O', 'O', 0, HOUR], ['West1WestS0', 'WestS', -HOUR, HOUR], ['West1WestS', 'WestS', -HOUR, HOUR], ['East-1EastS-2', 'EastS', HOUR, HOUR], ['East-1EastS', 'EastS', HOUR, HOUR], ['Neg2NegS3', 'NegS', -2 * HOUR, -HOUR], ['<-05>5<-04>4', '-04', -5 * HOUR, HOUR], ['STD5<-04>4', '-04', -5 * HOUR, HOUR], ['<+12>-12<+13>-13', '+13', 12 * HOUR, HOUR], ['STD-12<+13>-13', '+13', 12 * HOUR, HOUR], ['HMM2:30SHMM1:15', 'SHMM', -(2 * HOUR + 30 * MINUTE), HOUR + 15 * MINUTE], ['HHMM02:30SHHMM01:15', 'SHHMM', -(2 * HOUR + 30 * MINUTE), HOUR + 15 * MINUTE], ['HHMM+02:30SHHMM+01:15', 'SHHMM', -(2 * HOUR + 30 * MINUTE), HOUR + 15 * MINUTE], ['HHMSS-12:5:50SHHMSS-13:4:30', 'SHHMSS', 12 * HOUR + 5 * MINUTE + 50, 58 * MINUTE + 40], ['HHMMSS-12:05:50SHHMMSS-13:04:30', 'SHHMMSS', 12 * HOUR + 5 * MINUTE + 50, 58 * MINUTE + 40], ['HHMMS-12:05:7SHHMMSS-13:06:8', 'SHHMMSS', 12 * HOUR + 5 * MINUTE + 7, HOUR + MINUTE + 1], ].each do |(abbrevs_and_offsets, expected_abbrev, expected_base_offset, expected_std_offset)| define_method "test_dst_offset_#{abbrevs_and_offsets}" do result = @parser.parse(abbrevs_and_offsets + ',60,300') expected_dst_offset = TimezoneOffset.new(expected_base_offset, expected_std_offset, expected_abbrev) assert_equal(expected_dst_offset, result.dst_offset) end end ['01:-1', '01:60', '01:00:-1', '01:00:60'].each do |abbrev_and_offset| ['', 'DST,60,300'].each do |dst_suffix| tz_string = abbrev_and_offset + dst_suffix define_method "test_std_offset_invalid_#{tz_string}" do assert_raises(InvalidPosixTimeZone) { @parser.parse(tz_string) } end end tz_string = "STD1#{abbrev_and_offset},60,300" define_method "test_dst_offset_invalid_#{tz_string}" do assert_raises(InvalidPosixTimeZone) { @parser.parse(tz_string) } end end [ [nil, 2 * HOUR], ['2', 2 * HOUR], ['+2', 2 * HOUR], ['-2', -2 * HOUR], ['2:3:4', 2 * HOUR + 3 * MINUTE + 4], ['02:03:04', 2 * HOUR + 3 * MINUTE + 4], ['-2:3:4', -2 * HOUR + 3 * MINUTE + 4], # 22:03:04 on the day prior to the one specified ['-02:03:04', -2 * HOUR + 3 * MINUTE + 4], ['167', 167 * HOUR], ['-167', -167 * HOUR] ].each do |(time, expected_offset_from_midnight)| [ ['J1', 1], ['J365', 365] ].each do |(julian_day_rule, expected_julian_day)| rule = append_time_to_rule(julian_day_rule, time) define_method "test_julian_day_dst_start_rule_for_#{rule}" do result = @parser.parse("STD-1DST,#{rule},300") expected_dst_start_rule = JulianDayOfYearTransitionRule.new(expected_julian_day, expected_offset_from_midnight) assert_equal(expected_dst_start_rule, result.dst_start_rule) end define_method "test_julian_day_dst_end_rule_for_#{rule}" do result = @parser.parse("STD-1DST,60,#{rule}") expected_dst_end_rule = JulianDayOfYearTransitionRule.new(expected_julian_day, expected_offset_from_midnight) assert_equal(expected_dst_end_rule, result.dst_end_rule) end end [ ['0', 0], ['365', 365] ].each do |(absolute_day_rule, expected_day)| rule = append_time_to_rule(absolute_day_rule, time) define_method "test_absolute_day_dst_start_rule_for_#{rule}" do result = @parser.parse("STD-1DST,#{rule},J300") expected_dst_start_rule = AbsoluteDayOfYearTransitionRule.new(expected_day, expected_offset_from_midnight) assert_equal(expected_dst_start_rule, result.dst_start_rule) end define_method "test_absolute_day_dst_end_rule_for_#{rule}" do result = @parser.parse("STD-1DST,J60,#{rule}") expected_dst_end_rule = AbsoluteDayOfYearTransitionRule.new(expected_day, expected_offset_from_midnight) assert_equal(expected_dst_end_rule, result.dst_end_rule) end end [ ['M1.1.0', 1, 1, 0], ['M12.4.6', 12, 4, 6] ].each do |(day_of_month_rule, expected_month, expected_week, expected_day_of_week)| rule = append_time_to_rule(day_of_month_rule, time) define_method "test_day_of_month_dst_start_rule_for_#{rule}" do result = @parser.parse("STD-1DST,#{rule},300") expected_dst_start_rule = DayOfMonthTransitionRule.new(expected_month, expected_week, expected_day_of_week, expected_offset_from_midnight) assert_equal(expected_dst_start_rule, result.dst_start_rule) end define_method "test_day_of_month_dst_end_rule_for_#{rule}" do result = @parser.parse("STD-1DST,60,#{rule}") expected_dst_end_rule = DayOfMonthTransitionRule.new(expected_month, expected_week, expected_day_of_week, expected_offset_from_midnight) assert_equal(expected_dst_end_rule, result.dst_end_rule) end end [ ['M1.5.0', 1, 0], ['M12.5.6', 12, 6] ].each do |(last_day_of_month_rule, expected_month, expected_day_of_week)| rule = append_time_to_rule(last_day_of_month_rule, time) define_method "test_last_day_of_month_dst_start_rule_for_#{rule}" do result = @parser.parse("STD-1DST,#{rule},300") expected_dst_start_rule = LastDayOfMonthTransitionRule.new(expected_month, expected_day_of_week, expected_offset_from_midnight) assert_equal(expected_dst_start_rule, result.dst_start_rule) end define_method "test_last_day_of_month_dst_end_rule_for_#{rule}" do result = @parser.parse("STD-1DST,60,#{rule}") expected_dst_end_rule = LastDayOfMonthTransitionRule.new(expected_month, expected_day_of_week, expected_offset_from_midnight) assert_equal(expected_dst_end_rule, result.dst_end_rule) end end end ['J0', 'J366'].each do |julian_day_rule| define_invalid_dst_rule_tests('julian_day', julian_day_rule) end ['-1', '366'].each do |absolute_day_rule| define_invalid_dst_rule_tests('absolute_day', absolute_day_rule) end ['M0,1,0', 'M13,1,0', 'M6,0,0', 'M6,6,0', 'M6,1,-1', 'M6,1,7'].each do |day_of_month_rule| define_invalid_dst_rule_tests('day_of_month', day_of_month_rule) end ['M0,5,0', 'M13,5,0', 'M6,5,-1', 'M6,5,7'].each do |last_day_of_month_rule| define_invalid_dst_rule_tests('last_day_of_month', last_day_of_month_rule) end def test_invalid_dst_start_rule assert_raises(InvalidPosixTimeZone) { @parser.parse('STD1DST,X60,300') } end def test_invalid_dst_end_rule assert_raises(InvalidPosixTimeZone) { @parser.parse('STD1DST,60,X300') } end [ ['STD5DST,0/0,J365/25', 'DST', -5 * HOUR, HOUR], ['STD-5DST,0/0,J365/25', 'DST', 5 * HOUR, HOUR], ['STD5DST3,0/0,J365/26', 'DST', -5 * HOUR, 2 * HOUR], ['STD5DST6,0/0,J365/23', 'DST', -5 * HOUR, -HOUR], ['STD5DST,J1/0,J365/25', 'DST', -5 * HOUR, HOUR], ['Winter5Summer,0/0,J365/25', 'Summer', -5 * HOUR, HOUR], ['<-05>5<-06>,0/0,J365/25', '-06', -5 * HOUR, HOUR] ].each do |(tz_string, expected_abbrev, expected_base_offset, expected_std_offset)| define_method "test_dst_only_returns_continuous_offset_for_#{tz_string}" do result = @parser.parse(tz_string) expected = TimezoneOffset.new(expected_base_offset, expected_std_offset, expected_abbrev) assert_equal(expected, result) end end def test_returns_deduped_strings std = @string_deduper.dedupe('STD'.dup) dst = @string_deduper.dedupe('DST'.dup) result = @parser.parse('STD1DST,60,300') assert_same(std, result.std_offset.abbreviation) assert_same(dst, result.dst_offset.abbreviation) end def test_parses_tainted_string_in_safe_mode_and_returns_untainted_abbreviations skip_if_taint_is_undefined_or_no_op safe_test(unavailable: :skip) do result = @parser.parse('STD1DST,60,300'.dup.taint) refute(result.std_offset.abbreviation.tainted?) refute(result.dst_offset.abbreviation.tainted?) end end ['STD1', 'STD1DST,60,300'].each do |tz_string| tz_string += "-" define_method "test_content_after_end_for_#{tz_string}" do error = assert_raises(InvalidPosixTimeZone) { @parser.parse(tz_string) } assert_equal("Expected the end of a POSIX-style time zone string but found '-'.", error.message) end end ['X', 0].each do |invalid_tz_string| define_method "test_invalid_tz_string_#{invalid_tz_string}" do assert_raises(InvalidPosixTimeZone) { @parser.parse(invalid_tz_string) } end end end end tzinfo-2.0.6/test/data_sources/tc_ruby_data_source.rb000066400000000000000000000264331436527530500230520ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true require_relative '../test_utils' module DataSources class TCRubyDataSource < Minitest::Test include TZInfo include TZInfo::DataSources def setup @data_source = RubyDataSource.new end def test_initialize_not_found code = <<-EOF begin ds = TZInfo::DataSources::RubyDataSource.new puts "No exception raised, returned \#{ds} instead" rescue Exception => e puts e.class puts e.message end EOF assert_sub_process_returns([ 'TZInfo::DataSources::TZInfoDataNotFound', 'The tzinfo-data gem could not be found (require \'tzinfo/data\' failed).'], code) end def test_load_timezone_info_data info = @data_source.send(:load_timezone_info, 'Europe/London') assert_kind_of(DataTimezoneInfo, info) assert_equal('Europe/London', info.identifier) end def test_load_timezone_info_linked info = @data_source.send(:load_timezone_info, 'UTC') assert_kind_of(LinkedTimezoneInfo, info) assert_equal('UTC', info.identifier) assert_equal('Etc/UTC', info.link_to_identifier) end def test_load_timezone_info_does_not_exist error = assert_raises(InvalidTimezoneIdentifier) do @data_source.send(:load_timezone_info, 'Nowhere/Special') end assert_match(/\bNowhere\/Special\b/, error.message) end test_encodings('UTF-8', 'UTF-16').each do |encoding| define_method("test_load_timezone_info_in_index_but_file_does_not_exist_with_#{encoding.to_method}_encoded_identifier") do error = assert_raises(InvalidTimezoneIdentifier) do @data_source.send(:load_timezone_info, 'Europe/Berlin'.encode(encoding.name)) end assert_match(/\bEurope\/Berlin\b/, error.message) assert_equal(Encoding::UTF_8, error.message.encoding) assert_kind_of(LoadError, error.cause) if error.respond_to?(:cause) end define_method("test_load_timezone_info_module_names_do_not_match_zone_with_#{encoding.to_method}_encoded_identifier") do def @data_source.validate_timezone_identifier(identifier) identifier = identifier.encode(Encoding::UTF_8) raise "Unexpected identifier passed to validate_timezone_identifier: #{identifier}" unless identifier == 'Invalid/Incorrect_Module' 'Invalid/Incorrect_Module'.freeze end error = assert_raises(InvalidTimezoneIdentifier) do @data_source.send(:load_timezone_info, 'Invalid/Incorrect_Module'.encode(encoding.name)) end assert_match(/\bInvalid\/Incorrect_Module\b/, error.message) assert_kind_of(NameError, error.cause) if error.respond_to?(:cause) end end def test_load_timezone_info_invalid error = assert_raises(InvalidTimezoneIdentifier) do @data_source.send(:load_timezone_info, '../definitions/UTC') end assert_match(/\W\.\.\/definitions\/UTC\b/, error.message) end def test_load_timezone_info_nil error = assert_raises(InvalidTimezoneIdentifier) do @data_source.send(:load_timezone_info, nil) end assert_match(/\bnil\b/, error.message) end def test_load_timezone_info_false error = assert_raises(InvalidTimezoneIdentifier) do @data_source.send(:load_timezone_info, false) end assert_match(/\bfalse\b/, error.message) end def test_load_timezone_info_case error = assert_raises(InvalidTimezoneIdentifier) do @data_source.send(:load_timezone_info, 'europe/london') end assert_match(/\beurope\/london\b/, error.message) end def test_load_timezone_info_plus info = @data_source.send(:load_timezone_info, 'Etc/GMT+1') assert_equal('Etc/GMT+1', info.identifier) end def test_load_timezone_info_minus info = @data_source.send(:load_timezone_info, 'Etc/GMT-1') assert_equal('Etc/GMT-1', info.identifier) end def test_load_timezone_info_tainted skip_if_taint_is_undefined_or_no_op safe_test(unavailable: :skip) do identifier = 'Europe/Amsterdam'.dup.taint assert(identifier.tainted?) info = @data_source.send(:load_timezone_info, identifier) assert_equal('Europe/Amsterdam', info.identifier) assert(identifier.tainted?) end end def test_load_timezone_info_tainted_and_frozen skip_if_taint_is_undefined_or_no_op safe_test do info = @data_source.send(:load_timezone_info, 'Europe/Amsterdam'.dup.taint.freeze) assert_equal('Europe/Amsterdam', info.identifier) end end def test_load_timezone_info_returned_identifier_frozen info = @data_source.send(:load_timezone_info, 'Europe/London') assert(info.identifier.frozen?) end def test_load_timezone_info_parameter_remains_unfrozen identifier = 'Europe/London'.dup info = @data_source.send(:load_timezone_info, identifier) assert_equal('Europe/London', info.identifier) refute_same(identifier, info.identifier) assert(!identifier.frozen?) end def test_get_timezone_info info = @data_source.get_timezone_info('Europe/London') assert_equal('Europe/London', info.identifier) end test_encodings('UTF-8', 'UTF-16', 'ISO-8859-1') do |encoding| define_method("test_load_timezone_info_with_#{encoding.to_method}_encoded_identifier") do identifier = 'Europe/London'.encode(encoding.name).freeze info = @data_source.send(:load_timezone_info, identifier) assert_equal('Europe/London', info.identifier) end end def test_timezone_identifiers all = @data_source.timezone_identifiers assert_equal((TZInfo::Data::Indexes::Timezones.data_timezones + TZInfo::Data::Indexes::Timezones.linked_timezones).sort, all) assert(all.frozen?) assert(all.all?(&:frozen?)) end def test_data_timezone_identifiers all_data = @data_source.data_timezone_identifiers assert_same(TZInfo::Data::Indexes::Timezones.data_timezones, all_data) assert(all_data.frozen?) assert(all_data.all?(&:frozen?)) end def test_linked_timezone_identifiers all_linked = @data_source.linked_timezone_identifiers assert_same(TZInfo::Data::Indexes::Timezones.linked_timezones, all_linked) assert(all_linked.frozen?) assert(all_linked.all?(&:frozen?)) end def test_load_country_info info = @data_source.send(:load_country_info, 'GB') assert_equal('GB', info.code) end def test_load_country_info_not_exist error = assert_raises(InvalidCountryCode) do @data_source.send(:load_country_info, 'ZZ') end assert_match(/\bZZ\b/, error.message) end def test_load_country_info_invalid error = assert_raises(InvalidCountryCode) do @data_source.send(:load_country_info, '../Countries/GB') end assert_match(/\W\.\.\/Countries\/GB\b/, error.message) end def test_load_country_info_nil error = assert_raises(InvalidCountryCode) do @data_source.send(:load_country_info, nil) end assert_match(/\bnil\b/, error.message) end def test_load_country_info_false error = assert_raises(InvalidCountryCode) do @data_source.send(:load_country_info, false) end assert_match(/\bfalse\b/, error.message) end def test_load_country_info_case error = assert_raises(InvalidCountryCode) do @data_source.send(:load_country_info, 'gb') end assert_match(/\bgb\b/, error.message) end def test_load_country_info_tainted skip_if_taint_is_undefined_or_no_op safe_test(unavailable: :skip) do code = 'NL'.dup.taint assert(code.tainted?) info = @data_source.send(:load_country_info, code) assert_equal('NL', info.code) assert(code.tainted?) end end def test_load_country_info_tainted_and_frozen skip_if_taint_is_undefined_or_no_op safe_test do info = @data_source.send(:load_country_info, 'NL'.dup.taint.freeze) assert_equal('NL', info.code) end end def test_load_country_info_returned_strings_frozen info = @data_source.send(:load_country_info, 'US') assert(info.code.frozen?) assert(info.name.frozen?) assert(info.zones.map(&:identifier).all?(&:frozen?)) assert(info.zones.map(&:description).all?(&:frozen?)) end test_encodings('UTF-8', 'UTF-16', 'ISO-8859-1') do |encoding| define_method("test_load_country_info_with_#{encoding.to_method}_encoded_code") do code = 'GB'.encode(encoding.name).freeze info = @data_source.send(:load_country_info, code) assert_equal('GB', info.code) end end def test_get_country_info info = @data_source.get_country_info('GB') assert_equal('GB', info.code) end def test_country_codes codes = @data_source.country_codes assert_equal(TZInfo::Data::Indexes::Countries.countries.keys.sort, codes) assert(codes.frozen?) assert(codes.all?(&:frozen?)) assert_same(codes, @data_source.country_codes) end def test_to_s assert_equal("Ruby DataSource: tzdb v2020d, tzinfo-data v#{defined?(TZINFO_TEST_DATA_FORMAT) ? TZINFO_TEST_DATA_FORMAT : 2}.2020.4.test", @data_source.to_s) end def test_inspect assert_equal("#", @data_source.inspect) end if defined?(TZINFO_TEST_DATA_FORMAT) && TZINFO_TEST_DATA_FORMAT == 1 # The TZInfo::Data::VERSION and TZInfo::Data::Version::STRING constants # are only available from v1.2014.8 onwards. def test_to_s_no_tzinfo_data_version code = <<-EOF $:.unshift('#{TZINFO_TEST_DATA_DIR}') require 'tzinfo/data' TZInfo::Data.send(:remove_const, :VERSION) TZInfo::Data::Version.send(:remove_const, :STRING) ds = TZInfo::DataSources::RubyDataSource.new puts ds.to_s EOF assert_sub_process_returns(['Ruby DataSource: tzdb v2020d'], code) end def test_inspect_no_tzinfo_data_version code = <<-EOF $:.unshift('#{TZINFO_TEST_DATA_DIR}') require 'tzinfo/data' TZInfo::Data.send(:remove_const, :VERSION) TZInfo::Data::Version.send(:remove_const, :STRING) ds = TZInfo::DataSources::RubyDataSource.new puts ds.inspect EOF assert_sub_process_returns(['#'], code) end end def test_tzinfo_data_not_found_in_loaded_features code = <<-EOF def require(name) result = super if name == 'tzinfo/data' $".delete_if {|p| p.end_with?(File.join('', 'tzinfo', 'data.rb')) } end result end begin $:.unshift('#{TZINFO_TEST_DATA_DIR}') ds = TZInfo::DataSources::RubyDataSource.new c = ds.get_country_info('GB') puts c.code tz = ds.get_timezone_info('Europe/London') puts tz.identifier rescue Exception => e puts e.class puts e.message puts e.backtrace end EOF assert_sub_process_returns(['GB', 'Europe/London'], code) end end end tzinfo-2.0.6/test/data_sources/tc_timezone_info.rb000066400000000000000000000021201436527530500223500ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true require_relative '../test_utils' module DataSources class TCTimezoneInfo < Minitest::Test include TZInfo include TZInfo::DataSources def test_initialize_nil_identifier error = assert_raises(ArgumentError) { TimezoneInfo.new(nil) } assert_match(/\bidentifier\b/, error.message) end def test_identifier ti = TimezoneInfo.new('Test/Zone') assert_equal('Test/Zone', ti.identifier) end def test_identifier_frozen identifier = 'Test/Zone'.dup refute(identifier.frozen?) ti = TimezoneInfo.new(identifier) assert_same(identifier, ti.identifier) assert(ti.identifier.frozen?) end def test_inspect ti = TimezoneInfo.new('Test/Zone') assert_equal('#', ti.inspect) end def test_create_timezone ti = TimezoneInfo.new('Test/Zone') error = assert_raises(NotImplementedError) { ti.create_timezone } assert_equal('Subclasses must override create_timezone', error.message) end end end tzinfo-2.0.6/test/data_sources/tc_transitions_data_timezone_info.rb000066400000000000000000000475731436527530500260230ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true require_relative '../test_utils' module DataSources class TCTransitionsDataTimezoneInfo < Minitest::Test include TZInfo include TZInfo::DataSources def test_initialize_transitions o1 = TimezoneOffset.new(-17900, 0, 'TESTLMT') o2 = TimezoneOffset.new(-18000, 3600, 'TESTD') o3 = TimezoneOffset.new(-18000, 0, 'TESTS') t1 = TimezoneTransition.new(o2, o1, Time.utc(2000, 4,1,1,0,0).to_i) t2 = TimezoneTransition.new(o3, o2, Time.utc(2000,10,1,1,0,0).to_i) t3 = TimezoneTransition.new(o2, o3, Time.utc(2001, 3,1,1,0,0).to_i) transitions = [t1, t2, t3] identifier = 'Test/Zone'.dup refute(identifier.frozen?) i = TransitionsDataTimezoneInfo.new(identifier, transitions) assert_same(identifier, i.identifier) assert_same(transitions, i.transitions) assert_equal(true, i.identifier.frozen?) assert_equal(true, i.transitions.frozen?) end def test_initialize_empty_transitions error = assert_raises(ArgumentError) { TransitionsDataTimezoneInfo.new('Test/Zone', []) } assert_match(/\btransitions\b/, error.message) end def test_initialize_nil_identifier o1 = TimezoneOffset.new(-17900, 0, 'TESTLMT') o2 = TimezoneOffset.new(-18000, 0, 'TESTS') t1 = TimezoneTransition.new(o2, o1, Time.utc(2000,10,1,1,0,0).to_i) transitions = [t1] error = assert_raises(ArgumentError) { TransitionsDataTimezoneInfo.new(nil, transitions) } assert_match(/\bidentifier\b/, error.message) end def test_initialize_nil_transitions error = assert_raises(ArgumentError) { TransitionsDataTimezoneInfo.new('Test/Zone', nil) } assert_match(/\btransitions\b/, error.message) end def test_period_for o1 = TimezoneOffset.new(-17900, 0, 'TESTLMT') o2 = TimezoneOffset.new(-18000, 3600, 'TESTD') o3 = TimezoneOffset.new(-18000, 0, 'TESTS') o4 = TimezoneOffset.new(-21600, 3600, 'TESTD') t1 = TimezoneTransition.new(o2, o1, Time.utc(2000, 4,1,1,0,0).to_i) t2 = TimezoneTransition.new(o3, o2, Time.utc(2000,10,1,1,0,0).to_i) t3 = TimezoneTransition.new(o2, o3, Time.utc(2001, 3,1,1,0,0).to_i) t4 = TimezoneTransition.new(o4, o2, Time.utc(2001, 4,1,1,0,0).to_i) t5 = TimezoneTransition.new(o3, o4, Time.utc(2001,10,1,1,0,0).to_i) t6 = TimezoneTransition.new(o3, o3, Time.utc(2002,10,1,1,0,0).to_i) t7 = TimezoneTransition.new(o2, o3, Time.utc(2003, 2,1,1,0,0).to_i) t8 = TimezoneTransition.new(o3, o2, Time.utc(2003, 3,1,1,0,0).to_i) i = TransitionsDataTimezoneInfo.new('Test/Zone', [t1,t2,t3,t4,t5,t6,t7,t8]) assert_equal(TransitionsTimezonePeriod.new(nil, t1), i.period_for(Timestamp.for(Time.utc(1960, 1,1,1, 0, 0)))) assert_equal(TransitionsTimezonePeriod.new(nil, t1), i.period_for(Timestamp.for(Time.utc(1999,12,1,0, 0, 0)))) assert_equal(TransitionsTimezonePeriod.new(nil, t1), i.period_for(Timestamp.for(Time.utc(2000, 4,1,0,59,59)))) assert_equal(TransitionsTimezonePeriod.new(t1, t2), i.period_for(Timestamp.for(Time.utc(2000, 4,1,1, 0, 0)))) assert_equal(TransitionsTimezonePeriod.new(t1, t2), i.period_for(Timestamp.for(Time.utc(2000,10,1,0,59,59)))) assert_equal(TransitionsTimezonePeriod.new(t2, t3), i.period_for(Timestamp.for(Time.utc(2000,10,1,1, 0, 0)))) assert_equal(TransitionsTimezonePeriod.new(t2, t3), i.period_for(Timestamp.for(Time.utc(2001, 3,1,0,59,59)))) assert_equal(TransitionsTimezonePeriod.new(t3, t4), i.period_for(Timestamp.for(Time.utc(2001, 3,1,1, 0, 0)))) assert_equal(TransitionsTimezonePeriod.new(t3, t4), i.period_for(Timestamp.for(Time.utc(2001, 4,1,0,59,59)))) assert_equal(TransitionsTimezonePeriod.new(t4, t5), i.period_for(Timestamp.for(Time.utc(2001, 4,1,1, 0, 0)))) assert_equal(TransitionsTimezonePeriod.new(t4, t5), i.period_for(Timestamp.for(Time.utc(2001,10,1,0,59,59)))) assert_equal(TransitionsTimezonePeriod.new(t5, t6), i.period_for(Timestamp.for(Time.utc(2001,10,1,1, 0, 0)))) assert_equal(TransitionsTimezonePeriod.new(t5, t6), i.period_for(Timestamp.for(Time.utc(2002, 2,1,1, 0, 0)))) assert_equal(TransitionsTimezonePeriod.new(t5, t6), i.period_for(Timestamp.for(Time.utc(2002,10,1,0,59,59)))) assert_equal(TransitionsTimezonePeriod.new(t6, t7), i.period_for(Timestamp.for(Time.utc(2002,10,1,1, 0, 0)))) assert_equal(TransitionsTimezonePeriod.new(t6, t7), i.period_for(Timestamp.for(Time.utc(2003, 2,1,0,59,59)))) assert_equal(TransitionsTimezonePeriod.new(t7, t8), i.period_for(Timestamp.for(Time.utc(2003, 2,1,1, 0, 0)))) assert_equal(TransitionsTimezonePeriod.new(t7, t8), i.period_for(Timestamp.for(Time.utc(2003, 3,1,0,59,59)))) assert_equal(TransitionsTimezonePeriod.new(t8, nil), i.period_for(Timestamp.for(Time.utc(2003, 3,1,1, 0, 0)))) assert_equal(TransitionsTimezonePeriod.new(t8, nil), i.period_for(Timestamp.for(Time.utc(2004, 1,1,1, 0, 0)))) assert_equal(TransitionsTimezonePeriod.new(t8, nil), i.period_for(Timestamp.for(Time.utc(2050, 1,1,1, 0, 0)))) end def test_period_for_timestamp_with_zero_utc_offset o1 = TimezoneOffset.new(-17900, 0, 'TESTLMT') o2 = TimezoneOffset.new(-18000, 0, 'TEST') t1 = TimezoneTransition.new(o2, o1, Time.utc(2000,7,1,0,0,0).to_i) i = TransitionsDataTimezoneInfo.new('Test/Zone', [t1]) assert_equal(TransitionsTimezonePeriod.new(t1, nil), i.period_for(Timestamp.for(Time.new(2000,7,1,0,0,0,0)))) end def test_period_for_timestamp_with_non_zero_utc_offset o1 = TimezoneOffset.new(-17900, 0, 'TESTLMT') o2 = TimezoneOffset.new(-18000, 0, 'TEST') t1 = TimezoneTransition.new(o2, o1, Time.utc(2000,7,1,0,0,0).to_i) i = TransitionsDataTimezoneInfo.new('Test/Zone', [t1]) assert_equal(TransitionsTimezonePeriod.new(t1, nil), i.period_for(Timestamp.for(Time.new(2000,6,30,23, 0, 0,-3600)))) assert_equal(TransitionsTimezonePeriod.new(nil, t1), i.period_for(Timestamp.for(Time.new(2000,7, 1, 0,59,59, 3600)))) end def create_basic_info o1 = TimezoneOffset.new(-17900, 0, 'TESTLMT') o2 = TimezoneOffset.new(-18000, 0, 'TEST') t1 = TimezoneTransition.new(o2, o1, Time.utc(2000,7,1,0,0,0).to_i) TransitionsDataTimezoneInfo.new('Test/Zone', [t1]) end def test_period_for_timestamp_with_unspecified_offset i = create_basic_info error = assert_raises(ArgumentError) { i.period_for(Timestamp.for(Time.utc(2005,1,1,0,0,0), :ignore)) } assert_equal('timestamp must have a specified utc_offset', error.message) end def test_period_for_nil i = create_basic_info error = assert_raises(ArgumentError) { i.period_for(nil) } assert_equal('timestamp must be specified', error.message) end def test_periods_for_local o1 = TimezoneOffset.new(-17900, 0, 'TESTLMT') o2 = TimezoneOffset.new(-18000, 3600, 'TESTD') o3 = TimezoneOffset.new(-18000, 0, 'TESTS') o4 = TimezoneOffset.new(-21600, 3600, 'TESTD') t1 = TimezoneTransition.new(o2, o1, Time.utc(2000, 4,2,1,0,0).to_i) t2 = TimezoneTransition.new(o3, o2, Time.utc(2000,10,2,1,0,0).to_i) t3 = TimezoneTransition.new(o2, o3, Time.utc(2001, 3,2,1,0,0).to_i) t4 = TimezoneTransition.new(o4, o2, Time.utc(2001, 4,2,1,0,0).to_i) t5 = TimezoneTransition.new(o3, o4, Time.utc(2001,10,2,1,0,0).to_i) t6 = TimezoneTransition.new(o3, o3, Time.utc(2002,10,2,1,0,0).to_i) t7 = TimezoneTransition.new(o2, o3, Time.utc(2003, 2,2,1,0,0).to_i) i = TransitionsDataTimezoneInfo.new('Test/Zone', [t1,t2,t3,t4,t5,t6,t7]) assert_equal([TransitionsTimezonePeriod.new(nil, t1)], i.periods_for_local(Timestamp.for(Time.utc(1960, 1, 1, 1, 0, 0), :ignore))) assert_equal([TransitionsTimezonePeriod.new(nil, t1)], i.periods_for_local(Timestamp.for(Time.utc(1999,12, 1, 0, 0, 0), :ignore))) assert_equal([TransitionsTimezonePeriod.new(nil, t1)], i.periods_for_local(Timestamp.for(Time.utc(2000, 1, 1,10, 0, 0), :ignore))) assert_equal([TransitionsTimezonePeriod.new(nil, t1)], i.periods_for_local(Timestamp.for(Time.utc(2000, 4, 1,20, 1,39), :ignore))) assert_equal([], i.periods_for_local(Timestamp.for(Time.utc(2000, 4, 1,20, 1,40), :ignore))) assert_equal([], i.periods_for_local(Timestamp.for(Time.utc(2000, 4, 1,20,59,59), :ignore))) assert_equal([TransitionsTimezonePeriod.new(t1, t2)], i.periods_for_local(Timestamp.for(Time.utc(2000, 4, 1,21, 0, 0), :ignore))) assert_equal([TransitionsTimezonePeriod.new(t1, t2)], i.periods_for_local(Timestamp.for(Time.utc(2000,10, 1,19,59,59), :ignore))) assert_equal([TransitionsTimezonePeriod.new(t1, t2), TransitionsTimezonePeriod.new(t2, t3)], i.periods_for_local(Timestamp.for(Time.utc(2000,10, 1,20, 0, 0), :ignore))) assert_equal([TransitionsTimezonePeriod.new(t1, t2), TransitionsTimezonePeriod.new(t2, t3)], i.periods_for_local(Timestamp.for(Time.utc(2000,10, 1,20,59,59), :ignore))) assert_equal([TransitionsTimezonePeriod.new(t2, t3)], i.periods_for_local(Timestamp.for(Time.utc(2000,10, 1,21, 0, 0), :ignore))) assert_equal([TransitionsTimezonePeriod.new(t2, t3)], i.periods_for_local(Timestamp.for(Time.utc(2001, 3, 1,19,59,59), :ignore))) assert_equal([], i.periods_for_local(Timestamp.for(Time.utc(2001, 3, 1,20, 0, 0), :ignore))) assert_equal([], i.periods_for_local(Timestamp.for(Time.utc(2001, 3, 1,20,30, 0), :ignore))) assert_equal([], i.periods_for_local(Timestamp.for(Time.utc(2001, 3, 1,20,59,59), :ignore))) assert_equal([TransitionsTimezonePeriod.new(t3, t4)], i.periods_for_local(Timestamp.for(Time.utc(2001, 3, 1,21, 0, 0), :ignore))) assert_equal([TransitionsTimezonePeriod.new(t3, t4)], i.periods_for_local(Timestamp.for(Time.utc(2001, 4, 1,19,59,59), :ignore))) assert_equal([TransitionsTimezonePeriod.new(t3, t4), TransitionsTimezonePeriod.new(t4, t5)], i.periods_for_local(Timestamp.for(Time.utc(2001, 4, 1,20, 0, 0), :ignore))) assert_equal([TransitionsTimezonePeriod.new(t3, t4), TransitionsTimezonePeriod.new(t4, t5)], i.periods_for_local(Timestamp.for(Time.utc(2001, 4, 1,20,59,59), :ignore))) assert_equal([TransitionsTimezonePeriod.new(t4, t5)], i.periods_for_local(Timestamp.for(Time.utc(2001, 4, 1,21, 0, 0), :ignore))) assert_equal([TransitionsTimezonePeriod.new(t4, t5)], i.periods_for_local(Timestamp.for(Time.utc(2001,10, 1,19,59,59), :ignore))) assert_equal([TransitionsTimezonePeriod.new(t5, t6)], i.periods_for_local(Timestamp.for(Time.utc(2001,10, 1,20, 0, 0), :ignore))) assert_equal([TransitionsTimezonePeriod.new(t5, t6)], i.periods_for_local(Timestamp.for(Time.utc(2002, 2, 1,20, 0, 0), :ignore))) assert_equal([TransitionsTimezonePeriod.new(t5, t6)], i.periods_for_local(Timestamp.for(Time.utc(2002,10, 1,19,59,59), :ignore))) assert_equal([TransitionsTimezonePeriod.new(t6, t7)], i.periods_for_local(Timestamp.for(Time.utc(2002,10, 1,20, 0, 0), :ignore))) assert_equal([TransitionsTimezonePeriod.new(t6, t7)], i.periods_for_local(Timestamp.for(Time.utc(2003, 2, 1,19,59,59), :ignore))) assert_equal([], i.periods_for_local(Timestamp.for(Time.utc(2003, 2, 1,20, 0, 0), :ignore))) assert_equal([], i.periods_for_local(Timestamp.for(Time.utc(2003, 2, 1,20,59,59), :ignore))) assert_equal([TransitionsTimezonePeriod.new(t7, nil)], i.periods_for_local(Timestamp.for(Time.utc(2003, 2, 1,21, 0, 0), :ignore))) assert_equal([TransitionsTimezonePeriod.new(t7, nil)], i.periods_for_local(Timestamp.for(Time.utc(2004, 2, 1,20, 0, 0), :ignore))) assert_equal([TransitionsTimezonePeriod.new(t7, nil)], i.periods_for_local(Timestamp.for(Time.utc(2040, 2, 1,20, 0, 0), :ignore))) end def test_periods_for_local_warsaw o1 = TimezoneOffset.new(5040, 0, 'LMT') o2 = TimezoneOffset.new(5040, 0, 'WMT') o3 = TimezoneOffset.new(3600, 0, 'CET') o4 = TimezoneOffset.new(3600, 3600, 'CEST') t1 = TimezoneTransition.new(o2, o1, Time.utc(1879,12,31,22,36,0).to_i) t2 = TimezoneTransition.new(o3, o2, Time.utc(1915, 8, 4,22,36,0).to_i) t3 = TimezoneTransition.new(o4, o3, Time.utc(1916, 4,30,22, 0,0).to_i) i = TransitionsDataTimezoneInfo.new('Test/Europe/Warsaw', [t1,t2,t3]) assert_equal([TransitionsTimezonePeriod.new(t1, t2), TransitionsTimezonePeriod.new(t2, t3)], i.periods_for_local(Timestamp.for(Time.utc(1915,8,4,23,40,0), :ignore))) end def test_periods_for_local_single_transition o1 = TimezoneOffset.new(-3600, 0, 'TESTD') o2 = TimezoneOffset.new(-3600, 0, 'TESTS') t1 = TimezoneTransition.new(o2, o1, Time.utc(2000,7,1,0,0,0).to_i) i = TransitionsDataTimezoneInfo.new('Test/Zone', [t1]) assert_equal([TransitionsTimezonePeriod.new(nil, t1)], i.periods_for_local(Timestamp.for(Time.utc(2000,6,30,22,59,59), :ignore))) assert_equal([TransitionsTimezonePeriod.new(t1, nil)], i.periods_for_local(Timestamp.for(Time.utc(2000,6,30,23, 0, 0), :ignore))) assert_equal([TransitionsTimezonePeriod.new(t1, nil)], i.periods_for_local(Timestamp.for(Time.utc(2000,7, 1, 0, 0, 0), :ignore))) end def test_periods_for_local_timestamp_with_specified_offset i = create_basic_info error = assert_raises(ArgumentError) { i.periods_for_local(Timestamp.for(Time.utc(2005,1,1,0,0,0))) } assert_equal('local_timestamp must have an unspecified utc_offset', error.message) end def test_periods_for_local_nil i = create_basic_info error = assert_raises(ArgumentError) { i.periods_for_local(nil) } assert_equal('local_timestamp must be specified', error.message) end def test_transitions_up_to o1 = TimezoneOffset.new(-17900, 0, 'TESTLMT') o2 = TimezoneOffset.new(-18000, 3600, 'TESTD') o3 = TimezoneOffset.new(-18000, 0, 'TESTS') o4 = TimezoneOffset.new(-21600, 3600, 'TESTD') t1 = TimezoneTransition.new(o2, o1, Time.utc(2010, 4,1,1,0,0).to_i) t2 = TimezoneTransition.new(o3, o2, Time.utc(2010,10,1,1,0,0).to_i) t3 = TimezoneTransition.new(o2, o3, Time.utc(2011, 3,1,1,0,0).to_i) t4 = TimezoneTransition.new(o4, o2, Time.utc(2011, 4,1,1,0,0).to_i) t5 = TimezoneTransition.new(o3, o4, Time.utc(2011,10,1,1,0,0).to_i) i = TransitionsDataTimezoneInfo.new('Test/Zone', [t1,t2,t3,t4,t5]) assert_equal([], i.transitions_up_to(Timestamp.for(Time.utc(2010, 4,1,1,0,0)))) assert_equal([], i.transitions_up_to(Timestamp.for(Time.utc(2010, 4,1,1,0,0)), Timestamp.for(Time.utc(2000, 1,1,0,0,0)))) assert_equal([t1], i.transitions_up_to(Timestamp.for(Time.utc(2010, 4,1,1,0,1)))) assert_equal([t1], i.transitions_up_to(Timestamp.for(Time.utc(2010, 4,1,1,0,1)), Timestamp.for(Time.utc(2000, 1,1,0,0,0)))) assert_equal([t2,t3,t4], i.transitions_up_to(Timestamp.for(Time.utc(2011, 4,1,1,0,1)), Timestamp.for(Time.utc(2010,10,1,1,0,0)))) assert_equal([t2,t3,t4], i.transitions_up_to(Timestamp.for(Time.utc(2011,10,1,1,0,0)), Timestamp.for(Time.utc(2010, 4,1,1,0,1)))) assert_equal([t3], i.transitions_up_to(Timestamp.for(Time.utc(2011, 4,1,1,0,0)), Timestamp.for(Time.utc(2010,10,1,1,0,1)))) assert_equal([], i.transitions_up_to(Timestamp.for(Time.utc(2011, 3,1,1,0,0)), Timestamp.for(Time.utc(2010,10,1,1,0,1)))) assert_equal([t1,t2,t3,t4], i.transitions_up_to(Timestamp.for(Time.utc(2011,10,1,1,0,0)))) assert_equal([t1,t2,t3,t4,t5], i.transitions_up_to(Timestamp.for(Time.utc(2011,10,1,1,0,1)))) assert_equal([t1,t2,t3,t4,t5], i.transitions_up_to(Timestamp.for(Time.utc(2011,10,1,1,0,0,1)))) assert_equal([t1,t2,t3,t4,t5], i.transitions_up_to(Timestamp.for(Time.utc(2011,10,1,1,0,1)), Timestamp.for(Time.utc(2010, 4,1,1,0,0)))) assert_equal([t2,t3,t4,t5], i.transitions_up_to(Timestamp.for(Time.utc(2011,10,1,1,0,1)), Timestamp.for(Time.utc(2010, 4,1,1,0,1)))) assert_equal([t2,t3,t4,t5], i.transitions_up_to(Timestamp.for(Time.utc(2011,10,1,1,0,1)), Timestamp.for(Time.utc(2010, 4,1,1,0,0,1)))) assert_equal([t5], i.transitions_up_to(Timestamp.for(Time.utc(2015, 1,1,0,0,0)), Timestamp.for(Time.utc(2011,10,1,1,0,0)))) assert_equal([], i.transitions_up_to(Timestamp.for(Time.utc(2015, 1,1,0,0,0)), Timestamp.for(Time.utc(2011,10,1,1,0,1)))) end def test_transitions_up_to_timestamp_with_zero_utc_offset o1 = TimezoneOffset.new(-17900, 0, 'TESTLMT') o2 = TimezoneOffset.new(-18000, 0, 'TESTS') o3 = TimezoneOffset.new(-18000, 3600, 'TESTD') t1 = TimezoneTransition.new(o2, o1, Time.utc(2009,12,31,23,59,59).to_i) t2 = TimezoneTransition.new(o3, o2, Time.utc(2010, 7, 1, 0, 0, 0).to_i) i = TransitionsDataTimezoneInfo.new('Test/Zone', [t1,t2]) assert_equal([t1,t2], i.transitions_up_to(Timestamp.for(Time.new(2010,7,1,0,0,1,0)))) assert_equal([t1,t2], i.transitions_up_to(Timestamp.for(Time.new(2011,1,1,0,0,0,0)), Timestamp.for(Time.new(2009,12,31,23,59,59,0)))) end def test_transitions_up_to_timestamp_with_non_zero_utc_offset o1 = TimezoneOffset.new(-17900, 0, 'TESTLMT') o2 = TimezoneOffset.new(-18000, 0, 'TESTS') o3 = TimezoneOffset.new(-18000, 3600, 'TESTD') t1 = TimezoneTransition.new(o2, o1, Time.utc(2009,12,31,23,59,59).to_i) t2 = TimezoneTransition.new(o3, o2, Time.utc(2010, 7, 1, 0, 0, 0).to_i) i = TransitionsDataTimezoneInfo.new('Test/Zone', [t1,t2]) assert_equal([t1,t2], i.transitions_up_to(Timestamp.for(Time.new(2010,6,30,23,0,1,-3600)))) assert_equal([t1], i.transitions_up_to(Timestamp.for(Time.new(2010,7, 1, 1,0,0, 3600)))) assert_equal([t1,t2], i.transitions_up_to(Timestamp.for(Time.new(2011,1,1,0,0,0,0)), Timestamp.for(Time.new(2010, 1, 1, 0,59,59, 3600)))) assert_equal([t2], i.transitions_up_to(Timestamp.for(Time.new(2011,1,1,0,0,0,0)), Timestamp.for(Time.new(2009,12,31,23, 0, 0,-3600)))) end def test_transitions_up_to_to_not_greater_than_from i = create_basic_info to = Timestamp.for(Time.utc(2012,8,1,0,0,0)) from = Timestamp.for(Time.utc(2013,8,1,0,0,0)) error = assert_raises(ArgumentError) { i.transitions_up_to(to, from) } assert_equal('to_timestamp must be greater than from_timestamp', error.message) end def test_transitions_up_to_to_not_greater_than_from_subsecond i = create_basic_info to = Timestamp.for(Time.utc(2012,8,1,0,0,0)) from = Timestamp.for(Time.utc(2012,8,1,0,0,0,1)) error = assert_raises(ArgumentError) { i.transitions_up_to(to, from) } assert_equal('to_timestamp must be greater than from_timestamp', error.message) end def test_transitions_up_to_to_timestamp_with_unspecified_offset i = create_basic_info to = Timestamp.for(Time.utc(2015,1,1,0,0,0), :ignore) error = assert_raises(ArgumentError) { i.transitions_up_to(to) } assert_equal('to_timestamp must have a specified utc_offset', error.message) end def test_transitions_up_to_from_timestamp_with_unspecified_offset i = create_basic_info to = Timestamp.for(Time.utc(2015,1,1,0,0,0)) from = Timestamp.for(Time.utc(2014,1,1,0,0,0), :ignore) error = assert_raises(ArgumentError) { i.transitions_up_to(to, from) } assert_equal('from_timestamp must have a specified utc_offset', error.message) end def test_transitions_up_to_to_timestamp_nil i = create_basic_info error = assert_raises(ArgumentError) { i.transitions_up_to(nil) } assert_equal('to_timestamp must be specified', error.message) end def test_inspect i = create_basic_info assert_equal('#', i.inspect) end end end tzinfo-2.0.6/test/data_sources/tc_zoneinfo_data_source.rb000066400000000000000000001675431436527530500237300ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true require_relative '../test_utils' require 'fileutils' require 'pathname' require 'tmpdir' module DataSources class TCZoneinfoDataSource < Minitest::Test include TZInfo include TZInfo::DataSources ZONEINFO_DIR = File.expand_path(File.join(File.dirname(__FILE__), '..', 'zoneinfo')) RubyCoreSupport.untaint(ZONEINFO_DIR) def setup @orig_search_path = ZoneinfoDataSource.search_path.clone @orig_alternate_iso3166_tab_search_path = ZoneinfoDataSource.alternate_iso3166_tab_search_path.clone @orig_pwd = FileUtils.pwd # A zoneinfo directory containing files needed by the tests. # The symlinks in this directory are set up in test_utils.rb. @data_source = ZoneinfoDataSource.new(ZONEINFO_DIR) end def teardown ZoneinfoDataSource.search_path = @orig_search_path ZoneinfoDataSource.alternate_iso3166_tab_search_path = @orig_alternate_iso3166_tab_search_path FileUtils.chdir(@orig_pwd) end def test_default_search_path assert_equal(['/usr/share/zoneinfo', '/usr/share/lib/zoneinfo', '/etc/zoneinfo'], ZoneinfoDataSource.search_path) assert_equal(false, ZoneinfoDataSource.search_path.frozen?) end def test_set_search_path_default ZoneinfoDataSource.search_path = ['/tmp/zoneinfo1', '/tmp/zoneinfo2'] assert_equal(['/tmp/zoneinfo1', '/tmp/zoneinfo2'], ZoneinfoDataSource.search_path) ZoneinfoDataSource.search_path = nil assert_equal(['/usr/share/zoneinfo', '/usr/share/lib/zoneinfo', '/etc/zoneinfo'], ZoneinfoDataSource.search_path) assert_equal(false, ZoneinfoDataSource.search_path.frozen?) end def test_set_search_path_array path = ['/tmp/zoneinfo1', '/tmp/zoneinfo2'] ZoneinfoDataSource.search_path = path assert_equal(['/tmp/zoneinfo1', '/tmp/zoneinfo2'], ZoneinfoDataSource.search_path) refute_same(path, ZoneinfoDataSource.search_path) end def test_set_search_path_array_to_s ZoneinfoDataSource.search_path = [Pathname.new('/tmp/zoneinfo3')] assert_equal(['/tmp/zoneinfo3'], ZoneinfoDataSource.search_path) end def test_set_search_path_string ZoneinfoDataSource.search_path = ['/tmp/zoneinfo4', '/tmp/zoneinfo5'].join(File::PATH_SEPARATOR) assert_equal(['/tmp/zoneinfo4', '/tmp/zoneinfo5'], ZoneinfoDataSource.search_path) end def test_default_alternate_iso3166_tab_search_path assert_equal(['/usr/share/misc/iso3166.tab', '/usr/share/misc/iso3166'], ZoneinfoDataSource.alternate_iso3166_tab_search_path) assert_equal(false, ZoneinfoDataSource.alternate_iso3166_tab_search_path.frozen?) end def test_set_alternate_iso3166_tab_search_path_default ZoneinfoDataSource.alternate_iso3166_tab_search_path = ['/tmp/iso3166.tab', '/tmp/iso3166'] assert_equal(['/tmp/iso3166.tab', '/tmp/iso3166'], ZoneinfoDataSource.alternate_iso3166_tab_search_path) ZoneinfoDataSource.alternate_iso3166_tab_search_path = nil assert_equal(['/usr/share/misc/iso3166.tab', '/usr/share/misc/iso3166'], ZoneinfoDataSource.alternate_iso3166_tab_search_path) assert_equal(false, ZoneinfoDataSource.alternate_iso3166_tab_search_path.frozen?) end def test_set_alternate_iso3166_tab_search_path_array path = ['/tmp/iso3166.tab', '/tmp/iso3166'] ZoneinfoDataSource.alternate_iso3166_tab_search_path = path assert_equal(['/tmp/iso3166.tab', '/tmp/iso3166'], ZoneinfoDataSource.alternate_iso3166_tab_search_path) refute_same(path, ZoneinfoDataSource.alternate_iso3166_tab_search_path) end def test_set_alternate_iso3166_tab_search_path_array_to_s ZoneinfoDataSource.alternate_iso3166_tab_search_path = [Pathname.new('/tmp/iso3166.tab')] assert_equal(['/tmp/iso3166.tab'], ZoneinfoDataSource.alternate_iso3166_tab_search_path) end def test_set_alternate_iso3166_tab_search_path_string ZoneinfoDataSource.alternate_iso3166_tab_search_path = ['/tmp/iso3166.tab', '/tmp/iso3166'].join(File::PATH_SEPARATOR) assert_equal(['/tmp/iso3166.tab', '/tmp/iso3166'], ZoneinfoDataSource.alternate_iso3166_tab_search_path) end def test_new_search Dir.mktmpdir('tzinfo_test_dir1') do |dir1| Dir.mktmpdir('tzinfo_test_dir2') do |dir2| Dir.mktmpdir('tzinfo_test_dir3') do |dir3| Dir.mktmpdir('tzinfo_test_dir4') do |dir4| file = File.join(dir1, 'file') FileUtils.touch(File.join(dir2, 'zone.tab')) FileUtils.touch(File.join(dir3, 'iso3166.tab')) FileUtils.touch(File.join(dir4, 'zone.tab')) FileUtils.touch(File.join(dir4, 'iso3166.tab')) ZoneinfoDataSource.search_path = [file, dir2, dir3, dir4] ZoneinfoDataSource.alternate_iso3166_tab_search_path = [] data_source = ZoneinfoDataSource.new assert_equal(dir4, data_source.zoneinfo_dir) end end end end end def test_new_search_zone1970 Dir.mktmpdir('tzinfo_test_dir1') do |dir1| Dir.mktmpdir('tzinfo_test_dir2') do |dir2| Dir.mktmpdir('tzinfo_test_dir3') do |dir3| Dir.mktmpdir('tzinfo_test_dir4') do |dir4| file = File.join(dir1, 'file') FileUtils.touch(File.join(dir2, 'zone1970.tab')) FileUtils.touch(File.join(dir3, 'iso3166.tab')) FileUtils.touch(File.join(dir4, 'zone1970.tab')) FileUtils.touch(File.join(dir4, 'iso3166.tab')) ZoneinfoDataSource.search_path = [file, dir2, dir3, dir4] ZoneinfoDataSource.alternate_iso3166_tab_search_path = [] data_source = ZoneinfoDataSource.new assert_equal(dir4, data_source.zoneinfo_dir) end end end end end def test_new_search_solaris_tab_files # Solaris names the tab files 'tab/country.tab' (iso3166.tab) and # 'tab/zone_sun.tab' (zone.tab). Dir.mktmpdir('tzinfo_test_dir') do |dir| tab = File.join(dir, 'tab') FileUtils.mkdir(tab) FileUtils.touch(File.join(tab, 'country.tab')) FileUtils.touch(File.join(tab, 'zone_sun.tab')) ZoneinfoDataSource.search_path = [dir] ZoneinfoDataSource.alternate_iso3166_tab_search_path = [] data_source = ZoneinfoDataSource.new assert_equal(dir, data_source.zoneinfo_dir) end end def test_new_search_alternate_iso3166_path Dir.mktmpdir('tzinfo_test_dir_zoneinfo') do |zoneinfo_dir| Dir.mktmpdir('tzinfo_test_dir_tab') do |tab_dir| FileUtils.touch(File.join(zoneinfo_dir, 'zone.tab')) tab_file = File.join(tab_dir, 'iso3166') ZoneinfoDataSource.search_path = [zoneinfo_dir] ZoneinfoDataSource.alternate_iso3166_tab_search_path = [tab_file] assert_raises_directory_not_found { ZoneinfoDataSource.new } FileUtils.touch(tab_file) data_source = ZoneinfoDataSource.new assert_equal(zoneinfo_dir, data_source.zoneinfo_dir) end end end def test_new_search_not_found Dir.mktmpdir('tzinfo_test_dir1') do |dir1| Dir.mktmpdir('tzinfo_test_dir2') do |dir2| Dir.mktmpdir('tzinfo_test_dir3') do |dir3| Dir.mktmpdir('tzinfo_test_dir4') do |dir4| Dir.mktmpdir('tzinfo_test_dir5') do |dir5| file = File.join(dir1, 'file') FileUtils.touch(file) FileUtils.touch(File.join(dir2, 'zone.tab')) FileUtils.touch(File.join(dir3, 'zone1970.tab')) FileUtils.touch(File.join(dir4, 'iso3166.tab')) ZoneinfoDataSource.search_path = [file, dir2, dir3, dir4, dir5] ZoneinfoDataSource.alternate_iso3166_tab_search_path = [] assert_raises_directory_not_found { ZoneinfoDataSource.new } end end end end end end def test_new_search_relative Dir.mktmpdir('tzinfo_test') do |dir| FileUtils.touch(File.join(dir, 'zone.tab')) FileUtils.touch(File.join(dir, 'iso3166.tab')) FileUtils.chdir(dir) ZoneinfoDataSource.search_path = ['.'] ZoneinfoDataSource.alternate_iso3166_tab_search_path = [] data_source = ZoneinfoDataSource.new assert_equal(Pathname.new(dir).realpath.to_s, data_source.zoneinfo_dir) # Change out of the directory to allow it to be deleted on Windows. FileUtils.chdir(@orig_pwd) end end def test_new_dir Dir.mktmpdir('tzinfo_test') do |dir| FileUtils.touch(File.join(dir, 'zone.tab')) FileUtils.touch(File.join(dir, 'iso3166.tab')) data_source = ZoneinfoDataSource.new(dir) assert_equal(dir, data_source.zoneinfo_dir) end end def test_new_dir_zone1970 Dir.mktmpdir('tzinfo_test') do |dir| FileUtils.touch(File.join(dir, 'zone1970.tab')) FileUtils.touch(File.join(dir, 'iso3166.tab')) data_source = ZoneinfoDataSource.new(dir) assert_equal(dir, data_source.zoneinfo_dir) end end def test_new_dir_solaris_tab_files # Solaris names the tab files 'tab/country.tab' (iso3166.tab) and # 'tab/zone_sun.tab' (zone.tab). Dir.mktmpdir('tzinfo_test') do |dir| tab = File.join(dir, 'tab') FileUtils.mkdir(tab) FileUtils.touch(File.join(tab, 'country.tab')) FileUtils.touch(File.join(tab, 'zone_sun.tab')) data_source = ZoneinfoDataSource.new(dir) assert_equal(dir, data_source.zoneinfo_dir) end end def test_new_dir_alternate_iso3166_path Dir.mktmpdir('tzinfo_test_dir_zoneinfo') do |zoneinfo_dir| Dir.mktmpdir('tzinfo_test_dir_tab') do |tab_dir| FileUtils.touch(File.join(zoneinfo_dir, 'zone.tab')) tab_file = File.join(tab_dir, 'iso3166') FileUtils.touch(tab_file) ZoneinfoDataSource.alternate_iso3166_tab_search_path = [tab_file] assert_raises_invalid_directory(zoneinfo_dir) do # The alternate_iso3166_tab_search_path should not be used. This should raise # an exception. ZoneinfoDataSource.new(zoneinfo_dir) end data_source = ZoneinfoDataSource.new(zoneinfo_dir, tab_file) assert_equal(zoneinfo_dir, data_source.zoneinfo_dir) end end end def test_new_dir_invalid Dir.mktmpdir('tzinfo_test') do |dir| assert_raises_invalid_directory(dir) { ZoneinfoDataSource.new(dir) } end end def test_new_dir_invalid_alternate_iso3166_path Dir.mktmpdir('tzinfo_test_dir_zoneinfo') do |zoneinfo_dir| Dir.mktmpdir('tzinfo_test_dir_tab') do |tab_dir| FileUtils.touch(File.join(zoneinfo_dir, 'zone.tab')) assert_raises_invalid_directory(zoneinfo_dir) do ZoneinfoDataSource.new(zoneinfo_dir, File.join(tab_dir, 'iso3166')) end end end end def test_new_dir_invalid_alternate_iso3166_path_overrides_valid Dir.mktmpdir('tzinfo_test_dir_zoneinfo') do |zoneinfo_dir| Dir.mktmpdir('tzinfo_test_dir_tab') do |tab_dir| FileUtils.touch(File.join(zoneinfo_dir, 'iso3166.tab')) FileUtils.touch(File.join(zoneinfo_dir, 'zone.tab')) assert_raises_invalid_directory(zoneinfo_dir) do ZoneinfoDataSource.new(zoneinfo_dir, File.join(tab_dir, 'iso3166')) end end end end def test_new_file Dir.mktmpdir('tzinfo_test') do |dir| file = File.join(dir, 'file') FileUtils.touch(file) assert_raises_invalid_directory(file) do ZoneinfoDataSource.new(file) end end end def test_new_dir_relative Dir.mktmpdir('tzinfo_test') do |dir| FileUtils.touch(File.join(dir, 'zone.tab')) FileUtils.touch(File.join(dir, 'iso3166.tab')) FileUtils.chdir(dir) data_source = ZoneinfoDataSource.new('.') assert_equal(Pathname.new(dir).realpath.to_s, data_source.zoneinfo_dir) # Change out of the directory to allow it to be deleted on Windows. FileUtils.chdir(@orig_pwd) end end def test_zoneinfo_dir Dir.mktmpdir('tzinfo_test') do |dir| FileUtils.touch(File.join(dir, 'zone.tab')) FileUtils.touch(File.join(dir, 'iso3166.tab')) data_source = ZoneinfoDataSource.new(dir) assert_equal(dir, data_source.zoneinfo_dir) assert_equal(true, data_source.zoneinfo_dir.frozen?) end end def test_load_timezone_info_transitions o1 = TimezoneOffset.new(-17900, 0, 'TESTLMT') o2 = TimezoneOffset.new(-18000, 3600, 'TESTD') o3 = TimezoneOffset.new(-18000, 0, 'TESTS') t1 = TimezoneTransition.new(o2, o1, Time.utc(2000, 4,1,1,0,0).to_i) t2 = TimezoneTransition.new(o3, o2, Time.utc(2000,10,1,1,0,0).to_i) t3 = TimezoneTransition.new(o2, o3, Time.utc(2001, 3,1,1,0,0).to_i) transitions = [t1, t2, t3] reader_mock = Minitest::Mock.new reader_mock.expect(:read, transitions, [File.join(ZONEINFO_DIR, 'Europe', 'London')]) @data_source.instance_variable_set(:@zoneinfo_reader, reader_mock) info = @data_source.send(:load_timezone_info, 'Europe/London') reader_mock.verify assert_kind_of(TransitionsDataTimezoneInfo, info) assert_equal('Europe/London', info.identifier) assert_equal(transitions, info.transitions) end def test_load_timezone_info_constant_offset offset = TimezoneOffset.new(-17900, 0, 'TESTLMT') reader_mock = Minitest::Mock.new reader_mock.expect(:read, offset, [File.join(ZONEINFO_DIR, 'Europe', 'London')]) @data_source.instance_variable_set(:@zoneinfo_reader, reader_mock) info = @data_source.send(:load_timezone_info, 'Europe/London') reader_mock.verify assert_kind_of(ConstantOffsetDataTimezoneInfo, info) assert_equal('Europe/London', info.identifier) assert_same(offset, info.constant_offset) end def test_load_timezone_info_data info = @data_source.send(:load_timezone_info, 'Europe/London') assert_kind_of(TransitionsDataTimezoneInfo, info) assert_equal('Europe/London', info.identifier) end def test_load_timezone_info_linked info = @data_source.send(:load_timezone_info, 'UTC') # On platforms that don't support symlinks, 'UTC' will be created as a copy. # Either way, a ConstantOffsetDataTimezoneInfo should be returned. assert_kind_of(ConstantOffsetDataTimezoneInfo, info) assert_equal('UTC', info.identifier) end def test_load_timezone_info_does_not_exist error = assert_raises(InvalidTimezoneIdentifier) do @data_source.send(:load_timezone_info, 'Nowhere/Special') end assert_match(/\bNowhere\/Special\b/, error.message) end test_encodings('UTF-8', 'UTF-16').each do |encoding| define_method("test_load_timezone_info_file_does_not_exist_with_#{encoding.to_method}_encoded_identifier") do # Override the index so that an attempt is made to load the file. def @data_source.validate_timezone_identifier(identifier) identifier = identifier.encode(Encoding::UTF_8) raise "Unexpected identifier passed to validate_timezone_identifier: #{identifier}" unless identifier == 'Nowhere/Special' 'Nowhere/Special'.freeze end error = assert_raises(InvalidTimezoneIdentifier) do @data_source.send(:load_timezone_info, 'Nowhere/Special'.encode(encoding.name)) end assert_match(/\bNowhere\/Special\b/, error.message) assert_equal(Encoding::UTF_8, error.message.encoding) assert_kind_of(Errno::ENOENT, error.cause) if error.respond_to?(:cause) end define_method("test_load_timezone_info_path_component_not_dir_with_#{encoding.to_method}_encoded_identifier") do skip('JRuby 9.0.5.0 raises an unhandled Java IOException when encountering a path component that is not a directory') if RUBY_ENGINE == 'jruby' && JRUBY_VERSION.start_with?('9.0.') # Override the index so that an attempt is made to load the file. def @data_source.validate_timezone_identifier(identifier) identifier = identifier.encode(Encoding::UTF_8) raise "Unexpected identifier passed to validate_timezone_identifier: #{identifier}" unless identifier == 'UTC/File' 'UTC/File'.freeze end error = assert_raises(InvalidTimezoneIdentifier) do @data_source.send(:load_timezone_info, 'UTC/File'.encode(encoding.name)) end assert_match(/\bUTC\/File\b/, error.message) assert_equal(Encoding::UTF_8, error.message.encoding) # The cause is usually Errno::ENOTDIR. On Windows it is Errno::ENOENT # instead. if error.respond_to?(:cause) expected_cause = get_expected_file_open_and_read_cause(File.join(ZONEINFO_DIR, 'UTC', 'File')) assert_kind_of(expected_cause, error.cause) end end define_method("test_load_timezone_info_name_to_long_with_#{encoding.to_method}_encoded_identifier") do # Override the read method to raise Errno::ENAMETOOLONG and check that # this is handled correctly. zoneinfo_reader = @data_source.instance_variable_get(:@zoneinfo_reader) def zoneinfo_reader.read(file_path) raise Errno::ENAMETOOLONG, 'Test' end error = assert_raises(InvalidTimezoneIdentifier) do @data_source.send(:load_timezone_info, 'Europe/London'.encode(encoding.name)) end assert_match(/\bEurope\/London\b/, error.message) assert_equal(Encoding::UTF_8, error.message.encoding) assert_kind_of(Errno::ENAMETOOLONG, error.cause) if error.respond_to?(:cause) end end def test_load_timezone_info_invalid error = assert_raises(InvalidTimezoneIdentifier) do @data_source.send(:load_timezone_info, '../zoneinfo/Europe/London') end assert_match(/\W\.\.\/zoneinfo\/Europe\/London\b/, error.message) end def test_load_timezone_info_nil error = assert_raises(InvalidTimezoneIdentifier) do @data_source.send(:load_timezone_info, nil) end assert_match(/\bnil\b/, error.message) end def test_load_timezone_info_false error = assert_raises(InvalidTimezoneIdentifier) do @data_source.send(:load_timezone_info, false) end assert_match(/\bfalse\b/, error.message) end def test_load_timezone_info_case error = assert_raises(InvalidTimezoneIdentifier) do @data_source.send(:load_timezone_info, 'europe/london') end assert_match(/\beurope\/london/, error.message) end test_encodings('UTF-8', 'UTF-16').each do |encoding| define_method("test_load_timezone_info_permission_denied_with_#{encoding.to_method}_encoded_identifier") do Dir.mktmpdir('tzinfo_test') do |dir| FileUtils.touch(File.join(dir, 'zone.tab')) FileUtils.touch(File.join(dir, 'iso3166.tab')) file = File.join(dir, 'UTC') FileUtils.touch(file) FileUtils.chmod(0200, file) if File.stat(file).mode & 0400 == 0400 # chmod failed to remove read permissions. Assume this is Windows and # try setting permissions with icacls instead. `icacls "#{file}" /deny Everyone:R` end data_source = ZoneinfoDataSource.new(dir) error = assert_raises(InvalidTimezoneIdentifier) do data_source.send(:load_timezone_info, 'UTC'.encode(encoding.name)) end assert_match(/\bUTC\b/, error.message) assert_equal(Encoding::UTF_8, error.message.encoding) assert_kind_of(Errno::EACCES, error.cause) if error.respond_to?(:cause) end end end def test_load_timezone_info_directory Dir.mktmpdir('tzinfo_test') do |dir| FileUtils.touch(File.join(dir, 'zone.tab')) FileUtils.touch(File.join(dir, 'iso3166.tab')) subdir = File.join(dir, 'Subdir') FileUtils.mkdir(subdir) data_source = ZoneinfoDataSource.new(dir) error = assert_raises(InvalidTimezoneIdentifier) do data_source.send(:load_timezone_info, 'Subdir') end assert_match(/\bSubdir\b/, error.message) end end test_encodings('UTF-8', 'UTF-16').each do |encoding| define_method("test_load_timezone_info_file_is_directory_with_#{encoding.to_method}_encoded_identifier") do skip('JRuby 9.0.5.0 hangs when attempting to read a directory') if RUBY_ENGINE == 'jruby' && JRUBY_VERSION.start_with?('9.0.') Dir.mktmpdir('tzinfo_test') do |dir| FileUtils.touch(File.join(dir, 'zone.tab')) FileUtils.touch(File.join(dir, 'iso3166.tab')) subdir = File.join(dir, 'Subdir') FileUtils.mkdir(subdir) data_source = ZoneinfoDataSource.new(dir) # Override the index so that an attempt is made to load the file. def data_source.validate_timezone_identifier(identifier) identifier = identifier.encode(Encoding::UTF_8) raise "Unexpected identifier passed to validate_timezone_identifier: #{identifier}" unless identifier == 'Subdir' 'Subdir'.freeze end error = assert_raises(InvalidTimezoneIdentifier) do data_source.send(:load_timezone_info, 'Subdir'.encode(encoding.name)) end assert_match(/\bSubdir\b/, error.message) assert_equal(Encoding::UTF_8, error.message.encoding) if error.respond_to?(:cause) # Errno::EISDIR is normally raised either when attempting to read or # when opening the file (Windows). However, JRuby on Windows 9.1.14.0 # raises Errno::EACCES instead. # # Once https://github.com/jruby/jruby/pull/4818 has been fixed/merged, # this can be changed to: # # assert_kind_of(Errno::EISDIR, error.cause) expected_cause = get_expected_file_open_and_read_cause(File.join(dir, 'Subdir')) assert_kind_of(expected_cause, error.cause) end end end end def test_load_timezone_info_linked_absolute_outside Dir.mktmpdir('tzinfo_test') do |dir| Dir.mktmpdir('tzinfo_test') do |outside| outside_file = File.join(outside, 'EST') FileUtils.cp(File.join(@data_source.zoneinfo_dir, 'EST'), outside_file) FileUtils.touch(File.join(dir, 'zone.tab')) FileUtils.touch(File.join(dir, 'iso3166.tab')) file = File.join(dir, 'EST') begin FileUtils.ln_s(outside_file, file) rescue NotImplementedError, Errno::EACCES # Symlinks not supported on this platform, or permission denied # (administrative rights are required on some versions of Windows). skip('Symlinks are not supported on this platform, or permission was denied creating a symlink') end data_source = ZoneinfoDataSource.new(dir) info = data_source.send(:load_timezone_info, 'EST') assert_kind_of(ConstantOffsetDataTimezoneInfo, info) assert_equal('EST', info.identifier) # JRuby 9.1.14.0 on Windows (running elevated) fails to clean up symlinks. File.delete(file) end end end def test_load_timezone_info_linked_absolute_inside Dir.mktmpdir('tzinfo_test') do |dir| FileUtils.touch(File.join(dir, 'zone.tab')) FileUtils.touch(File.join(dir, 'iso3166.tab')) FileUtils.cp(File.join(@data_source.zoneinfo_dir, 'EST'), File.join(dir, 'EST')) link = File.join(dir, 'Link') begin FileUtils.ln_s(File.join(File.expand_path(dir), 'EST'), link) rescue NotImplementedError, Errno::EACCES # Symlinks not supported on this platform, or permission denied # (administrative rights are required on some versions of Windows). skip('Symlinks are not supported on this platform, or permission was denied creating a symlink') end data_source = ZoneinfoDataSource.new(dir) info = data_source.send(:load_timezone_info, 'Link') assert_kind_of(ConstantOffsetDataTimezoneInfo, info) assert_equal('Link', info.identifier) # JRuby 9.1.14.0 on Windows (running elevated) fails to clean up symlinks. File.delete(link) end end def test_load_timezone_info_linked_relative_outside Dir.mktmpdir('tzinfo_test') do |root| FileUtils.cp(File.join(@data_source.zoneinfo_dir, 'EST'), File.join(root, 'outside')) dir = File.join(root, 'zoneinfo') FileUtils.mkdir(dir) FileUtils.touch(File.join(dir, 'zone.tab')) FileUtils.touch(File.join(dir, 'iso3166.tab')) link = File.join(dir, 'Link') begin FileUtils.ln_s('../outside', link) rescue NotImplementedError, Errno::EACCES # Symlinks not supported on this platform, or permission denied # (administrative rights are required on some versions of Windows). skip('Symlinks are not supported on this platform, or permission was denied creating a symlink') end subdir = File.join(dir, 'Subdir') subdir_link = File.join(subdir, 'Link') FileUtils.mkdir(subdir) FileUtils.ln_s('../../outside', subdir_link) data_source = ZoneinfoDataSource.new(dir) info = data_source.send(:load_timezone_info, 'Link') assert_kind_of(ConstantOffsetDataTimezoneInfo, info) assert_equal('Link', info.identifier) info = data_source.send(:load_timezone_info, 'Subdir/Link') assert_kind_of(ConstantOffsetDataTimezoneInfo, info) assert_equal('Subdir/Link', info.identifier) # JRuby 9.1.14.0 on Windows (running elevated) fails to clean up symlinks. File.delete(link) File.delete(subdir_link) end end def test_load_timezone_info_linked_relative_parent_inside Dir.mktmpdir('tzinfo_test') do |dir| FileUtils.touch(File.join(dir, 'zone.tab')) FileUtils.touch(File.join(dir, 'iso3166.tab')) FileUtils.cp(File.join(@data_source.zoneinfo_dir, 'EST'), File.join(dir, 'EST')) subdir = File.join(dir, 'Subdir') FileUtils.mkdir(subdir) FileUtils.cp(File.join(@data_source.zoneinfo_dir, 'EST'), File.join(subdir, 'EST')) subdir_link = File.join(subdir, 'Link') begin FileUtils.ln_s('../Subdir/EST', subdir_link) rescue NotImplementedError, Errno::EACCES # Symlinks not supported on this platform, or permission denied # (administrative rights are required on some versions of Windows). skip('Symlinks are not supported on this platform, or permission was denied creating a symlink') end subdir_link2 = File.join(subdir, 'Link2') FileUtils.ln_s('../EST', subdir_link2) subdir2 = File.join(dir, 'Subdir2') FileUtils.mkdir(subdir2) subdir2_link = File.join(subdir2, 'Link') FileUtils.ln_s('../Subdir/EST', subdir2_link) data_source = ZoneinfoDataSource.new(dir) info = data_source.send(:load_timezone_info, 'Subdir/Link') assert_kind_of(ConstantOffsetDataTimezoneInfo, info) assert_equal('Subdir/Link', info.identifier) info = data_source.send(:load_timezone_info, 'Subdir/Link2') assert_kind_of(ConstantOffsetDataTimezoneInfo, info) assert_equal('Subdir/Link2', info.identifier) info = data_source.send(:load_timezone_info, 'Subdir2/Link') assert_kind_of(ConstantOffsetDataTimezoneInfo, info) assert_equal('Subdir2/Link', info.identifier) # JRuby 9.1.14.0 on Windows (running elevated) fails to clean up symlinks. File.delete(subdir_link) File.delete(subdir_link2) File.delete(subdir2_link) end end test_encodings('UTF-8', 'UTF-16').each do |encoding| define_method("test_load_timezone_info_invalid_file_with_#{encoding.to_method}_encoded_identifier") do Dir.mktmpdir('tzinfo_test') do |dir| FileUtils.touch(File.join(dir, 'zone.tab')) FileUtils.touch(File.join(dir, 'iso3166.tab')) File.open(File.join(dir, 'Zone'), 'wb') do |file| file.write('NotAValidTZifFile') end data_source = ZoneinfoDataSource.new(dir) error = assert_raises(InvalidTimezoneIdentifier) do data_source.send(:load_timezone_info, 'Zone'.encode(encoding.name)) end assert_match(/\bZone\b/, error.message) assert_equal(Encoding::UTF_8, error.message.encoding) end end define_method("test_load_timezone_info_invalid_file_2_with_#{encoding.to_method}_encoded_identifier") do Dir.mktmpdir('tzinfo_test') do |dir| FileUtils.touch(File.join(dir, 'zone.tab')) FileUtils.touch(File.join(dir, 'iso3166.tab')) zone = File.join(dir, 'Zone') File.open(File.join(@data_source.zoneinfo_dir, 'EST')) do |src| # Change header to TZif1 (which is not a valid header). File.open(zone, 'wb') do |dest| dest.write('TZif1') src.pos = 5 FileUtils.copy_stream(src, dest) end end data_source = ZoneinfoDataSource.new(dir) error = assert_raises(InvalidTimezoneIdentifier) do data_source.send(:load_timezone_info, 'Zone'.encode(encoding.name)) end assert_match(/\bZone\b/, error.message) assert_equal(Encoding::UTF_8, error.message.encoding) end end end def test_load_timezone_info_tainted skip_if_taint_is_undefined_or_no_op safe_test(unavailable: :skip) do identifier = 'Europe/Amsterdam'.dup.taint assert(identifier.tainted?) info = @data_source.send(:load_timezone_info, identifier) assert_equal('Europe/Amsterdam', info.identifier) assert(identifier.tainted?) end end def test_load_timezone_info_tainted_and_frozen skip_if_taint_is_undefined_or_no_op safe_test do info = @data_source.send(:load_timezone_info, 'Europe/Amsterdam'.dup.taint.freeze) assert_equal('Europe/Amsterdam', info.identifier) end end def test_load_timezone_info_tainted_zoneinfo_dir_safe_mode skip_if_taint_is_undefined_or_no_op safe_test(unavailable: :skip) do assert_raises(SecurityError) do ZoneinfoDataSource.new(@data_source.zoneinfo_dir.dup.taint) end end end def test_load_timezone_info_tainted_zoneinfo_dir skip_if_taint_is_undefined_or_no_op data_source = ZoneinfoDataSource.new(@data_source.zoneinfo_dir.dup.taint) info = data_source.send(:load_timezone_info, 'Europe/London') assert_kind_of(TransitionsDataTimezoneInfo, info) assert_equal('Europe/London', info.identifier) end def test_load_timezone_info_returned_identifier_frozen info = @data_source.send(:load_timezone_info, 'Europe/London') assert(info.identifier.frozen?) end def test_load_timezone_info_parameter_remains_unfrozen identifier = 'Europe/London'.dup info = @data_source.send(:load_timezone_info, identifier) assert_equal('Europe/London', info.identifier) refute_same(identifier, info.identifier) assert(!identifier.frozen?) end test_encodings('UTF-8', 'UTF-16', 'ISO-8859-1') do |encoding| define_method("test_load_timezone_info_with_#{encoding.to_method}_encoded_identifier") do identifier = 'Europe/London'.encode(encoding.name).freeze info = @data_source.send(:load_timezone_info, identifier) assert_equal('Europe/London', info.identifier) end end def test_get_timezone_info info = @data_source.get_timezone_info('Europe/London') assert_equal('Europe/London', info.identifier) end def get_timezone_filenames(directory) entries = Dir.glob(File.join(directory, '**', '*')) entries = entries.select do |file| RubyCoreSupport.untaint(file) File.file?(file) end entries = entries.collect {|file| file[directory.length + File::SEPARATOR.length, file.length - directory.length - File::SEPARATOR.length]} # Exclude right (with leapseconds) and posix (copy) directories; .tab files; leapseconds, localtime and posixrules files. entries = entries.select do |file| file !~ /\A(posix|right)\// && file !~ /\.tab\z/ && !%w(leapseconds localtime posixrules).include?(file) end entries.sort end def test_timezone_identifiers expected = get_timezone_filenames(@data_source.zoneinfo_dir).sort! all = @data_source.timezone_identifiers assert_kind_of(Array, all) assert_equal(expected, all) assert(all.frozen?) assert(all.all?(&:frozen?)) assert(all.all? {|s| s.encoding == Encoding::UTF_8}) assert_same(all, @data_source.timezone_identifiers) end def test_data_timezone_identifiers expected = get_timezone_filenames(@data_source.zoneinfo_dir).sort! all_data = @data_source.data_timezone_identifiers assert_kind_of(Array, all_data) assert_equal(expected, all_data) assert(all_data.frozen?) assert(all_data.all?(&:frozen?)) assert(all_data.all? {|s| s.encoding == Encoding::UTF_8}) assert_same(all_data, @data_source.data_timezone_identifiers) end def test_linked_timezone_identifiers all_linked = @data_source.linked_timezone_identifiers assert_kind_of(Array, all_linked) assert_equal([], all_linked) assert(all_linked.frozen?) end ['UTF-8', 'ISO-8859-1', nil].each do |encoding| define_method("test_timezone_identifiers_loaded_as_utf_8_when_internal_encoding_is_#{encoding ? encoding.downcase.gsub('-', '_') : 'nil'}") do Dir.mktmpdir('tzinfo_test') do |dir| FileUtils.touch(File.join(dir, 'zone.tab')) FileUtils.touch(File.join(dir, 'iso3166.tab')) subdir = File.join(dir, 'Subdir') FileUtils.mkdir(subdir) FileUtils.touch(File.join(subdir, 'Zone')) orig_verbose = $VERBOSE orig_default_internal_encoding = Encoding.default_internal begin $VERBOSE = nil Encoding.default_internal = encoding data_source = ZoneinfoDataSource.new(dir) all = data_source.timezone_identifiers assert_equal(1, all.length) assert_equal('Subdir/Zone', all[0]) assert_equal(Encoding::UTF_8, all[0].encoding) ensure Encoding.default_internal = orig_default_internal_encoding $VERBOSE = orig_verbose end end end end ['UTF-8', 'ISO-8859-1'].each do |encoding| define_method("test_timezone_identifiers_loaded_when_zoneinfo_dir_encoded_as_#{encoding.downcase.gsub('-', '_')}") do Dir.mktmpdir('tzinfo_test') do |dir| FileUtils.touch(File.join(dir, 'zone.tab')) FileUtils.touch(File.join(dir, 'iso3166.tab')) subdir = File.join(dir, 'Subdir') FileUtils.mkdir(subdir) FileUtils.touch(File.join(subdir, 'Zone')) data_source = ZoneinfoDataSource.new(dir.encode(encoding)) all = data_source.timezone_identifiers assert_equal(1, all.length) assert_equal('Subdir/Zone', all[0]) assert_equal(Encoding::UTF_8, all[0].encoding) end end end def test_timezone_identifiers_excludes_those_that_cannot_be_utf8_encoded file_expand_path = ->(path) do raise "Unexpected path: #{path}" unless path == '/test' path end file_directory = ->(path) do path == '/test' end file_file = ->(path) do path =~ /\A\/test\/((iso3166|zone).tab|Zone[123])\z/ end file_read = ->(path, options = {}) do raise "Unexpected path: #{path}" unless path == '/test/iso3166.tab' || path == '/test/zone.tab' '' end dir_foreach = ->(path, &block) do raise "Unexpected path: #{path}" unless path == '/test' block.call('Zone1'.dup.force_encoding(Encoding::UTF_16)) # Invalid, can't be converted. block.call('Zone2'.dup) block.call('Zone3'.dup.force_encoding(Encoding::UTF_16)) # Invalid, can't be converted. end File.stub(:expand_path, file_expand_path) do File.stub(:directory?, file_directory) do File.stub(:file?, file_file) do File.stub(:read, file_read) do Dir.stub(:foreach, dir_foreach) do data_source = ZoneinfoDataSource.new('/test') all = data_source.timezone_identifiers assert_equal(1, all.length) assert_equal('Zone2', all[0]) assert_equal(Encoding::UTF_8, all[0].encoding) end end end end end end def test_timezone_identifiers_are_utf8_when_file_join_returns_non_utf8 file_join = ->(*paths) do if paths.length == 2 && paths[0] == 'Test' && paths[1] == 'Zone' 'Test/Zone'.encode(Encoding::ISO_8859_1) else File.__minitest_stub__join(*paths) end end Dir.mktmpdir('tzinfo_test') do |dir| FileUtils.touch(File.join(dir, 'zone.tab')) FileUtils.touch(File.join(dir, 'iso3166.tab')) test_path = File.join(dir, 'Test') FileUtils.mkdir(test_path) zone_path = File.join(test_path, 'Zone') FileUtils.touch(zone_path) File.stub(:join, file_join) do data_source = ZoneinfoDataSource.new(dir) assert_equal(['Test/Zone'], data_source.timezone_identifiers) assert_equal(Encoding::UTF_8, data_source.timezone_identifiers[0].encoding) end end end def test_timezone_identifiers_ignored_plus_version_file # Mac OS X includes a file named +VERSION containing the tzdata version. Dir.mktmpdir('tzinfo_test') do |dir| FileUtils.touch(File.join(dir, 'zone.tab')) FileUtils.touch(File.join(dir, 'iso3166.tab')) FileUtils.cp(File.join(@data_source.zoneinfo_dir, 'EST'), File.join(dir, 'EST')) File.open(File.join(dir, '+VERSION'), 'w') do |f| f.binmode f.write("2013a\n") end data_source = ZoneinfoDataSource.new(dir) assert_equal(['EST'], data_source.timezone_identifiers) end end def test_timezone_identifiers_ignored_timeconfig_symlink # Slackware includes a symlink named timeconfig that points at /usr/sbin/timeconfig. Dir.mktmpdir('tzinfo_test_target') do |target_dir| target_path = File.join(target_dir, 'timeconfig') File.open(target_path, 'w') do |f| f.write("#!/bin/sh\n") f.write("#\n") f.write('# timeconfig Slackware Linux timezone configuration utility.\n') end Dir.mktmpdir('tzinfo_test') do |dir| FileUtils.touch(File.join(dir, 'zone.tab')) FileUtils.touch(File.join(dir, 'iso3166.tab')) FileUtils.cp(File.join(@data_source.zoneinfo_dir, 'EST'), File.join(dir, 'EST')) symlink_path = File.join(dir, 'timeconfig') begin FileUtils.ln_s(target_path, symlink_path) rescue NotImplementedError, Errno::EACCES # Symlinks not supported on this platform, or permission denied # (administrative rights are required on Windows). Copy instead. FileUtils.cp(target_path, symlink_path) end data_source = ZoneinfoDataSource.new(dir) assert_equal(['EST'], data_source.timezone_identifiers) end end end def test_timezone_identifiers_ignored_src_directory # Solaris includes a src directory containing the source timezone data files # from the tzdata distribution. These should be ignored. Dir.mktmpdir('tzinfo_test') do |dir| FileUtils.touch(File.join(dir, 'zone.tab')) FileUtils.touch(File.join(dir, 'iso3166.tab')) FileUtils.cp(File.join(@data_source.zoneinfo_dir, 'EST'), File.join(dir, 'EST')) src_dir = File.join(dir, 'src') FileUtils.mkdir(src_dir) File.open(File.join(src_dir, 'europe'), 'w') do |f| f.binmode f.write("Zone\tEurope/London\t0:00\tEU\tGMT/BST\n") end data_source = ZoneinfoDataSource.new(dir) assert_equal(['EST'], data_source.timezone_identifiers) end end def test_timezone_identifiers_ignored_security_file # The Arch linux tzdata package includes a file named SECURITY giving # instructions for reporting security-related bugs. Dir.mktmpdir('tzinfo_test') do |dir| FileUtils.touch(File.join(dir, 'zone.tab')) FileUtils.touch(File.join(dir, 'iso3166.tab')) FileUtils.cp(File.join(@data_source.zoneinfo_dir, 'EST'), File.join(dir, 'EST')) File.open(File.join(dir, 'SECURITY'), 'w') do |f| f.binmode f.write("Please report any sensitive security-related bugs...\n") end data_source = ZoneinfoDataSource.new(dir) assert_equal(['EST'], data_source.timezone_identifiers) end end def test_load_country_info info = @data_source.send(:load_country_info, 'GB') assert_equal('GB', info.code) assert_equal('Britain (UK)', info.name) end def test_load_country_info_not_exist error = assert_raises(InvalidCountryCode) do @data_source.send(:load_country_info, 'ZZ') end assert_match(/\bZZ\b/, error.message) end def test_load_country_info_invalid error = assert_raises(InvalidCountryCode) do @data_source.send(:load_country_info, '../Countries/GB') end assert_match(/\W\.\.\/Countries\/GB\b/, error.message) end def test_load_country_info_nil error = assert_raises(InvalidCountryCode) do @data_source.send(:load_country_info, nil) end assert_match(/\bnil\b/, error.message) end def test_load_country_info_false error = assert_raises(InvalidCountryCode) do @data_source.send(:load_country_info, false) end assert_match(/\bfalse\b/, error.message) end def test_load_country_info_case error = assert_raises(InvalidCountryCode) do @data_source.send(:load_country_info, 'gb') end assert_match(/\bgb\b/, error.message) end def test_load_country_info_tainted skip_if_taint_is_undefined_or_no_op safe_test(unavailable: :skip) do code = 'NL'.dup.taint assert(code.tainted?) info = @data_source.send(:load_country_info, code) assert_equal('NL', info.code) assert(code.tainted?) end end def test_load_country_info_returned_strings_frozen info = @data_source.send(:load_country_info, 'US') assert(info.code.frozen?) assert(info.name.frozen?) assert(info.zones.map(&:identifier).all?(&:frozen?)) assert(info.zones.map(&:description).all?(&:frozen?)) end def test_load_country_info_check_zones Dir.mktmpdir('tzinfo_test') do |dir| File.open(File.join(dir, 'iso3166.tab'), 'w', external_encoding: Encoding::UTF_8) do |iso3166| iso3166.puts('# iso3166.tab') iso3166.puts('') iso3166.puts("FC\tFake Country") iso3166.puts("OC\tOther Country") end File.open(File.join(dir, 'zone.tab'), 'w', external_encoding: Encoding::UTF_8) do |zone| zone.puts('# zone.tab') zone.puts('') zone.puts("FC\t+513030-0000731\tFake/One\tDescription of one") zone.puts("FC\t+353916+1394441\tFake/Two\tAnother description") zone.puts("FC\t-2332-04637\tFake/Three\tThis is Three") zone.puts("OC\t+5005+01426\tOther/One") end data_source = ZoneinfoDataSource.new(dir) info = data_source.send(:load_country_info, 'FC') assert_equal('FC', info.code) assert_equal('Fake Country', info.name) assert_equal([ CountryTimezone.new('Fake/One', Rational(6181, 120), Rational(-451, 3600), 'Description of one'), CountryTimezone.new('Fake/Two', Rational(32089, 900), Rational(503081, 3600), 'Another description'), CountryTimezone.new('Fake/Three', Rational(-353, 15), Rational(-2797, 60), 'This is Three')], info.zones) assert_equal(true, info.zones.frozen?) info = data_source.send(:load_country_info, 'OC') assert_equal('OC', info.code) assert_equal('Other Country', info.name) assert_equal([CountryTimezone.new('Other/One', Rational(601, 12), Rational(433, 30))], info.zones) assert_equal(true, info.zones.frozen?) end end def test_load_country_info_check_zones_zone1970 Dir.mktmpdir('tzinfo_test') do |dir| File.open(File.join(dir, 'iso3166.tab'), 'w', external_encoding: Encoding::UTF_8) do |iso3166| iso3166.puts('# iso3166.tab') iso3166.puts('') iso3166.puts("AC\tAnother Country") iso3166.puts("FC\tFake Country") iso3166.puts("OC\tOther Country") end # zone.tab will be ignored. File.open(File.join(dir, 'zone.tab'), 'w', external_encoding: Encoding::UTF_8) do |zone| zone.puts('# zone.tab') zone.puts('') zone.puts("FC\t+513030-0000731\tFake/One\tDescription of one") zone.puts("FC\t+353916+1394441\tFake/Two\tAnother description") zone.puts("FC\t-2332-04637\tFake/Three\tThis is Three") zone.puts("OC\t+5005+01426\tOther/One") end # zone1970.tab will be used. File.open(File.join(dir, 'zone1970.tab'), 'w', external_encoding: Encoding::UTF_8) do |zone| zone.puts('# zone1970.tab') zone.puts('') zone.puts("AC,OC\t+0000+00000\tMiddle/Another/One\tAnother's One") zone.puts("FC\t+513030-0000731\tFake/One\tDescription of one") zone.puts("FC,OC\t+353916+1394441\tFake/Two\tAnother description") zone.puts("FC,OC\t-2332-04637\tFake/Three\tThis is Three") zone.puts("OC\t+5005+01426\tOther/One") zone.puts("OC\t+5015+11426\tOther/Two") end data_source = ZoneinfoDataSource.new(dir) info = data_source.send(:load_country_info, 'AC') assert_equal('AC', info.code) assert_equal('Another Country', info.name) assert_equal([CountryTimezone.new('Middle/Another/One', Rational(0, 1), Rational(0, 1), "Another's One")], info.zones) assert_equal(true, info.zones.frozen?) info = data_source.send(:load_country_info, 'FC') assert_equal('FC', info.code) assert_equal('Fake Country', info.name) assert_equal([ CountryTimezone.new('Fake/One', Rational(6181, 120), Rational(-451, 3600), 'Description of one'), CountryTimezone.new('Fake/Two', Rational(32089, 900), Rational(503081, 3600), 'Another description'), CountryTimezone.new('Fake/Three', Rational(-353, 15), Rational(-2797, 60), 'This is Three')], info.zones) assert_equal(true, info.zones.frozen?) # Testing the ordering of zones. A zone can either be primary (country # code is the first in the first column), or secondary (country code is # not the first). Should return all the primaries first in the order they # appeared in the file, followed by all the secondaries in the order they # appeared in file. info = data_source.send(:load_country_info, 'OC') assert_equal('OC', info.code) assert_equal('Other Country', info.name) assert_equal([ CountryTimezone.new('Other/One', Rational(601, 12), Rational( 433, 30)), CountryTimezone.new('Other/Two', Rational(201, 4), Rational(3433, 30)), CountryTimezone.new('Middle/Another/One', Rational(0, 1), Rational(0, 1), "Another's One"), CountryTimezone.new('Fake/Two', Rational(32089, 900), Rational(503081, 3600), 'Another description'), CountryTimezone.new('Fake/Three', Rational(-353, 15), Rational(-2797, 60), 'This is Three')], info.zones) assert_equal(true, info.zones.frozen?) end end def test_load_country_info_check_zones_solaris_tab_files # Solaris uses 5 columns instead of the usual 4 in zone_sun.tab. # An extra column before the comment gives an optional linked/alternate # timezone identifier (or '-' if not set). # # Additionally, there is a section at the end of the file for timezones # covering regions. These are given lower-case "country" codes. The timezone # identifier column refers to a continent instead of an identifier. These # lines will be ignored by TZInfo. Dir.mktmpdir('tzinfo_test') do |dir| tab_dir = File.join(dir, 'tab') FileUtils.mkdir(tab_dir) File.open(File.join(tab_dir, 'country.tab'), 'w', external_encoding: Encoding::UTF_8) do |country| country.puts('# country.tab') country.puts('# Solaris') country.puts("FC\tFake Country") country.puts("OC\tOther Country") end File.open(File.join(tab_dir, 'zone_sun.tab'), 'w', external_encoding: Encoding::UTF_8) do |zone_sun| zone_sun.puts('# zone_sun.tab') zone_sun.puts('# Solaris') zone_sun.puts('# Countries') zone_sun.puts("FC\t+513030-0000731\tFake/One\t-\tDescription of one") zone_sun.puts("FC\t+353916+1394441\tFake/Two\tFake/Alias/Two\tAnother description") zone_sun.puts("FC\t-2332-04637\tFake/Three\tFake/Alias/Three\tThis is Three") zone_sun.puts("OC\t+5005+01426\tOther/One\tOther/Linked/One") zone_sun.puts("OC\t+5015+01436\tOther/Two\t-") zone_sun.puts('# Regions') zone_sun.puts("ee\t+0000+00000\tEurope/\tEET") zone_sun.puts("me\t+0000+00000\tEurope/\tMET") zone_sun.puts("we\t+0000+00000\tEurope/\tWET") end data_source = ZoneinfoDataSource.new(dir) info = data_source.send(:load_country_info, 'FC') assert_equal('FC', info.code) assert_equal('Fake Country', info.name) assert_equal([ CountryTimezone.new('Fake/One', Rational(6181, 120), Rational(-451, 3600), 'Description of one'), CountryTimezone.new('Fake/Two', Rational(32089, 900), Rational(503081, 3600), 'Another description'), CountryTimezone.new('Fake/Three', Rational(-353, 15), Rational(-2797, 60), 'This is Three')], info.zones) assert_equal(true, info.zones.frozen?) info = data_source.send(:load_country_info, 'OC') assert_equal('OC', info.code) assert_equal('Other Country', info.name) assert_equal([ CountryTimezone.new('Other/One', Rational(601, 12), Rational(433, 30)), CountryTimezone.new('Other/Two', Rational(201, 4), Rational(73, 5))], info.zones) assert_equal(true, info.zones.frozen?) end end def test_load_country_info_check_zones_alternate_iso3166_file Dir.mktmpdir('tzinfo_test') do |dir| zoneinfo_dir = File.join(dir, 'zoneinfo') tab_dir = File.join(dir, 'tab') FileUtils.mkdir(zoneinfo_dir) FileUtils.mkdir(tab_dir) tab_file = File.join(tab_dir, 'iso3166') File.open(tab_file, 'w', external_encoding: Encoding::UTF_8) do |iso3166| # Use the BSD 4 column format (alternate iso3166 is used on BSD). iso3166.puts("FC\tFCC\t001\tFake Country") iso3166.puts("OC\tOCC\t002\tOther Country") end File.open(File.join(zoneinfo_dir, 'zone.tab'), 'w', external_encoding: Encoding::UTF_8) do |zone| zone.puts("FC\t+513030-0000731\tFake/One\tDescription of one") zone.puts("FC\t+353916+1394441\tFake/Two\tAnother description") zone.puts("FC\t-2332-04637\tFake/Three\tThis is Three") zone.puts("OC\t+5005+01426\tOther/One") end data_source = ZoneinfoDataSource.new(zoneinfo_dir, tab_file) info = data_source.send(:load_country_info, 'FC') assert_equal('FC', info.code) assert_equal('Fake Country', info.name) assert_equal([ CountryTimezone.new('Fake/One', Rational(6181, 120), Rational(-451, 3600), 'Description of one'), CountryTimezone.new('Fake/Two', Rational(32089, 900), Rational(503081, 3600), 'Another description'), CountryTimezone.new('Fake/Three', Rational(-353, 15), Rational(-2797, 60), 'This is Three')], info.zones) assert_equal(true, info.zones.frozen?) info = data_source.send(:load_country_info, 'OC') assert_equal('OC', info.code) assert_equal('Other Country', info.name) assert_equal([CountryTimezone.new('Other/One', Rational(601, 12), Rational(433, 30))], info.zones) assert_equal(true, info.zones.frozen?) end end def test_load_country_info_four_column_iso31611 # OpenBSD and FreeBSD use a 4 column iso3166.tab file that includes # alpha-3 and numeric-3 codes in addition to the alpha-2 and name in the # tz database version. Dir.mktmpdir('tzinfo_test') do |dir| File.open(File.join(dir, 'iso3166.tab'), 'w', external_encoding: Encoding::UTF_8) do |iso3166| iso3166.puts("FC\tFCC\t001\tFake Country") iso3166.puts("OC\tOCC\t002\tOther Country") end File.open(File.join(dir, 'zone.tab'), 'w', external_encoding: Encoding::UTF_8) do |zone| zone.puts("FC\t+513030-0000731\tFake/One\tDescription of one") zone.puts("OC\t+5005+01426\tOther/One") end data_source = ZoneinfoDataSource.new(dir) info = data_source.send(:load_country_info, 'FC') assert_equal('FC', info.code) assert_equal('Fake Country', info.name) info = data_source.send(:load_country_info, 'OC') assert_equal('OC', info.code) assert_equal('Other Country', info.name) end end def test_load_country_info_utf8 # iso3166.tab is currently in ASCII (as of tzdata 2014f), but will be # changed to UTF-8 in the future. # zone.tab is in ASCII, with no plans to change. Since ASCII is a subset of # UTF-8, test that this is loaded in UTF-8 anyway. Dir.mktmpdir('tzinfo_test') do |dir| File.open(File.join(dir, 'iso3166.tab'), 'w', external_encoding: Encoding::UTF_8) do |iso3166| iso3166.puts("UT\tUnicode Test ✓") end File.open(File.join(dir, 'zone.tab'), 'w', external_encoding: Encoding::UTF_8) do |zone| zone.puts("UT\t+513030-0000731\tUnicode✓/One\tUnicode Description ✓") end data_source = ZoneinfoDataSource.new(dir) info = data_source.send(:load_country_info, 'UT') assert_equal('UT', info.code) assert_equal('Unicode Test ✓', info.name) assert_equal([CountryTimezone.new('Unicode✓/One', Rational(6181, 120), Rational(-451, 3600), 'Unicode Description ✓')], info.zones) end end def test_load_country_info_utf8_zone1970 # iso3166.tab is currently in ASCII (as of tzdata 2014f), but will be # changed to UTF-8 in the future. # zone1970.tab is in UTF-8. Dir.mktmpdir('tzinfo_test') do |dir| File.open(File.join(dir, 'iso3166.tab'), 'w', external_encoding: Encoding::UTF_8) do |iso3166| iso3166.puts("UT\tUnicode Test ✓") end File.open(File.join(dir, 'zone1970.tab'), 'w', external_encoding: Encoding::UTF_8) do |zone| zone.puts("UT\t+513030-0000731\tUnicode✓/One\tUnicode Description ✓") end data_source = ZoneinfoDataSource.new(dir) info = data_source.send(:load_country_info, 'UT') assert_equal('UT', info.code) assert_equal('Unicode Test ✓', info.name) assert_equal([CountryTimezone.new('Unicode✓/One', Rational(6181, 120), Rational(-451, 3600), 'Unicode Description ✓')], info.zones) end end test_encodings('UTF-8', 'UTF-16', 'ISO-8859-1') do |encoding| define_method("test_load_country_info_with_#{encoding.to_method}_encoded_code") do code = 'GB'.encode(encoding.name).freeze info = @data_source.send(:load_country_info, code) assert_equal('GB', info.code) end end def test_get_country_info info = @data_source.get_country_info('GB') assert_equal('GB', info.code) end def test_country_codes file_codes = [] file = File.read(File.join(@data_source.zoneinfo_dir, 'iso3166.tab'), external_encoding: Encoding::UTF_8, internal_encoding: Encoding::UTF_8) file.each_line do |line| line.chomp! file_codes << $1 if line =~ /\A([A-Z]{2})\t/ end file_codes.sort! codes = @data_source.country_codes assert_kind_of(Array, codes) assert_equal(file_codes, codes) assert(codes.frozen?) assert(codes.all?(&:frozen?)) assert_same(codes, @data_source.country_codes) end def test_country_codes_four_column_iso3166 # OpenBSD and FreeBSD use a 4 column iso3166.tab file that includes # alpha-3 and numeric-3 codes in addition to the alpha-2 and name in the # tz database version. Dir.mktmpdir('tzinfo_test') do |dir| File.open(File.join(dir, 'iso3166.tab'), 'w', external_encoding: Encoding::UTF_8) do |iso3166| iso3166.puts("FC\tFCC\t001\tFake Country") iso3166.puts("OC\tOCC\t002\tOther Country") end File.open(File.join(dir, 'zone.tab'), 'w', external_encoding: Encoding::UTF_8) do |zone| zone.puts("FC\t+513030-0000731\tFake/One\tDescription of one") zone.puts("OC\t+5005+01426\tOther/One") end data_source = ZoneinfoDataSource.new(dir) codes = data_source.country_codes assert_equal(%w(FC OC), codes) end end def test_to_s assert_equal("Zoneinfo DataSource: #{ZONEINFO_DIR}", @data_source.to_s) end def test_inspect assert_equal("#", @data_source.inspect) end def test_country_info_strings_deduped Dir.mktmpdir('tzinfo_test') do |dir| File.open(File.join(dir, 'iso3166.tab'), 'w', external_encoding: Encoding::UTF_8) do |iso3166| iso3166.puts("FC\tFake Country") iso3166.puts("OC\tOther Country") end File.open(File.join(dir, 'zone.tab'), 'w', external_encoding: Encoding::UTF_8) do |zone| zone.puts("FC\t+513030-0000731\tFake/One\tDescription of onex") zone.puts("OC\t+513030-0000731\tFake/One\tDescription of onex") zone.puts("OC,FC\t+513030-0000731\tFake/Two\tDescription of two") end fake_dir = File.join(dir, 'Fake') FileUtils.mkdir(fake_dir) FileUtils.touch(File.join(fake_dir, 'Two')) data_source = ZoneinfoDataSource.new(dir) fc = data_source.send(:load_country_info, 'FC') oc = data_source.send(:load_country_info, 'OC') assert_same(fc.zones[0].identifier, oc.zones[0].identifier) assert_same(fc.zones[0].description, oc.zones[0].description) assert_same(fc.zones[1].identifier, oc.zones[1].identifier) assert_same(fc.zones[1].description, oc.zones[1].description) assert_same(data_source.timezone_identifiers[0], fc.zones[1].identifier) end def test_timezone_abbreviations_deduped london = @data_source.load_timezone_info('Europe/London').transitions[0].previous_offset new_york = @data_source.load_timezone_info('America/New_York').transitions[0].previous_offset assert_equal('LMT', london) assert_same(london, new_york) end end private def assert_raises_directory_not_found(&block) error = assert_raises(ZoneinfoDirectoryNotFound, &block) assert_equal('None of the paths included in TZInfo::DataSources::ZoneinfoDataSource.search_path are valid zoneinfo directories.', error.message) end def assert_raises_invalid_directory(zoneinfo_dir, &block) error = assert_raises(InvalidZoneinfoDirectory, &block) assert_equal("#{zoneinfo_dir} is not a directory or doesn't contain a iso3166.tab file and a zone1970.tab or zone.tab file.", error.message) end def get_expected_file_open_and_read_cause(path) expected_error = assert_raises(SystemCallError) do File.open(path, 'r') {|f| f.read(1) } end expected_error.class end end end tzinfo-2.0.6/test/data_sources/tc_zoneinfo_reader.rb000066400000000000000000002405121436527530500226650ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true require_relative '../test_utils' require 'tempfile' module DataSources class TCZoneinfoReader < Minitest::Test include TZInfo include TZInfo::DataSources class FakePosixTimeZoneParser def initialize(&block) @on_parse = block end def parse(tz_string) @on_parse.call(tz_string) end end MIN_FORMAT = 1 MAX_FORMAT = 3 def convert_times_to_i(items, key = :at) items.each do |item| if item[key].kind_of?(Time) item[key] = item[key].utc.to_i end end end def select_with_32bit_values(items, key = :at) items.select do |item| i = item[key] i >= -2147483648 && i <= 2147483647 end end def pack_int64_network_order(values) values.collect {|value| [value >> 32, value & 0xFFFFFFFF]}.flatten.pack('NN' * values.length) end def pack_int64_signed_network_order(values) # Convert to the equivalent 64-bit unsigned integer with the same bit representation pack_int64_network_order(values.collect {|value| value < 0 ? value + 0x10000000000000000 : value}) end def write_tzif(format, offsets, transitions, tz_string, leaps, options = {}) # Options for testing malformed zoneinfo files. magic = options[:magic] section2_magic = options[:section2_magic] abbrev_separator = options[:abbrev_separator] || "\0" abbrev_offset_base = options[:abbrev_offset_base] || 0 omit_tz_string_start_new_line = options[:omit_tz_string_start_new_line] omit_tz_string_end_new_line = options[:omit_tz_string_end_new_line] unless magic if format == 1 magic = "TZif\0" elsif format >= 2 magic = "TZif#{format}" else raise ArgumentError, 'Invalid format specified' end end if section2_magic.kind_of?(Proc) section2_magic = section2_magic.call(format) else section2_magic = magic unless section2_magic end convert_times_to_i(transitions) convert_times_to_i(leaps) abbrevs = offsets.collect {|o| o[:abbrev]}.uniq if abbrevs.length > 0 abbrevs = abbrevs.collect {|a| a.encode(Encoding::UTF_8)} if abbrevs.first.respond_to?(:bytesize) abbrevs_length = abbrevs.inject(0) {|sum, a| sum + a.bytesize + abbrev_separator.bytesize} else abbrevs_length = abbrevs.inject(0) {|sum, a| sum + a.length + abbrev_separator.length} end else abbrevs_length = 0 end b32_transitions = select_with_32bit_values(transitions) b32_leaps = select_with_32bit_values(leaps) Tempfile.open('tzinfo-test-zone') do |file| file.binmode file.write( [magic, offsets.length, offsets.length, leaps.length, b32_transitions.length, offsets.length, abbrevs_length].pack('a5 x15 NNNNNN')) unless b32_transitions.empty? file.write(b32_transitions.collect {|t| t[:at]}.pack('N' * b32_transitions.length)) file.write(b32_transitions.collect {|t| t[:offset_index]}.pack('C' * b32_transitions.length)) end offsets.each do |offset| index = abbrevs.index(offset[:abbrev]) abbrev_offset = abbrev_offset_base 0.upto(index - 1) {|i| abbrev_offset += abbrevs[i].length + 1} file.write([offset[:gmtoff], offset[:isdst] ? 1 : 0, abbrev_offset].pack('NCC')) end abbrevs.each do |a| file.write(a) file.write(abbrev_separator) end b32_leaps.each do |leap| file.write([leap[:at], leap[:seconds]].pack('NN')) end unless offsets.empty? file.write("\0" * offsets.length * 2) end if format >= 2 file.write( [section2_magic, offsets.length, offsets.length, leaps.length, transitions.length, offsets.length, abbrevs_length].pack('a5 x15 NNNNNN')) unless transitions.empty? file.write(pack_int64_signed_network_order(transitions.collect {|t| t[:at]})) file.write(transitions.collect {|t| t[:offset_index]}.pack('C' * transitions.length)) end offsets.each do |offset| index = abbrevs.index(offset[:abbrev]) abbrev_offset = abbrev_offset_base 0.upto(index - 1) {|i| abbrev_offset += abbrevs[i].length + 1} file.write([offset[:gmtoff], offset[:isdst] ? 1 : 0, abbrev_offset].pack('NCC')) end abbrevs.each do |a| file.write(a) file.write(abbrev_separator) end leaps.each do |leap| file.write(pack_int64_signed_network_order([leap[:at]])) file.write([leap[:seconds]].pack('N')) end unless offsets.empty? file.write("\0" * offsets.length * 2) end file.write("\n") unless omit_tz_string_start_new_line file.write(tz_string.encode(Encoding::UTF_8)) file.write("\n") unless omit_tz_string_end_new_line end file.flush yield file.path end end def tzif_test(offsets, transitions, options = {}, &block) rules = options[:rules] tz_string = options[:tz_string] || (rules ? "TEST_TZ_STRING_#{rand(1000000)}" : '') leaps = options[:leaps] || [] min_format = options[:min_format] || (tz_string.empty? ? MIN_FORMAT : 2) min_format.upto(MAX_FORMAT) do |format| write_tzif(format, offsets, transitions, tz_string, leaps, options) do |path| if format >= 2 @tz_parse_result = rules @expect_tz_string = tz_string end begin yield path, format ensure @tz_parse_result = nil @expect_tz_string = nil end end end end def setup @expect_tz_string = nil @tz_parse_result = nil @posix_tz_parser = FakePosixTimeZoneParser.new do |tz_string| raise "Unexpected tz_string passed to PosixTimeZoneParser: #{tz_string}" unless tz_string == @expect_tz_string raise InvalidPosixTimeZone, 'FakePosixTimeZoneParser Failure.' if @tz_parse_result == :fail @tz_parse_result end @reader = ZoneinfoReader.new(@posix_tz_parser, StringDeduper.new) end def test_read offsets = [ {gmtoff: 3542, isdst: false, abbrev: 'LMT'}, {gmtoff: 3600, isdst: false, abbrev: 'XST'}, {gmtoff: 7200, isdst: true, abbrev: 'XDT'}, {gmtoff: 0, isdst: false, abbrev: 'XNST'}] transitions = [ {at: Time.utc(1971, 1, 2), offset_index: 1}, {at: Time.utc(1980, 4, 22), offset_index: 2}, {at: Time.utc(1980, 10, 21), offset_index: 1}, {at: Time.utc(2000, 12, 31), offset_index: 3}] o0 = TimezoneOffset.new(3542, 0, 'LMT') o1 = TimezoneOffset.new(3600, 0, 'XST') o2 = TimezoneOffset.new(3600, 3600, 'XDT') o3 = TimezoneOffset.new( 0, 0, 'XNST') t0 = TimezoneTransition.new(o1, o0, Time.utc(1971, 1, 2).to_i) t1 = TimezoneTransition.new(o2, o1, Time.utc(1980, 4, 22).to_i) t2 = TimezoneTransition.new(o1, o2, Time.utc(1980, 10, 21).to_i) t3 = TimezoneTransition.new(o3, o1, Time.utc(2000, 12, 31).to_i) tzif_test(offsets, transitions) do |path, format| assert_equal([t0,t1,t2,t3], @reader.read(path)) end end def test_read_negative_utc_offset offsets = [ {gmtoff: -12492, isdst: false, abbrev: 'LMT'}, {gmtoff: -12000, isdst: false, abbrev: 'XST'}, {gmtoff: -8400, isdst: true, abbrev: 'XDT'}, {gmtoff: -8400, isdst: false, abbrev: 'XNST'}] transitions = [ {at: Time.utc(1971, 7, 9, 3, 0, 0), offset_index: 1}, {at: Time.utc(1972, 10, 12, 3, 0, 0), offset_index: 2}, {at: Time.utc(1973, 4, 29, 3, 0, 0), offset_index: 1}, {at: Time.utc(1992, 4, 1, 4, 30, 0), offset_index: 3}] o0 = TimezoneOffset.new(-12492, 0, 'LMT') o1 = TimezoneOffset.new(-12000, 0, 'XST') o2 = TimezoneOffset.new(-12000, 3600, 'XDT') o3 = TimezoneOffset.new( -8400, 0, 'XNST') t0 = TimezoneTransition.new(o1, o0, Time.utc(1971, 7, 9, 3, 0, 0).to_i) t1 = TimezoneTransition.new(o2, o1, Time.utc(1972, 10, 12, 3, 0, 0).to_i) t2 = TimezoneTransition.new(o1, o2, Time.utc(1973, 4, 29, 3, 0, 0).to_i) t3 = TimezoneTransition.new(o3, o1, Time.utc(1992, 4, 1, 4, 30, 0).to_i) tzif_test(offsets, transitions) do |path, format| assert_equal([t0,t1,t2,t3], @reader.read(path)) end end def test_read_dst_first offsets = [ {gmtoff: 7200, isdst: true, abbrev: 'XDT'}, {gmtoff: 3542, isdst: false, abbrev: 'LMT'}, {gmtoff: 3600, isdst: false, abbrev: 'XST'}, {gmtoff: 0, isdst: false, abbrev: 'XNST'}] transitions = [ {at: Time.utc(1979, 1, 2), offset_index: 2}, {at: Time.utc(1980, 4, 22), offset_index: 0}, {at: Time.utc(1980, 10, 21), offset_index: 2}, {at: Time.utc(2000, 12, 31), offset_index: 3}] o1 = TimezoneOffset.new(3542, 0, 'LMT') o2 = TimezoneOffset.new(3600, 0, 'XST') t0 = TimezoneTransition.new(o2, o1, Time.utc(1979, 1, 2).to_i) tzif_test(offsets, transitions) do |path, format| assert_equal(t0, @reader.read(path).first) end end def test_read_no_transitions offsets = [{gmtoff: -12094, isdst: false, abbrev: 'LT'}] o0 = TimezoneOffset.new(-12094, 0, 'LT') tzif_test(offsets, []) do |path, format| assert_equal(o0, @reader.read(path)) end end def test_read_no_transitions_dst_first offsets = [ {gmtoff: -10800, isdst: true, abbrev: 'XDT'}, {gmtoff: -12094, isdst: false, abbrev: 'LT'}] o1 = TimezoneOffset.new(-12094, 0, 'LT') tzif_test(offsets, []) do |path, format| assert_equal(o1, @reader.read(path)) end end def test_read_no_transitions_dst_only offsets = [{gmtoff: -10800, isdst: true, abbrev: 'XDT'}] o0 = TimezoneOffset.new(-14400, 3600, 'XDT') tzif_test(offsets, []) do |path, format| assert_equal(o0, @reader.read(path)) end end def test_read_initial_transition_to_first_offset offsets = [ {gmtoff: 3542, isdst: false, abbrev: 'LMT'}, {gmtoff: 3600, isdst: false, abbrev: 'XST'}] transitions = [ {at: Time.utc(1950, 1, 1), offset_index: 0}, {at: Time.utc(2000, 1, 1), offset_index: 1}] o0 = TimezoneOffset.new(3542, 0, 'LMT') o1 = TimezoneOffset.new(3600, 0, 'XST') t0 = TimezoneTransition.new(o0, o0, Time.utc(1950, 1, 1).to_i) t1 = TimezoneTransition.new(o1, o0, Time.utc(2000, 1, 1).to_i) tzif_test(offsets, transitions) do |path, format| assert_equal([t0,t1], @reader.read(path)) end end def test_read_no_offsets offsets = [] transitions = [{at: Time.utc(2000, 12, 31), offset_index: 0}] tzif_test(offsets, transitions) do |path, format| error = assert_raises(InvalidZoneinfoFile) { @reader.read(path) } assert_equal("Invalid offset referenced by transition in file '#{path}'.", error.message) end end def test_read_invalid_offset_index offsets = [{gmtoff: -0, isdst: false, abbrev: 'LMT'}] transitions = [{at: Time.utc(2000, 12, 31), offset_index: 2}] tzif_test(offsets, transitions) do |path, format| error = assert_raises(InvalidZoneinfoFile) { @reader.read(path) } assert_equal("Invalid offset referenced by transition in file '#{path}'.", error.message) end end def test_read_with_leap_seconds offsets = [{gmtoff: -0, isdst: false, abbrev: 'LMT'}] leaps = [{at: Time.utc(1972,6,30,23,59,60), seconds: 1}] tzif_test(offsets, [], leaps: leaps) do |path, format| error = assert_raises(InvalidZoneinfoFile) { @reader.read(path) } assert_equal("The file '#{path}' contains leap second data. TZInfo requires zoneinfo files that omit leap seconds.", error.message) end end def test_read_invalid_magic ['tzif2', '12345'].each do |magic| offsets = [{gmtoff: -12094, isdst: false, abbrev: 'LT'}] tzif_test(offsets, [], magic: magic) do |path, format| error = assert_raises(InvalidZoneinfoFile) { @reader.read(path) } assert_equal("The file '#{path}' does not start with the expected header.", error.message) end end end def test_read_invalid_version offsets = [{gmtoff: -12094, isdst: false, abbrev: 'LT'}] tzif_test(offsets, [], magic: 'TZif4') do |path, format| error = assert_raises(InvalidZoneinfoFile) { @reader.read(path) } assert_equal("The file '#{path}' contains a version of the zoneinfo format that is not currently supported.", error.message) end end def test_read_invalid_section2_magic ['TZif4', 'tzif2', '12345'].each do |section2_magic| offsets = [{gmtoff: -12094, isdst: false, abbrev: 'LT'}] tzif_test(offsets, [], min_format: 2, section2_magic: section2_magic) do |path, format| error = assert_raises(InvalidZoneinfoFile) { @reader.read(path) } assert_equal("The file '#{path}' contains an invalid 64-bit section header.", error.message) end end end def test_read_mismatched_section2_magic minus_one = Proc.new {|f| f == 2 ? "TZif\0" : "TZif#{f - 1}" } plus_one = Proc.new {|f| "TZif#{f + 1}" } [minus_one, plus_one].each do |section2_magic| offsets = [{gmtoff: -12094, isdst: false, abbrev: 'LT'}] tzif_test(offsets, [], min_format: 2, section2_magic: section2_magic) do |path, format| error = assert_raises(InvalidZoneinfoFile) { @reader.read(path) } assert_equal("The file '#{path}' contains an invalid 64-bit section header.", error.message) end end end def test_read_invalid_format Tempfile.open('tzinfo-test-zone') do |file| file.write('Invalid') file.flush error = assert_raises(InvalidZoneinfoFile) { @reader.read(file.path) } assert_match(/Expected \d+ bytes reading/, error.message) end end def test_read_missing_abbrev_null_termination offsets = [ {gmtoff: 3542, isdst: false, abbrev: 'LMT'}, {gmtoff: 3600, isdst: false, abbrev: 'XST'}] transitions = [ {at: Time.utc(2000, 1, 1), offset_index: 1}] tzif_test(offsets, transitions, abbrev_separator: '^') do |path, format| error = assert_raises(InvalidZoneinfoFile) { @reader.read(path) } assert_equal("Missing abbreviation null terminator in file '#{path}'.", error.message) end end def test_read_out_of_range_abbrev_offsets offsets = [ {gmtoff: 3542, isdst: false, abbrev: 'LMT'}, {gmtoff: 3600, isdst: false, abbrev: 'XST'}] transitions = [ {at: Time.utc(2000, 1, 1), offset_index: 1}] tzif_test(offsets, transitions, abbrev_offset_base: 8) do |path, format| error = assert_raises(InvalidZoneinfoFile) { @reader.read(path) } assert_equal("Abbreviation index is out of range in file '#{path}'.", error.message) end end def test_read_subsequent_transition_same offsets = [ {gmtoff: 3542, isdst: false, abbrev: 'LMT'}, {gmtoff: 3600, isdst: false, abbrev: 'XST'}, {gmtoff: 7200, isdst: true, abbrev: 'XDT'}] transitions = [ {at: Time.utc(2000, 1, 1, 12, 0, 0), offset_index: 1}, {at: Time.utc(2000, 1, 1, 12, 0, 0), offset_index: 2}] tzif_test(offsets, transitions) do |path, format| error = assert_raises(InvalidZoneinfoFile) { @reader.read(path) } assert_equal("Transition at #{Time.utc(2000, 1, 1, 12, 0, 0).to_i} is not later than the previous transition at #{Time.utc(2000, 1, 1, 12, 0, 0).to_i} in file '#{path}'.", error.message) end end def test_read_subsequent_transition_less offsets = [ {gmtoff: 3542, isdst: false, abbrev: 'LMT'}, {gmtoff: 3600, isdst: false, abbrev: 'XST'}, {gmtoff: 7200, isdst: true, abbrev: 'XDT'}] transitions = [ {at: Time.utc(2000, 1, 1, 12, 0, 0), offset_index: 1}, {at: Time.utc(2000, 1, 1, 11, 59, 59), offset_index: 2}] tzif_test(offsets, transitions) do |path, format| error = assert_raises(InvalidZoneinfoFile) { @reader.read(path) } assert_equal("Transition at #{Time.utc(2000, 1, 1, 11, 59, 59).to_i} is not later than the previous transition at #{Time.utc(2000, 1, 1, 12, 0, 0).to_i} in file '#{path}'.", error.message) end end def test_read_before_epoch offsets = [ {gmtoff: 3542, isdst: false, abbrev: 'LMT'}, {gmtoff: 3600, isdst: false, abbrev: 'XST'}, {gmtoff: 7200, isdst: true, abbrev: 'XDT'}, {gmtoff: 0, isdst: false, abbrev: 'XNST'}] transitions = [ {at: Time.utc(1948, 1, 2), offset_index: 1}, {at: Time.utc(1969, 4, 22), offset_index: 2}, {at: Time.utc(1970, 10, 21), offset_index: 1}, {at: Time.utc(2000, 12, 31), offset_index: 3}] o0 = TimezoneOffset.new(3542, 0, 'LMT') o1 = TimezoneOffset.new(3600, 0, 'XST') o2 = TimezoneOffset.new(3600, 3600, 'XDT') o3 = TimezoneOffset.new( 0, 0, 'XNST') t0 = TimezoneTransition.new(o1, o0, Time.utc(1948, 1, 2).to_i) t1 = TimezoneTransition.new(o2, o1, Time.utc(1969, 4, 22).to_i) t2 = TimezoneTransition.new(o1, o2, Time.utc(1970, 10, 21).to_i) t3 = TimezoneTransition.new(o3, o1, Time.utc(2000, 12, 31).to_i) tzif_test(offsets, transitions) do |path, format| assert_equal([t0,t1,t2,t3], @reader.read(path)) end end def test_read_on_epoch offsets = [ {gmtoff: 3542, isdst: false, abbrev: 'LMT'}, {gmtoff: 3600, isdst: false, abbrev: 'XST'}, {gmtoff: 7200, isdst: true, abbrev: 'XDT'}, {gmtoff: 0, isdst: false, abbrev: 'XNST'}] transitions = [ {at: Time.utc(1948, 1, 2), offset_index: 1}, {at: Time.utc(1969, 4, 22), offset_index: 2}, {at: Time.utc(1970, 1, 1), offset_index: 1}, {at: Time.utc(2000, 12, 31), offset_index: 3}] o0 = TimezoneOffset.new(3542, 0, 'LMT') o1 = TimezoneOffset.new(3600, 0, 'XST') o2 = TimezoneOffset.new(3600, 3600, 'XDT') o3 = TimezoneOffset.new( 0, 0, 'XNST') t0 = TimezoneTransition.new(o1, o0, Time.utc(1948, 1, 2).to_i) t1 = TimezoneTransition.new(o2, o1, Time.utc(1969, 4, 22).to_i) t2 = TimezoneTransition.new(o1, o2, Time.utc(1970, 1, 1).to_i) t3 = TimezoneTransition.new(o3, o1, Time.utc(2000, 12, 31).to_i) tzif_test(offsets, transitions) do |path, format| assert_equal([t0,t1,t2,t3], @reader.read(path)) end end def test_read_64bit # TZif format 2 and later contains both 32-bit and 64-bit times. Where a # TZif 2 or later file is provided, the 64-bit times should be used. offsets = [ {gmtoff: 3542, isdst: false, abbrev: 'LMT'}, {gmtoff: 3600, isdst: false, abbrev: 'XST'}, {gmtoff: 7200, isdst: true, abbrev: 'XDT'}, {gmtoff: 0, isdst: false, abbrev: 'XNST'}] transitions = [ {at: Time.utc(1850, 1, 2), offset_index: 1}, {at: Time.utc(2003, 4, 22), offset_index: 2}, {at: Time.utc(2003, 10, 21), offset_index: 1}, {at: Time.utc(2040, 12, 31), offset_index: 3}] o0 = TimezoneOffset.new(3542, 0, 'LMT') o1 = TimezoneOffset.new(3600, 0, 'XST') o2 = TimezoneOffset.new(3600, 3600, 'XDT') o3 = TimezoneOffset.new( 0, 0, 'XNST') t0 = TimezoneTransition.new(o1, o0, Time.utc(1850, 1, 2).to_i) t1_f1 = TimezoneTransition.new(o2, o0, Time.utc(2003, 4, 22).to_i) t1_f2 = TimezoneTransition.new(o2, o1, Time.utc(2003, 4, 22).to_i) t2 = TimezoneTransition.new(o1, o2, Time.utc(2003, 10, 21).to_i) t3 = TimezoneTransition.new(o3, o1, Time.utc(2040, 12, 31).to_i) tzif_test(offsets, transitions) do |path, format| transitions = @reader.read(path) if format >= 2 assert_equal([t0,t1_f2,t2,t3], transitions) else assert_equal([t1_f1,t2], transitions) end end end def test_read_64bit_range offsets = [ {gmtoff: 3542, isdst: false, abbrev: 'LMT'}, {gmtoff: 3600, isdst: false, abbrev: 'XST'}, {gmtoff: 7200, isdst: false, abbrev: 'XNST'}] transitions = [ {at: -2**63, offset_index: 1}, {at: Time.utc(2014, 5, 27), offset_index: 2}, {at: 2**63 - 1, offset_index: 0}] o0 = TimezoneOffset.new(3542, 0, 'LMT') o1 = TimezoneOffset.new(3600, 0, 'XST') o2 = TimezoneOffset.new(7200, 0, 'XNST') t0 = TimezoneTransition.new(o1, o0, -2**63) t1_f1 = TimezoneTransition.new(o2, o0, Time.utc(2014, 5, 27).to_i) t1_f2 = TimezoneTransition.new(o2, o1, Time.utc(2014, 5, 27).to_i) t2 = TimezoneTransition.new(o0, o2, 2**63 - 1) tzif_test(offsets, transitions) do |path, format| transitions = @reader.read(path) if format >= 2 assert_equal([t0, t1_f2, t2], transitions) else assert_equal([t1_f1], transitions) end end end def test_read_32bit_range offsets = [ {gmtoff: 3542, isdst: false, abbrev: 'LMT'}, {gmtoff: 3600, isdst: false, abbrev: 'XST'}, {gmtoff: 7200, isdst: false, abbrev: 'XNST'}] transitions = [ {at: -2**31, offset_index: 1}, {at: Time.utc(2014, 5, 27), offset_index: 2}, {at: 2**31 - 1, offset_index: 0}] o0 = TimezoneOffset.new(3542, 0, 'LMT') o1 = TimezoneOffset.new(3600, 0, 'XST') o2 = TimezoneOffset.new(7200, 0, 'XNST') t0 = TimezoneTransition.new(o1, o0, -2**31) t1 = TimezoneTransition.new(o2, o1, Time.utc(2014, 5, 27).to_i) t2 = TimezoneTransition.new(o0, o2, 2**31 - 1) tzif_test(offsets, transitions) do |path, format| assert_equal([t0,t1,t2], @reader.read(path)) end end def test_read_std_offset_changes # The zoneinfo files don't include the offset from standard time, so this # has to be derived by looking at changes in the total UTC offset. offsets = [ {gmtoff: 3542, isdst: false, abbrev: 'LMT'}, {gmtoff: 3600, isdst: false, abbrev: 'XST'}, {gmtoff: 7200, isdst: true, abbrev: 'XDT'}, {gmtoff: 10800, isdst: true, abbrev: 'XDDT'}] transitions = [ {at: Time.utc(2000, 1, 1), offset_index: 1}, {at: Time.utc(2000, 2, 1), offset_index: 2}, {at: Time.utc(2000, 3, 1), offset_index: 3}, {at: Time.utc(2000, 4, 1), offset_index: 1}] o0 = TimezoneOffset.new(3542, 0, 'LMT') o1 = TimezoneOffset.new(3600, 0, 'XST') o2 = TimezoneOffset.new(3600, 3600, 'XDT') o3 = TimezoneOffset.new(3600, 7200, 'XDDT') t0 = TimezoneTransition.new(o1, o0, Time.utc(2000, 1, 1).to_i) t1 = TimezoneTransition.new(o2, o1, Time.utc(2000, 2, 1).to_i) t2 = TimezoneTransition.new(o3, o2, Time.utc(2000, 3, 1).to_i) t3 = TimezoneTransition.new(o1, o3, Time.utc(2000, 4, 1).to_i) tzif_test(offsets, transitions) do |path, format| assert_equal([t0,t1,t2,t3], @reader.read(path)) end end def test_read_std_offset_changes_jump_to_double_dst # The zoneinfo files don't include the offset from standard time, so this # has to be derived by looking at changes in the total UTC offset. offsets = [ {gmtoff: 3542, isdst: false, abbrev: 'LMT'}, {gmtoff: 3600, isdst: false, abbrev: 'XST'}, {gmtoff: 10800, isdst: true, abbrev: 'XDDT'}] transitions = [ {at: Time.utc(2000, 4, 1), offset_index: 1}, {at: Time.utc(2000, 5, 1), offset_index: 2}, {at: Time.utc(2000, 6, 1), offset_index: 1}] o0 = TimezoneOffset.new(3542, 0, 'LMT') o1 = TimezoneOffset.new(3600, 0, 'XST') o2 = TimezoneOffset.new(3600, 7200, 'XDDT') t0 = TimezoneTransition.new(o1, o0, Time.utc(2000, 4, 1).to_i) t1 = TimezoneTransition.new(o2, o1, Time.utc(2000, 5, 1).to_i) t2 = TimezoneTransition.new(o1, o2, Time.utc(2000, 6, 1).to_i) tzif_test(offsets, transitions) do |path, format| assert_equal([t0,t1,t2], @reader.read(path)) end end def test_read_std_offset_changes_negative # The zoneinfo files don't include the offset from standard time, so this # has to be derived by looking at changes in the total UTC offset. offsets = [ {gmtoff: -10821, isdst: false, abbrev: 'LMT'}, {gmtoff: -10800, isdst: false, abbrev: 'XST'}, {gmtoff: -7200, isdst: true, abbrev: 'XDT'}, {gmtoff: -3600, isdst: true, abbrev: 'XDDT'}] transitions = [ {at: Time.utc(2000, 1, 1), offset_index: 1}, {at: Time.utc(2000, 2, 1), offset_index: 2}, {at: Time.utc(2000, 3, 1), offset_index: 3}, {at: Time.utc(2000, 4, 1), offset_index: 1}, {at: Time.utc(2000, 5, 1), offset_index: 3}, {at: Time.utc(2000, 6, 1), offset_index: 1}] o0 = TimezoneOffset.new(-10821, 0, 'LMT') o1 = TimezoneOffset.new(-10800, 0, 'XST') o2 = TimezoneOffset.new(-10800, 3600, 'XDT') o3 = TimezoneOffset.new(-10800, 7200, 'XDDT') t0 = TimezoneTransition.new(o1, o0, Time.utc(2000, 1, 1).to_i) t1 = TimezoneTransition.new(o2, o1, Time.utc(2000, 2, 1).to_i) t2 = TimezoneTransition.new(o3, o2, Time.utc(2000, 3, 1).to_i) t3 = TimezoneTransition.new(o1, o3, Time.utc(2000, 4, 1).to_i) t4 = TimezoneTransition.new(o3, o1, Time.utc(2000, 5, 1).to_i) t5 = TimezoneTransition.new(o1, o3, Time.utc(2000, 6, 1).to_i) tzif_test(offsets, transitions) do |path, format| assert_equal([t0,t1,t2,t3,t4,t5], @reader.read(path)) end end def test_read_starts_two_hour_std_offset # The zoneinfo files don't include the offset from standard time, so this # has to be derived by looking at changes in the total UTC offset. offsets = [ {gmtoff: 3542, isdst: false, abbrev: 'LMT'}, {gmtoff: 3600, isdst: false, abbrev: 'XST'}, {gmtoff: 7200, isdst: true, abbrev: 'XDT'}, {gmtoff: 10800, isdst: true, abbrev: 'XDDT'}] transitions = [ {at: Time.utc(2000, 1, 1), offset_index: 3}, {at: Time.utc(2000, 2, 1), offset_index: 2}, {at: Time.utc(2000, 3, 1), offset_index: 1}] o0 = TimezoneOffset.new(3542, 0, 'LMT') o1 = TimezoneOffset.new(3600, 0, 'XST') o2 = TimezoneOffset.new(3600, 3600, 'XDT') o3 = TimezoneOffset.new(3600, 7200, 'XDDT') t0 = TimezoneTransition.new(o3, o0, Time.utc(2000, 1, 1).to_i) t1 = TimezoneTransition.new(o2, o3, Time.utc(2000, 2, 1).to_i) t2 = TimezoneTransition.new(o1, o2, Time.utc(2000, 3, 1).to_i) tzif_test(offsets, transitions) do |path, format| assert_equal([t0,t1,t2], @reader.read(path)) end end def test_read_starts_only_dst_transition_with_lmt # The zoneinfo files don't include the offset from standard time, so this # has to be derived by looking at changes in the total UTC offset. offsets = [ {gmtoff: 3542, isdst: false, abbrev: 'LMT'}, {gmtoff: 7200, isdst: true, abbrev: 'XDT'}] transitions = [{at: Time.utc(2000, 1, 1), offset_index: 1}] o0 = TimezoneOffset.new(3542, 0, 'LMT') o1 = TimezoneOffset.new(3542, 3658, 'XDT') t0 = TimezoneTransition.new(o1, o0, Time.utc(2000, 1, 1).to_i) tzif_test(offsets, transitions) do |path, format| assert_equal([t0], @reader.read(path)) end end def test_read_starts_only_dst_transition_without_lmt # The zoneinfo files don't include the offset from standard time, so this # has to be derived by looking at changes in the total UTC offset. offsets = [{gmtoff: 7200, isdst: true, abbrev: 'XDT'}] transitions = [{at: Time.utc(2000, 1, 1), offset_index: 0}] o0 = TimezoneOffset.new(3600, 3600, 'XDT') t0 = TimezoneTransition.new(o0, o0, Time.utc(2000, 1, 1).to_i) tzif_test(offsets, transitions) do |path, format| assert_equal([t0], @reader.read(path)) end end def test_read_switch_to_dst_and_change_utc_offset # The zoneinfo files don't include the offset from standard time, so this # has to be derived by looking at changes in the total UTC offset. # Switch from non-DST to DST at the same time as moving the UTC offset # back an hour (i.e. wall clock time doesn't change). offsets = [ {gmtoff: 3542, isdst: false, abbrev: 'LMT'}, {gmtoff: 3600, isdst: false, abbrev: 'YST'}, {gmtoff: 3600, isdst: true, abbrev: 'XDT'}] transitions = [ {at: Time.utc(2000, 1, 1), offset_index: 1}, {at: Time.utc(2000, 2, 1), offset_index: 2}] o0 = TimezoneOffset.new(3542, 0, 'LMT') o1 = TimezoneOffset.new(3600, 0, 'YST') o2 = TimezoneOffset.new( 0, 3600, 'XDT') t0 = TimezoneTransition.new(o1, o0, Time.utc(2000, 1, 1).to_i) t1 = TimezoneTransition.new(o2, o1, Time.utc(2000, 2, 1).to_i) tzif_test(offsets, transitions) do |path, format| assert_equal([t0,t1], @reader.read(path)) end end def test_read_apia_international_dateline_change # The zoneinfo files don't include the offset from standard time, so this # has to be derived by looking at changes in the total UTC offset. # Pacific/Apia moved across the International Date Line whilst observing # daylight savings time. offsets = [ {gmtoff: 45184, isdst: false, abbrev: 'LMT'}, {gmtoff: -39600, isdst: false, abbrev: '-11'}, {gmtoff: -36000, isdst: true, abbrev: '-10'}, {gmtoff: 50400, isdst: true, abbrev: '+14'}, {gmtoff: 46800, isdst: false, abbrev: '+13'}] transitions = [ {at: Time.utc(2011, 4, 2, 14, 0, 0), offset_index: 1}, {at: Time.utc(2011, 9, 24, 14, 0, 0), offset_index: 2}, {at: Time.utc(2011, 12, 30, 10, 0, 0), offset_index: 3}, {at: Time.utc(2012, 3, 31, 14, 0, 0), offset_index: 4}] o0 = TimezoneOffset.new( 45184, 0, 'LMT') o1 = TimezoneOffset.new(-39600, 0, '-11') o2 = TimezoneOffset.new(-39600, 3600, '-10') o3 = TimezoneOffset.new( 46800, 3600, '+14') o4 = TimezoneOffset.new( 46800, 0, '+13') t0 = TimezoneTransition.new(o1, o0, Time.utc(2011, 4, 2, 14, 0, 0).to_i) t1 = TimezoneTransition.new(o2, o1, Time.utc(2011, 9, 24, 14, 0, 0).to_i) t2 = TimezoneTransition.new(o3, o2, Time.utc(2011, 12, 30, 10, 0, 0).to_i) t3 = TimezoneTransition.new(o4, o3, Time.utc(2012, 3, 31, 14, 0, 0).to_i) tzif_test(offsets, transitions) do |path, format| assert_equal([t0,t1,t2,t3], @reader.read(path)) end end def test_read_offset_split_for_different_utc_offset # The zoneinfo files don't include the offset from standard time, so this # has to be derived by looking at changes in the total UTC offset. offsets = [ {gmtoff: 3542, isdst: false, abbrev: 'LMT'}, {gmtoff: 3600, isdst: false, abbrev: 'XST1'}, {gmtoff: 7200, isdst: false, abbrev: 'XST2'}, {gmtoff: 10800, isdst: true, abbrev: 'XDT'}] transitions = [ {at: Time.utc(2000, 1, 1), offset_index: 1}, {at: Time.utc(2000, 2, 1), offset_index: 3}, {at: Time.utc(2000, 3, 1), offset_index: 1}, {at: Time.utc(2000, 4, 1), offset_index: 2}, {at: Time.utc(2000, 5, 1), offset_index: 3}, {at: Time.utc(2000, 6, 1), offset_index: 2}, {at: Time.utc(2000, 7, 1), offset_index: 1}, {at: Time.utc(2000, 8, 1), offset_index: 3}, {at: Time.utc(2000, 9, 1), offset_index: 1}, {at: Time.utc(2000, 10, 1), offset_index: 2}, {at: Time.utc(2000, 11, 1), offset_index: 3}, {at: Time.utc(2000, 12, 1), offset_index: 2}] # XDT will be split and defined according to its surrounding standard time # offsets. o0 = TimezoneOffset.new(3542, 0, 'LMT') o1 = TimezoneOffset.new(3600, 0, 'XST1') o2 = TimezoneOffset.new(7200, 0, 'XST2') o3_1 = TimezoneOffset.new(3600, 7200, 'XDT') o3_2 = TimezoneOffset.new(7200, 3600, 'XDT') t0 = TimezoneTransition.new(o1, o0, Time.utc(2000, 1, 1).to_i) t1 = TimezoneTransition.new(o3_1, o1, Time.utc(2000, 2, 1).to_i) t2 = TimezoneTransition.new(o1, o3_1, Time.utc(2000, 3, 1).to_i) t3 = TimezoneTransition.new(o2, o1, Time.utc(2000, 4, 1).to_i) t4 = TimezoneTransition.new(o3_2, o2, Time.utc(2000, 5, 1).to_i) t5 = TimezoneTransition.new(o2, o3_2, Time.utc(2000, 6, 1).to_i) t6 = TimezoneTransition.new(o1, o2, Time.utc(2000, 7, 1).to_i) t7 = TimezoneTransition.new(o3_1, o1, Time.utc(2000, 8, 1).to_i) t8 = TimezoneTransition.new(o1, o3_1, Time.utc(2000, 9, 1).to_i) t9 = TimezoneTransition.new(o2, o1, Time.utc(2000, 10, 1).to_i) t10 = TimezoneTransition.new(o3_2, o2, Time.utc(2000, 11, 1).to_i) t11 = TimezoneTransition.new(o2, o3_2, Time.utc(2000, 12, 1).to_i) tzif_test(offsets, transitions) do |path, format| transitions = @reader.read(path) assert_equal([t0,t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11], transitions) 0.upto(5) do |i| assert_same(transitions[i].offset, transitions[i + 6].offset, "Offsets for transitions #{i} and #{i + 6} are not the same") end end end def test_read_offset_utc_offset_taken_from_minimum_difference_minimum_after # The zoneinfo files don't include the offset from standard time, so this # has to be derived by looking at changes in the total UTC offset. offsets = [ {gmtoff: 3542, isdst: false, abbrev: 'LMT'}, {gmtoff: 3600, isdst: false, abbrev: 'XST1'}, {gmtoff: 7200, isdst: false, abbrev: 'XST2'}, {gmtoff: 10800, isdst: true, abbrev: 'XDT'}] transitions = [ {at: Time.utc(2000, 1, 1), offset_index: 1}, {at: Time.utc(2000, 2, 1), offset_index: 3}, {at: Time.utc(2000, 3, 1), offset_index: 2}] # XDT should use the closest utc_offset (7200) (and not an equivalent # utc_offset of 3600 and std_offset of 7200). o0 = TimezoneOffset.new(3542, 0, 'LMT') o1 = TimezoneOffset.new(3600, 0, 'XST1') o2 = TimezoneOffset.new(7200, 0, 'XST2') o3 = TimezoneOffset.new(7200, 3600, 'XDT') t0 = TimezoneTransition.new(o1, o0, Time.utc(2000, 1, 1).to_i) t1 = TimezoneTransition.new(o3, o1, Time.utc(2000, 2, 1).to_i) t2 = TimezoneTransition.new(o2, o3, Time.utc(2000, 3, 1).to_i) tzif_test(offsets, transitions) do |path, format| assert_equal([t0,t1,t2], @reader.read(path)) end end def test_read_offset_utc_offset_taken_from_minimum_difference_minimum_before # The zoneinfo files don't include the offset from standard time, so this # has to be derived by looking at changes in the total UTC offset. offsets = [ {gmtoff: 3542, isdst: false, abbrev: 'LMT'}, {gmtoff: 3600, isdst: false, abbrev: 'XST1'}, {gmtoff: 7200, isdst: false, abbrev: 'XST2'}, {gmtoff: 10800, isdst: true, abbrev: 'XDT'}] transitions = [ {at: Time.utc(2000, 1, 1), offset_index: 2}, {at: Time.utc(2000, 2, 1), offset_index: 3}, {at: Time.utc(2000, 3, 1), offset_index: 1}] # XDT should use the closest utc_offset (7200) (and not an equivalent # utc_offset of 3600 and std_offset of 7200). o0 = TimezoneOffset.new(3542, 0, 'LMT') o1 = TimezoneOffset.new(3600, 0, 'XST1') o2 = TimezoneOffset.new(7200, 0, 'XST2') o3 = TimezoneOffset.new(7200, 3600, 'XDT') t0 = TimezoneTransition.new(o2, o0, Time.utc(2000, 1, 1).to_i) t1 = TimezoneTransition.new(o3, o2, Time.utc(2000, 2, 1).to_i) t2 = TimezoneTransition.new(o1, o3, Time.utc(2000, 3, 1).to_i) tzif_test(offsets, transitions) do |path, format| assert_equal([t0,t1,t2], @reader.read(path)) end end def test_read_offset_does_not_use_equal_observed_utc_offset_equal_after # The zoneinfo files don't include the offset from standard time, so this # has to be derived by looking at changes in the total UTC offset. offsets = [ {gmtoff: 3542, isdst: false, abbrev: 'LMT'}, {gmtoff: 3600, isdst: false, abbrev: 'XST1'}, {gmtoff: 7200, isdst: false, abbrev: 'XST2'}, {gmtoff: 7200, isdst: true, abbrev: 'XDT'}] transitions = [ {at: Time.utc(2000, 1, 1), offset_index: 1}, {at: Time.utc(2000, 2, 1), offset_index: 3}, {at: Time.utc(2000, 3, 1), offset_index: 2}] # XDT will be based on the utc_offset of XST1 even though XST2 has an # equivalent (or greater) observed_utc_offset. o0 = TimezoneOffset.new(3542, 0, 'LMT') o1 = TimezoneOffset.new(3600, 0, 'XST1') o2 = TimezoneOffset.new(7200, 0, 'XST2') o3 = TimezoneOffset.new(3600, 3600, 'XDT') t0 = TimezoneTransition.new(o1, o0, Time.utc(2000, 1, 1).to_i) t1 = TimezoneTransition.new(o3, o1, Time.utc(2000, 2, 1).to_i) t2 = TimezoneTransition.new(o2, o3, Time.utc(2000, 3, 1).to_i) tzif_test(offsets, transitions) do |path, format| assert_equal([t0,t1,t2], @reader.read(path)) end end def test_read_offset_does_not_use_equal_observed_utc_offset_equal_before # The zoneinfo files don't include the offset from standard time, so this # has to be derived by looking at changes in the total UTC offset. offsets = [ {gmtoff: 3542, isdst: false, abbrev: 'LMT'}, {gmtoff: 3600, isdst: false, abbrev: 'XST1'}, {gmtoff: 7200, isdst: false, abbrev: 'XST2'}, {gmtoff: 7200, isdst: true, abbrev: 'XDT'}] transitions = [ {at: Time.utc(2000, 1, 1), offset_index: 2}, {at: Time.utc(2000, 2, 1), offset_index: 3}, {at: Time.utc(2000, 3, 1), offset_index: 1}] # XDT will be based on the utc_offset of XST1 even though XST2 has an # equivalent (or greater) observed_utc_offset. o0 = TimezoneOffset.new(3542, 0, 'LMT') o1 = TimezoneOffset.new(3600, 0, 'XST1') o2 = TimezoneOffset.new(7200, 0, 'XST2') o3 = TimezoneOffset.new(3600, 3600, 'XDT') t0 = TimezoneTransition.new(o2, o0, Time.utc(2000, 1, 1).to_i) t1 = TimezoneTransition.new(o3, o2, Time.utc(2000, 2, 1).to_i) t2 = TimezoneTransition.new(o1, o3, Time.utc(2000, 3, 1).to_i) tzif_test(offsets, transitions) do |path, format| assert_equal([t0,t1,t2], @reader.read(path)) end end def test_read_offset_both_adjacent_non_dst_equal_observed_utc_offset # The zoneinfo files don't include the offset from standard time, so this # has to be derived by looking at changes in the total UTC offset. offsets = [ {gmtoff: 7142, isdst: false, abbrev: 'LMT'}, {gmtoff: 7200, isdst: false, abbrev: 'XST'}, {gmtoff: 7200, isdst: true, abbrev: 'XDT'}] transitions = [ {at: Time.utc(2000, 1, 1), offset_index: 1}, {at: Time.utc(2000, 2, 1), offset_index: 2}, {at: Time.utc(2000, 3, 1), offset_index: 1}] # XDT will just assume an std_offset of +1 hour and calculate the utc_offset # from observed_utc_offset - std_offset. o0 = TimezoneOffset.new(7142, 0, 'LMT') o1 = TimezoneOffset.new(7200, 0, 'XST') o2 = TimezoneOffset.new(3600, 3600, 'XDT') t0 = TimezoneTransition.new(o1, o0, Time.utc(2000, 1, 1).to_i) t1 = TimezoneTransition.new(o2, o1, Time.utc(2000, 2, 1).to_i) t2 = TimezoneTransition.new(o1, o2, Time.utc(2000, 3, 1).to_i) tzif_test(offsets, transitions) do |path, format| assert_equal([t0,t1,t2], @reader.read(path)) end end def test_read_offset_utc_offset_preserved_from_next # The zoneinfo files don't include the offset from standard time, so this # has to be derived by looking at changes in the total UTC offset. offsets = [ {gmtoff: 3542, isdst: false, abbrev: 'LMT'}, {gmtoff: 3600, isdst: false, abbrev: 'XST1'}, {gmtoff: 7200, isdst: false, abbrev: 'XST2'}, {gmtoff: 10800, isdst: true, abbrev: 'XDT1'}, {gmtoff: 10800, isdst: true, abbrev: 'XDT2'}] transitions = [ {at: Time.utc(2000, 1, 1), offset_index: 1}, {at: Time.utc(2000, 2, 1), offset_index: 3}, {at: Time.utc(2000, 3, 1), offset_index: 4}, {at: Time.utc(2000, 4, 1), offset_index: 2}] # Both XDT1 and XDT2 should both use the closest utc_offset (7200) (and not # an equivalent utc_offset of 3600 and std_offset of 7200). o0 = TimezoneOffset.new(3542, 0, 'LMT') o1 = TimezoneOffset.new(3600, 0, 'XST1') o2 = TimezoneOffset.new(7200, 0, 'XST2') o3 = TimezoneOffset.new(7200, 3600, 'XDT1') o4 = TimezoneOffset.new(7200, 3600, 'XDT2') t0 = TimezoneTransition.new(o1, o0, Time.utc(2000, 1, 1).to_i) t1 = TimezoneTransition.new(o3, o1, Time.utc(2000, 2, 1).to_i) t2 = TimezoneTransition.new(o4, o3, Time.utc(2000, 3, 1).to_i) t3 = TimezoneTransition.new(o2, o4, Time.utc(2000, 4, 1).to_i) tzif_test(offsets, transitions) do |path, format| assert_equal([t0,t1,t2,t3], @reader.read(path)) end end def test_read_offset_utc_offset_preserved_from_previous # The zoneinfo files don't include the offset from standard time, so this # has to be derived by looking at changes in the total UTC offset. offsets = [ {gmtoff: 3542, isdst: false, abbrev: 'LMT'}, {gmtoff: 3600, isdst: false, abbrev: 'XST1'}, {gmtoff: 7200, isdst: false, abbrev: 'XST2'}, {gmtoff: 10800, isdst: true, abbrev: 'XDT1'}, {gmtoff: 10800, isdst: true, abbrev: 'XDT2'}] transitions = [ {at: Time.utc(2000, 1, 1), offset_index: 2}, {at: Time.utc(2000, 2, 1), offset_index: 3}, {at: Time.utc(2000, 3, 1), offset_index: 4}, {at: Time.utc(2000, 4, 1), offset_index: 1}] # Both XDT1 and XDT2 should both use the closest utc_offset (7200) (and not # an equivalent utc_offset of 3600 and std_offset of 7200). o0 = TimezoneOffset.new(3542, 0, 'LMT') o1 = TimezoneOffset.new(3600, 0, 'XST1') o2 = TimezoneOffset.new(7200, 0, 'XST2') o3 = TimezoneOffset.new(7200, 3600, 'XDT1') o4 = TimezoneOffset.new(7200, 3600, 'XDT2') t0 = TimezoneTransition.new(o2, o0, Time.utc(2000, 1, 1).to_i) t1 = TimezoneTransition.new(o3, o2, Time.utc(2000, 2, 1).to_i) t2 = TimezoneTransition.new(o4, o3, Time.utc(2000, 3, 1).to_i) t3 = TimezoneTransition.new(o1, o4, Time.utc(2000, 4, 1).to_i) tzif_test(offsets, transitions) do |path, format| assert_equal([t0,t1,t2,t3], @reader.read(path)) end end def test_read_offset_negative_std_offset_dst # The zoneinfo files don't include the offset from standard time, so this # has to be derived by looking at changes in the total UTC offset. offsets = [ {gmtoff: -100, isdst: false, abbrev: 'LMT'}, {gmtoff: 3600, isdst: false, abbrev: 'XST'}, {gmtoff: 0, isdst: true, abbrev: 'XWT'}] transitions = [ {at: Time.utc(2000, 1, 1), offset_index: 1}, {at: Time.utc(2000, 2, 1), offset_index: 2}, {at: Time.utc(2000, 3, 1), offset_index: 1}, {at: Time.utc(2000, 4, 1), offset_index: 2}, {at: Time.utc(2000, 5, 1), offset_index: 1}] o0 = TimezoneOffset.new(-100, 0, 'LMT') o1 = TimezoneOffset.new(3600, 0, 'XST') o2 = TimezoneOffset.new(3600, -3600, 'XWT') t0 = TimezoneTransition.new(o1, o0, Time.utc(2000, 1, 1).to_i) t1 = TimezoneTransition.new(o2, o1, Time.utc(2000, 2, 1).to_i) t2 = TimezoneTransition.new(o1, o2, Time.utc(2000, 3, 1).to_i) t3 = TimezoneTransition.new(o2, o1, Time.utc(2000, 4, 1).to_i) t4 = TimezoneTransition.new(o1, o2, Time.utc(2000, 5, 1).to_i) tzif_test(offsets, transitions) do |path, format| assert_equal([t0,t1,t2,t3,t4], @reader.read(path)) end end def test_read_offset_negative_std_offset_dst_initial_dst # The zoneinfo files don't include the offset from standard time, so this # has to be derived by looking at changes in the total UTC offset. offsets = [ {gmtoff: -100, isdst: false, abbrev: 'LMT'}, {gmtoff: 0, isdst: true, abbrev: 'XWT'}, {gmtoff: 3600, isdst: false, abbrev: 'XST'}] transitions = [ {at: Time.utc(2000, 1, 1), offset_index: 1}, {at: Time.utc(2000, 2, 1), offset_index: 2}, {at: Time.utc(2000, 3, 1), offset_index: 1}, {at: Time.utc(2000, 4, 1), offset_index: 2}, {at: Time.utc(2000, 5, 1), offset_index: 1}] o0 = TimezoneOffset.new(-100, 0, 'LMT') o1 = TimezoneOffset.new(3600, -3600, 'XWT') o2 = TimezoneOffset.new(3600, 0, 'XST') t0 = TimezoneTransition.new(o1, o0, Time.utc(2000, 1, 1).to_i) t1 = TimezoneTransition.new(o2, o1, Time.utc(2000, 2, 1).to_i) t2 = TimezoneTransition.new(o1, o2, Time.utc(2000, 3, 1).to_i) t3 = TimezoneTransition.new(o2, o1, Time.utc(2000, 4, 1).to_i) t4 = TimezoneTransition.new(o1, o2, Time.utc(2000, 5, 1).to_i) tzif_test(offsets, transitions) do |path, format| assert_equal([t0,t1,t2,t3,t4], @reader.read(path)) end end def test_read_offset_prefer_base_offset_moves_to_dst_not_hour offsets = [ {gmtoff: -100, isdst: false, abbrev: 'LMT'}, {gmtoff: 0, isdst: false, abbrev: 'XST'}, {gmtoff: 1800, isdst: true, abbrev: 'XDT'}, {gmtoff: 1800, isdst: false, abbrev: 'XST'}] transitions = [ {at: Time.utc(2000, 1, 1), offset_index: 1}, {at: Time.utc(2000, 2, 1), offset_index: 2}, {at: Time.utc(2000, 3, 1), offset_index: 3}] o0 = TimezoneOffset.new(-100, 0, 'LMT') o1 = TimezoneOffset.new( 0, 0, 'XST') o2 = TimezoneOffset.new( 0, 1800, 'XDT') o3 = TimezoneOffset.new(1800, 0, 'XST') t0 = TimezoneTransition.new(o1, o0, Time.utc(2000, 1, 1).to_i) t1 = TimezoneTransition.new(o2, o1, Time.utc(2000, 2, 1).to_i) t2 = TimezoneTransition.new(o3, o2, Time.utc(2000, 3, 1).to_i) tzif_test(offsets, transitions) do |path, format| assert_equal([t0,t1,t2], @reader.read(path)) end end def test_read_offset_prefer_base_offset_moves_from_dst_not_hour offsets = [ {gmtoff: -100, isdst: false, abbrev: 'LMT'}, {gmtoff: 1800, isdst: false, abbrev: 'XST'}, {gmtoff: 1800, isdst: true, abbrev: 'XDT'}, {gmtoff: 0, isdst: false, abbrev: 'XST'}] transitions = [ {at: Time.utc(2000, 1, 1), offset_index: 1}, {at: Time.utc(2000, 2, 1), offset_index: 2}, {at: Time.utc(2000, 3, 1), offset_index: 3}] o0 = TimezoneOffset.new(-100, 0, 'LMT') o1 = TimezoneOffset.new(1800, 0, 'XST') o2 = TimezoneOffset.new( 0, 1800, 'XDT') o3 = TimezoneOffset.new( 0, 0, 'XST') t0 = TimezoneTransition.new(o1, o0, Time.utc(2000, 1, 1).to_i) t1 = TimezoneTransition.new(o2, o1, Time.utc(2000, 2, 1).to_i) t2 = TimezoneTransition.new(o3, o2, Time.utc(2000, 3, 1).to_i) tzif_test(offsets, transitions) do |path, format| assert_equal([t0,t1,t2], @reader.read(path)) end end def test_read_untainted_in_safe_mode offsets = [{gmtoff: -12094, isdst: false, abbrev: 'LT'}] o0 = TimezoneOffset.new(-12094, 0, 'LT') tzif_test(offsets, []) do |path, format| safe_test do # Temp file path is tainted with Ruby >= 2.3 & < 2.7. Untaint for this test. RubyCoreSupport.untaint(path) assert_equal(o0, @reader.read(path)) end end end def test_read_tainted_in_safe_mode skip_if_taint_is_undefined_or_no_op offsets = [{gmtoff: -12094, isdst: false, abbrev: 'LT'}] tzif_test(offsets, []) do |path, format| safe_test(unavailable: :skip) do # Temp file path is only tainted with Ruby >= 2.3 & < 2.7. Taint for this test. path.taint assert_raises(SecurityError) { @reader.read(path) } end end end def test_read_abbreviations_not_tainted skip_if_taint_is_undefined_or_no_op offsets = [{gmtoff: -12094, isdst: false, abbrev: 'LT'}] tzif_test(offsets, []) do |path, format| safe_test(unavailable: :skip) do # Temp file path is only tainted with Ruby >= 2.3 & < 2.7. Untaint for this test. path.untaint refute(@reader.read(path).abbreviation.tainted?) end end end def test_read_encoding # tzfile.5 doesn't specify an encoding, but the source data is in ASCII. # ZoneinfoTimezoneInfo will load as UTF-8 (a superset of ASCII). offsets = [ {gmtoff: 3542, isdst: false, abbrev: 'LMT'}, {gmtoff: 3600, isdst: false, abbrev: 'XST©'}] transitions = [ {at: Time.utc(1971, 1, 2), offset_index: 1}] o0 = TimezoneOffset.new(3542, 0, 'LMT') o1 = TimezoneOffset.new(3600, 0, 'XST©') t0 = TimezoneTransition.new(o1, o0, Time.utc(1971, 1, 2).to_i) tzif_test(offsets, transitions) do |path, format| assert_equal([t0], @reader.read(path)) end end def test_read_binmode offsets = [ {gmtoff: 3542, isdst: false, abbrev: 'LMT'}, {gmtoff: 3600, isdst: false, abbrev: 'XST'}] # Transition time that includes CRLF (4EFF0D0A). # Test that this doesn't get corrupted by translating CRLF to LF. transitions = [ {at: Time.utc(2011, 12, 31, 13, 24, 26), offset_index: 1}] o0 = TimezoneOffset.new(3542, 0, 'LMT') o1 = TimezoneOffset.new(3600, 0, 'XST') t0 = TimezoneTransition.new(o1, o0, Time.utc(2011, 12, 31, 13, 24, 26).to_i) tzif_test(offsets, transitions) do |path, format| assert_equal([t0], @reader.read(path)) end end def test_read_returns_deduped_strings offsets = [{gmtoff: 3542, isdst: false, abbrev: 'ZIDDSMT'}] tzif_test(offsets, []) do |path, format| abbreviations = 2.times.collect do @reader.read(path).abbreviation end assert_same(abbreviations[0], abbreviations[1]) end end def test_read_invalid_tz_string offsets = [{gmtoff: 0, isdst: false, abbrev: 'UTC'}] tzif_test(offsets, [], rules: :fail) do |path, format| error = assert_raises(InvalidZoneinfoFile) { @reader.read(path) } assert_equal("Failed to parse POSIX-style TZ string in file '#{path}': FakePosixTimeZoneParser Failure.", error.message) end end def test_read_tz_string_missing_start_newline offsets = [{gmtoff: 0, isdst: false, abbrev: 'UTC'}] rules = TimezoneOffset.new(0, 0, 'UTC') tzif_test(offsets, [], rules: rules, omit_tz_string_start_new_line: true) do |path, format| error = assert_raises(InvalidZoneinfoFile) { @reader.read(path) } assert_equal("Expected newline starting POSIX-style TZ string in file '#{path}'.", error.message) end end def test_read_tz_string_missing_end_newline offsets = [{gmtoff: 0, isdst: false, abbrev: 'UTC'}] rules = TimezoneOffset.new(0, 0, 'UTC') tzif_test(offsets, [], rules: rules, omit_tz_string_end_new_line: true) do |path, format| error = assert_raises(InvalidZoneinfoFile) { @reader.read(path) } assert_equal("Expected newline ending POSIX-style TZ string in file '#{path}'.", error.message) end end [ [false, 1, 0, 'TEST'], [false, 0, 1, 'TEST'], [false, 0, 0, 'TEST2'], [false, -1, 1, 'TEST'], [true, 0, 0, 'TEST'] ].each do |(isdst, base_utc_offset, std_offset, abbreviation)| define_method "test_read_tz_string_does_not_match_#{isdst ? 'dst' : 'std'}_constant_offset_#{base_utc_offset}_#{std_offset}_#{abbreviation}" do offsets = [{gmtoff: 0, isdst: isdst, abbrev: 'TEST'}] rules = TimezoneOffset.new(base_utc_offset, std_offset, abbreviation) tzif_test(offsets, [], rules: rules) do |path, format| error = assert_raises(InvalidZoneinfoFile) { @reader.read(path) } assert_equal("Constant offset POSIX-style TZ string does not match constant offset in file '#{path}'.", error.message) end end end [ [3601, 'XST'], [3600, 'YST'] ].each do |(base_utc_offset, abbreviation)| define_method "test_read_tz_string_does_not_match_final_std_transition_offset_#{base_utc_offset}_#{abbreviation}" do offsets = [ {gmtoff: 3542, isdst: false, abbrev: 'LMT'}, {gmtoff: 3600, isdst: false, abbrev: 'XST'}, {gmtoff: 7200, isdst: true, abbrev: 'XDT'} ] transitions = [ {at: Time.new(1971, 1, 2, 2, 0, 0, 3542), offset_index: 1}, {at: Time.new(1981, 4, 10, 2, 0, 0, 3600), offset_index: 2}, {at: Time.new(1981, 10, 27, 2, 0, 0, 7200), offset_index: 1} ] rules = AnnualRules.new( TimezoneOffset.new(base_utc_offset, 0, abbreviation), TimezoneOffset.new(3600, 3600, 'XDT'), JulianDayOfYearTransitionRule.new(100, 7200), JulianDayOfYearTransitionRule.new(300, 7200) ) tzif_test(offsets, transitions, rules: rules) do |path, format| error = assert_raises(InvalidZoneinfoFile) { @reader.read(path) } assert_equal("The first offset indicated by the POSIX-style TZ string did not match the final defined offset in file '#{path}'.", error.message) end end end [ [3601, 0, 'XST'], [3600, 1, 'XST'], [3600, 0, 'YST'] ].each do |(base_utc_offset, std_offset, abbreviation)| define_method "test_read_tz_string_does_not_match_final_dst_transition_offset_#{base_utc_offset}_#{std_offset}_#{abbreviation}" do offsets = [ {gmtoff: 3542, isdst: false, abbrev: 'LMT'}, {gmtoff: 3600, isdst: false, abbrev: 'XST'}, {gmtoff: 7200, isdst: true, abbrev: 'XDT'} ] transitions = [ {at: Time.new(1971, 1, 2, 2, 0, 0, 3542), offset_index: 1}, {at: Time.new(1981, 4, 10, 2, 0, 0, 3600), offset_index: 2} ] rules = AnnualRules.new( TimezoneOffset.new(3600, 0, 'XST'), TimezoneOffset.new(base_utc_offset, std_offset, abbreviation), JulianDayOfYearTransitionRule.new(100, 7200), JulianDayOfYearTransitionRule.new(300, 7200) ) tzif_test(offsets, transitions, rules: rules) do |path, format| error = assert_raises(InvalidZoneinfoFile) { @reader.read(path) } assert_equal("The first offset indicated by the POSIX-style TZ string did not match the final defined offset in file '#{path}'.", error.message) end end end [ [3600, 0], [3600, 3600], [10800, -3600] ].each do |(base_utc_offset, std_offset)| rules = TimezoneOffset.new(base_utc_offset, std_offset, 'TEST') define_method "test_read_tz_string_uses_constant_offset_with_no_transitions_#{base_utc_offset}_#{std_offset}" do offsets = [{gmtoff: base_utc_offset + std_offset, isdst: std_offset != 0, abbrev: 'TEST'}] tzif_test(offsets, [], rules: rules) do |path, format| assert_equal(rules, @reader.read(path)) end end define_method "test_read_tz_string_uses_constant_offset_after_last_transition_#{base_utc_offset}_#{std_offset}" do offsets = [ {gmtoff: 3542, isdst: false, abbrev: 'LMT'}, {gmtoff: base_utc_offset + std_offset, isdst: std_offset != 0, abbrev: 'TEST'} ] transitions = [ {at: Time.new(1971, 1, 2, 2, 0, 0, 3542), offset_index: 1} ] o0 = TimezoneOffset.new(3542, 0, 'LMT') t0 = TimezoneTransition.new(rules, o0, Time.new(1971, 1, 2, 2, 0, 0, 3542).to_i) tzif_test(offsets, transitions, rules: rules) do |path, format| assert_equal([t0], @reader.read(path)) end end end def test_read_tz_string_uses_rules_to_generate_all_transitions_when_none_defined offsets = [{gmtoff: 7200, isdst: false, abbrev: 'XST'}] rules = AnnualRules.new( TimezoneOffset.new(7200, 0, 'XST'), TimezoneOffset.new(7200, 3600, 'XDT'), JulianDayOfYearTransitionRule.new(100, 3600), JulianDayOfYearTransitionRule.new(300, 7200) ) o0 = TimezoneOffset.new(7200, 0, 'XST') o1 = TimezoneOffset.new(7200, 3600, 'XDT') t = 1970.upto(ZoneinfoReader.const_get(:GENERATE_UP_TO)).flat_map do |year| [ TimezoneTransition.new(o1, o0, Time.new(year, 4, 10, 1, 0, 0, 7200).to_i), TimezoneTransition.new(o0, o1, Time.new(year, 10, 27, 2, 0, 0, 10800).to_i) ] end tzif_test(offsets, [], rules: rules) do |path, format| assert_equal(t, @reader.read(path)) end end def test_read_tz_string_uses_rules_to_generate_all_transitions_when_none_defined_omitting_first_if_matches_first_offset offsets = [{gmtoff: 10800, isdst: true, abbrev: 'XDT'}] rules = AnnualRules.new( TimezoneOffset.new(7200, 0, 'XST'), TimezoneOffset.new(7200, 3600, 'XDT'), JulianDayOfYearTransitionRule.new(100, 3600), JulianDayOfYearTransitionRule.new(300, 7200) ) o0 = TimezoneOffset.new(7200, 3600, 'XDT') o1 = TimezoneOffset.new(7200, 0, 'XST') t0 = TimezoneTransition.new(o1, o0, Time.new(1970, 10, 27, 2, 0, 0, 10800).to_i) tn = 1971.upto(ZoneinfoReader.const_get(:GENERATE_UP_TO)).flat_map do |year| [ TimezoneTransition.new(o0, o1, Time.new(year, 4, 10, 1, 0, 0, 7200).to_i), TimezoneTransition.new(o1, o0, Time.new(year, 10, 27, 2, 0, 0, 10800).to_i) ] end t = [t0] + tn tzif_test(offsets, [], rules: rules) do |path, format| assert_equal(t, @reader.read(path)) end end def test_read_tz_string_uses_rules_to_generate_all_transitions_when_none_defined_with_previous_offset_of_first_matching_first_offset offsets = [{gmtoff: 7142, isdst: false, abbrev: 'LMT'}] rules = AnnualRules.new( TimezoneOffset.new(7200, 0, 'XST'), TimezoneOffset.new(7200, 3600, 'XDT'), JulianDayOfYearTransitionRule.new(100, 3600), JulianDayOfYearTransitionRule.new(300, 7200) ) o0 = TimezoneOffset.new(7142, 0, 'LMT') o1 = TimezoneOffset.new(7200, 0, 'XST') o2 = TimezoneOffset.new(7200, 3600, 'XDT') t0 = TimezoneTransition.new(o2, o0, Time.new(1970, 4, 10, 1, 0, 0, 7200).to_i) t1 = TimezoneTransition.new(o1, o2, Time.new(1970, 10, 27, 2, 0, 0, 10800).to_i) tn = 1971.upto(ZoneinfoReader.const_get(:GENERATE_UP_TO)).flat_map do |year| [ TimezoneTransition.new(o2, o1, Time.new(year, 4, 10, 1, 0, 0, 7200).to_i), TimezoneTransition.new(o1, o2, Time.new(year, 10, 27, 2, 0, 0, 10800).to_i) ] end t = [t0, t1] + tn tzif_test(offsets, [], rules: rules) do |path, format| assert_equal(t, @reader.read(path)) end end def test_read_tz_string_uses_rules_to_generate_all_transitions_when_none_defined_correcting_initial_offset offsets = [{gmtoff: 10800, isdst: true, abbrev: 'XDDT'}] rules = AnnualRules.new( TimezoneOffset.new(3600, 0, 'XST'), TimezoneOffset.new(3600, 7200, 'XDDT'), JulianDayOfYearTransitionRule.new(100, 3600), JulianDayOfYearTransitionRule.new(300, 7200) ) o0 = TimezoneOffset.new(3600, 7200, 'XDDT') o1 = TimezoneOffset.new(3600, 0, 'XST') t0 = TimezoneTransition.new(o1, o0, Time.new(1970, 10, 27, 2, 0, 0, 10800).to_i) tn = 1971.upto(ZoneinfoReader.const_get(:GENERATE_UP_TO)).flat_map do |year| [ TimezoneTransition.new(o0, o1, Time.new(year, 4, 10, 1, 0, 0, 3600).to_i), TimezoneTransition.new(o1, o0, Time.new(year, 10, 27, 2, 0, 0, 10800).to_i) ] end t = [t0] + tn tzif_test(offsets, [], rules: rules) do |path, format| assert_equal(t, @reader.read(path)) end end def test_read_tz_string_extends_transitions_starting_from_std_to_dst_following_year offsets = [ {gmtoff: 7142, isdst: false, abbrev: 'LMT'}, {gmtoff: 7200, isdst: false, abbrev: 'XST'}, {gmtoff: 10800, isdst: true, abbrev: 'XDT'} ] transitions = [ {at: Time.new(1971, 1, 2, 2, 0, 0, 7142), offset_index: 1}, {at: Time.new(1981, 4, 10, 1, 0, 0, 7200), offset_index: 2}, {at: Time.new(1981, 10, 27, 2, 0, 0, 10800), offset_index: 1} ] rules = AnnualRules.new( TimezoneOffset.new(7200, 0, 'XST'), TimezoneOffset.new(7200, 3600, 'XDT'), JulianDayOfYearTransitionRule.new(100, 3600), JulianDayOfYearTransitionRule.new(300, 7200) ) o0 = TimezoneOffset.new(7142, 0, 'LMT') o1 = TimezoneOffset.new(7200, 0, 'XST') o2 = TimezoneOffset.new(7200, 3600, 'XDT') t0 = TimezoneTransition.new(o1, o0, Time.new(1971, 1, 2, 2, 0, 0, 7142).to_i) tn = 1981.upto(ZoneinfoReader.const_get(:GENERATE_UP_TO)).flat_map do |year| [ TimezoneTransition.new(o2, o1, Time.new(year, 4, 10, 1, 0, 0, 7200).to_i), TimezoneTransition.new(o1, o2, Time.new(year, 10, 27, 2, 0, 0, 10800).to_i) ] end t = [t0] + tn tzif_test(offsets, transitions, rules: rules) do |path, format| assert_equal(t, @reader.read(path)) end end def test_read_tz_string_extends_transitions_starting_from_dst_to_std_same_year offsets = [ {gmtoff: 7142, isdst: false, abbrev: 'LMT'}, {gmtoff: 7200, isdst: false, abbrev: 'XST'}, {gmtoff: 10800, isdst: true, abbrev: 'XDT'} ] transitions = [ {at: Time.new(1971, 1, 2, 2, 0, 0, 7142), offset_index: 1}, {at: Time.new(1981, 4, 10, 1, 0, 0, 7200), offset_index: 2}, {at: Time.new(1981, 10, 27, 2, 0, 0, 10800), offset_index: 1}, {at: Time.new(1982, 4, 10, 1, 0, 0, 7200), offset_index: 2} ] rules = AnnualRules.new( TimezoneOffset.new(7200, 0, 'XST'), TimezoneOffset.new(7200, 3600, 'XDT'), JulianDayOfYearTransitionRule.new(100, 3600), JulianDayOfYearTransitionRule.new(300, 7200) ) o0 = TimezoneOffset.new(7142, 0, 'LMT') o1 = TimezoneOffset.new(7200, 0, 'XST') o2 = TimezoneOffset.new(7200, 3600, 'XDT') t0 = TimezoneTransition.new(o1, o0, Time.new(1971, 1, 2, 2, 0, 0, 7142).to_i) tn = 1981.upto(ZoneinfoReader.const_get(:GENERATE_UP_TO)).flat_map do |year| [ TimezoneTransition.new(o2, o1, Time.new(year, 4, 10, 1, 0, 0, 7200).to_i), TimezoneTransition.new(o1, o2, Time.new(year, 10, 27, 2, 0, 0, 10800).to_i) ] end t = [t0] + tn tzif_test(offsets, transitions, rules: rules) do |path, format| assert_equal(t, @reader.read(path)) end end def test_read_tz_string_extends_transitions_starting_from_dst_to_std_following_year offsets = [ {gmtoff: 7142, isdst: false, abbrev: 'LMT'}, {gmtoff: 7200, isdst: false, abbrev: 'XST'}, {gmtoff: 10800, isdst: true, abbrev: 'XDT'} ] transitions = [ {at: Time.new(1971, 1, 2, 1, 0, 0, 7142), offset_index: 1}, {at: Time.new(1981, 10, 27, 1, 0, 0, 7200), offset_index: 2}, {at: Time.new(1982, 4, 10, 2, 0, 0, 10800), offset_index: 1}, {at: Time.new(1982, 10, 27, 1, 0, 0, 7200), offset_index: 2} ] rules = AnnualRules.new( TimezoneOffset.new(7200, 0, 'XST'), TimezoneOffset.new(7200, 3600, 'XDT'), JulianDayOfYearTransitionRule.new(300, 3600), JulianDayOfYearTransitionRule.new(100, 7200) ) o0 = TimezoneOffset.new(7142, 0, 'LMT') o1 = TimezoneOffset.new(7200, 0, 'XST') o2 = TimezoneOffset.new(7200, 3600, 'XDT') t0 = TimezoneTransition.new(o1, o0, Time.new(1971, 1, 2, 1, 0, 0, 7142).to_i) t1 = TimezoneTransition.new(o2, o1, Time.new(1981, 10, 27, 1, 0, 0, 7200).to_i) tn = 1982.upto(ZoneinfoReader.const_get(:GENERATE_UP_TO)).flat_map do |year| [ TimezoneTransition.new(o1, o2, Time.new(year, 4, 10, 2, 0, 0, 10800).to_i), TimezoneTransition.new(o2, o1, Time.new(year, 10, 27, 1, 0, 0, 7200).to_i) ] end t = [t0, t1] + tn tzif_test(offsets, transitions, rules: rules) do |path, format| assert_equal(t, @reader.read(path)) end end def test_read_tz_string_extends_transitions_starting_from_std_to_dst_same_year offsets = [ {gmtoff: 7142, isdst: false, abbrev: 'LMT'}, {gmtoff: 7200, isdst: false, abbrev: 'XST'}, {gmtoff: 10800, isdst: true, abbrev: 'XDT'} ] transitions = [ {at: Time.new(1971, 1, 2, 1, 0, 0, 7142), offset_index: 1}, {at: Time.new(1981, 10, 27, 1, 0, 0, 7200), offset_index: 2}, {at: Time.new(1982, 4, 10, 2, 0, 0, 10800), offset_index: 1}, {at: Time.new(1982, 10, 27, 1, 0, 0, 7200), offset_index: 2}, {at: Time.new(1983, 4, 10, 2, 0, 0, 10800), offset_index: 1} ] rules = AnnualRules.new( TimezoneOffset.new(7200, 0, 'XST'), TimezoneOffset.new(7200, 3600, 'XDT'), JulianDayOfYearTransitionRule.new(300, 3600), JulianDayOfYearTransitionRule.new(100, 7200) ) o0 = TimezoneOffset.new(7142, 0, 'LMT') o1 = TimezoneOffset.new(7200, 0, 'XST') o2 = TimezoneOffset.new(7200, 3600, 'XDT') t0 = TimezoneTransition.new(o1, o0, Time.new(1971, 1, 2, 1, 0, 0, 7142).to_i) t1 = TimezoneTransition.new(o2, o1, Time.new(1981, 10, 27, 1, 0, 0, 7200).to_i) tn = 1982.upto(ZoneinfoReader.const_get(:GENERATE_UP_TO)).flat_map do |year| [ TimezoneTransition.new(o1, o2, Time.new(year, 4, 10, 2, 0, 0, 10800).to_i), TimezoneTransition.new(o2, o1, Time.new(year, 10, 27, 1, 0, 0, 7200).to_i) ] end t = [t0, t1] + tn tzif_test(offsets, transitions, rules: rules) do |path, format| assert_equal(t, @reader.read(path)) end end def test_read_tz_string_extends_transitions_negative_dst offsets = [ {gmtoff: 7142, isdst: false, abbrev: 'LMT'}, {gmtoff: 7200, isdst: true, abbrev: 'XDT'}, {gmtoff: 10800, isdst: false, abbrev: 'XST'} ] transitions = [ {at: Time.new(1971, 1, 2, 2, 0, 0, 7142), offset_index: 1}, {at: Time.new(1981, 4, 10, 1, 0, 0, 7200), offset_index: 2}, {at: Time.new(1981, 10, 27, 2, 0, 0, 10800), offset_index: 1} ] rules = AnnualRules.new( TimezoneOffset.new(10800, 0, 'XST'), TimezoneOffset.new(10800, -3600, 'XDT'), JulianDayOfYearTransitionRule.new(300, 7200), JulianDayOfYearTransitionRule.new(100, 3600) ) o0 = TimezoneOffset.new( 7142, 0, 'LMT') o1 = TimezoneOffset.new(10800, -3600, 'XDT') o2 = TimezoneOffset.new(10800, 0, 'XST') t0 = TimezoneTransition.new(o1, o0, Time.new(1971, 1, 2, 2, 0, 0, 7142).to_i) tn = 1981.upto(ZoneinfoReader.const_get(:GENERATE_UP_TO)).flat_map do |year| [ TimezoneTransition.new(o2, o1, Time.new(year, 4, 10, 1, 0, 0, 7200).to_i), TimezoneTransition.new(o1, o2, Time.new(year, 10, 27, 2, 0, 0, 10800).to_i) ] end t = [t0] + tn tzif_test(offsets, transitions, rules: rules) do |path, format| assert_equal(t, @reader.read(path)) end end def test_read_tz_string_extends_single_transition_in_final_year offsets = [ {gmtoff: 7142, isdst: false, abbrev: 'LMT'}, {gmtoff: 7200, isdst: false, abbrev: 'XST'}, {gmtoff: 10800, isdst: true, abbrev: 'XDT'} ] generate_up_to = ZoneinfoReader.const_get(:GENERATE_UP_TO) transitions = [ {at: Time.new( 1971, 1, 2, 2, 0, 0, 7142), offset_index: 1}, {at: Time.new(generate_up_to - 1, 4, 10, 1, 0, 0, 7200), offset_index: 2}, {at: Time.new(generate_up_to - 1, 10, 27, 2, 0, 0, 10800), offset_index: 1}, {at: Time.new(generate_up_to, 4, 10, 1, 0, 0, 7200), offset_index: 2} ] rules = AnnualRules.new( TimezoneOffset.new(7200, 0, 'XST'), TimezoneOffset.new(7200, 3600, 'XDT'), JulianDayOfYearTransitionRule.new(100, 3600), JulianDayOfYearTransitionRule.new(300, 7200) ) o0 = TimezoneOffset.new(7142, 0, 'LMT') o1 = TimezoneOffset.new(7200, 0, 'XST') o2 = TimezoneOffset.new(7200, 3600, 'XDT') t0 = TimezoneTransition.new(o1, o0, Time.new(1971, 1, 2, 2, 0, 0, 7142).to_i) tn = (generate_up_to - 1).upto(generate_up_to).flat_map do |year| [ TimezoneTransition.new(o2, o1, Time.new(year, 4, 10, 1, 0, 0, 7200).to_i), TimezoneTransition.new(o1, o2, Time.new(year, 10, 27, 2, 0, 0, 10800).to_i) ] end t = [t0] + tn tzif_test(offsets, transitions, rules: rules) do |path, format| assert_equal(t, @reader.read(path)) end end def test_read_tz_string_adds_nothing_if_transitions_up_to_final_year offsets = [ {gmtoff: 7142, isdst: false, abbrev: 'LMT'}, {gmtoff: 7200, isdst: false, abbrev: 'XST'}, {gmtoff: 10800, isdst: true, abbrev: 'XDT'} ] generate_up_to = ZoneinfoReader.const_get(:GENERATE_UP_TO) transitions = [ {at: Time.new( 1971, 1, 2, 2, 0, 0, 7142), offset_index: 1}, {at: Time.new(generate_up_to, 4, 10, 1, 0, 0, 7200), offset_index: 2}, {at: Time.new(generate_up_to, 10, 27, 2, 0, 0, 10800), offset_index: 1}, ] rules = AnnualRules.new( TimezoneOffset.new(7200, 0, 'XST'), TimezoneOffset.new(7200, 3600, 'XDT'), JulianDayOfYearTransitionRule.new(100, 3600), JulianDayOfYearTransitionRule.new(300, 7200) ) o0 = TimezoneOffset.new(7142, 0, 'LMT') o1 = TimezoneOffset.new(7200, 0, 'XST') o2 = TimezoneOffset.new(7200, 3600, 'XDT') t0 = TimezoneTransition.new(o1, o0, Time.new( 1971, 1, 2, 2, 0, 0, 7142).to_i) t1 = TimezoneTransition.new(o2, o1, Time.new(generate_up_to, 4, 10, 1, 0, 0, 7200).to_i) t2 = TimezoneTransition.new(o1, o2, Time.new(generate_up_to, 10, 27, 2, 0, 0, 10800).to_i) tzif_test(offsets, transitions, rules: rules) do |path, format| assert_equal([t0,t1,t2], @reader.read(path)) end end def test_read_tz_string_corrects_offset_of_final_transition_same_year offsets = [ {gmtoff: 3542, isdst: false, abbrev: 'LMT'}, {gmtoff: 7200, isdst: true, abbrev: 'XDT'}] transitions = [{at: Time.new(2000, 4, 10, 1, 0, 0, 3542), offset_index: 1}] rules = AnnualRules.new( TimezoneOffset.new(3600, 0, 'XST'), TimezoneOffset.new(3600, 3600, 'XDT'), JulianDayOfYearTransitionRule.new(100, 3600), JulianDayOfYearTransitionRule.new(300, 7200) ) o0 = TimezoneOffset.new(3542, 0, 'LMT') o1 = TimezoneOffset.new(3600, 3600, 'XDT') # without tz_string would be 3542, 3658, 'XDT' o2 = TimezoneOffset.new(3600, 0, 'XST') t0 = TimezoneTransition.new(o1, o0, Time.new(2000, 4, 10, 1, 0, 0, 3542).to_i) t1 = TimezoneTransition.new(o2, o1, Time.new(2000, 10, 27, 2, 0, 0, 7200).to_i) tn = 2001.upto(ZoneinfoReader.const_get(:GENERATE_UP_TO)).flat_map do |year| [ TimezoneTransition.new(o1, o2, Time.new(year, 4, 10, 1, 0, 0, 3600).to_i), TimezoneTransition.new(o2, o1, Time.new(year, 10, 27, 2, 0, 0, 7200).to_i) ] end t = [t0, t1] + tn tzif_test(offsets, transitions, rules: rules) do |path, format| assert_equal(t, @reader.read(path)) end end def test_read_tz_string_specifies_transition_to_offset_of_final_transition_same_year_skip_dst_start # TZInfo v2.0.3 considered this to be an error. However, this is a valid # situation with Africa/Casablanca in 2018e. # # The last defined transitions are: # At 2037-03-29 02:00Z change to WEST UTC+1 # At 2037-10-04 02:00Z change to WET UTC+0 # # The rules define the end of DST to be at 03:00 local time on the last # Sunday of October (2037-10-31). This later transition needs to be # ignored. offsets = [ {gmtoff: 7142, isdst: false, abbrev: 'LMT'}, {gmtoff: 7200, isdst: false, abbrev: 'XST'}, {gmtoff: 10800, isdst: true, abbrev: 'XDT'} ] transitions = [ {at: Time.new(1971, 1, 2, 2, 0, 0, 7142), offset_index: 1}, {at: Time.new(1981, 4, 10, 1, 0, 0, 7200), offset_index: 2}, {at: Time.new(1981, 10, 27, 2, 0, 0, 10800), offset_index: 1}, {at: Time.new(1982, 4, 10, 1, 0, 0, 7200), offset_index: 2} ] rules = AnnualRules.new( TimezoneOffset.new(7200, 0, 'XST'), TimezoneOffset.new(7200, 3600, 'XDT'), JulianDayOfYearTransitionRule.new(101, 3600), JulianDayOfYearTransitionRule.new(300, 7200) ) o0 = TimezoneOffset.new(7142, 0, 'LMT') o1 = TimezoneOffset.new(7200, 0, 'XST') o2 = TimezoneOffset.new(7200, 3600, 'XDT') t0 = TimezoneTransition.new(o1, o0, Time.new(1971, 1, 2, 2, 0, 0, 7142).to_i) t1 = TimezoneTransition.new(o2, o1, Time.new(1981, 4, 10, 1, 0, 0, 7200).to_i) t2 = TimezoneTransition.new(o1, o2, Time.new(1981, 10, 27, 2, 0, 0, 10800).to_i) t3 = TimezoneTransition.new(o2, o1, Time.new(1982, 4, 10, 1, 0, 0, 7200).to_i) t4 = TimezoneTransition.new(o1, o2, Time.new(1982, 10, 27, 2, 0, 0, 10800).to_i) tn = 1983.upto(ZoneinfoReader.const_get(:GENERATE_UP_TO)).flat_map do |year| [ TimezoneTransition.new(o2, o1, Time.new(year, 4, 11, 1, 0, 0, 7200).to_i), TimezoneTransition.new(o1, o2, Time.new(year, 10, 27, 2, 0, 0, 10800).to_i) ] end t = [t0, t1, t2, t3, t4] + tn tzif_test(offsets, transitions, rules: rules) do |path, format| assert_equal(t, @reader.read(path)) end end def test_read_tz_string_specifies_transition_to_offset_of_final_transition_same_year_skip_dst_end # TZInfo v2.0.3 considered this to be an error. However, this is a valid # situation with Africa/Casablanca in 2018e. # # The last defined transitions are: # At 2037-03-29 02:00Z change to WEST UTC+1 # At 2037-10-04 02:00Z change to WET UTC+0 # # The rules define the end of DST to be at 03:00 local time on the last # Sunday of October (2037-10-31). This later transition needs to be # ignored. offsets = [ {gmtoff: 7142, isdst: false, abbrev: 'LMT'}, {gmtoff: 7200, isdst: false, abbrev: 'XST'}, {gmtoff: 10800, isdst: true, abbrev: 'XDT'} ] transitions = [ {at: Time.new(1971, 1, 2, 2, 0, 0, 7142), offset_index: 1}, {at: Time.new(1981, 4, 10, 1, 0, 0, 7200), offset_index: 2}, {at: Time.new(1981, 10, 27, 2, 0, 0, 10800), offset_index: 1} ] rules = AnnualRules.new( TimezoneOffset.new(7200, 0, 'XST'), TimezoneOffset.new(7200, 3600, 'XDT'), JulianDayOfYearTransitionRule.new(100, 3600), JulianDayOfYearTransitionRule.new(301, 7200) ) o0 = TimezoneOffset.new(7142, 0, 'LMT') o1 = TimezoneOffset.new(7200, 0, 'XST') o2 = TimezoneOffset.new(7200, 3600, 'XDT') t0 = TimezoneTransition.new(o1, o0, Time.new(1971, 1, 2, 2, 0, 0, 7142).to_i) t1 = TimezoneTransition.new(o2, o1, Time.new(1981, 4, 10, 1, 0, 0, 7200).to_i) t2 = TimezoneTransition.new(o1, o2, Time.new(1981, 10, 27, 2, 0, 0, 10800).to_i) tn = 1982.upto(ZoneinfoReader.const_get(:GENERATE_UP_TO)).flat_map do |year| [ TimezoneTransition.new(o2, o1, Time.new(year, 4, 10, 1, 0, 0, 7200).to_i), TimezoneTransition.new(o1, o2, Time.new(year, 10, 28, 2, 0, 0, 10800).to_i) ] end t = [t0, t1, t2] + tn tzif_test(offsets, transitions, rules: rules) do |path, format| assert_equal(t, @reader.read(path)) end end def test_read_tz_string_specifies_transition_to_offset_of_final_transition_following_year offsets = [ {gmtoff: 7142, isdst: false, abbrev: 'LMT'}, {gmtoff: 7200, isdst: false, abbrev: 'XST'}, {gmtoff: 10800, isdst: true, abbrev: 'XDT'} ] transitions = [ {at: Time.new(1971, 1, 2, 2, 0, 0, 7142), offset_index: 1}, {at: Time.new(1981, 10, 27, 2, 0, 0, 7200), offset_index: 2}, ] rules = AnnualRules.new( TimezoneOffset.new(7200, 0, 'XST'), TimezoneOffset.new(7200, 3600, 'XDT'), JulianDayOfYearTransitionRule.new(100, 3600), JulianDayOfYearTransitionRule.new(299, 7200) ) tzif_test(offsets, transitions, rules: rules) do |path, format| error = assert_raises(InvalidZoneinfoFile) { @reader.read(path) } assert_equal("The first offset indicated by the POSIX-style TZ string did not match the final defined offset in file '#{path}'.", error.message) end end def test_read_tz_string_generates_from_last_transition_if_before_1970 offsets = [ {gmtoff: 7142, isdst: false, abbrev: 'LMT'}, {gmtoff: 7200, isdst: false, abbrev: 'XST'}, {gmtoff: 10800, isdst: true, abbrev: 'XDT'} ] transitions = [ {at: Time.new(1961, 1, 2, 2, 0, 0, 7142), offset_index: 1}, {at: Time.new(1962, 4, 10, 1, 0, 0, 7200), offset_index: 2}, {at: Time.new(1962, 10, 27, 2, 0, 0, 10800), offset_index: 1} ] rules = AnnualRules.new( TimezoneOffset.new(7200, 0, 'XST'), TimezoneOffset.new(7200, 3600, 'XDT'), JulianDayOfYearTransitionRule.new(100, 3600), JulianDayOfYearTransitionRule.new(300, 7200) ) o0 = TimezoneOffset.new(7142, 0, 'LMT') o1 = TimezoneOffset.new(7200, 0, 'XST') o2 = TimezoneOffset.new(7200, 3600, 'XDT') t0 = TimezoneTransition.new(o1, o0, Time.new(1961, 1, 2, 2, 0, 0, 7142).to_i) tn = 1962.upto(ZoneinfoReader.const_get(:GENERATE_UP_TO)).flat_map do |year| [ TimezoneTransition.new(o2, o1, Time.new(year, 4, 10, 1, 0, 0, 7200).to_i), TimezoneTransition.new(o1, o2, Time.new(year, 10, 27, 2, 0, 0, 10800).to_i) ] end t = [t0] + tn tzif_test(offsets, transitions, rules: rules) do |path, format| assert_equal(t, @reader.read(path)) end end def test_read_tz_string_reuses_offset_instances_when_adding_to_exsisting_transitions offsets = [ {gmtoff: 7142, isdst: false, abbrev: 'LMT'}, {gmtoff: 7200, isdst: false, abbrev: 'XST'}, {gmtoff: 10800, isdst: true, abbrev: 'XDT'} ] transitions = [ {at: Time.new(1971, 1, 2, 2, 0, 0, 7142), offset_index: 1}, {at: Time.new(1981, 4, 10, 1, 0, 0, 7200), offset_index: 2}, {at: Time.new(1981, 10, 27, 2, 0, 0, 10800), offset_index: 1} ] rules = AnnualRules.new( TimezoneOffset.new(7200, 0, 'XST'), TimezoneOffset.new(7200, 3600, 'XDT'), JulianDayOfYearTransitionRule.new(100, 3600), JulianDayOfYearTransitionRule.new(300, 7200) ) tzif_test(offsets, transitions, rules: rules) do |path, format| transitions = @reader.read(path) xst = transitions[0].offset xdt = transitions[1].offset assert_equal(TimezoneOffset.new(7200, 0, 'XST'), xst) assert_equal(TimezoneOffset.new(7200, 3600, 'XDT'), xdt) 1.upto((transitions.length - 1) / 2) do |i| # 2, 4, 6, ... assert_same(xst, transitions[i * 2].offset) assert_same(xdt, transitions[i * 2].previous_offset) end 1.upto(transitions.length / 2 - 1) {|i| assert_same(xdt, transitions[i * 2 + 1].offset) } # 3, 5, 7, ... 1.upto(transitions.length / 2) {|i| assert_same(xst, transitions[i * 2 - 1].previous_offset) } # 1, 3, 5, ... end end def test_read_tz_string_as_utf8 offsets = [{gmtoff: 3600, isdst: false, abbrev: 'áccént'}] rules = TimezoneOffset.new(3600, 0, 'áccént') tzif_test(offsets, [], tz_string: '<áccént>1', rules: rules) do |path, format| # FakePosixTimeZoneParser will test that the tz_string matches. assert_same(rules, @reader.read(path)) end end end end tzinfo-2.0.6/test/format1/000077500000000000000000000000001436527530500153725ustar00rootroot00000000000000tzinfo-2.0.6/test/format1/tc_country_definer.rb000066400000000000000000000033751436527530500216140ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true require_relative '../test_utils' module Format1 class TCCountryDefiner < Minitest::Test include TZInfo include TZInfo.const_get(:Format1) def setup @identifier_deduper = StringDeduper.new @description_deduper = StringDeduper.new end def test_no_timezones cd = create_country_definer assert_equal([], cd.timezones) end def test_timezones cd = create_country_definer cd.timezone('Test/One', 1, 2, 3, 4) cd.timezone('Test/Two', -1, 2, -3, 4, nil) cd.timezone('Test/Three', 5, 6, -7, 8, 'Test Three') assert_equal([ CountryTimezone.new('Test/One', Rational( 1, 2), Rational( 3, 4), nil), CountryTimezone.new('Test/Two', Rational(-1, 2), Rational(-3, 4), nil), CountryTimezone.new('Test/Three', Rational( 5, 6), Rational(-7, 8), 'Test Three')], cd.timezones) end def test_strings_frozen cd = create_country_definer cd.timezone('Test/One'.dup, 1, 2, 3, 4, 'Test 1'.dup) timezone = cd.timezones.first assert(timezone.identifier.frozen?) assert(timezone.description.frozen?) end def test_strings_deduped tz = 2.times.collect do cd = create_country_definer cd.timezone('Test/One'.dup, 1, 2, 3, 4, 'Test 1'.dup) cd.timezones.first end assert_same(tz[0].identifier, tz[1].identifier) assert_same(tz[0].description, tz[1].description) assert_same(@identifier_deduper.dedupe('Test/One'.dup), tz[0].identifier) assert_same(@description_deduper.dedupe('Test 1'.dup), tz[0].description) end private def create_country_definer CountryDefiner.new(@identifier_deduper, @description_deduper) end end end tzinfo-2.0.6/test/format1/tc_country_index_definition.rb000066400000000000000000000134311436527530500235110ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true require_relative '../test_utils' module Format1 class TCCountryIndexDefinition < Minitest::Test include TZInfo include TZInfo.const_get(:Format1) def test_none m = Module.new m.send(:include, CountryIndexDefinition) countries = m.countries assert_equal({}, countries) assert(countries.frozen?) end def test_multiple m = Module.new m.send(:include, CountryIndexDefinition) m.send(:country, 'ZZ', 'Country One') do |c| assert_kind_of(CountryDefiner, c) c.timezone 'Test/Zone/1', 3, 2, 41, 20 end m.send(:country, 'AA', 'Aland') do |c| assert_kind_of(CountryDefiner, c) c.timezone 'Test/Zone/3', 71, 30, 358, 15, 'Zone 3' c.timezone 'Test/Zone/2', 41, 20, 211, 30 end m.send(:country, 'TE', 'Three') m.send(:country, 'FR', 'Four') do |c| end countries = m.countries assert_equal(%w(ZZ AA TE FR), countries.keys) assert(countries.frozen?) country = countries['ZZ'] assert_kind_of(DataSources::CountryInfo, country) assert_equal('ZZ', country.code) assert_equal('Country One', country.name) assert_equal([CountryTimezone.new('Test/Zone/1', Rational(3, 2), Rational(41, 20))], country.zones) country = countries['AA'] assert_kind_of(DataSources::CountryInfo, country) assert_equal('AA', country.code) assert_equal('Aland', country.name) assert_equal([ CountryTimezone.new('Test/Zone/3', Rational(71, 30), Rational(358, 15), 'Zone 3'), CountryTimezone.new('Test/Zone/2', Rational(41, 20), Rational(211, 30))], country.zones) country = countries['TE'] assert_kind_of(DataSources::CountryInfo, country) assert_equal('TE', country.code) assert_equal('Three', country.name) assert_equal([], country.zones) country = countries['FR'] assert_kind_of(DataSources::CountryInfo, country) assert_equal('FR', country.code) assert_equal('Four', country.name) assert_equal([], country.zones) end def test_redefined m = Module.new m.send(:include, CountryIndexDefinition) m.send(:country, 'TT', 'Test1') do |c| assert_kind_of(CountryDefiner, c) c.timezone 'Test/Zone/1', 1, 2, 3, 4, 'Zone 1' end m.send(:country, 'TT', 'Test2') do |c| assert_kind_of(CountryDefiner, c) c.timezone 'Test/Zone/2', 5, 6, 7, 8, 'Zone 2' end countries = m.countries assert_equal(%w(TT), countries.keys) assert(countries.frozen?) country = countries['TT'] assert_kind_of(DataSources::CountryInfo, country) assert_equal('TT', country.code) assert_equal('Test2', country.name) assert_equal([CountryTimezone.new('Test/Zone/2', Rational(5, 6), Rational(7, 8), 'Zone 2')], country.zones) end def test_strings_frozen m = Module.new m.send(:include, CountryIndexDefinition) m.send(:country, 'TT'.dup, 'Test'.dup) do |c| assert_kind_of(CountryDefiner, c) c.timezone 'Test/Zone/1'.dup, 1, 2, 3, 4, 'Zone One'.dup end countries = m.countries assert(countries.keys.all?(&:frozen?)) country = countries['TT'] assert(country.code.frozen?) assert(country.name.frozen?) zone = country.zones.first assert(zone.identifier.frozen?) assert(zone.description.frozen?) end def test_strings_deduped m = Module.new m.send(:include, CountryIndexDefinition) # There will never be a country defined with either a duplicate code or # a duplicate name. m.send(:country, 'TT', 'Test') do |c| c.timezone 'Test/Zone/Shared1'.dup, 1, 2, 3, 4, 'Shared 1'.dup c.timezone 'Test/Zone/Shared2'.dup, 5, 6, 7, 8, 'Shared 2'.dup end m.send(:country, 'TU', 'Test 2') do |c| c.timezone 'Test/Zone/Shared1'.dup, 9, 10, 11, 12, 'Shared 1'.dup c.timezone 'Test/Zone/Shared2'.dup, 1, 2, 3, 4, 'Shared 2'.dup end countries = m.countries country_tt = countries['TT'] country_tu = countries['TU'] assert_same(country_tt.zones[0].identifier, country_tu.zones[0].identifier) assert_same(country_tt.zones[0].description, country_tu.zones[0].description) assert_same(country_tt.zones[1].identifier, country_tu.zones[1].identifier) assert_same(country_tt.zones[1].description, country_tu.zones[1].description) # The time zone identifier is required to have been deduped globally # because it will be referenced separately by the time zone module. # The descriptions are only referenced in the index, so can be handled # locally. sd = StringDeduper.global assert_same(sd.dedupe('Test/Zone/Shared1'.dup), country_tt.zones[0].identifier) assert_same(sd.dedupe('Test/Zone/Shared2'.dup), country_tt.zones[1].identifier) end def test_global_and_local_string_dedupers_used_for_country_definer block_called = 0 description_deduper = nil m = Module.new m.send(:include, CountryIndexDefinition) m.send(:country, 'TT', 'Test') do |c| assert_kind_of(CountryDefiner, c) assert_same(StringDeduper.global, c.instance_variable_get(:@identifier_deduper)) description_deduper = c.instance_variable_get(:@description_deduper) assert_same(StringDeduper, description_deduper.class) block_called += 1 end assert_equal(1, block_called) m.send(:country, 'TU', 'Test 2') do |c| assert_same(description_deduper, c.instance_variable_get(:@description_deduper)) block_called += 1 end assert_equal(2, block_called) end def test_tzinfo_module_alias assert_same(CountryIndexDefinition, CountryIndexDefinition) end end end tzinfo-2.0.6/test/format1/tc_timezone_definer.rb000066400000000000000000000052161436527530500217370ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true require_relative '../test_utils' module Format1 class TCTimezoneDefiner < Minitest::Test include TZInfo include TZInfo.const_get(:Format1) def setup @string_deduper = StringDeduper.new @definer = TimezoneDefiner.new(@string_deduper) end def test_transitions_with_timestamps @definer.offset :o1, -17900, 0, :TESTLMT @definer.offset :o2, -18000, 3600, :TEST @definer.offset :o3, -18000, 0, :TESTD @definer.transition 2016, 3, :o2, 1456790400 @definer.transition 2016, 9, :o3, 1472688000 @definer.transition 2016, 3, :o2, 1488326400 o1 = TimezoneOffset.new(-17900, 0, 'TESTLMT') o2 = TimezoneOffset.new(-18000, 3600, 'TEST') o3 = TimezoneOffset.new(-18000, 0, 'TESTD') t1 = TimezoneTransition.new(o2, o1, 1456790400) t2 = TimezoneTransition.new(o3, o2, 1472688000) t3 = TimezoneTransition.new(o2, o3, 1488326400) assert_equal(o1, @definer.first_offset) assert_equal([t1,t2,t3], @definer.transitions) end def test_transitions_with_timestamps_and_datetimes @definer.offset :o1, -17900, 0, :TESTLMT @definer.offset :o2, -18000, 3600, :TEST @definer.offset :o3, -18000, 0, :TESTD # DateTimes are defined 1 second after the timestamps. The timestamp values # will be used to construct TimezoneTransitions. @definer.transition 2016, 3, :o2, 1456790400, 212323550401, 86400 @definer.transition 2016, 9, :o3, 1472688000, 212339448001, 86400 @definer.transition 2016, 3, :o2, 1488326400, 212355086401, 86400 o1 = TimezoneOffset.new(-17900, 0, 'TESTLMT') o2 = TimezoneOffset.new(-18000, 3600, 'TEST') o3 = TimezoneOffset.new(-18000, 0, 'TESTD') t1 = TimezoneTransition.new(o2, o1, 1456790400) t2 = TimezoneTransition.new(o3, o2, 1472688000) t3 = TimezoneTransition.new(o2, o3, 1488326400) assert_equal(o1, @definer.first_offset) assert_equal([t1,t2,t3], @definer.transitions) end def test_transition_with_datetime # The ability to specify a transition solely as a DateTime has not been used # in any released version of TZInfo::Data. This is now not supporte@definer. @definer.offset :o1, -17900, 0, :TESTLMT error = assert_raises(ArgumentError) { @definer.transition 2016, 3, :o1, 4914897, 2 } assert_match(/\bDateTime\b/, error.message) end def test_strings_deduped abbreviation = @string_deduper.dedupe(:SYMDDLMT.to_s) @definer.offset :o1, 3600, 0, :SYMDDLMT assert_same(abbreviation, @definer.first_offset.abbreviation) end end end tzinfo-2.0.6/test/format1/tc_timezone_definition.rb000066400000000000000000000156621436527530500224610ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true require_relative '../test_utils' module Format1 class TCTimezoneDefinition < Minitest::Test include TZInfo include TZInfo.const_get(:Format1) def test_timezone_definer_class m = Module.new m.send(:include, TimezoneDefinition) assert_same(TimezoneDefiner, m.send(:timezone_definer_class)) end def test_data_transitions m = Module.new m.send(:include, TimezoneDefinition) block_called = 0 m.send(:timezone, 'Test/Data/Zone') do |tz| block_called += 1 assert_kind_of(TimezoneDefiner, tz) tz.offset :o0, -75, 0, :LMT tz.offset :o1, 0, 0, :GMT tz.offset :o2, 0, 3600, :BST tz.transition 1847, 12, :o1, -3852662325 tz.transition 2016, 3, :o2, 1459040400 end assert_equal(1, block_called) ti = m.get assert_kind_of(DataSources::TransitionsDataTimezoneInfo, ti) assert_equal('Test/Data/Zone', ti.identifier) o0 = TimezoneOffset.new(-75, 0, 'LMT') o1 = TimezoneOffset.new( 0, 0, 'GMT') o2 = TimezoneOffset.new( 0, 3600, 'BST') t1 = TimezoneTransition.new(o1, o0, -3852662325) t2 = TimezoneTransition.new(o2, o1, 1459040400) assert_equal([t1, t2], ti.transitions) end def test_data_constant_offset m = Module.new m.send(:include, TimezoneDefinition) block_called = 0 m.send(:timezone, 'Test/Data/Zone') do |tz| block_called += 1 assert_kind_of(TimezoneDefiner, tz) tz.offset :o0, -75, 0, :LMT end assert_equal(1, block_called) ti = m.get assert_kind_of(DataSources::ConstantOffsetDataTimezoneInfo, ti) assert_equal('Test/Data/Zone', ti.identifier) assert_equal(TimezoneOffset.new(-75, 0, 'LMT'), ti.constant_offset) end def test_data_frozen_identifier m = Module.new m.send(:include, TimezoneDefinition) m.send(:timezone, 'Test/Data/Zone') {|tz| tz.offset :o0, 0, 0, :UTC } ti = m.get assert(ti.identifier.frozen?) end def test_linked m = Module.new m.send(:include, TimezoneDefinition) m.send(:linked_timezone, 'Test/Linked/Zone', 'Test/Linked_To/Zone') ti = m.get assert_kind_of(DataSources::LinkedTimezoneInfo, ti) assert_equal('Test/Linked/Zone', ti.identifier) assert_equal('Test/Linked_To/Zone', ti.link_to_identifier) end def test_linked_frozen_identifiers m = Module.new m.send(:include, TimezoneDefinition) m.send(:linked_timezone, 'Test/Linked/Zone', 'Test/Linked_To/Zone') ti = m.get assert(ti.identifier.frozen?) assert(ti.link_to_identifier.frozen?) end def test_double_data m = Module.new m.send(:include, TimezoneDefinition) block_called = 0 m.send(:timezone, 'Test/Data/Zone') do |tz| block_called += 1 assert_kind_of(TimezoneDefiner, tz) tz.offset :o0, -75, 0, :LMT tz.offset :o1, 0, 0, :GMT tz.transition 1847, 12, :o1, -3852662325 end assert_equal(1, block_called) m.send(:timezone, 'Test/Data/Zone2') do |tz| block_called += 1 assert_kind_of(TimezoneDefiner, tz) tz.offset :o0, 3525, 0, :LMT tz.offset :o1, 3600, 0, :CET tz.transition 1847, 12, :o1, -3852658875 end assert_equal(2, block_called) ti = m.get assert_kind_of(DataSources::TransitionsDataTimezoneInfo, ti) assert_equal('Test/Data/Zone2', ti.identifier) o0 = TimezoneOffset.new(3525, 0, 'LMT') o1 = TimezoneOffset.new(3600, 0, 'CET') t1 = TimezoneTransition.new(o1, o0, -3852658875) assert_equal([t1], ti.transitions) end def test_double_linked m = Module.new m.send(:include, TimezoneDefinition) m.send(:linked_timezone, 'Test/Linked/Zone', 'Test/Linked_To/Zone') m.send(:linked_timezone, 'Test/Linked/Zone2', 'Test/Linked_To/Zone2') ti = m.get assert_kind_of(DataSources::LinkedTimezoneInfo, ti) assert_equal('Test/Linked/Zone2', ti.identifier) assert_equal('Test/Linked_To/Zone2', ti.link_to_identifier) end def test_data_linked m = Module.new m.send(:include, TimezoneDefinition) block_called = 0 m.send(:timezone, 'Test/Data/Zone') do |tz| block_called += 1 assert_kind_of(TimezoneDefiner, tz) tz.offset :o0, -75, 0, :LMT tz.offset :o1, 0, 0, :GMT tz.transition 1847, 12, :o1, -3852662325 end assert_equal(1, block_called) m.send(:linked_timezone, 'Test/Linked/Zone2', 'Test/Linked_To/Zone2') ti = m.get assert_kind_of(DataSources::LinkedTimezoneInfo, ti) assert_equal('Test/Linked/Zone2', ti.identifier) assert_equal('Test/Linked_To/Zone2', ti.link_to_identifier) end def test_linked_data m = Module.new m.send(:include, TimezoneDefinition) m.send(:linked_timezone, 'Test/Linked/Zone1', 'Test/Linked_To/Zone1') block_called = 0 m.send(:timezone, 'Test/Data/Zone2') do |tz| block_called += 1 assert_kind_of(TimezoneDefiner, tz) tz.offset :o0, -75, 0, :LMT tz.offset :o1, 0, 0, :GMT tz.transition 1847, 12, :o1, -3852662325 end assert_equal(1, block_called) ti = m.get assert_kind_of(DataSources::TransitionsDataTimezoneInfo, ti) assert_equal('Test/Data/Zone2', ti.identifier) o0 = TimezoneOffset.new(-75, 0, 'LMT') o1 = TimezoneOffset.new( 0, 0, 'GMT') t1 = TimezoneTransition.new(o1, o0, -3852662325) assert_equal([t1], ti.transitions) end def test_timezone_strings_deduped identifier = StringDeduper.global.dedupe('Test/One'.dup) m = Module.new m.send(:include, TimezoneDefinition) m.send(:timezone, 'Test/One'.dup) do |tz| tz.offset :o0, -75, 0, :LMT end ti = m.get assert_same(identifier, ti.identifier) end def test_linked_timezone_strings_deduped identifier = StringDeduper.global.dedupe('Test/Linked/Zone1'.dup) link_to_identifier = StringDeduper.global.dedupe('Test/Linked_To/Zone1'.dup) m = Module.new m.send(:include, TimezoneDefinition) m.send(:linked_timezone, 'Test/Linked/Zone1'.dup, 'Test/Linked_To/Zone1'.dup) ti = m.get assert_same(identifier, ti.identifier) assert_same(link_to_identifier, ti.link_to_identifier) end def test_global_string_deduper_used m = Module.new m.send(:include, TimezoneDefinition) block_called = 0 m.send(:timezone, 'Test/Data/Zone') do |tz| block_called += 1 assert_kind_of(TimezoneDefiner, tz) assert_same(StringDeduper.global, tz.instance_variable_get(:@string_deduper)) tz.offset :o0, -75, 0, 'LMT' end assert_equal(1, block_called) end def test_tzinfo_module_alias assert_same(TimezoneDefinition, TimezoneDefinition) end end end tzinfo-2.0.6/test/format1/tc_timezone_index_definition.rb000066400000000000000000000064621436527530500236460ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true require_relative '../test_utils' module Format1 class TCTimezoneIndexDefinition < Minitest::Test include TZInfo include TZInfo.const_get(:Format1) def test_mixed m = Module.new m.send(:include, TimezoneIndexDefinition) m.send(:timezone, 'Test/One') m.send(:timezone, 'Test/Two') m.send(:linked_timezone, 'Test/Three') m.send(:timezone, 'Another/Zone') m.send(:linked_timezone, 'And/Yet/Another') data_timezones = m.data_timezones assert_equal(['Another/Zone', 'Test/One', 'Test/Two'], data_timezones) assert(data_timezones.frozen?) assert(data_timezones.all?(&:frozen?)) assert_same(data_timezones, m.data_timezones) linked_timezones = m.linked_timezones assert_equal(['And/Yet/Another', 'Test/Three'], linked_timezones) assert(linked_timezones.frozen?) assert(linked_timezones.all?(&:frozen?)) assert_same(linked_timezones, m.linked_timezones) end def test_data_only m = Module.new m.send(:include, TimezoneIndexDefinition) m.send(:timezone, 'Test/A/One') m.send(:timezone, 'Test/A/Two') m.send(:timezone, 'Test/A/Three') data_timezones = m.data_timezones assert_equal(['Test/A/One', 'Test/A/Three', 'Test/A/Two'], data_timezones) assert(data_timezones.frozen?) assert(data_timezones.all?(&:frozen?)) assert_same(data_timezones, m.data_timezones) linked_timezones = m.linked_timezones assert_equal([], linked_timezones) assert(linked_timezones.frozen?) assert_same(linked_timezones, m.linked_timezones) end def test_linked_only m = Module.new m.send(:include, TimezoneIndexDefinition) m.send(:linked_timezone, 'Test/B/One') m.send(:linked_timezone, 'Test/B/Two') m.send(:linked_timezone, 'Test/B/Three') data_timezones = m.data_timezones assert_equal([], data_timezones) assert(data_timezones.frozen?) assert_same(data_timezones, m.data_timezones) linked_timezones = m.linked_timezones assert_equal(['Test/B/One', 'Test/B/Three', 'Test/B/Two'], linked_timezones) assert(linked_timezones.frozen?) assert(linked_timezones.all?(&:frozen?)) assert_same(linked_timezones, m.linked_timezones) end def test_none m = Module.new m.send(:include, TimezoneIndexDefinition) data_timezones = m.data_timezones assert_equal([], data_timezones) assert(data_timezones.frozen?) assert_same(data_timezones, m.data_timezones) linked_timezones = m.linked_timezones assert_equal([], linked_timezones) assert(linked_timezones.frozen?) assert_same(linked_timezones, m.linked_timezones) end def test_strings_deduped identifier = StringDeduper.global.dedupe('Test/A/One'.dup) linked_identifier = StringDeduper.global.dedupe('Test/B/One'.dup) m = Module.new m.send(:include, TimezoneIndexDefinition) m.send(:timezone, 'Test/A/One'.dup) m.send(:linked_timezone, 'Test/B/One'.dup) assert_same(identifier, m.data_timezones.first) assert_same(linked_identifier, m.linked_timezones.first) end def test_tzinfo_module_alias assert_same(TimezoneIndexDefinition, TimezoneIndexDefinition) end end end tzinfo-2.0.6/test/format2/000077500000000000000000000000001436527530500153735ustar00rootroot00000000000000tzinfo-2.0.6/test/format2/tc_country_definer.rb000066400000000000000000000061551436527530500216140ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true require_relative '../test_utils' module Format2 class TCCountryDefiner < Minitest::Test include TZInfo include TZInfo.const_get(:Format2) def setup @identifier_deduper = StringDeduper.new @description_deduper = StringDeduper.new end def test_no_timezones cd = create_country_definer({}) assert_equal([], cd.timezones) end def test_defined_timezones cd = create_country_definer({}) cd.timezone('Test/One', 1, 2, 3, 4) cd.timezone('Test/Two', -1, 2, -3, 4, nil) cd.timezone('Test/Three', 5, 6, -7, 8, 'Test Three') assert_equal([ CountryTimezone.new('Test/One', Rational( 1, 2), Rational( 3, 4), nil), CountryTimezone.new('Test/Two', Rational(-1, 2), Rational(-3, 4), nil), CountryTimezone.new('Test/Three', Rational( 5, 6), Rational(-7, 8), 'Test Three')], cd.timezones) end def test_shared_timezones shared_timezones = { t1: CountryTimezone.new('Test/One', Rational( 1, 2), Rational( 3, 4), nil), t2: CountryTimezone.new('Test/Two', Rational(-1, 2), Rational(-3, 4), nil), t3: CountryTimezone.new('Test/Three', Rational( 5, 6), Rational(-7, 8), 'Test Three') } cd = create_country_definer(shared_timezones) cd.timezone(:t1) cd.timezone(:t2) cd.timezone(:t3) assert_equal(3, cd.timezones.length) assert_same(shared_timezones[:t1], cd.timezones[0]) assert_same(shared_timezones[:t2], cd.timezones[1]) assert_same(shared_timezones[:t3], cd.timezones[2]) end def test_shared_timezone_not_found cd = create_country_definer({}) error = assert_raises(ArgumentError) { cd.timezone(:t1) } assert_equal("Unknown shared timezone: t1", error.message) end def test_missing_arguments cd = create_country_definer( t1: CountryTimezone.new('Test/One', Rational( 1, 2), Rational( 3, 4), nil) ) 1.upto(3) do |count| args = [:t1] + 1.upto(count).to_a error = assert_raises(ArgumentError) { cd.timezone(*args) } assert_equal('Either just a reference should be supplied, or the identifier, latitude and longitude must all be specified', error.message) end end def test_strings_frozen cd = create_country_definer({}) cd.timezone('Test/One', 1, 2, 3, 4, 'Test 1') timezone = cd.timezones.first assert(timezone.identifier.frozen?) assert(timezone.description.frozen?) end def test_strings_deduped tz = 2.times.collect do cd = create_country_definer({}) cd.timezone('Test/One', 1, 2, 3, 4, 'Test 1') cd.timezones.first end assert_same(tz[0].identifier, tz[1].identifier) assert_same(tz[0].description, tz[1].description) assert_same(@identifier_deduper.dedupe('Test/One'), tz[0].identifier) assert_same(@description_deduper.dedupe('Test 1'), tz[0].description) end private def create_country_definer(shared_timezones) CountryDefiner.new(shared_timezones, @identifier_deduper, @description_deduper) end end end tzinfo-2.0.6/test/format2/tc_country_index_definer.rb000066400000000000000000000152251436527530500230010ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true require_relative '../test_utils' module Format2 class TCCountryIndexDefiner < Minitest::Test include TZInfo include TZInfo.const_get(:Format2) def setup @identifier_deduper = StringDeduper.new @description_deduper = StringDeduper.new @definer = CountryIndexDefiner.new(@identifier_deduper, @description_deduper) end def test_none countries = @definer.countries assert_equal({}, countries) end def test_multiple @definer.timezone(:t1, 'Test/Zone/Shared1', -1, -2, -3, -4) @definer.timezone(:t2, 'Test/Zone/Shared2', 1, 2, 3, 4, 'Shared 2') @definer.country('ZZ', 'Country One') do |c| assert_kind_of(CountryDefiner, c) c.timezone :t1 c.timezone 'Test/Zone/1', 3, 2, 41, 20 end @definer.country('AA', 'Aland') do |c| assert_kind_of(CountryDefiner, c) c.timezone 'Test/Zone/3', 71, 30, 358, 15, 'Zone 3' c.timezone 'Test/Zone/2', 41, 20, 211, 30 c.timezone :t1 c.timezone :t2 end @definer.country('TE', 'Three') @definer.country('FR', 'Four') do |c| end countries = @definer.countries assert_equal(%w(ZZ AA TE FR), countries.keys) country_zz = countries['ZZ'] assert_kind_of(DataSources::CountryInfo, country_zz) assert_equal('ZZ', country_zz.code) assert_equal('Country One', country_zz.name) assert_equal([ CountryTimezone.new('Test/Zone/Shared1', Rational(-1, -2), Rational(-3, -4)), CountryTimezone.new('Test/Zone/1', Rational(3, 2), Rational(41, 20))], country_zz.zones) country_aa = countries['AA'] assert_kind_of(DataSources::CountryInfo, country_aa) assert_equal('AA', country_aa.code) assert_equal('Aland', country_aa.name) assert_equal([ CountryTimezone.new('Test/Zone/3', Rational(71, 30), Rational(358, 15), 'Zone 3'), CountryTimezone.new('Test/Zone/2', Rational(41, 20), Rational(211, 30)), CountryTimezone.new('Test/Zone/Shared1', Rational(-1, -2), Rational(-3, -4)), CountryTimezone.new('Test/Zone/Shared2', Rational(1, 2), Rational(3, 4), 'Shared 2')], country_aa.zones) assert_same(country_zz.zones[0], country_aa.zones[2]) country_te = countries['TE'] assert_kind_of(DataSources::CountryInfo, country_te) assert_equal('TE', country_te.code) assert_equal('Three', country_te.name) assert_equal([], country_te.zones) country_fr = countries['FR'] assert_kind_of(DataSources::CountryInfo, country_fr) assert_equal('FR', country_fr.code) assert_equal('Four', country_fr.name) assert_equal([], country_fr.zones) end def test_redefined_country @definer.country('TT', 'Test1') do |c| assert_kind_of(CountryDefiner, c) c.timezone 'Test/Zone/1', 1, 2, 3, 4, 'Zone 1' end @definer.country('TT', 'Test2') do |c| assert_kind_of(CountryDefiner, c) c.timezone 'Test/Zone/2', 5, 6, 7, 8, 'Zone 2' end countries = @definer.countries assert_equal(%w(TT), countries.keys) country_tt = countries['TT'] assert_kind_of(DataSources::CountryInfo, country_tt) assert_equal('TT', country_tt.code) assert_equal('Test2', country_tt.name) assert_equal([CountryTimezone.new('Test/Zone/2', Rational(5, 6), Rational(7, 8), 'Zone 2')], country_tt.zones) end def test_redefined_shared_timezone @definer.timezone(:t1, 'Test/Zone/Shared1', -1, -2, -3, -4) @definer.timezone(:t1, 'Test/Zone/Shared2', 1, 2, 3, 4, 'Shared 2') @definer.country('TT', 'Test1') do |c| assert_kind_of(CountryDefiner, c) c.timezone(:t1) end countries = @definer.countries assert_equal(%w(TT), countries.keys) country_tt = countries['TT'] assert_kind_of(DataSources::CountryInfo, country_tt) assert_equal('TT', country_tt.code) assert_equal('Test1', country_tt.name) assert_equal([CountryTimezone.new('Test/Zone/Shared2', Rational(1, 2), Rational(3, 4), 'Shared 2')], country_tt.zones) end def test_strings_frozen @definer.timezone(:t1, 'Test/Zone/Shared1', 1, 2, 3, 4, 'Shared 1') @definer.country('TT', 'Test') do |c| assert_kind_of(CountryDefiner, c) c.timezone 'Test/Zone/1', 1, 2, 3, 4, 'Zone One' c.timezone :t1 end countries = @definer.countries assert(countries.keys.all?(&:frozen?)) country_tt = countries['TT'] assert(country_tt.code.frozen?) assert(country_tt.name.frozen?) zone0 = country_tt.zones[0] assert(zone0.identifier.frozen?) assert(zone0.description.frozen?) zone1 = country_tt.zones[1] assert(zone1.identifier.frozen?) assert(zone1.description.frozen?) end def test_strings_deduped @definer.timezone(:t1, 'Test/Zone/Shared1', 1, 2, 3, 4, 'Shared 1') @definer.timezone(:t2, 'Test/Zone/Shared2', 1, 2, 3, 4, 'Shared 2') # There will never be a country defined with either a duplicate code or # a duplicate name. @definer.country('TT', 'Test') do |c| c.timezone :t1 c.timezone 'Test/Zone/Shared2', 5, 6, 7, 8, 'Shared 2' end @definer.country('TU', 'Test 2') do |c| c.timezone 'Test/Zone/Shared1', 9, 10, 11, 12, 'Shared 1' c.timezone :t2 end countries = @definer.countries country_tt = countries['TT'] country_tu = countries['TU'] assert_same(country_tt.zones[0].identifier, country_tu.zones[0].identifier) assert_same(country_tt.zones[0].description, country_tu.zones[0].description) assert_same(country_tt.zones[1].identifier, country_tu.zones[1].identifier) assert_same(country_tt.zones[1].description, country_tu.zones[1].description) assert_same(@identifier_deduper.dedupe('Test/Zone/Shared1'), country_tt.zones[0].identifier) assert_same(@identifier_deduper.dedupe('Test/Zone/Shared2'), country_tt.zones[1].identifier) assert_same(@description_deduper.dedupe('Shared 1'), country_tt.zones[0].description) assert_same(@description_deduper.dedupe('Shared 2'), country_tt.zones[1].description) end def test_identifier_and_description_string_dedupers_used_for_country_definer block_called = 0 @definer.country('TT', 'Test') do |c| block_called += 1 assert_kind_of(CountryDefiner, c) assert_same(@identifier_deduper, c.instance_variable_get(:@identifier_deduper)) assert_same(@description_deduper, c.instance_variable_get(:@description_deduper)) c.timezone 'Test/Zone/1', 1, 2, 3, 4, 'One' end assert_equal(1, block_called) end end end tzinfo-2.0.6/test/format2/tc_country_index_definition.rb000066400000000000000000000067501436527530500235200ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true require_relative '../test_utils' module Format2 class TCCountryIndexDefinition < Minitest::Test include TZInfo include TZInfo.const_get(:Format2) def test_not_defined m = Module.new m.send(:include, CountryIndexDefinition) countries = m.countries assert_equal({}, countries) assert(countries.frozen?) end def test_none m = Module.new m.send(:include, CountryIndexDefinition) m.send(:country_index) do |i| assert_kind_of(CountryIndexDefiner, i) end countries = m.countries assert_equal({}, countries) assert(countries.frozen?) end def test_multiple m = Module.new m.send(:include, CountryIndexDefinition) m.send(:country_index) do |i| assert_kind_of(CountryIndexDefiner, i) i.timezone(:t1, 'Test/Zone/Shared1', -1, -2, -3, -4) i.timezone(:t2, 'Test/Zone/Shared2', 1, 2, 3, 4, 'Shared 2') i.country('ZZ', 'Country One') do |c| c.timezone :t1 c.timezone 'Test/Zone/1', 3, 2, 41, 20 end i.country('AA', 'Aland') do |c| c.timezone 'Test/Zone/3', 71, 30, 358, 15, 'Zone 3' c.timezone 'Test/Zone/2', 41, 20, 211, 30 c.timezone :t1 c.timezone :t2 end i.country('TE', 'Three') i.country('FR', 'Four') do |c| end end countries = m.countries assert_equal(%w(ZZ AA TE FR), countries.keys) assert(countries.frozen?) country_zz = countries['ZZ'] assert_kind_of(DataSources::CountryInfo, country_zz) assert_equal('ZZ', country_zz.code) assert_equal('Country One', country_zz.name) assert_equal([ CountryTimezone.new('Test/Zone/Shared1', Rational(-1, -2), Rational(-3, -4)), CountryTimezone.new('Test/Zone/1', Rational(3, 2), Rational(41, 20))], country_zz.zones) country_aa = countries['AA'] assert_kind_of(DataSources::CountryInfo, country_aa) assert_equal('AA', country_aa.code) assert_equal('Aland', country_aa.name) assert_equal([ CountryTimezone.new('Test/Zone/3', Rational(71, 30), Rational(358, 15), 'Zone 3'), CountryTimezone.new('Test/Zone/2', Rational(41, 20), Rational(211, 30)), CountryTimezone.new('Test/Zone/Shared1', Rational(-1, -2), Rational(-3, -4)), CountryTimezone.new('Test/Zone/Shared2', Rational(1, 2), Rational(3, 4), 'Shared 2')], country_aa.zones) assert_same(country_zz.zones[0], country_aa.zones[2]) country_te = countries['TE'] assert_kind_of(DataSources::CountryInfo, country_te) assert_equal('TE', country_te.code) assert_equal('Three', country_te.name) assert_equal([], country_te.zones) country_fr = countries['FR'] assert_kind_of(DataSources::CountryInfo, country_fr) assert_equal('FR', country_fr.code) assert_equal('Four', country_fr.name) assert_equal([], country_fr.zones) end def test_global_and_local_string_dedupers_used_for_country_index_definer block_called = 0 m = Module.new m.send(:include, CountryIndexDefinition) m.send(:country_index) do |i| assert_kind_of(CountryIndexDefiner, i) assert_same(StringDeduper.global, i.instance_variable_get(:@identifier_deduper)) assert_same(StringDeduper, i.instance_variable_get(:@description_deduper).class) block_called += 1 end assert_equal(1, block_called) end end end tzinfo-2.0.6/test/format2/tc_timezone_definer.rb000066400000000000000000000077121436527530500217430ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true require_relative '../test_utils' module Format2 class TCTimezoneDefiner < Minitest::Test include TZInfo include TZInfo.const_get(:Format2) def setup @string_deduper = StringDeduper.new @definer = TimezoneDefiner.new(@string_deduper) end def test_no_offsets_or_transitions assert_nil(@definer.first_offset) assert_equal([], @definer.transitions) end def test_single_offset_no_transitions @definer.offset :o1, -17900, 0, 'TESTLMT' o1 = TimezoneOffset.new(-17900, 0, 'TESTLMT') assert_equal(o1, @definer.first_offset) assert_equal([], @definer.transitions) end def test_single_offset_single_transition @definer.offset :o1, -17900, 0, 'TESTLMT' @definer.transition :o1, 1456790400 o1 = TimezoneOffset.new(-17900, 0, 'TESTLMT') t1 = TimezoneTransition.new(o1, o1, 1456790400) assert_equal(o1, @definer.first_offset) assert_equal([t1], @definer.transitions) end def test_multiple_offsets_single_transition @definer.offset :o1, -17900, 0, 'TESTLMT' @definer.offset :o2, -18000, 3600, 'TEST' @definer.transition :o2, 1456790400 o1 = TimezoneOffset.new(-17900, 0, 'TESTLMT') o2 = TimezoneOffset.new(-18000, 3600, 'TEST') t1 = TimezoneTransition.new(o2, o1, 1456790400) assert_equal(o1, @definer.first_offset) assert_equal([t1], @definer.transitions) end def test_multiple_offsets_multiple_transitions @definer.offset :o1, -17900, 0, 'TESTLMT' @definer.offset :o2, -18000, 3600, 'TEST' @definer.offset :o3, -18000, 0, 'TESTD' @definer.transition :o2, 1456790400 @definer.transition :o3, 1472688000 @definer.transition :o2, 1488326400 o1 = TimezoneOffset.new(-17900, 0, 'TESTLMT') o2 = TimezoneOffset.new(-18000, 3600, 'TEST') o3 = TimezoneOffset.new(-18000, 0, 'TESTD') t1 = TimezoneTransition.new(o2, o1, 1456790400) t2 = TimezoneTransition.new(o3, o2, 1472688000) t3 = TimezoneTransition.new(o2, o3, 1488326400) assert_equal(o1, @definer.first_offset) assert_equal([t1,t2,t3], @definer.transitions) end def test_offset_already_defined @definer.offset :o1, -17900, 0, 'TESTLMT' @definer.offset :o2, 18000, 0, 'TEST' error = assert_raises(ArgumentError) { @definer.offset :o2, 1800, 3600, :TESTD } assert_match(/\bid\b/, error.message) end def test_transition_with_no_offsets error = assert_raises(ArgumentError) { @definer.transition :o1, 1456790400 } assert_match(/\boffset_id\b/, error.message) end def test_transition_with_undefined_offset @definer.offset :o1, -17900, 0, 'TESTLMT' @definer.transition :o1, 1456790400 error = assert_raises(ArgumentError) { @definer.transition :o2, 1472688000 } assert_match(/\boffset_id\b/, error.message) end def test_transition_not_increased @definer.offset :o1, -17900, 0, 'TESTLMT' @definer.transition :o1, 1456790400 error = assert_raises(ArgumentError) { @definer.transition :o1, 1456790400 } assert_match(/\btimestamp\b/, error.message) end def test_transition_decreased @definer.offset :o1, -17900, 0, 'TESTLMT' @definer.transition :o1, 1456790400 error = assert_raises(ArgumentError) { @definer.transition :o1, 1456790399 } assert_match(/\btimestamp\b/, error.message) end def test_strings_deduped abbreviation = @string_deduper.dedupe('DEFDDSMT') @definer.offset :o1, 3600, 0, 'DEFDDSMT' assert_same(abbreviation, @definer.first_offset.abbreviation) end # subsequent_rules is just a placeholder for forward compatibility, # accepting an arbitrary number of arguments and ignoring them. 0.upto(5) do |n| define_method("test_subsequent_rules_#{n}_args") do assert_nil(@definer.subsequent_rules(*(0..n).to_a)) end end end end tzinfo-2.0.6/test/format2/tc_timezone_definition.rb000066400000000000000000000153551436527530500224610ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true require_relative '../test_utils' module Format2 class TCTimezoneDefinition < Minitest::Test include TZInfo include TZInfo.const_get(:Format2) def test_timezone_definer_class m = Module.new m.send(:include, TimezoneDefinition) assert_same(TimezoneDefiner, m.send(:timezone_definer_class)) end def test_data_transitions m = Module.new m.send(:include, TimezoneDefinition) block_called = 0 m.send(:timezone, 'Test/Data/Zone') do |tz| block_called += 1 assert_kind_of(TimezoneDefiner, tz) tz.offset :o0, -75, 0, 'LMT' tz.offset :o1, 0, 0, 'GMT' tz.offset :o2, 0, 3600, 'BST' tz.transition :o1, -3852662325 tz.transition :o2, 1459040400 end assert_equal(1, block_called) ti = m.get assert_kind_of(DataSources::TransitionsDataTimezoneInfo, ti) assert_equal('Test/Data/Zone', ti.identifier) o0 = TimezoneOffset.new(-75, 0, 'LMT') o1 = TimezoneOffset.new( 0, 0, 'GMT') o2 = TimezoneOffset.new( 0, 3600, 'BST') t1 = TimezoneTransition.new(o1, o0, -3852662325) t2 = TimezoneTransition.new(o2, o1, 1459040400) assert_equal([t1, t2], ti.transitions) end def test_data_constant_offset m = Module.new m.send(:include, TimezoneDefinition) block_called = 0 m.send(:timezone, 'Test/Data/Zone') do |tz| block_called += 1 assert_kind_of(TimezoneDefiner, tz) tz.offset :o0, -75, 0, 'LMT' end assert_equal(1, block_called) ti = m.get assert_kind_of(DataSources::ConstantOffsetDataTimezoneInfo, ti) assert_equal('Test/Data/Zone', ti.identifier) assert_equal(TimezoneOffset.new(-75, 0, 'LMT'), ti.constant_offset) end def test_data_frozen_identifier m = Module.new m.send(:include, TimezoneDefinition) m.send(:timezone, 'Test/Data/Zone') {|tz| tz.offset :o0, 0, 0, 'UTC' } ti = m.get assert(ti.identifier.frozen?) end def test_linked m = Module.new m.send(:include, TimezoneDefinition) m.send(:linked_timezone, 'Test/Linked/Zone', 'Test/Linked_To/Zone') ti = m.get assert_kind_of(DataSources::LinkedTimezoneInfo, ti) assert_equal('Test/Linked/Zone', ti.identifier) assert_equal('Test/Linked_To/Zone', ti.link_to_identifier) end def test_linked_frozen_identifiers m = Module.new m.send(:include, TimezoneDefinition) m.send(:linked_timezone, 'Test/Linked/Zone', 'Test/Linked_To/Zone') ti = m.get assert(ti.identifier.frozen?) assert(ti.link_to_identifier.frozen?) end def test_double_data m = Module.new m.send(:include, TimezoneDefinition) block_called = 0 m.send(:timezone, 'Test/Data/Zone') do |tz| block_called += 1 assert_kind_of(TimezoneDefiner, tz) tz.offset :o0, -75, 0, 'LMT' tz.offset :o1, 0, 0, 'GMT' tz.transition :o1, -3852662325 end assert_equal(1, block_called) m.send(:timezone, 'Test/Data/Zone2') do |tz| block_called += 1 assert_kind_of(TimezoneDefiner, tz) tz.offset :o0, 3525, 0, 'LMT' tz.offset :o1, 3600, 0, 'CET' tz.transition :o1, -3852658875 end assert_equal(2, block_called) ti = m.get assert_kind_of(DataSources::TransitionsDataTimezoneInfo, ti) assert_equal('Test/Data/Zone2', ti.identifier) o0 = TimezoneOffset.new(3525, 0, 'LMT') o1 = TimezoneOffset.new(3600, 0, 'CET') t1 = TimezoneTransition.new(o1, o0, -3852658875) assert_equal([t1], ti.transitions) end def test_double_linked m = Module.new m.send(:include, TimezoneDefinition) m.send(:linked_timezone, 'Test/Linked/Zone', 'Test/Linked_To/Zone') m.send(:linked_timezone, 'Test/Linked/Zone2', 'Test/Linked_To/Zone2') ti = m.get assert_kind_of(DataSources::LinkedTimezoneInfo, ti) assert_equal('Test/Linked/Zone2', ti.identifier) assert_equal('Test/Linked_To/Zone2', ti.link_to_identifier) end def test_data_linked m = Module.new m.send(:include, TimezoneDefinition) block_called = 0 m.send(:timezone, 'Test/Data/Zone') do |tz| block_called += 1 assert_kind_of(TimezoneDefiner, tz) tz.offset :o0, -75, 0, 'LMT' tz.offset :o1, 0, 0, 'GMT' tz.transition :o1, -3852662325 end assert_equal(1, block_called) m.send(:linked_timezone, 'Test/Linked/Zone2', 'Test/Linked_To/Zone2') ti = m.get assert_kind_of(DataSources::LinkedTimezoneInfo, ti) assert_equal('Test/Linked/Zone2', ti.identifier) assert_equal('Test/Linked_To/Zone2', ti.link_to_identifier) end def test_linked_data m = Module.new m.send(:include, TimezoneDefinition) m.send(:linked_timezone, 'Test/Linked/Zone1', 'Test/Linked_To/Zone1') block_called = 0 m.send(:timezone, 'Test/Data/Zone2') do |tz| block_called += 1 assert_kind_of(TimezoneDefiner, tz) tz.offset :o0, -75, 0, 'LMT' tz.offset :o1, 0, 0, 'GMT' tz.transition :o1, -3852662325 end ti = m.get assert_kind_of(DataSources::TransitionsDataTimezoneInfo, ti) assert_equal('Test/Data/Zone2', ti.identifier) o0 = TimezoneOffset.new(-75, 0, 'LMT') o1 = TimezoneOffset.new( 0, 0, 'GMT') t1 = TimezoneTransition.new(o1, o0, -3852662325) assert_equal([t1], ti.transitions) end def test_timezone_strings_deduped identifier = StringDeduper.global.dedupe('Test/One') m = Module.new m.send(:include, TimezoneDefinition) m.send(:timezone, 'Test/One') do |tz| tz.offset :o0, -75, 0, 'LMT' end ti = m.get assert_same(identifier, ti.identifier) end def test_linked_timezone_strings_deduped identifier = StringDeduper.global.dedupe('Test/Linked/Zone1') link_to_identifier = StringDeduper.global.dedupe('Test/Linked_To/Zone1') m = Module.new m.send(:include, TimezoneDefinition) m.send(:linked_timezone, 'Test/Linked/Zone1', 'Test/Linked_To/Zone1') ti = m.get assert_same(identifier, ti.identifier) assert_same(link_to_identifier, ti.link_to_identifier) end def test_global_string_deduper_used_for_definer m = Module.new m.send(:include, TimezoneDefinition) block_called = 0 m.send(:timezone, 'Test/Data/Zone') do |tz| block_called += 1 assert_kind_of(TimezoneDefiner, tz) assert_same(StringDeduper.global, tz.instance_variable_get(:@string_deduper)) tz.offset :o0, -75, 0, 'LMT' end assert_equal(1, block_called) end end end tzinfo-2.0.6/test/format2/tc_timezone_index_definer.rb000066400000000000000000000041161436527530500231250ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true require_relative '../test_utils' module Format2 class TCTimezoneIndexDefiner < Minitest::Test include TZInfo include TZInfo.const_get(:Format2) def setup @string_deduper = StringDeduper.new @definer = TimezoneIndexDefiner.new(@string_deduper) end def test_mixed @definer.data_timezone 'Test/One' @definer.data_timezone 'Test/Two' @definer.linked_timezone 'Test/Three' @definer.data_timezone 'Another/Zone' @definer.linked_timezone 'And/Yet/Another' assert_array_same_items(['Another/Zone', 'Test/One', 'Test/Two'], @definer.data_timezones) assert_array_same_items(['And/Yet/Another', 'Test/Three'], @definer.linked_timezones) assert(@definer.data_timezones.all?(&:frozen?)) assert(@definer.linked_timezones.all?(&:frozen?)) end def test_data_only @definer.data_timezone 'Test/A/One' @definer.data_timezone 'Test/A/Two' @definer.data_timezone 'Test/A/Three' assert_array_same_items(['Test/A/One', 'Test/A/Two', 'Test/A/Three'], @definer.data_timezones) assert_equal([], @definer.linked_timezones) assert(@definer.data_timezones.all?(&:frozen?)) end def test_linked_only @definer.linked_timezone 'Test/B/One' @definer.linked_timezone 'Test/B/Two' @definer.linked_timezone 'Test/B/Three' assert_equal([], @definer.data_timezones) assert_array_same_items(['Test/B/One', 'Test/B/Three', 'Test/B/Two'], @definer.linked_timezones) assert(@definer.linked_timezones.all?(&:frozen?)) end def test_none assert_equal([], @definer.data_timezones) assert_equal([], @definer.linked_timezones) end def test_strings_deduped identifier = @string_deduper.dedupe('Test/A/One') linked_identifier = @string_deduper.dedupe('Test/B/One') @definer.data_timezone 'Test/A/One' @definer.linked_timezone 'Test/B/One' assert_same(identifier, @definer.data_timezones.first) assert_same(linked_identifier, @definer.linked_timezones.first) end end end tzinfo-2.0.6/test/format2/tc_timezone_index_definition.rb000066400000000000000000000075231436527530500236460ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true require_relative '../test_utils' module Format2 class TCTimezoneIndexDefinition < Minitest::Test include TZInfo include TZInfo.const_get(:Format2) def test_mixed m = Module.new m.send(:include, TimezoneIndexDefinition) m.send(:timezone_index) do |i| assert_kind_of(TimezoneIndexDefiner, i) i.data_timezone 'Test/One' i.data_timezone 'Test/Two' i.linked_timezone 'Test/Three' i.data_timezone 'Another/Zone' i.linked_timezone 'And/Yet/Another' end data_timezones = m.data_timezones assert_equal(['Another/Zone', 'Test/One', 'Test/Two'], data_timezones) assert(data_timezones.frozen?) assert(data_timezones.all?(&:frozen?)) assert_same(data_timezones, m.data_timezones) linked_timezones = m.linked_timezones assert_equal(['And/Yet/Another', 'Test/Three'], linked_timezones) assert(linked_timezones.frozen?) assert(linked_timezones.all?(&:frozen?)) assert_same(linked_timezones, m.linked_timezones) end def test_data_only m = Module.new m.send(:include, TimezoneIndexDefinition) m.send(:timezone_index) do |i| assert_kind_of(TimezoneIndexDefiner, i) i.data_timezone 'Test/A/One' i.data_timezone 'Test/A/Two' i.data_timezone 'Test/A/Three' end data_timezones = m.data_timezones assert_equal(['Test/A/One', 'Test/A/Three', 'Test/A/Two'], data_timezones) assert(data_timezones.frozen?) assert(data_timezones.all?(&:frozen?)) assert_same(data_timezones, m.data_timezones) linked_timezones = m.linked_timezones assert_equal([], linked_timezones) assert(linked_timezones.frozen?) assert_same(linked_timezones, m.linked_timezones) end def test_linked_only m = Module.new m.send(:include, TimezoneIndexDefinition) m.send(:timezone_index) do |i| assert_kind_of(TimezoneIndexDefiner, i) i.linked_timezone 'Test/B/One' i.linked_timezone 'Test/B/Two' i.linked_timezone 'Test/B/Three' end data_timezones = m.data_timezones assert_equal([], data_timezones) assert(data_timezones.frozen?) assert_same(data_timezones, m.data_timezones) linked_timezones = m.linked_timezones assert_equal(['Test/B/One', 'Test/B/Three', 'Test/B/Two'], linked_timezones) assert(linked_timezones.frozen?) assert(linked_timezones.all?(&:frozen?)) assert_same(linked_timezones, m.linked_timezones) end def test_none m = Module.new m.send(:include, TimezoneIndexDefinition) m.send(:timezone_index) do |i| assert_kind_of(TimezoneIndexDefiner, i) end data_timezones = m.data_timezones assert_equal([], data_timezones) assert(data_timezones.frozen?) assert_same(data_timezones, m.data_timezones) linked_timezones = m.linked_timezones assert_equal([], linked_timezones) assert(linked_timezones.frozen?) assert_same(linked_timezones, m.linked_timezones) end def test_not_defined m = Module.new m.send(:include, TimezoneIndexDefinition) data_timezones = m.data_timezones assert_equal([], data_timezones) assert(data_timezones.frozen?) assert_same(data_timezones, m.data_timezones) linked_timezones = m.linked_timezones assert_equal([], linked_timezones) assert(linked_timezones.frozen?) assert_same(linked_timezones, m.linked_timezones) end def test_global_string_deduper_used_for_definer m = Module.new m.send(:include, TimezoneIndexDefinition) m.send(:timezone_index) do |i| assert_kind_of(TimezoneIndexDefiner, i) assert_same(StringDeduper.global, i.instance_variable_get(:@string_deduper)) end end end end tzinfo-2.0.6/test/tc_annual_rules.rb000066400000000000000000000057371436527530500175400ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true require_relative 'test_utils' class TCAnnualRules < Minitest::Test include TZInfo def test_initialize std_offset = TimezoneOffset.new(0, 0, 'GMT') dst_offset = TimezoneOffset.new(0, 3600, 'BST') dst_start_rule = FakeAlwaysDateAdjustmentRule.new(3, 1) dst_end_rule = FakeAlwaysDateAdjustmentRule.new(10, 1) rules = AnnualRules.new(std_offset, dst_offset, dst_start_rule, dst_end_rule) assert_same(std_offset, rules.std_offset) assert_same(dst_offset, rules.dst_offset) assert_same(dst_start_rule, rules.dst_start_rule) assert_same(dst_end_rule, rules.dst_end_rule) end [2020, 2021].each do |year| define_method "test_transitions_for_dst_mid_year_#{year}" do std_offset = TimezoneOffset.new(3600, 0, 'TEST') dst_offset = TimezoneOffset.new(3600, 3600, 'TESTS') rules = AnnualRules.new( std_offset, dst_offset, FakeAlwaysDateAdjustmentRule.new(3, 21), FakeAlwaysDateAdjustmentRule.new(10, 22) ) result = rules.transitions(year) expected = [ TimezoneTransition.new(dst_offset, std_offset, Time.new(year, 3, 21, 0, 0, 0, 3600).to_i), TimezoneTransition.new(std_offset, dst_offset, Time.new(year, 10, 22, 0, 0, 0, 7200).to_i) ] assert_equal(expected, result) end define_method "test_transitions_for_dst_start_and_end_of_year_#{year}" do std_offset = TimezoneOffset.new(3600, 0, 'TEST') dst_offset = TimezoneOffset.new(3600, 3600, 'TESTS') rules = AnnualRules.new( std_offset, dst_offset, FakeAlwaysDateAdjustmentRule.new(10, 22), FakeAlwaysDateAdjustmentRule.new(3, 21) ) result = rules.transitions(year) expected = [ TimezoneTransition.new(std_offset, dst_offset, Time.new(year, 3, 21, 0, 0, 0, 7200).to_i), TimezoneTransition.new(dst_offset, std_offset, Time.new(year, 10, 22, 0, 0, 0, 3600).to_i) ] assert_equal(expected, result) end define_method "test_transitions_for_negative_dst_start_and_end_of_year_#{year}" do std_offset = TimezoneOffset.new(7200, 0, 'TEST') dst_offset = TimezoneOffset.new(7200, -3600, 'TESTW') rules = AnnualRules.new( std_offset, dst_offset, FakeAlwaysDateAdjustmentRule.new(10, 22), FakeAlwaysDateAdjustmentRule.new(3, 21) ) result = rules.transitions(year) expected = [ TimezoneTransition.new(std_offset, dst_offset, Time.new(year, 3, 21, 0, 0, 0, 3600).to_i), TimezoneTransition.new(dst_offset, std_offset, Time.new(year, 10, 22, 0, 0, 0, 7200).to_i) ] assert_equal(expected, result) end end class FakeAlwaysDateAdjustmentRule def initialize(month, day) @month = month @day = day end def at(offset, year) TZInfo::TimestampWithOffset.for(Time.new(year, @month, @day, 0, 0, 0, offset.observed_utc_offset)).set_timezone_offset(offset) end end end tzinfo-2.0.6/test/tc_country.rb000066400000000000000000000135671436527530500165530ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true require_relative 'test_utils' class TCCountry < Minitest::Test include TZInfo def setup @orig_data_source = DataSource.get end def teardown DataSource.set(@orig_data_source) end test_encodings('ISO-8859-1', 'UTF-8', 'UTF-16').each do |encoding| define_method("test_get_valid_with_#{encoding.to_method}_encoded_code") do c = Country.get('GB'.encode(encoding.name)) refute_nil(c) assert_equal('GB', c.code) end define_method("test_get_not_exist_with_#{encoding.to_method}_encoded_code") do error = assert_raises(InvalidCountryCode) { Country.get('ZZ'.encode(encoding.name)) } assert_match(/\bZZ\b/, error.message) end define_method("test_get_invalid_with_#{encoding.to_method}_encoded_code") do error = assert_raises(InvalidCountryCode) { Country.get('../Countries/GB'.encode(encoding.name)) } assert_match(/\W\.\.\/Countries\/GB\b/, error.message) end define_method("test_get_case_with_#{encoding.to_method}_encoded_code") do error = assert_raises(InvalidCountryCode) { Country.get('gb'.encode(encoding.name)) } assert_match(/\bgb\b/, error.message) end end def test_get_nil error = assert_raises(InvalidCountryCode) { Country.get(nil) } assert_match(/\bnil\b/, error.message) end def test_get_tainted_loaded skip_if_taint_is_undefined_or_no_op Country.get('GB') safe_test(unavailable: :skip) do code = 'GB'.dup.taint assert(code.tainted?) country = Country.get(code) assert_equal('GB', country.code) assert(code.tainted?) end end def test_get_tainted_and_frozen_loaded skip_if_taint_is_undefined_or_no_op Country.get('GB') safe_test do country = Country.get('GB'.dup.taint.freeze) assert_equal('GB', country.code) end end def test_get_tainted_not_previously_loaded skip_if_taint_is_undefined_or_no_op safe_test(unavailable: :skip) do code = 'GB'.dup.taint assert(code.tainted?) country = Country.get(code) assert_equal('GB', country.code) assert(code.tainted?) end end def test_get_tainted_and_frozen_not_previously_loaded skip_if_taint_is_undefined_or_no_op safe_test do country = Country.get('GB'.dup.taint.freeze) assert_equal('GB', country.code) end end def test_all_codes assert_equal(DataSource.get.country_codes, Country.all_codes) end def test_all assert_equal(Country.all_codes, Country.all.collect(&:code)) end def test_initialize info = DataSources::CountryInfo.new('TT', 'Test', []) c = Country.new(info) assert_equal('TT', c.code) assert_equal('Test', c.name) assert_equal([], c.zones) end def test_code assert_equal('US', Country.get('US').code) end def test_name assert_equal('United States', Country.get('US').name) end def test_to_s assert_equal(Country.get('US').name, Country.get('US').to_s) assert_equal(Country.get('GB').name, Country.get('GB').to_s) end def test_inspect assert_equal('#', Country.get('GB').inspect) end def test_zone_identifiers zone_identifiers = Country.get('US').zone_identifiers assert_equal(DataSource.get.get_country_info('US').zones.map(&:identifier), zone_identifiers) end def test_zone_names assert_equal(Country.get('US').zone_identifiers, Country.get('US').zone_names) end def test_zones zones = Country.get('US').zones assert_kind_of(Array, zones) assert_equal(Country.get('US').zone_identifiers, zones.collect(&:identifier)) zones.each {|z| assert_kind_of(TimezoneProxy, z)} end def test_zone_info zone_info = Country.get('US').zone_info assert_equal(DataSource.get.get_country_info('US').zones, zone_info) assert_equal(true, zone_info.frozen?) end def test_compare assert_equal(0, Country.get('GB') <=> Country.get('GB')) assert_equal(-1, Country.get('GB') <=> Country.get('US')) assert_equal(1, Country.get('US') <=> Country.get('GB')) assert_equal(-1, Country.get('FR') <=> Country.get('US')) assert_equal(1, Country.get('US') <=> Country.get('FR')) end def test_compare_non_comparable assert_nil(Country.get('GB') <=> Object.new) end def test_equality assert_equal(true, Country.get('GB') == Country.get('GB')) assert_equal(false, Country.get('GB') == Country.get('US')) assert(!(Country.get('GB') == Object.new)) end def test_eql assert_equal(true, Country.get('GB').eql?(Country.get('GB'))) assert_equal(false, Country.get('GB').eql?(Country.get('US'))) assert(!Country.get('GB').eql?(Object.new)) end def test_hash assert_equal('GB'.hash, Country.get('GB').hash) assert_equal('US'.hash, Country.get('US').hash) end define_method("test_=~_operator_matches_against_code") do c = Country.get('GB') assert_equal(0, c =~ /\AGB\z/) assert_equal(1, c =~ /B/) end define_method("test_=~_operator_returns_nil_when_regexp_does_not_match") do c = Country.get('GB') assert_nil(c =~ /US/) end def test_marshal c = Country.get('US') marshalled_c = Marshal.load(Marshal.dump(c)) assert_kind_of(Country, marshalled_c) assert_equal('US', marshalled_c.code) end def test_get_missing_data_source DataSource.set(DataSource.new) error = assert_raises(InvalidDataSource) do Country.get('GB') end assert_equal('load_country_info not defined', error.message) end def test_all_codes_missing_data_source DataSource.set(DataSource.new) error = assert_raises(InvalidDataSource) do Country.all_codes end assert_equal('country_codes not defined', error.message) end def test_all_missing_data_source DataSource.set(DataSource.new) error = assert_raises(InvalidDataSource) do Country.all end assert_equal('country_codes not defined', error.message) end end tzinfo-2.0.6/test/tc_country_timezone.rb000066400000000000000000000117361436527530500204610ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true require_relative 'test_utils' class TCCountryTimezone < Minitest::Test include TZInfo def test_identifier ct = CountryTimezone.new('Europe/London', Rational(2059, 40), Rational(-5, 16)) assert_equal('Europe/London', ct.identifier) assert(ct.identifier.frozen?) end def test_latitude ct = CountryTimezone.new('Europe/London', Rational(2059, 40), Rational(-5, 16)) assert_equal(Rational(2059, 40), ct.latitude) end def test_longitude ct = CountryTimezone.new('Europe/London', Rational(2059, 40), Rational(-5, 16)) assert_equal(Rational(-5, 16), ct.longitude) end def test_default_description ct = CountryTimezone.new('Europe/London', Rational(2059, 40), Rational(-5, 16)) assert_nil(ct.description) end def test_nil_description nil_frozen = nil.frozen? ct = CountryTimezone.new('Europe/London', Rational(2059, 40), Rational(-5, 16), nil) assert_nil(ct.description) # nil is frozen by default from Ruby 2.2.0. Check that CountryTimezone.new # didn't freeze nil on earlier Ruby versions. assert_equal(nil_frozen, nil.frozen?) end def test_description ct = CountryTimezone.new('America/New_York', Rational(48857, 1200), Rational(-266423, 3600), 'Eastern Time') assert_equal('Eastern Time', ct.description) assert(ct.description.frozen?) end def test_timezone ct = CountryTimezone.new('Europe/London', Rational(2059, 40), Rational(-5, 16)) assert_kind_of(TimezoneProxy, ct.timezone) assert_equal('Europe/London', ct.timezone.identifier) end def test_description_or_friendly_idenfier_no_description ct = CountryTimezone.new('Europe/London', Rational(2059, 40), Rational(-5, 16)) assert_equal('London', ct.description_or_friendly_identifier) end def test_description_or_friendly_idenfier_description ct = CountryTimezone.new('America/New_York', Rational(48857, 1200), Rational(-266423, 3600), 'Eastern Time') assert_equal('Eastern Time', ct.description_or_friendly_identifier) end def test_equality_1 ct1 = CountryTimezone.new('Europe/London', Rational(2059, 40), Rational(-5, 16)) ct2 = CountryTimezone.new('Europe/London', Rational(2059, 40), Rational(-5, 16)) ct3 = CountryTimezone.new('Europe/London', Rational(2059, 40), Rational(-5, 16), 'Description') ct4 = CountryTimezone.new('Europe/LondonB', Rational(2059, 40), Rational(-5, 16)) ct5 = CountryTimezone.new('Europe/London', Rational(2060, 40), Rational(-5, 16)) ct6 = CountryTimezone.new('Europe/London', Rational(2059, 40), Rational(-6, 16)) assert_equal(true, ct1 == ct1) assert_equal(true, ct1 == ct2) assert_equal(false, ct1 == ct3) assert_equal(false, ct1 == ct4) assert_equal(false, ct1 == ct5) assert_equal(false, ct1 == ct6) end def test_equality_2 ct1 = CountryTimezone.new('America/New_York', Rational(48857, 1200), Rational(-266423, 3600), 'Eastern Time') ct2 = CountryTimezone.new('America/New_York', Rational(48857, 1200), Rational(-266423, 3600), 'Eastern Time2') assert_equal(true, ct1 == ct1) assert_equal(false, ct1 == ct2) end def test_equality_non_country_timezone ct = CountryTimezone.new('Europe/London', Rational(2059, 40), Rational(-5, 16)) assert_equal(false, ct == Object.new) end def test_eql_1 ct1 = CountryTimezone.new('Europe/London', Rational(2059, 40), Rational(-5, 16)) ct2 = CountryTimezone.new('Europe/London', Rational(2059, 40), Rational(-5, 16)) ct3 = CountryTimezone.new('Europe/London', Rational(2059, 40), Rational(-5, 16), 'Description') ct4 = CountryTimezone.new('Europe/LondonB', Rational(2059, 40), Rational(-5, 16)) ct5 = CountryTimezone.new('Europe/London', Rational(2060, 40), Rational(-5, 16)) ct6 = CountryTimezone.new('Europe/London', Rational(2059, 40), Rational(-6, 16)) assert_equal(true, ct1.eql?(ct1)) assert_equal(true, ct1.eql?(ct2)) assert_equal(false, ct1.eql?(ct3)) assert_equal(false, ct1.eql?(ct4)) assert_equal(false, ct1.eql?(ct5)) assert_equal(false, ct1.eql?(ct6)) end def test_eql_2 ct1 = CountryTimezone.new('America/New_York', Rational(48857, 1200), Rational(-266423, 3600), 'Eastern Time') ct2 = CountryTimezone.new('America/New_York', Rational(48857, 1200), Rational(-266423, 3600), 'Eastern Time2') assert_equal(true, ct1.eql?(ct1)) assert_equal(false, ct1.eql?(ct2)) end def test_eql_non_country_timezone ct = CountryTimezone.new('Europe/London', Rational(2059, 40), Rational(-5, 16)) assert_equal(false, ct.eql?(Object.new)) end def test_hash_new ct1 = CountryTimezone.new('Europe/London', Rational(2059, 40), Rational(-5, 16)) ct2 = CountryTimezone.new('America/New_York', Rational(48857, 1200), Rational(-266423, 3600), 'Eastern Time') assert_equal(['Europe/London', Rational(2059, 40), Rational(-5, 16), nil].hash, ct1.hash) assert_equal(['America/New_York', Rational(48857, 1200), Rational(-266423, 3600), 'Eastern Time'].hash, ct2.hash) end end tzinfo-2.0.6/test/tc_data_source.rb000066400000000000000000000465131436527530500173360ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true require_relative 'test_utils' require 'tmpdir' class TCDataSource < Minitest::Test include TZInfo class InitDataSource < DataSource end class DummyDataSource < DataSource end class TestDataSource < DataSource attr_reader :called def initialize super @called = 0 end end class GetTimezoneInfoTestDataSource < TestDataSource include TZInfo protected def load_timezone_info(identifier) @called += 1 raise InvalidTimezoneIdentifier, identifier if identifier == 'Test/Invalid' DataSources::TimezoneInfo.new(identifier) end end class GetCountryInfoTestDataSource < TestDataSource include TZInfo protected def load_country_info(code) @called += 1 raise InvalidCountryCode, code if code == 'XX' DataSources::CountryInfo.new(code, "Country #{code}", []) end end class GetTimezoneIdentifiersTestDataSource < DataSource attr_reader :data_timezone_identifiers_called attr_reader :linked_timezone_identifiers_called def initialize(data_timezone_identifiers, linked_timezone_identifiers) @data_timezone_identifiers = data_timezone_identifiers.each(&:freeze).freeze @linked_timezone_identifiers = linked_timezone_identifiers.each(&:freeze).freeze @data_timezone_identifiers_called = 0 @linked_timezone_identifiers_called = 0 end def data_timezone_identifiers @data_timezone_identifiers_called += 1 @data_timezone_identifiers end def linked_timezone_identifiers @linked_timezone_identifiers_called += 1 @linked_timezone_identifiers end end class ValidateTimezoneIdentifierTestDataSource < DataSource attr_reader :data_timezone_identifiers attr_reader :linked_timezone_identifiers attr_reader :timezone_identifier_encoding def initialize(data_timezone_identifiers, linked_timezone_identifiers, timezone_identifier_encoding = Encoding::UTF_8) super() @data_timezone_identifiers = data_timezone_identifiers.sort.freeze @linked_timezone_identifiers = linked_timezone_identifiers.sort.freeze @timezone_identifier_encoding = timezone_identifier_encoding end def call_validate_timezone_identifier(identifier) validate_timezone_identifier(identifier) end end class LookupCountryInfoTestDataSource < DataSource def call_lookup_country_info(hash, code, encoding = Encoding::UTF_8) lookup_country_info(hash, code, encoding) end end class EagerLoadTestDataSource < GetTimezoneIdentifiersTestDataSource include TZInfo attr_reader :country_codes_called attr_reader :loaded_timezones attr_reader :loaded_countries def initialize(data_timezone_identifiers, linked_timezone_identifiers, country_codes) super(data_timezone_identifiers, linked_timezone_identifiers) @country_codes = country_codes @country_codes_called = 0 @loaded_timezones = [] @loaded_countries = [] end protected def country_codes @country_codes_called += 1 @country_codes end def load_timezone_info(identifier) @loaded_timezones << identifier DataSources::TimezoneInfo.new(identifier) end def load_country_info(code) @loaded_countries << code DataSources::CountryInfo.new(code, "Country #{code}", []) end end def setup @orig_data_source = DataSource.get DataSource.set(InitDataSource.new) @orig_search_path = DataSources::ZoneinfoDataSource.search_path.clone end def teardown DataSource.set(@orig_data_source) DataSources::ZoneinfoDataSource.search_path = @orig_search_path end def test_get data_source = DataSource.get assert_kind_of(InitDataSource, data_source) end def test_get_default_ruby_only code = <<-EOF require 'tmpdir' begin Dir.mktmpdir('tzinfo_test_dir') do |dir| TZInfo::DataSources::ZoneinfoDataSource.search_path = [dir] puts TZInfo::DataSource.get.class end rescue Exception => e puts "Unexpected exception: \#{e}" end EOF assert_sub_process_returns(['TZInfo::DataSources::RubyDataSource'], code, [TZINFO_TEST_DATA_DIR]) end def test_get_default_zoneinfo_only code = <<-EOF require 'tmpdir' begin Dir.mktmpdir('tzinfo_test_dir') do |dir| TZInfo::DataSources::ZoneinfoDataSource.search_path = [dir, '#{TZINFO_TEST_ZONEINFO_DIR}'] puts TZInfo::DataSource.get.class puts TZInfo::DataSource.get.zoneinfo_dir end rescue Exception => e puts "Unexpected exception: \#{e}" end EOF assert_sub_process_returns( ['TZInfo::DataSources::ZoneinfoDataSource', TZINFO_TEST_ZONEINFO_DIR], code) end def test_get_default_ruby_and_zoneinfo code = <<-EOF begin TZInfo::DataSources::ZoneinfoDataSource.search_path = ['#{TZINFO_TEST_ZONEINFO_DIR}'] puts TZInfo::DataSource.get.class rescue Exception => e puts "Unexpected exception: \#{e}" end EOF assert_sub_process_returns(['TZInfo::DataSources::RubyDataSource'], code, [TZINFO_TEST_DATA_DIR]) end def test_get_default_no_data code = <<-EOF require 'tmpdir' begin Dir.mktmpdir('tzinfo_test_dir') do |dir| TZInfo::DataSources::ZoneinfoDataSource.search_path = [dir] begin data_source = TZInfo::DataSource.get puts "No exception raised, returned \#{data_source} instead" rescue Exception => e puts e.class end end rescue Exception => e puts "Unexpected exception: \#{e}" end EOF assert_sub_process_returns(['TZInfo::DataSourceNotFound'], code) end def test_set_instance DataSource.set(DummyDataSource.new) data_source = DataSource.get assert_kind_of(DummyDataSource, data_source) end def test_set_standard_ruby DataSource.set(:ruby) data_source = DataSource.get assert_kind_of(DataSources::RubyDataSource, data_source) end def test_set_standard_ruby_not_found code = <<-EOF begin TZInfo::DataSources::RubyDataSource.set(:ruby) puts 'No exception raised' rescue Exception => e puts e.class puts e.message end EOF assert_sub_process_returns([ 'TZInfo::DataSources::TZInfoDataNotFound', 'The tzinfo-data gem could not be found (require \'tzinfo/data\' failed).'], code) end def test_set_standard_zoneinfo_search Dir.mktmpdir('tzinfo_test_dir') do |dir| FileUtils.touch(File.join(dir, 'iso3166.tab')) FileUtils.touch(File.join(dir, 'zone.tab')) DataSources::ZoneinfoDataSource.search_path = [dir] DataSource.set(:zoneinfo) data_source = DataSource.get assert_kind_of(DataSources::ZoneinfoDataSource, data_source) assert_equal(dir, data_source.zoneinfo_dir) end end def test_set_standard_zoneinfo_search_zone1970 Dir.mktmpdir('tzinfo_test_dir') do |dir| FileUtils.touch(File.join(dir, 'iso3166.tab')) FileUtils.touch(File.join(dir, 'zone1970.tab')) DataSources::ZoneinfoDataSource.search_path = [dir] DataSource.set(:zoneinfo) data_source = DataSource.get assert_kind_of(DataSources::ZoneinfoDataSource, data_source) assert_equal(dir, data_source.zoneinfo_dir) end end def test_set_standard_zoneinfo_explicit Dir.mktmpdir('tzinfo_test_dir') do |dir| FileUtils.touch(File.join(dir, 'iso3166.tab')) FileUtils.touch(File.join(dir, 'zone.tab')) DataSource.set(:zoneinfo, dir) data_source = DataSource.get assert_kind_of(DataSources::ZoneinfoDataSource, data_source) assert_equal(dir, data_source.zoneinfo_dir) end end def test_set_standard_zoneinfo_explicit_zone1970 Dir.mktmpdir('tzinfo_test_dir') do |dir| FileUtils.touch(File.join(dir, 'iso3166.tab')) FileUtils.touch(File.join(dir, 'zone.tab')) DataSource.set(:zoneinfo, dir) data_source = DataSource.get assert_kind_of(DataSources::ZoneinfoDataSource, data_source) assert_equal(dir, data_source.zoneinfo_dir) end end def test_set_standard_zoneinfo_explicit_alternate_iso3166 Dir.mktmpdir('tzinfo_test_dir') do |dir| zoneinfo_dir = File.join(dir, 'zoneinfo') tab_dir = File.join(dir, 'tab') FileUtils.mkdir(zoneinfo_dir) FileUtils.mkdir(tab_dir) FileUtils.touch(File.join(zoneinfo_dir, 'zone.tab')) iso3166_file = File.join(tab_dir, 'iso3166.tab') FileUtils.touch(iso3166_file) DataSource.set(:zoneinfo, zoneinfo_dir, iso3166_file) data_source = DataSource.get assert_kind_of(DataSources::ZoneinfoDataSource, data_source) assert_equal(zoneinfo_dir, data_source.zoneinfo_dir) end end def test_set_standard_zoneinfo_search_not_found Dir.mktmpdir('tzinfo_test_dir') do |dir| DataSources::ZoneinfoDataSource.search_path = [dir] error = assert_raises(DataSources::ZoneinfoDirectoryNotFound) do DataSource.set(:zoneinfo) end assert_equal('None of the paths included in TZInfo::DataSources::ZoneinfoDataSource.search_path are valid zoneinfo directories.', error.message) assert_kind_of(InitDataSource, DataSource.get) end end def test_set_standard_zoneinfo_explicit_invalid Dir.mktmpdir('tzinfo_test_dir') do |dir| error = assert_raises(DataSources::InvalidZoneinfoDirectory) do DataSource.set(:zoneinfo, dir) end assert_equal("#{dir} is not a directory or doesn't contain a iso3166.tab file and a zone1970.tab or zone.tab file.", error.message) assert_kind_of(InitDataSource, DataSource.get) end end def test_set_standard_zoneinfo_wrong_arg_count assert_raises(ArgumentError) do DataSource.set(:zoneinfo, 1, 2, 3) end assert_kind_of(InitDataSource, DataSource.get) end def test_set_invalid_datasource_type error = assert_raises(ArgumentError) { DataSource.set(:other) } assert_equal('data_source_or_type must be a DataSource instance or a data source type (:ruby or :zoneinfo)', error.message) end def test_set_not_a_datasource error = assert_raises(ArgumentError) { DataSource.set(Object.new) } assert_equal('data_source_or_type must be a DataSource instance or a data source type (:ruby or :zoneinfo)', error.message) end def test_get_timezone_info ds = GetTimezoneInfoTestDataSource.new info = ds.get_timezone_info('Test/Simple') assert_equal('Test/Simple', info.identifier) assert_equal(1, ds.called) end def test_get_timezone_info_caches_result ds = GetTimezoneInfoTestDataSource.new info = ds.get_timezone_info('Test/Cache') assert_equal('Test/Cache', info.identifier) assert_same(info, ds.get_timezone_info('Test/Cache')) assert_equal(1, ds.called) end def test_get_timezone_info_invalid_identifier ds = GetTimezoneInfoTestDataSource.new error = assert_raises(InvalidTimezoneIdentifier) { ds.get_timezone_info('Test/Invalid') } assert_equal('Test/Invalid', error.message) assert(1, ds.called) end def test_timezone_identifiers data_identifiers = ['Test/Aaa', 'Test/Ccc'] linked_identifiers = ['Test/Bbb'] ds = GetTimezoneIdentifiersTestDataSource.new(data_identifiers, linked_identifiers) result = ds.timezone_identifiers assert_kind_of(Array, result) assert_equal(['Test/Aaa', 'Test/Bbb', 'Test/Ccc'], result) assert_same(data_identifiers[0], result[0]) assert_same(linked_identifiers[0], result[1]) assert_same(data_identifiers[1], result[2]) assert(result.frozen?) assert(result.all?(&:frozen?)) assert_equal(1, ds.data_timezone_identifiers_called) assert_equal(1, ds.linked_timezone_identifiers_called) end def test_timezone_identifiers_caches_result ds = GetTimezoneIdentifiersTestDataSource.new(['Test/Aaa', 'Test/Ccc'], ['Test/Bbb']) result = ds.timezone_identifiers assert_same(result, ds.timezone_identifiers) assert_equal(1, ds.data_timezone_identifiers_called) assert_equal(1, ds.linked_timezone_identifiers_called) end def test_timezone_identifiers_returns_data_array_if_linked_is_empty data_identifiers = ['Test/Aaa', 'Test/Ccc'] ds = GetTimezoneIdentifiersTestDataSource.new(data_identifiers, []) result = ds.timezone_identifiers assert_same(data_identifiers, result) assert_equal(1, ds.data_timezone_identifiers_called) assert_equal(1, ds.linked_timezone_identifiers_called) end def test_timezone_identifiers_caches_result_if_linked_is_empty data_identifiers = ['Test/Aaa', 'Test/Ccc'] ds = GetTimezoneIdentifiersTestDataSource.new(data_identifiers, []) result = ds.timezone_identifiers assert_same(data_identifiers, result) assert_same(data_identifiers, ds.timezone_identifiers) assert_equal(1, ds.data_timezone_identifiers_called) assert_equal(1, ds.linked_timezone_identifiers_called) end def abstract_test(method, public, *args) ds = DataSource.new error = assert_raises(InvalidDataSource) { ds.public_send(*([public ? :public_send : :send, method] + args)) } assert_equal("#{method} not defined", error.message) end def test_data_timezone_identifiers abstract_test(:data_timezone_identifiers, true) end def test_linked_timezone_identifiers abstract_test(:linked_timezone_identifiers, true) end def test_get_country_info ds = GetCountryInfoTestDataSource.new info = ds.get_country_info('CC') assert_equal('CC', info.code) assert_equal(1, ds.called) end def test_get_country_info_invalid_identifier ds = GetCountryInfoTestDataSource.new error = assert_raises(InvalidCountryCode) { ds.get_country_info('XX') } assert_equal('XX', error.message) assert_equal(1, ds.called) end def test_country_codes abstract_test(:country_codes, true) end def test_to_s assert_equal('Default DataSource', DataSource.new.to_s) end def test_inspect assert_equal('#', TestDataSource.new.inspect) end def test_load_timezone_info abstract_test(:load_timezone_info, false, 'Test/Identifier') end def test_load_country_info abstract_test(:load_country_info, false, 'CC') end def test_validate_timezone_identifier data_identifiers = ['Test/One', 'Test/Two', 'Test/Three'] linked_identifiers = ['Test/Four', 'Test/Five'] ds = ValidateTimezoneIdentifierTestDataSource.new(data_identifiers, linked_identifiers) [data_identifiers, linked_identifiers].each do |identifiers| identifiers.each do |identifier| assert_same(identifier, ds.call_validate_timezone_identifier(identifier.dup)) end end ['Test/Invalid', 'Invalid/Test', 'TST'].each do |identifier| error = assert_raises(InvalidTimezoneIdentifier) { ds.call_validate_timezone_identifier(identifier) } assert_match(Regexp.new("\\b#{Regexp.escape(identifier)}\\b"), error.message) end error = assert_raises(InvalidTimezoneIdentifier) { ds.call_validate_timezone_identifier(nil) } assert_match(/\bnil\b/, error.message) error = assert_raises(InvalidTimezoneIdentifier) { ds.call_validate_timezone_identifier(false) } assert_match(/\bfalse\b/, error.message) end test_encodings('UTF-8', 'UTF-16', 'ISO-8859-1') do |identifier_encoding| test_encodings('UTF-8', 'UTF-16', 'ISO-8859-1') do |index_encoding| define_method("test_validate_timezone_identifier_with_#{index_encoding.to_method}_encoded_index_and_#{identifier_encoding.to_method}_encoded_identifier") do data_identifiers = ['Test/One'.encode(index_encoding.name).freeze] ds = ValidateTimezoneIdentifierTestDataSource.new(data_identifiers, [], index_encoding.find) assert_same(data_identifiers[0], ds.call_validate_timezone_identifier('Test/One'.encode(identifier_encoding.name).freeze)) end end define_method("test_validate_timezone_identifier_with_invalid_#{identifier_encoding.to_method}_encoded_identifier") do data_identifiers = ['Test/One'.freeze] linked_identifiers = ['Test/Two'.freeze] ds = ValidateTimezoneIdentifierTestDataSource.new(data_identifiers, linked_identifiers) encoded_identifier = 'Test/Invalid'.encode(identifier_encoding.name).freeze error = assert_raises(InvalidTimezoneIdentifier) { ds.call_validate_timezone_identifier(encoded_identifier) } assert_match(/\bTest\/Invalid\b/, error.message) assert_equal(Encoding::UTF_8, error.message.encoding) end end def test_lookup_country_info ds = LookupCountryInfoTestDataSource.new hash = {'GB' => Object.new} info = ds.call_lookup_country_info(hash, 'GB') assert_same(hash['GB'], info) end def test_lookup_country_info_not_exist ds = LookupCountryInfoTestDataSource.new hash = {'GB' => Object.new} error = assert_raises(InvalidCountryCode) do ds.call_lookup_country_info(hash, 'ZZ') end assert_match(/\bZZ\b/, error.message) end def test_lookup_country_info_nil ds = LookupCountryInfoTestDataSource.new hash = {'GB' => Object.new} error = assert_raises(InvalidCountryCode) do ds.call_lookup_country_info(hash, nil) end assert_match(/\bnil\b/, error.message) end def test_lookup_country_info_false ds = LookupCountryInfoTestDataSource.new hash = {'GB' => Object.new} error = assert_raises(InvalidCountryCode) do ds.call_lookup_country_info(hash, false) end assert_match(/\bfalse\b/, error.message) end def test_lookup_country_info_case ds = LookupCountryInfoTestDataSource.new hash = {'GB' => Object.new} error = assert_raises(InvalidCountryCode) do ds.call_lookup_country_info(hash, 'gb') end assert_match(/\bgb\b/, error.message) end test_encodings('UTF-8', 'UTF-16', 'ISO-8859-1') do |code_encoding| test_encodings('UTF-8', 'UTF-16', 'ISO-8859-1') do |index_encoding| define_method("test_lookup_country_info_with_#{index_encoding.to_method}_encoded_index_and_#{code_encoding.to_method}_encoded_identifier") do ds = LookupCountryInfoTestDataSource.new info = Object.new hash = {'GB'.encode(index_encoding).freeze => info} assert_same(info, ds.call_lookup_country_info(hash, 'GB'.encode(code_encoding.name).freeze, index_encoding.find)) end end define_method("test_lookup_country_info_with_invalid_#{code_encoding.to_method}_encoded_identifier") do ds = LookupCountryInfoTestDataSource.new hash = {} error = assert_raises(InvalidCountryCode) { ds.call_lookup_country_info(hash, 'ZZ'.encode(code_encoding.name).freeze) } assert_match(/\bZZ\b/, error.message) assert_equal(Encoding::UTF_8, error.message.encoding) end end def test_eager_load data_timezone_identifiers = ['Data/Zone1', 'Data/Zone2'] linked_timezone_identifiers = ['Linked/Zone1', 'Linked/Zone2'] all_timezone_identifiers = data_timezone_identifiers + linked_timezone_identifiers country_codes = ['AA', 'BB', 'CC'] ds = EagerLoadTestDataSource.new(data_timezone_identifiers, linked_timezone_identifiers, country_codes) assert_nil(ds.eager_load!) assert_equal(1, ds.data_timezone_identifiers_called) assert_equal(1, ds.linked_timezone_identifiers_called) assert_equal(all_timezone_identifiers, ds.loaded_timezones) assert_equal(all_timezone_identifiers, ds.instance_variable_get(:@timezone_identifiers)) assert_equal(1, ds.country_codes_called) assert_equal(country_codes, ds.loaded_countries) end end tzinfo-2.0.6/test/tc_data_timezone.rb000066400000000000000000000323131436527530500176610ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true require_relative 'test_utils' class TCDataTimezone < Minitest::Test include TZInfo class TestTimezoneInfo < DataSources::TimezoneInfo attr_reader :timestamp attr_reader :local_timestamp attr_reader :to_timestamp attr_reader :from_timestamp def initialize(identifier, period_for_result, periods_for_local_result, transitions_up_to_result) super(identifier) @period_for_result = period_for_result @periods_for_local_result = periods_for_local_result || [] @transitions_up_to_result = transitions_up_to_result end def period_for(timestamp) raise ArgumentError, 'timestamp must be specified' unless timestamp raise ArgumentError, 'timestamp must have a specified utc_offset' unless timestamp.utc_offset @timestamp = timestamp @period_for_result end def periods_for_local(local_timestamp) raise ArgumentError, 'local_timestamp must be specified' unless local_timestamp raise ArgumentError, 'local_timestamp must have an unspecified utc_offset' if local_timestamp.utc_offset @local_timestamp = local_timestamp @periods_for_local_result end def transitions_up_to(to_timestamp, from_timestamp = nil) raise ArgumentError, 'to_timestamp must be specified' unless to_timestamp raise ArgumentError, 'to_timestamp must have a specified utc_offset' unless to_timestamp.utc_offset if from_timestamp raise ArgumentError, 'from_timestamp must have a specified utc_offset' unless from_timestamp.utc_offset raise ArgumentError, 'to_timestamp must be greater than from_timestamp' if to_timestamp <= from_timestamp end @to_timestamp = to_timestamp @from_timestamp = from_timestamp @transitions_up_to_result end end def test_identifier tz = DataTimezone.new(TestTimezoneInfo.new('Test/Zone', nil, [], [])) assert_equal('Test/Zone', tz.identifier) end def test_period_for time_types_test(:utc) do |h| # Don't need actual TimezonePeriods. DataTimezone isn't supposed to do # anything with them apart from return them. period = Object.new tti = TestTimezoneInfo.new('Test/Zone', period, [], []) tz = DataTimezone.new(tti) assert_same(period, tz.period_for(h.time(2006, 6, 27, 22, 50, 12, Rational(1,10), :utc))) assert_equal_with_offset(Timestamp.create(2006, 6, 27, 22, 50, 12, Rational(1,10), :utc), tti.timestamp) end end def test_period_for_zero_offset time_types_test do |h| # Don't need actual TimezonePeriods. DataTimezone isn't supposed to do # anything with them apart from return them. period = Object.new tti = TestTimezoneInfo.new('Test/Zone', period, [], []) tz = DataTimezone.new(tti) assert_same(period, tz.period_for(h.time(2006, 6, 27, 22, 50, 12, Rational(1,10), 0))) assert_equal_with_offset(Timestamp.create(2006, 6, 27, 22, 50, 12, Rational(1,10), h.expected_zero_offset), tti.timestamp) end end def test_period_for_offset time_types_test(:offset) do |h| # Don't need actual TimezonePeriods. DataTimezone isn't supposed to do # anything with them apart from return them. period = Object.new tti = TestTimezoneInfo.new('Test/Zone', period, [], []) tz = DataTimezone.new(tti) assert_same(period, tz.period_for(h.time(2006, 6, 27, 22, 50, 12, Rational(1,10), 3600))) assert_equal_with_offset(Timestamp.create(2006, 6, 27, 22, 50, 12, Rational(1,10), 3600), tti.timestamp) end end def test_period_for_unspecified time_types_test(:unspecified_offset) do |h| # Don't need actual TimezonePeriods. DataTimezone isn't supposed to do # anything with them apart from return them. tti = TestTimezoneInfo.new('Test/Zone', Object.new, [], []) tz = DataTimezone.new(tti) t = h.time(2006, 6, 27, 22, 50, 12, Rational(1,10)) error = assert_raises(ArgumentError) { tz.period_for(t) } assert_match(/\btime\b/, error.message) end end def test_period_for_nil tti = TestTimezoneInfo.new('Test/Zone', Object.new, [], []) tz = DataTimezone.new(tti) error = assert_raises(ArgumentError) { tz.period_for(nil) } assert_match(/\btime\b/, error.message) end def test_period_for_unsupported_value tti = TestTimezoneInfo.new('Test/Zone', Object.new, [], []) tz = DataTimezone.new(tti) t = Time.utc(2006, 6, 27, 22, 50, 12).to_i error = assert_raises(ArgumentError) { tz.period_for(t) } assert_match(Regexp.new("\\b#{Regexp.escape(t.class.name)}\\b"), error.message) end def test_periods_for_local_unspecified time_types_test(:unspecified_offset) do |h| # Don't need actual TimezonePeriods. DataTimezone isn't supposed to do # anything with them apart from return them. periods = [Object.new, Object.new] tti = TestTimezoneInfo.new('Test/Zone', nil, periods, []) tz = DataTimezone.new(tti) assert_same(periods, tz.periods_for_local(h.time(2006, 6, 27, 22, 50, 12, Rational(1,10)))) assert_equal_with_offset(Timestamp.create(2006, 6, 27, 22, 50, 12, Rational(1,10)), tti.local_timestamp) end end def test_periods_for_local_utc time_types_test(:utc) do |h| # Don't need actual TimezonePeriods. DataTimezone isn't supposed to do # anything with them apart from return them. periods = [Object.new, Object.new] tti = TestTimezoneInfo.new('Test/Zone', nil, periods, []) tz = DataTimezone.new(tti) assert_same(periods, tz.periods_for_local(h.time(2006, 6, 27, 22, 50, 12, Rational(1,10), :utc))) assert_equal_with_offset(Timestamp.create(2006, 6, 27, 22, 50, 12, Rational(1,10)), tti.local_timestamp) end end def test_periods_for_local_zero_offset time_types_test do |h| # Don't need actual TimezonePeriods. DataTimezone isn't supposed to do # anything with them apart from return them. periods = [Object.new, Object.new] tti = TestTimezoneInfo.new('Test/Zone', nil, periods, []) tz = DataTimezone.new(tti) assert_same(periods, tz.periods_for_local(h.time(2006, 6, 27, 22, 50, 12, Rational(1,10), 0))) assert_equal_with_offset(Timestamp.create(2006, 6, 27, 22, 50, 12, Rational(1,10)), tti.local_timestamp) end end def test_periods_for_local_with_offset time_types_test(:offset) do |h| # Don't need actual TimezonePeriods. DataTimezone isn't supposed to do # anything with them apart from return them. periods = [Object.new, Object.new] tti = TestTimezoneInfo.new('Test/Zone', nil, periods, []) tz = DataTimezone.new(tti) assert_same(periods, tz.periods_for_local(h.time(2006, 6, 27, 22, 50, 12, Rational(1,10), 3600))) assert_equal_with_offset(Timestamp.create(2006, 6, 27, 22, 50, 12, Rational(1,10)), tti.local_timestamp) end end def test_periods_for_local_not_found periods = [] tti = TestTimezoneInfo.new('Test/Zone', nil, periods, []) tz = DataTimezone.new(tti) t = Time.utc(2006, 6, 27, 22, 50, 12 + Rational(1,10)) assert_same(periods, tz.periods_for_local(t)) assert_equal_with_offset(Timestamp.new(t.to_i, Rational(1,10)), tti.local_timestamp) end def test_periods_for_local_nil tti = TestTimezoneInfo.new('Test/Zone', Object.new, [], []) tz = DataTimezone.new(tti) error = assert_raises(ArgumentError) { tz.periods_for_local(nil) } assert_match(/\blocal_time\b/, error.message) end def test_periods_for_local_unsupported tti = TestTimezoneInfo.new('Test/Zone', Object.new, [], []) tz = DataTimezone.new(tti) t = Time.utc(2006, 6, 27, 22, 50, 12).to_i error = assert_raises(ArgumentError) { tz.periods_for_local(t) } assert_match(Regexp.new("\\b#{Regexp.escape(t.class.name)}\\b"), error.message) end def test_transitions_up_to_utc time_types_test(:utc) do |h| # Don't need actual TimezoneTransition instances. DataTimezone isn't # supposed to do anything with them apart from return them. transitions = [Object.new, Object.new] tti = TestTimezoneInfo.new('Test/Zone', nil, nil, transitions) tz = DataTimezone.new(tti) assert_same(transitions, tz.transitions_up_to(h.time(2013, 1, 1, 0, 0, 0, Rational(1,10), :utc), h.time(2012, 1, 1, 0, 0, 0, Rational(1,10), :utc))) assert_equal_with_offset(Timestamp.create(2013, 1, 1, 0, 0, 0, Rational(1,10), :utc), tti.to_timestamp) assert_equal_with_offset(Timestamp.create(2012, 1, 1, 0, 0, 0, Rational(1,10), :utc), tti.from_timestamp) end end def test_transitions_up_to_zero_offset time_types_test do |h| # Don't need actual TimezoneTransition instances. DataTimezone isn't # supposed to do anything with them apart from return them. transitions = [Object.new, Object.new] tti = TestTimezoneInfo.new('Test/Zone', nil, nil, transitions) tz = DataTimezone.new(tti) assert_same(transitions, tz.transitions_up_to(h.time(2013, 1, 1, 0, 0, 0, Rational(1,10), 0), h.time(2012, 1, 1, 0, 0, 0, Rational(1,10), 0))) assert_equal_with_offset(Timestamp.create(2013, 1, 1, 0, 0, 0, Rational(1,10), h.expected_zero_offset), tti.to_timestamp) assert_equal_with_offset(Timestamp.create(2012, 1, 1, 0, 0, 0, Rational(1,10), h.expected_zero_offset), tti.from_timestamp) end end def test_transitions_up_to_offset time_types_test(:offset) do |h| # Don't need actual TimezoneTransition instances. DataTimezone isn't # supposed to do anything with them apart from return them. transitions = [Object.new, Object.new] tti = TestTimezoneInfo.new('Test/Zone', nil, nil, transitions) tz = DataTimezone.new(tti) assert_same(transitions, tz.transitions_up_to(h.time(2013, 1, 1, 0, 0, 0, Rational(1,10), -3600), h.time(2012, 1, 1, 0, 0, 0, Rational(1,10), 3600))) assert_equal_with_offset(Timestamp.create(2013, 1, 1, 0, 0, 0, Rational(1,10), -3600), tti.to_timestamp) assert_equal_with_offset(Timestamp.create(2012, 1, 1, 0, 0, 0, Rational(1,10), 3600), tti.from_timestamp) end end def test_transitions_up_to_utc_to_not_greater_than_utc_from time_types_test do |h| tti = TestTimezoneInfo.new('Test/Zone', nil, nil, nil) tz = DataTimezone.new(tti) to = h.time(2013,1,1,0,0,0,0,0) from = h.time(2013,1,1,0,0,0,0,0) error = assert_raises(ArgumentError) { tz.transitions_up_to(to, from) } assert_equal('to must be greater than from', error.message) end end def test_transitions_up_to_unspecified_from time_types_test(:unspecified_offset) do |h| tti = TestTimezoneInfo.new('Test/Zone', nil, nil, nil) tz = DataTimezone.new(tti) to = h.time(2013, 1, 1, 0, 0, 0, Rational(1,10), 0) from = h.time(2012, 1, 1, 0, 0, 0, Rational(1,10)) error = assert_raises(ArgumentError) { tz.transitions_up_to(to, from) } assert_equal('from must have a specified utc_offset', error.message) end end def test_transitions_up_to_unspecified_to time_types_test(:unspecified_offset) do |h| tti = TestTimezoneInfo.new('Test/Zone', nil, nil, nil) tz = DataTimezone.new(tti) to = h.time(2013, 1, 1, 0, 0, 0, Rational(1,10)) error = assert_raises(ArgumentError) { tz.transitions_up_to(to) } assert_equal('to must have a specified utc_offset', error.message) end end def test_transitions_up_to_nil_from # Don't need actual TimezoneTransition instances. DataTimezone isn't # supposed to do anything with them apart from return them. transitions = [Object.new, Object.new] tti = TestTimezoneInfo.new('Test/Zone', nil, nil, transitions) tz = DataTimezone.new(tti) to = Time.utc(2013, 1, 1, 0, 0, Rational(1,10)) assert_same(transitions, tz.transitions_up_to(to)) assert_equal_with_offset(Timestamp.new(to.to_i, Rational(1,10), :utc), tti.to_timestamp) assert_nil(tti.from_timestamp) end def test_transitions_up_to_nil_to tti = TestTimezoneInfo.new('Test/Zone', nil, nil, nil) tz = DataTimezone.new(tti) error = assert_raises(ArgumentError) { tz.transitions_up_to(nil) } assert_equal('to must be specified', error.message) end def test_transitions_up_to_unsupported_to tti = TestTimezoneInfo.new('Test/Zone', nil, nil, nil) tz = DataTimezone.new(tti) to = Time.utc(2013, 1, 1, 0, 0, 0).to_i error = assert_raises(ArgumentError) { tz.transitions_up_to(to) } assert_match(Regexp.new("\\b#{Regexp.escape(to.class.name)}\\b"), error.message) end def test_transitions_up_to_unsupported_from tti = TestTimezoneInfo.new('Test/Zone', nil, nil, nil) tz = DataTimezone.new(tti) to = Time.utc(2013, 1, 1, 0, 0, 0) from = Time.utc(2012, 1, 1, 0, 0, 0).to_i error = assert_raises(ArgumentError) { tz.transitions_up_to(to, from) } assert_match(Regexp.new("\\b#{Regexp.escape(from.class.name)}\\b"), error.message) end def test_canonical_identifier tz = DataTimezone.new(TestTimezoneInfo.new('Test/Zone', nil, [], [])) assert_equal('Test/Zone', tz.canonical_identifier) end def test_canonical_zone tz = DataTimezone.new(TestTimezoneInfo.new('Test/Zone', nil, [], [])) assert_same(tz, tz.canonical_zone) end def test_inspect tz = DataTimezone.new(TestTimezoneInfo.new('Test/Zone', nil, [], [])) assert_equal('#', tz.inspect) end end tzinfo-2.0.6/test/tc_datetime_with_offset.rb000066400000000000000000000273651436527530500212460ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true require_relative 'test_utils' class TCDateTimeWithOffset < Minitest::Test include TZInfo def datetime_with_offset(year, month, day, hour, minute, second, tz_offset) DateTimeWithOffset.new(year, month, day, hour, minute, second, tz_offset.observed_utc_offset.to_r / 86400).set_timezone_offset(tz_offset) end def test_with_offset [DateTimeWithOffset.new(2017,1,15,23,0,Rational(11,10),0), DateTimeWithOffset.new(2017,1,15,23,0,Rational(11,10),Rational(1,24))].each do |dtwo| o1 = TimezoneOffset.new(dtwo.offset * 86400, 0, 'TEST') o2 = TimezoneOffset.new(0, dtwo.offset * 86400, 'TEST') assert_nil(dtwo.timezone_offset) assert_same(dtwo, dtwo.set_timezone_offset(o1)) assert_same(o1, dtwo.timezone_offset) assert_same(dtwo, dtwo.set_timezone_offset(o2)) assert_same(o2, dtwo.timezone_offset) end end def test_with_offset_offset_mismatch dtwo1 = DateTimeWithOffset.new(2017,1,15,23,0,Rational(11,10),0) o1a = TimezoneOffset.new(3600, 0, 'TEST') o1b = TimezoneOffset.new( 0, 3600, 'TEST') dtwo2 = DateTimeWithOffset.new(2017,1,15,23,0,Rational(11,10),Rational(1,24)) o2a = TimezoneOffset.new(3600, 3600, 'TEST') o2b = TimezoneOffset.new( 0, 0, 'TEST') [[dtwo1, [o1a, o1b]], [dtwo2, [o2a, o2b]]].each do |dtwo, offsets| offsets.each do |o| error = assert_raises(ArgumentError) { dtwo.set_timezone_offset(o) } assert_match(/\bmatch\b/, error.message) end end end def test_with_offset_nil_timezone_offset lt = DateTimeWithOffset.new(2017,1,15,23,0,Rational(11,10),0) error = assert_raises(ArgumentError) { lt.set_timezone_offset(nil) } assert_match(/\btimezone_offset\b/, error.message) end def test_strftime dtwo = datetime_with_offset(2017,1,15,23,0,1,TimezoneOffset.new(0, 3600, 'TEST')) assert_equal('23:00:01 TEST', dtwo.strftime('%H:%M:%S %Z')) assert_equal('TEST', dtwo.strftime('%Z')) assert_equal('%ZTEST', dtwo.strftime('%%Z%Z')) assert_equal('TEST TEST', dtwo.strftime('%Z %Z')) assert_equal('TEST %Z %TEST %%Z %%TEST', dtwo.strftime('%Z %%Z %%%Z %%%%Z %%%%%Z')) end def test_strftime_handles_percent_in_abbreviation dtwo = datetime_with_offset(2017,1,15,23,0,1,TimezoneOffset.new(0, 0, '%H:%M:%S')) assert_equal('%H:%M:%S', dtwo.strftime('%Z')) end def test_strftime_nil_timezone_offset # Will use DateTime#strftime's handling of the %Z directive. dtwo = DateTimeWithOffset.new(2017,1,15,23,0,1,Rational(1,24)) assert_nil(dtwo.timezone_offset) assert_equal('+01:00', dtwo.strftime('%Z')) end def test_strftime_nil_format dtwo = datetime_with_offset(2017,1,15,23,0,1,TimezoneOffset.new(0, 0, 'TEST')) error = assert_raises(ArgumentError) { dtwo.strftime(nil) } assert_match(/\bformat\b/, error.message) end def test_to_date dtwo = datetime_with_offset(2017,1,15,23,0,1,TimezoneOffset.new(0, 3600, 'TEST')) d = dtwo.to_date assert_equal(Date, d.class) assert_equal(Date.new(2017,1,15), d) end def test_to_datetime dtwo = datetime_with_offset(2017,1,15,23,0,1,TimezoneOffset.new(0, 3600, 'TEST')) assert_same(dtwo, dtwo.to_datetime) end def test_to_time o = TimezoneOffset.new(3600, 0, 'TEST') dtwo = datetime_with_offset(2017,1,15,23,0,Rational(11,10),o) t = dtwo.to_time assert_kind_of(TimeWithOffset, t) assert_same(o, t.timezone_offset) assert_equal_with_offset(Time.new(2017,1,15,23,0,Rational(11,10),3600), t) end def test_to_time_nil_timezone_offset dtwo = DateTimeWithOffset.new(2017,1,15,23,0,Rational(11,10),Rational(1,24)) assert_nil(dtwo.timezone_offset) t = dtwo.to_time assert_equal(Time, t.class) # Depending on the version of Ruby, this will return a Time instance using # the local system offset or the offset of the DateTime. Don't test the # offset. assert_equal(Time.new(2017,1,15,23,0,Rational(11,10),3600), t) end def test_add dtwo = datetime_with_offset(2017,1,15,23,0,1,TimezoneOffset.new(0, 3600, 'TEST')) assert_nil((dtwo + 1).timezone_offset) end def test_subtract_seconds dtwo = datetime_with_offset(2017,1,15,23,0,1,TimezoneOffset.new(0, 3600, 'TEST')) assert_nil((dtwo - 1).timezone_offset) end def test_subtract_datetime dtwo = datetime_with_offset(2017,1,15,23,0,1,TimezoneOffset.new(0, 3600, 'TEST')) assert_equal(dtwo - DateTime.new(2017,1,15,22,0,0), Rational(1, 86400)) end def test_subtract_datetime_with_offset dtwo1 = datetime_with_offset(2017,1,15,23,0,1,TimezoneOffset.new(0, 3600, 'TEST')) dtwo2 = datetime_with_offset(2017,1,15,23,0,0,TimezoneOffset.new(0, 3600, 'TEST')) assert_equal(dtwo1 - dtwo2, Rational(1, 86400)) end def test_add_months dtwo = datetime_with_offset(2017,1,15,23,0,1,TimezoneOffset.new(0, 3600, 'TEST')) assert_nil((dtwo >> 1).timezone_offset) end def test_subtract_months dtwo = datetime_with_offset(2017,1,15,23,0,1,TimezoneOffset.new(0, 3600, 'TEST')) assert_nil((dtwo << 1).timezone_offset) end def test_compare o = TimezoneOffset.new(0, 0, 'TEST') dt1 = DateTime.new(2017,1,15,23,0,1) dt2 = DateTime.new(2017,1,15,23,0,2) dtwo1 = datetime_with_offset(2017,1,15,23,0,1,o) dtwo2 = datetime_with_offset(2017,1,15,23,0,2,o) assert_equal(0, dtwo1 <=> dtwo1) assert_equal(0, dtwo1 <=> dt1) assert_equal(0, dt1 <=> dtwo1) assert_equal(-1, dtwo1 <=> dtwo2) assert_equal(-1, dtwo1 <=> dt2) assert_equal(-1, dt1 <=> dtwo2) assert_equal(1, dtwo2 <=> dtwo1) assert_equal(1, dtwo2 <=> dt1) assert_equal(1, dt2 <=> dtwo1) end def test_day_equals o = TimezoneOffset.new(0, 0, 'TEST') dt1 = DateTime.new(2017,1,15,23,0,1) dt2 = DateTime.new(2017,1,16,23,0,1) dtwo1 = datetime_with_offset(2017,1,15,23,0,1,o) dtwo2 = datetime_with_offset(2017,1,16,23,0,1,o) d1 = Date.new(2017,1,15) d2 = Date.new(2017,1,16) assert_equal(true, dtwo1 === dtwo1) assert_equal(true, dtwo1 === dt1) assert_equal(true, dtwo1 === d1) assert_equal(true, dt1 === dtwo1) assert_equal(true, d1 === dtwo1) assert_equal(false, dtwo1 === dtwo2) assert_equal(false, dtwo1 === dt2) assert_equal(false, dtwo1 === d2) assert_equal(false, dt2 === dtwo1) assert_equal(false, d2 === dtwo1) end def test_downto_block dtwo = datetime_with_offset(2017,1,15,23,0,1,TimezoneOffset.new(0, 0, 'TEST')) block_call_count = 0 result = dtwo.downto(Date.new(2017,1,14)) do |v| assert_nil(v.timezone_offset) block_call_count += 1 end assert_same(dtwo, result) assert_equal(2, block_call_count) end def test_downto_enumerator dtwo = datetime_with_offset(2017,1,15,23,0,1,TimezoneOffset.new(0, 0, 'TEST')) block_call_count = 0 dtwo.downto(Date.new(2017,1,14)).each do |v| assert_nil(v.timezone_offset) block_call_count += 1 end assert_equal(2, block_call_count) end def new_start_wrapper_test(method, start) o = TimezoneOffset.new(0, 0, 'TEST') dtwo = datetime_with_offset(2017,1,15,23,0,1,o) result = dtwo.public_send(method) assert_equal(start, result.start) assert_same(o, result.timezone_offset) end def test_england new_start_wrapper_test(:england, Date::ENGLAND) end def test_gregorian new_start_wrapper_test(:gregorian, Date::GREGORIAN) end def test_italy new_start_wrapper_test(:italy, Date::ITALY) end def test_julian new_start_wrapper_test(:julian, Date::JULIAN) end def test_new_start o = TimezoneOffset.new(0, 0, 'TEST') dtwo = datetime_with_offset(2017,1,15,23,0,1,o) result = dtwo.new_start(Date::ENGLAND) assert_equal(Date::ENGLAND, result.start) assert_same(o, result.timezone_offset) end def test_next dtwo = datetime_with_offset(2017,1,15,23,0,1,TimezoneOffset.new(0, 0, 'TEST')) assert_nil(dtwo.next.timezone_offset) end def next_prev_test(type, unit) dt = DateTime.new(2017,1,15,23,0,1) dtwo = datetime_with_offset(2017,1,15,23,0,1,TimezoneOffset.new(0, 0, 'TEST')) method = "#{type}_#{unit}" no_args = dtwo.public_send(method) assert_equal_with_offset(dt.public_send(method), no_args) assert_nil(no_args.timezone_offset) args = dtwo.public_send(method, 2) assert_equal_with_offset(dt.public_send(method, 2), args) assert_nil(args.timezone_offset) end def next_test(unit) next_prev_test(:next, unit) end def test_next_day next_test(:day) end def test_next_month next_test(:month) end def test_next_year next_test(:year) end def prev_test(unit) next_prev_test(:prev, unit) end def test_prev_day prev_test(:day) end def test_prev_month prev_test(:month) end def test_prev_year prev_test(:year) end def test_step_block dtwo = datetime_with_offset(2017,1,15,23,0,1,TimezoneOffset.new(0, 0, 'TEST')) block_call_count = 0 result = dtwo.step(Date.new(2017,1,17)) do |v| assert_nil(v.timezone_offset) block_call_count += 1 end assert_same(dtwo, result) assert_equal(2, block_call_count) end def test_step_enumerator dtwo = datetime_with_offset(2017,1,15,23,0,1,TimezoneOffset.new(0, 0, 'TEST')) block_call_count = 0 dtwo.step(Date.new(2017,1,17)).each do |v| assert_nil(v.timezone_offset) block_call_count += 1 end assert_equal(2, block_call_count) end def test_step_non_default_block dtwo = datetime_with_offset(2017,1,15,23,0,1,TimezoneOffset.new(0, 0, 'TEST')) block_call_count = 0 result = dtwo.step(Date.new(2017,1,14), -2) do |v| assert_nil(v.timezone_offset) block_call_count += 1 end assert_same(dtwo, result) assert_equal(1, block_call_count) end def test_step_non_default_enumerator dtwo = datetime_with_offset(2017,1,15,23,0,1,TimezoneOffset.new(0, 0, 'TEST')) block_call_count = 0 dtwo.step(Date.new(2017,1,14), -2).each do |v| assert_nil(v.timezone_offset) block_call_count += 1 end assert_equal(1, block_call_count) end def test_succ dtwo = datetime_with_offset(2017,1,15,23,0,1,TimezoneOffset.new(0, 0, 'TEST')) assert_nil(dtwo.succ.timezone_offset) end def test_upto_block dtwo = datetime_with_offset(2017,1,15,23,0,1,TimezoneOffset.new(0, 0, 'TEST')) block_call_count = 0 result = dtwo.upto(Date.new(2017,1,17)) do |v| assert_nil(v.timezone_offset) block_call_count += 1 end assert_same(dtwo, result) assert_equal(2, block_call_count) end def test_upto_enumerator dtwo = datetime_with_offset(2017,1,15,23,0,1,TimezoneOffset.new(0, 0, 'TEST')) block_call_count = 0 dtwo.upto(Date.new(2017,1,17)).each do |v| assert_nil(v.timezone_offset) block_call_count += 1 end assert_equal(2, block_call_count) end def test_new_offset # new_offset isn't formally documented, but is referenced in a code sample # in the description of the DateTime class. dt = DateTime.new(2017,1,15,23,0,1) dtwo = datetime_with_offset(2017,1,15,23,0,1,TimezoneOffset.new(0, 0, 'TEST')) [0, Rational(1,24), '-01:00'].each do |o| result = dtwo.new_offset(o) assert_equal_with_offset(dt.new_offset(o), result) assert_nil(result.timezone_offset) end end def test_class_jd_returns_local_datetime ld = DateTimeWithOffset.jd(Rational(212351324401, 86400)) assert_kind_of(DateTimeWithOffset, ld) assert_nil(ld.timezone_offset) assert_equal(2457769, ld.jd) assert_equal(Rational(82801, 86400), ld.day_fraction) end def test_class_new_returns_local_datetime ld = DateTimeWithOffset.new(2017,1,15,23,0,1) assert_kind_of(DateTimeWithOffset, ld) assert_nil(ld.timezone_offset) assert_equal(2457769, ld.jd) assert_equal(Rational(82801, 86400), ld.day_fraction) end end tzinfo-2.0.6/test/tc_info_timezone.rb000066400000000000000000000011471436527530500177040ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true require_relative 'test_utils' class TCInfoTimezone < Minitest::Test include TZInfo def test_identifier tz = InfoTimezone.new(DataSources::TimezoneInfo.new('Test/Identifier')) assert_equal('Test/Identifier', tz.identifier) end def test_info i = DataSources::TimezoneInfo.new('Test/Identifier') tz = InfoTimezone.new(i) assert_same(i, tz.send(:info)) end def test_inspect tz = InfoTimezone.new(DataSources::TimezoneInfo.new('Test/Identifier')) assert_equal('#', tz.inspect) end end tzinfo-2.0.6/test/tc_linked_timezone.rb000066400000000000000000000152551436527530500202240ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true require_relative 'test_utils' class TCLinkedTimezone < Minitest::Test include TZInfo class TestTimezone < Timezone attr_reader :period_for_result attr_reader :periods_for_local_result attr_reader :transitions_up_to_result attr_reader :time attr_reader :local_time attr_reader :to attr_reader :from def initialize(identifier, no_local_periods = false) super() @identifier = identifier # Don't have to be real TimezonePeriod or TimezoneTransition objects # (nothing will use them). @period_for_result = Object.new @periods_for_local_result = no_local_periods ? [] : [Object.new, Object.new] @transitions_up_to_result = [Object.new, Object.new] end def identifier @identifier end def period_for(time) raise ArgumentError, 'linked zone exception: nil' unless time @time = time @period_for_result end def periods_for_local(local_time) raise ArgumentError, 'linked zone exception: nil' unless local_time @local_time = local_time @periods_for_local_result end def transitions_up_to(to, from = nil) @to = to @from = from @transitions_up_to_result end def canonical_zone self end end def get_timezone(linked_tz, identifier) assert_equal(linked_tz.identifier, identifier) linked_tz end def stub_timezone_get(linked_tz = nil) linked_tz = TestTimezone.new('Test/Linked') unless linked_tz Timezone.stub(:get, ->(i) { get_timezone(linked_tz, i) }) { yield linked_tz } end def test_identifier stub_timezone_get do tz = LinkedTimezone.new(DataSources::LinkedTimezoneInfo.new('Test/Zone', 'Test/Linked')) assert_equal('Test/Zone', tz.identifier) end end def test_invalid_linked_identifier error = assert_raises(InvalidTimezoneIdentifier) { LinkedTimezone.new(DataSources::LinkedTimezoneInfo.new('Test/Zone', 'Invalid/Identifier')) } assert_match(/\bInvalid\/Identifier\b/, error.message) end def test_period_for stub_timezone_get do |linked_tz| time_types_test do |h| tz = LinkedTimezone.new(DataSources::LinkedTimezoneInfo.new('Test/Zone', 'Test/Linked')) t = h.time(2006, 6, 27, 23, 12, 28, Rational(1, 10), 0) assert_same(linked_tz.period_for_result, tz.period_for(t)) assert_same(t, linked_tz.time) end end end def test_period_for_nil stub_timezone_get do tz = LinkedTimezone.new(DataSources::LinkedTimezoneInfo.new('Test/Zone', 'Test/Linked')) error = assert_raises(ArgumentError) { tz.period_for(nil) } assert_equal('linked zone exception: nil', error.message) end end def test_periods_for_local stub_timezone_get do |linked_tz| time_types_test do |h| tz = LinkedTimezone.new(DataSources::LinkedTimezoneInfo.new('Test/Zone', 'Test/Linked')) t = h.time(2006, 6, 27, 23, 12, 28, Rational(1, 10), 0) assert_same(linked_tz.periods_for_local_result, tz.periods_for_local(t)) assert_same(t, linked_tz.local_time) end end end def test_periods_for_local_not_found stub_timezone_get(TestTimezone.new('Test/No/Local', true)) do |linked_tz| tz = LinkedTimezone.new(DataSources::LinkedTimezoneInfo.new('Test/Zone', 'Test/No/Local')) t = Time.utc(2006, 6, 27, 23, 12, 28) assert_equal([], linked_tz.periods_for_local_result) assert_same(linked_tz.periods_for_local_result, tz.periods_for_local(t)) assert_same(t, linked_tz.local_time) end end def test_periods_for_local_nil stub_timezone_get do tz = LinkedTimezone.new(DataSources::LinkedTimezoneInfo.new('Test/Zone', 'Test/Linked')) error = assert_raises(ArgumentError) { tz.periods_for_local(nil) } assert_equal('linked zone exception: nil', error.message) end end def test_transitions_up_to stub_timezone_get do |linked_tz| time_types_test do |h| tz = LinkedTimezone.new(DataSources::LinkedTimezoneInfo.new('Test/Zone', 'Test/Linked')) to = h.time(2013, 1, 1, 0, 0, 0, Rational(1, 10), 0) from = h.time(2012, 1, 1, 0, 0, 0, Rational(1, 10), 0) assert_same(linked_tz.transitions_up_to_result, tz.transitions_up_to(to, from)) assert_same(to, linked_tz.to) assert_same(from, linked_tz.from) end end end def test_transitions_up_to_nil_from stub_timezone_get do |linked_tz| time_types_test do |h| tz = LinkedTimezone.new(DataSources::LinkedTimezoneInfo.new('Test/Zone', 'Test/Linked')) linked_tz = Timezone.get('Test/Linked') to = h.time(2013, 1, 1, 0, 0, 0, Rational(1, 10), 0) assert_same(linked_tz.transitions_up_to_result, tz.transitions_up_to(to)) assert_same(to, linked_tz.to) assert_nil(linked_tz.from) end end end def test_canonical_identifier stub_timezone_get do tz = LinkedTimezone.new(DataSources::LinkedTimezoneInfo.new('Test/Zone', 'Test/Linked')) assert_equal('Test/Linked', tz.canonical_identifier) end end def test_canonical_identifier_recursive # Recursive links are not currently used in the Time Zone database, but # will be supported by TZInfo. recursive_data = TestTimezone.new('Test/Recursive/Data') recursive_linked = stub_timezone_get(recursive_data) do LinkedTimezone.new(DataSources::LinkedTimezoneInfo.new('Test/Recursive/Linked', 'Test/Recursive/Data')) end stub_timezone_get(recursive_linked) do tz = LinkedTimezone.new(DataSources::LinkedTimezoneInfo.new('Test/Zone', 'Test/Recursive/Linked')) assert_equal('Test/Recursive/Data', tz.canonical_identifier) end end def test_canonical_zone stub_timezone_get do |linked_tz| tz = LinkedTimezone.new(DataSources::LinkedTimezoneInfo.new('Test/Zone', 'Test/Linked')) assert_same(linked_tz, tz.canonical_zone) end end def test_canonical_zone_recursive # Recursive links are not currently used in the Time Zone database, but # will be supported by TZInfo. recursive_data = TestTimezone.new('Test/Recursive/Data') recursive_linked = stub_timezone_get(recursive_data) do LinkedTimezone.new(DataSources::LinkedTimezoneInfo.new('Test/Recursive/Linked', 'Test/Recursive/Data')) end stub_timezone_get(recursive_linked) do tz = LinkedTimezone.new(DataSources::LinkedTimezoneInfo.new('Test/Zone', 'Test/Recursive/Linked')) assert_same(recursive_data, tz.canonical_zone) end end def test_inspect stub_timezone_get do tz = LinkedTimezone.new(DataSources::LinkedTimezoneInfo.new('Test/Zone', 'Test/Linked')) assert_equal('#', tz.inspect) end end end tzinfo-2.0.6/test/tc_offset_timezone_period.rb000066400000000000000000000033361436527530500216030ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true require_relative 'test_utils' class TCOffsetTimezonePeriod < Minitest::Test include TZInfo def test_initialize o = TimezoneOffset.new(-7200, 3600, 'SPECIAL') p = OffsetTimezonePeriod.new(o) assert_same(o, p.offset) end def test_initialize_nil error = assert_raises(ArgumentError) { OffsetTimezonePeriod.new(nil) } assert_match(/\boffset\b/, error.message) end def test_start_transition p = OffsetTimezonePeriod.new(TimezoneOffset.new(-7200, 3600, 'SPECIAL')) assert_nil(p.start_transition) end def test_end_transition p = OffsetTimezonePeriod.new(TimezoneOffset.new(-7200, 3600, 'SPECIAL')) assert_nil(p.end_transition) end def test_equality o1 = TimezoneOffset.new(0, 3600, 'TEST') o2 = TimezoneOffset.new(0, 0, 'TEST') p1 = OffsetTimezonePeriod.new(o1) p2 = OffsetTimezonePeriod.new(o1) p3 = OffsetTimezonePeriod.new(o2) p4 = TimezonePeriod.new(o1) assert_equal(true, p1 == p1) assert_equal(true, p1 == p2) assert_equal(false, p1 == p3) assert_equal(false, p1 == p4) assert_equal(false, p1 == Object.new) end def test_eql o1 = TimezoneOffset.new(0, 3600, 'TEST') o2 = TimezoneOffset.new(0, 0, 'TEST') p1 = OffsetTimezonePeriod.new(o1) p2 = OffsetTimezonePeriod.new(o1) p3 = OffsetTimezonePeriod.new(o2) p4 = TimezonePeriod.new(o1) assert_equal(true, p1.eql?(p1)) assert_equal(true, p1.eql?(p2)) assert_equal(false, p1.eql?(p3)) assert_equal(false, p1.eql?(p4)) assert_equal(false, p1.eql?(Object.new)) end def test_hash o = TimezoneOffset.new(0, 3600, 'TEST') p = OffsetTimezonePeriod.new(o) assert_equal(o.hash, p.hash) end end tzinfo-2.0.6/test/tc_ruby_core_support.rb000066400000000000000000000007051436527530500206230ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true require_relative 'test_utils' class TCRubyCoreSupport < Minitest::Test def test_untaint_returns_object o = Object.new assert_same(o, TZInfo.const_get(:RubyCoreSupport).untaint(o)) end def test_untaint_untaints_object skip_if_taint_is_undefined_or_no_op o = Object.new.taint assert(o.tainted?) TZInfo.const_get(:RubyCoreSupport).untaint(o) refute(o.tainted?) end end tzinfo-2.0.6/test/tc_ruby_time_timezone.rb000066400000000000000000000061341436527530500207510ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true require_relative 'test_utils' class TCRubyTimeTimezone < Minitest::Test include TZInfo def test_new_time_with_time_zone_paris check_can_create_time_with_time_zone tz = Timezone.get('Europe/Paris') std_time = Time.new(2018, 12, 1, 0, 0, 0, tz) assert_same(tz, std_time.zone) assert_equal(3600, std_time.utc_offset) assert_equal(Time.utc(2018, 11, 30, 23, 0, 0), std_time.getutc) dst_time = Time.new(2018, 6, 1, 0, 0, 0, tz) assert_same(tz, dst_time.zone) assert_equal(7200, dst_time.utc_offset) assert_equal(Time.utc(2018, 5, 31, 22, 0, 0), dst_time.getutc) end def test_new_time_with_time_zone_new_york check_can_create_time_with_time_zone tz = Timezone.get('America/New_York') std_time = Time.new(2018, 12, 1, 0, 0, 0, tz) assert_same(tz, std_time.zone) assert_equal(-18000, std_time.utc_offset) assert_equal(Time.utc(2018, 12, 1, 5, 0, 0), std_time.getutc) dst_time = Time.new(2018, 6, 1, 0, 0, 0, tz) assert_same(tz, dst_time.zone) assert_equal(-14400, dst_time.utc_offset) assert_equal(Time.utc(2018, 6, 1, 4, 0, 0), dst_time.getutc) end def test_time_at_with_time_zone_paris check_can_create_time_with_time_zone tz = Timezone.get('Europe/Paris') std_time = Time.at(1543618800, in: tz) assert_same(tz, std_time.zone) assert_equal(3600, std_time.utc_offset) assert_equal(2018, std_time.year) assert_equal(12, std_time.month) assert_equal(1, std_time.day) assert_equal(0, std_time.hour) assert_equal(0, std_time.min) assert_equal(0, std_time.sec) dst_time = Time.at(1527804000, in: tz) assert_same(tz, dst_time.zone) assert_equal(7200, dst_time.utc_offset) assert_equal(2018, dst_time.year) assert_equal(6, dst_time.month) assert_equal(1, dst_time.day) assert_equal(0, dst_time.hour) assert_equal(0, dst_time.min) assert_equal(0, dst_time.sec) end def test_time_at_with_time_zone_new_york check_can_create_time_with_time_zone if RUBY_ENGINE == 'ruby' && RUBY_VERSION < '2.7' && [0].pack('J').bytesize <= 4 skip('`Time.at(n, in: zone)` is broken with negative UTC offsets on 32-bit MRI Ruby 2.6') end tz = Timezone.get('America/New_York') std_time = Time.at(1543640400, in: tz) assert_same(tz, std_time.zone) assert_equal(-18000, std_time.utc_offset) assert_equal(2018, std_time.year) assert_equal(12, std_time.month) assert_equal(1, std_time.day) assert_equal(0, std_time.hour) assert_equal(0, std_time.min) assert_equal(0, std_time.sec) dst_time = Time.at(1527825600, in: tz) assert_same(tz, dst_time.zone) assert_equal(-14400, dst_time.utc_offset) assert_equal(2018, dst_time.year) assert_equal(6, dst_time.month) assert_equal(1, dst_time.day) assert_equal(0, dst_time.hour) assert_equal(0, dst_time.min) assert_equal(0, dst_time.sec) end private def check_can_create_time_with_time_zone unless RUBY_VERSION >= '2.6' skip("Cannot create Time with a time zone with Ruby #{RUBY_VERSION}") end end end tzinfo-2.0.6/test/tc_string_deduper.rb000066400000000000000000000031441436527530500200540ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true require_relative 'test_utils' require 'concurrent' class TCStringDeduper < Minitest::Test include TZInfo def test_string_deduper_dedupe dedupe_tests(StringDeduper.new) end def test_concurrent_string_deduper_dedupe dedupe_tests(ConcurrentStringDeduper.new) end if TZInfo.const_defined?(:UnaryMinusGlobalStringDeduper) def test_unary_minus_global_string_deduper dedupe_tests(UnaryMinusGlobalStringDeduper.new) end end def test_global_uses_unary_minus_when_available global = StringDeduper.global if RUBY_VERSION >= '2.5' assert_kind_of(UnaryMinusGlobalStringDeduper, global) else assert_kind_of(StringDeduper, global) end end def test_global_returns_same_instance global = StringDeduper.global assert_same(global, StringDeduper.global) end def test_global_dedupe dedupe_tests(StringDeduper.global) end private def dedupe_tests(sd) s1 = rand.to_s s2 = s1.dup s3 = s1.dup.freeze refute_same(s1, s2) refute_same(s1, s3) assert_equal(false, s1.frozen?) assert_equal(false, s2.frozen?) assert_equal(true, s3.frozen?) r1 = sd.dedupe(s1) assert_equal(s1, r1) refute_same(s1, r1) assert_equal(false, s1.frozen?) assert_equal(true, r1.frozen?) r2 = sd.dedupe(s2) assert_equal(false, s2.frozen?) assert_same(r1, r2) r3 = sd.dedupe(s3) assert_equal(s3, r3) refute_same(r1, r3) end def dedupe_tests_with_hash_class_check(sd, hash_class) assert_same(hash_class, sd.hash_class) dedupe_tests(sd) end end tzinfo-2.0.6/test/tc_time_with_offset.rb000066400000000000000000000311741436527530500204010ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true require_relative 'test_utils' class TCTimeWithOffset < Minitest::Test include TZInfo def time_with_offset(year, month, day, hour, minute, second, tz_offset) TimeWithOffset.new(year, month, day, hour, minute, second, tz_offset.observed_utc_offset).set_timezone_offset(tz_offset) end def assert_is_time_or_time_with_offset_with_nil_timezone_offset(value) if value.kind_of?(TimeWithOffset) assert_nil(value.timezone_offset) else assert_equal(Time, value.class) end end def test_set_timezone_offset_unchanged_offset [TimeWithOffset.new(2017,1,15,23,0,Rational(11,10),0), TimeWithOffset.new(2017,1,15,23,0,Rational(11,10),3600)].each do |two| o1 = TimezoneOffset.new(two.utc_offset, 0, 'TEST') o2 = TimezoneOffset.new(0, two.utc_offset, 'TEST') assert_nil(two.timezone_offset) assert_same(two, two.set_timezone_offset(o1)) assert_same(o1, two.timezone_offset) assert_same(two, two.set_timezone_offset(o2)) assert_same(o2, two.timezone_offset) end end def test_set_timezone_offset_set_offset o = TimezoneOffset.new(3600, 0, 'TEST') [TimeWithOffset.utc(2017,1,15,23,0,Rational(11,10)), TimeWithOffset.new(2017,1,15,23,0,Rational(11,10),0), TimeWithOffset.new(2017,1,15,22,0,Rational(11,10),-3600)].each do |two| assert_nil(two.timezone_offset) assert_same(two, two.set_timezone_offset(o)) assert_same(o, two.timezone_offset) assert_equal_with_offset(Time.new(2017,1,16,0,0,Rational(11,10),3600), two) end end def test_set_timezone_offset_utc two = TimeWithOffset.utc(2017,1,15,23,0,Rational(11,10)) o = TimezoneOffset.new(0, 0, 'TEST') assert_equal(true, two.utc?) assert_same(two, two.set_timezone_offset(o)) assert_same(o, two.timezone_offset) assert_equal_with_offset(Time.new(2017,1,15,23,0,Rational(11,10),0), two) end def test_set_timezone_offset_nil_timezone_offset two = TimeWithOffset.new(2017,1,15,23,0,Rational(11,10),0) error = assert_raises(ArgumentError) { two.set_timezone_offset(nil) } assert_match(/\btimezone_offset\b/, error.message) end def test_strftime two = time_with_offset(2017,1,15,23,0,1,TimezoneOffset.new(0, 3600, 'TEST')) assert_equal('23:00:01 TEST', two.strftime('%H:%M:%S %Z')) assert_equal('TEST', two.strftime('%Z')) assert_equal('%ZTEST', two.strftime('%%Z%Z')) assert_equal('TEST TEST', two.strftime('%Z %Z')) assert_equal('TEST %Z %TEST %%Z %%TEST', two.strftime('%Z %%Z %%%Z %%%%Z %%%%%Z')) end def test_strftime_handles_percent_in_abbreviation two = time_with_offset(2017,1,15,23,0,1,TimezoneOffset.new(0, 0, '%H:%M:%S')) assert_equal('%H:%M:%S', two.strftime('%Z')) end def test_strftime_nil_timezone_offset # Will use Time#strftime's handling of the %Z directive. t = Time.new(2017,1,15,23,0,1,3600) two = TimeWithOffset.new(2017,1,15,23,0,1,3600) assert_nil(two.timezone_offset) # JRuby 1.7 returns '+01:00' instead of empty string. assert_equal(t.strftime('%Z'), two.strftime('%Z')) end def test_strftime_nil_format two = time_with_offset(2017,1,15,23,0,1,TimezoneOffset.new(0, 0, 'TEST')) error = assert_raises(ArgumentError) { two.strftime(nil) } assert_match(/\bformat\b/, error.message) end def test_add two = time_with_offset(2017,1,15,23,0,1,TimezoneOffset.new(0, 3600, 'TEST')) # MRI returns Time. JRuby returns TimeWithOffset. assert_is_time_or_time_with_offset_with_nil_timezone_offset(two + 1) end def test_subtract_seconds two = time_with_offset(2017,1,15,23,0,1,TimezoneOffset.new(0, 3600, 'TEST')) # MRI returns Time. JRuby returns TimeWithOffset. assert_is_time_or_time_with_offset_with_nil_timezone_offset(two - 1) end def test_subtract_time two = time_with_offset(2017,1,15,23,0,1,TimezoneOffset.new(0, 3600, 'TEST')) assert_equal(1, two - Time.utc(2017,1,15,22,0,0)) end def test_subtract_time_with_offset two1 = time_with_offset(2017,1,15,23,0,1,TimezoneOffset.new(0, 3600, 'TEST')) two2 = time_with_offset(2017,1,15,23,0,0,TimezoneOffset.new(0, 3600, 'TEST')) assert_equal(1, two1 - two2) end def test_compare o = TimezoneOffset.new(0, 0, 'TEST') t1 = Time.new(2017,1,15,23,0,1,0) t2 = Time.new(2017,1,15,23,0,2,0) two1 = time_with_offset(2017,1,15,23,0,1,o) two2 = time_with_offset(2017,1,15,23,0,2,o) assert_equal(0, two1 <=> two1) assert_equal(0, two1 <=> t1) assert_equal(0, t1 <=> two1) assert_equal(-1, two1 <=> two2) assert_equal(-1, two1 <=> t2) assert_equal(-1, t1 <=> two2) assert_equal(1, two2 <=> two1) assert_equal(1, two2 <=> t1) assert_equal(1, t2 <=> two1) end def test_dst two1 = time_with_offset(2017,1,15,23,0,1,TimezoneOffset.new( 0, 0, 'TEST')) two2 = time_with_offset(2017,1,15,23,0,1,TimezoneOffset.new( 0, 3600, 'TEST')) two3 = time_with_offset(2017,1,15,23,0,1,TimezoneOffset.new(3600, 0, 'TEST')) two4 = time_with_offset(2017,1,15,23,0,1,TimezoneOffset.new(3600, 3600, 'TEST')) assert_equal(false, two1.dst?) assert_equal(true, two2.dst?) assert_equal(false, two3.dst?) assert_equal(true, two4.dst?) end def test_dst_nil_timezone_offset two = TimeWithOffset.new(2017,1,15,23,0,1,3600) assert_nil(two.timezone_offset) assert_equal(false, two.dst?) end def test_eql o = TimezoneOffset.new(0, 0, 'TEST') t1 = Time.new(2017,1,15,23,0,1,0) t2 = Time.new(2017,1,15,23,0,2,0) two1 = time_with_offset(2017,1,15,23,0,1,o) two2 = time_with_offset(2017,1,15,23,0,2,o) assert_equal(true, two1.eql?(two1)) assert_equal(true, two1.eql?(t1)) assert_equal(true, t1.eql?(two1)) assert_equal(false, two1.eql?(two2)) assert_equal(false, two1.eql?(t2)) assert_equal(false, t1.eql?(two2)) end def test_getgm two = time_with_offset(2017,1,15,23,0,1,TimezoneOffset.new(0, 0, 'TEST')) # MRI returns TimeWithOffset. JRuby returns Time. assert_is_time_or_time_with_offset_with_nil_timezone_offset(two.getgm) end def test_getlocal two = time_with_offset(2017,1,15,23,0,1,TimezoneOffset.new(0, 0, 'TEST')) # MRI returns TimeWithOffset. JRuby returns Time. assert_is_time_or_time_with_offset_with_nil_timezone_offset(two.getlocal) end def test_getlocal_0 two = time_with_offset(2017,1,15,23,0,1,TimezoneOffset.new(0, 0, 'TEST')) # MRI and JRuby >= 9.3 returns TimeWithOffset. JRuby < 9.3 returns Time. local = two.getlocal(0) assert_equal(0, local.utc_offset) assert_is_time_or_time_with_offset_with_nil_timezone_offset(two.getlocal(0)) end def test_getutc two = time_with_offset(2017,1,15,23,0,1,TimezoneOffset.new(0, 0, 'TEST')) # MRI returns TimeWithOffset. JRuby returns Time. assert_is_time_or_time_with_offset_with_nil_timezone_offset(two.getutc) end def test_gmtime two = time_with_offset(2017,1,15,23,0,1,TimezoneOffset.new(3600, 0, 'TEST')) assert_same(two, two.gmtime) assert_equal(true, two.utc?) assert_nil(two.timezone_offset) end def test_isdst two1 = time_with_offset(2017,1,15,23,0,1,TimezoneOffset.new( 0, 0, 'TEST')) two2 = time_with_offset(2017,1,15,23,0,1,TimezoneOffset.new( 0, 3600, 'TEST')) two3 = time_with_offset(2017,1,15,23,0,1,TimezoneOffset.new(3600, 0, 'TEST')) two4 = time_with_offset(2017,1,15,23,0,1,TimezoneOffset.new(3600, 3600, 'TEST')) assert_equal(false, two1.isdst) assert_equal(true, two2.isdst) assert_equal(false, two3.isdst) assert_equal(true, two4.isdst) end def test_isdst_nil_timezone_offset two = TimeWithOffset.new(2017,1,15,23,0,1,3600) assert_nil(two.timezone_offset) assert_equal(false, two.isdst) end def test_localtime_without_offset two = time_with_offset(2017,1,15,23,0,1,TimezoneOffset.new(0, 0, 'TEST')) assert_same(two, two.localtime) assert_nil(two.timezone_offset) end def test_localtime_with_offset two = time_with_offset(2017,1,15,23,0,1,TimezoneOffset.new(0, 0, 'TEST')) assert_same(two, two.localtime(3600)) assert_equal(3600, two.utc_offset) assert_nil(two.timezone_offset) end def test_localtime_with_offset_unchanged two = time_with_offset(2017,1,15,23,0,1,TimezoneOffset.new(3600, 0, 'TEST')) assert_same(two, two.localtime(3600)) assert_equal(3600, two.utc_offset) assert_nil(two.timezone_offset) end def test_round o = TimezoneOffset.new(3600, 0, 'TEST') two = time_with_offset(2017,1,15,23,0,Rational(111,100),o) r = two.round r0 = two.round(0) r1 = two.round(1) [r, r0, r1].each do |result| assert_kind_of(TimeWithOffset, result) assert_same(o, result.timezone_offset) end assert_equal_with_offset(Time.new(2017,1,15,23,0,1,3600), r) assert_equal_with_offset(Time.new(2017,1,15,23,0,1,3600), r0) assert_equal_with_offset(Time.new(2017,1,15,23,0,Rational(11,10),3600), r1) end def test_round_nil_timezone_offset two = TimeWithOffset.new(2017,1,15,23,0,Rational(111,100),3600) assert_nil(two.timezone_offset) r = two.round r0 = two.round(0) r1 = two.round(1) [r, r0, r1].each { |result| assert_equal(Time, result.class) } assert_equal_with_offset(Time.new(2017,1,15,23,0,1,3600), r) assert_equal_with_offset(Time.new(2017,1,15,23,0,1,3600), r0) assert_equal_with_offset(Time.new(2017,1,15,23,0,Rational(11,10),3600), r1) end def test_succ skip('Time#succ is not supported') unless Time.new.respond_to?(:succ) two = time_with_offset(2017,1,15,23,0,1,TimezoneOffset.new(0, 3600, 'BST')) # succ is obsolete and outputs a warning. without_warnings do assert_is_time_or_time_with_offset_with_nil_timezone_offset(two.succ) end end def test_to_a two1 = time_with_offset(2017,1,15,23,0,1,TimezoneOffset.new( 0, 0, 'TEST')) two2 = time_with_offset(2017,1,15,23,0,1,TimezoneOffset.new( 0, 3600, 'TEST')) two3 = time_with_offset(2017,1,15,23,0,1,TimezoneOffset.new(3600, 0, 'TEST')) two4 = time_with_offset(2017,1,15,23,0,1,TimezoneOffset.new(3600, 3600, 'TEST')) assert_equal([1,0,23,15,1,2017,0,15,false,'TEST'], two1.to_a) assert_equal([1,0,23,15,1,2017,0,15,true, 'TEST'], two2.to_a) assert_equal([1,0,23,15,1,2017,0,15,false,'TEST'], two3.to_a) assert_equal([1,0,23,15,1,2017,0,15,true, 'TEST'], two4.to_a) end def test_to_a_nil_timezone_offset t = Time.new(2017,1,15,23,0,1,3600) two = TimeWithOffset.new(2017,1,15,23,0,1,3600) assert_nil(two.timezone_offset) # For local times, the last element is nil on MRI and empty string on JRuby. # Compare with the actual Time#to_a output. assert_equal(t.to_a, two.to_a) end def test_utc two = time_with_offset(2017,1,15,23,0,1,TimezoneOffset.new(3600, 0, 'TEST')) assert_same(two, two.utc) assert_equal(true, two.utc?) assert_nil(two.timezone_offset) end def test_zone two1 = time_with_offset(2017,1,15,23,0,1,TimezoneOffset.new(3600, 0, 'TEST')) two2 = TimeWithOffset.utc(2017,1,15,23,0,1).set_timezone_offset(TimezoneOffset.new(0, 0, 'GMT')) assert_equal('TEST', two1.zone) assert_equal('GMT', two2.zone) end def test_zone_nil_timezone_offset t = Time.new(2017,1,15,23,0,1,3600) two = TimeWithOffset.new(2017,1,15,23,0,1,3600) assert_nil(two.timezone_offset) # For local times, zone returns nil on MRI and empty string on JRuby. # Compare with the actual Time#zone output. assert_nil_or_equal(t.zone, two.zone) end def test_to_datetime o = TimezoneOffset.new(3600, 0, 'TEST') two = time_with_offset(2017,1,15,23,0,Rational(11,10),o) d = two.to_datetime assert_kind_of(DateTimeWithOffset, d) assert_same(o, d.timezone_offset) assert_equal_with_offset(DateTime.new(2017,1,15,23,0,Rational(11,10),Rational(1,24)), d) end def test_to_datetime_nil_timezone_offset two = TimeWithOffset.new(2017,1,15,23,0,Rational(11,10),3600) assert_nil(two.timezone_offset) d = two.to_datetime assert_equal(DateTime, d.class) assert_equal_with_offset(DateTime.new(2017,1,15,23,0,Rational(11,10),Rational(1,24)), d) end def test_class_at_returns_local_time two = TimeWithOffset.at(1484521201) assert_kind_of(TimeWithOffset, two) assert_nil(two.timezone_offset) assert_equal(1484521201, two.to_i) end def test_class_new_returns_local_time two = TimeWithOffset.new(2017,1,15,23,0,1,0) assert_kind_of(TimeWithOffset, two) assert_nil(two.timezone_offset) assert_equal(1484521201, two.to_i) end def test_class_utc_returns_local_time two = TimeWithOffset.utc(2017,1,15,23,0,1) assert_kind_of(TimeWithOffset, two) assert_nil(two.timezone_offset) assert_equal(1484521201, two.to_i) end end tzinfo-2.0.6/test/tc_timestamp.rb000066400000000000000000001461621436527530500170510ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true require_relative 'test_utils' require 'date' class TCTimestamp < Minitest::Test include TZInfo class TestTimestampSubclass < Timestamp end def test_initialize_timestamp_only t = Timestamp.new(1476316800) assert_equal(1476316800, t.value) assert_kind_of(Integer, t.sub_second) assert_equal(0, t.sub_second) assert_nil(t.utc_offset) assert_nil(t.utc?) end def test_initialize_sub_second t = Timestamp.new(1476316800, Rational(1, 10)) assert_equal(Rational(1, 10), t.sub_second) end def test_initialize_sub_second_zero t = Timestamp.new(1476316800, 0) assert_kind_of(Integer, t.sub_second) assert_equal(0, t.sub_second) end def test_initialize_zero_utc_offset t = Timestamp.new(1476316800, 0, 0) assert_equal(1476316800, t.value) assert_equal(0, t.utc_offset) assert_equal(false, t.utc?) end def test_initialize_non_zero_utc_offset t = Timestamp.new(1476316800, 0, 3600) assert_equal(1476316800, t.value) assert_equal(3600, t.utc_offset) assert_equal(false, t.utc?) end def test_initialize_utc t = Timestamp.new(1476316800, 0, :utc) assert_equal(1476316800, t.value) assert_equal(0, t.utc_offset) assert_equal(true, t.utc?) end def test_initialize_value_nil error = assert_raises(ArgumentError) { Timestamp.new(nil) } assert_equal('value must be an Integer', error.message) end def test_initialize_valuenot_integer error = assert_raises(ArgumentError) { Timestamp.new(1476316800.0) } assert_equal('value must be an Integer', error.message) end def test_initialize_sub_second_nil error = assert_raises(ArgumentError) { Timestamp.new(1476316800, nil) } assert_equal('sub_second must be a Rational or the Integer 0', error.message) end def test_initialize_sub_second_not_integer_or_rational error = assert_raises(ArgumentError) { Timestamp.new(1476316800, 0.1) } assert_equal('sub_second must be a Rational or the Integer 0', error.message) end def test_initialize_sub_second_integer_not_zero error = assert_raises(ArgumentError) { Timestamp.new(1476316800, 1) } assert_equal('sub_second must be a Rational or the Integer 0', error.message) end def test_initialize_sub_second_less_than_zero error = assert_raises(RangeError) { Timestamp.new(1476316800, Rational(-1, 10)) } assert_equal('sub_second must be >= 0 and < 1', error.message) end def test_initialize_sub_second_greater_than_or_equal_to_one error = assert_raises(RangeError) { Timestamp.new(1476316800, Rational(1, 1)) } assert_equal('sub_second must be >= 0 and < 1', error.message) end def test_initialize_utc_offset_not_integer_or_utc [1.0, :zero].each do |utc_offset| error = assert_raises(ArgumentError) { Timestamp.new(1476316800, 0, utc_offset) } assert_equal('utc_offset must be an Integer, :utc or nil', error.message) end end def test_add_and_set_utc_offset_utc t1 = Timestamp.new(1476316800, Rational(1, 10)) t2 = Timestamp.new(1476316800, Rational(1, 10), 0) t3 = Timestamp.new(1476316800, Rational(1, 10), :utc) r1 = t1.add_and_set_utc_offset(-1, :utc) r2 = t2.add_and_set_utc_offset(1, :utc) r3 = t3.add_and_set_utc_offset(2, :utc) assert_equal(1476316799, r1.value) assert_equal(1476316801, r2.value) assert_equal(1476316802, r3.value) assert_equal(Rational(1, 10), r1.sub_second) assert_equal(Rational(1, 10), r2.sub_second) assert_equal(Rational(1, 10), r3.sub_second) assert_equal(0, r1.utc_offset) assert_equal(0, r2.utc_offset) assert_equal(0, r3.utc_offset) assert_equal(true, r1.utc?) assert_equal(true, r2.utc?) assert_equal(true, r3.utc?) end def test_add_and_set_utc_offset_zero t1 = Timestamp.new(1476316800, Rational(1, 10)) t2 = Timestamp.new(1476316800, Rational(1, 10), 0) t3 = Timestamp.new(1476316800, Rational(1, 10), :utc) r1 = t1.add_and_set_utc_offset(-1, 0) r2 = t2.add_and_set_utc_offset(1, 0) r3 = t3.add_and_set_utc_offset(2, 0) assert_equal(1476316799, r1.value) assert_equal(1476316801, r2.value) assert_equal(1476316802, r3.value) assert_equal(Rational(1, 10), r1.sub_second) assert_equal(Rational(1, 10), r2.sub_second) assert_equal(Rational(1, 10), r3.sub_second) assert_equal(0, r1.utc_offset) assert_equal(0, r2.utc_offset) assert_equal(0, r3.utc_offset) assert_equal(false, r1.utc?) assert_equal(false, r2.utc?) assert_equal(false, r3.utc?) end def test_add_and_set_utc_offset_non_zero t1 = Timestamp.new(1476316800, Rational(1, 10)) t2 = Timestamp.new(1476316800, Rational(1, 10), 0) t3 = Timestamp.new(1476316800, Rational(1, 10), :utc) r1 = t1.add_and_set_utc_offset(-1, 3600) r2 = t2.add_and_set_utc_offset(1, 3600) r3 = t3.add_and_set_utc_offset(2, 3600) assert_equal(1476316799, r1.value) assert_equal(1476316801, r2.value) assert_equal(1476316802, r3.value) assert_equal(Rational(1, 10), r1.sub_second) assert_equal(Rational(1, 10), r2.sub_second) assert_equal(Rational(1, 10), r3.sub_second) assert_equal(3600, r1.utc_offset) assert_equal(3600, r2.utc_offset) assert_equal(3600, r3.utc_offset) assert_equal(false, r1.utc?) assert_equal(false, r2.utc?) assert_equal(false, r3.utc?) end def test_add_and_set_utc_offset_unspecified t1 = Timestamp.new(1476316800, Rational(1, 10)) t2 = Timestamp.new(1476316800, Rational(1, 10), 0) t3 = Timestamp.new(1476316800, Rational(1, 10), :utc) r1 = t1.add_and_set_utc_offset(-1, nil) r2 = t2.add_and_set_utc_offset(1, nil) r3 = t3.add_and_set_utc_offset(2, nil) assert_equal(1476316799, r1.value) assert_equal(1476316801, r2.value) assert_equal(1476316802, r3.value) assert_equal(Rational(1, 10), r1.sub_second) assert_equal(Rational(1, 10), r2.sub_second) assert_equal(Rational(1, 10), r3.sub_second) assert_nil(r1.utc_offset) assert_nil(r2.utc_offset) assert_nil(r3.utc_offset) assert_nil(r1.utc?) assert_nil(r2.utc?) assert_nil(r3.utc?) end def test_add_and_set_utc_offset_add_zero_same_offset t1 = Timestamp.new(1476316800, Rational(1, 10)) t2 = Timestamp.new(1476316800, Rational(1, 10), 0) t3 = Timestamp.new(1476316800, Rational(1, 10), :utc) r1 = t1.add_and_set_utc_offset(0, nil) r2 = t2.add_and_set_utc_offset(0, 0) r3 = t3.add_and_set_utc_offset(0, :utc) assert_same(t1, r1) assert_same(t2, r2) assert_same(t3, r3) end def test_add_and_set_utc_offset_seconds_nil error = assert_raises(ArgumentError) { Timestamp.new(1476316800).add_and_set_utc_offset(nil, 0) } assert_equal('seconds must be an Integer', error.message) end def test_add_and_set_utc_offset_seconds_non_integer error = assert_raises(ArgumentError) { Timestamp.new(1476316800).add_and_set_utc_offset(1.0, 0) } assert_equal('seconds must be an Integer', error.message) end def test_add_and_set_utc_offset_utc_offset_not_integer_or_utc [1.0, :zero].each do |utc_offset| error = assert_raises(ArgumentError) { Timestamp.new(1476316800).add_and_set_utc_offset(1, utc_offset) } assert_equal('utc_offset must be an Integer, :utc or nil', error.message) end end def test_utc_from_utc t = Timestamp.new(1476316800, 0, :utc) assert_same(t, t.utc) end def test_utc_from_zero_offset t = Timestamp.new(1476316800, 0, 0).utc assert_equal(1476316800, t.value) assert_equal(0, t.sub_second) assert_equal(0, t.utc_offset) assert_equal(true, t.utc?) end def test_utc_from_non_zero_offset t = Timestamp.new(1476316800, 0, 3600).utc assert_equal(1476316800, t.value) assert_equal(0, t.sub_second) assert_equal(0, t.utc_offset) assert_equal(true, t.utc?) end def test_utc_from_unspecified_offset t = Timestamp.new(1476316800, 0).utc assert_equal(1476316800, t.value) assert_equal(0, t.sub_second) assert_equal(0, t.utc_offset) assert_equal(true, t.utc?) end def test_utc_sub_second t = Timestamp.new(1476316800, Rational(1, 10), 0).utc assert_equal(1476316800, t.value) assert_equal(Rational(1, 10), t.sub_second) assert_equal(0, t.utc_offset) assert_equal(true, t.utc?) end def test_to_time assert_equal_with_offset(Time.utc(2016,10,13,0,0,1), Timestamp.new(1476316801).to_time) assert_equal_with_offset(Time.utc(2016,10,13,0,0,1,Rational(100_000,1)), Timestamp.new(1476316801, Rational(1,10)).to_time) assert_equal_with_offset(Time.new(2016,10,13,0,0,1,0), Timestamp.new(1476316801, 0, 0).to_time) assert_equal_with_offset(Time.new(2016,10,13,0,0,1+Rational(1,10), 0), Timestamp.new(1476316801, Rational(1,10), 0).to_time) assert_equal_with_offset(Time.utc(2016,10,13,0,0,1), Timestamp.new(1476316801, 0, :utc).to_time) assert_equal_with_offset(Time.utc(2016,10,13,0,0,1,Rational(100_000,1)), Timestamp.new(1476316801, Rational(1,10), :utc).to_time) assert_equal_with_offset(Time.new(2016,10,13,1,0,1,3600), Timestamp.new(1476316801, 0, 3600).to_time) assert_equal_with_offset(Time.new(2016,10,13,1,0,Rational(11,10),3600), Timestamp.new(1476316801, Rational(1,10), 3600).to_time) end def test_to_datetime assert_equal_with_offset(DateTime.new(2016,10,13,0,0,1), Timestamp.new(1476316801).to_datetime) assert_equal_with_offset(DateTime.new(2016,10,13,0,0,Rational(11,10)), Timestamp.new(1476316801, Rational(1,10)).to_datetime) assert_equal_with_offset(DateTime.new(2016,10,13,0,0,1), Timestamp.new(1476316801, 0, 0).to_datetime) assert_equal_with_offset(DateTime.new(2016,10,13,0,0,Rational(11,10)), Timestamp.new(1476316801, Rational(1,10), 0).to_datetime) assert_equal_with_offset(DateTime.new(2016,10,13,0,0,1), Timestamp.new(1476316801, 0, :utc).to_datetime) assert_equal_with_offset(DateTime.new(2016,10,13,0,0,Rational(11,10)), Timestamp.new(1476316801, Rational(1,10), :utc).to_datetime) assert_equal_with_offset(DateTime.new(2016,10,13,1,0,1,Rational(1,24)), Timestamp.new(1476316801, 0, 3600).to_datetime) assert_equal_with_offset(DateTime.new(2016,10,13,1,0,Rational(11,10),Rational(1,24)), Timestamp.new(1476316801, Rational(1,10), 3600).to_datetime) end def test_to_i assert_equal(1476316801, Timestamp.new(1476316801).to_i) assert_equal(1476316801, Timestamp.new(1476316801, Rational(1,10)).to_i) assert_equal(1476316801, Timestamp.new(1476316801, 0, 0).to_i) assert_equal(1476316801, Timestamp.new(1476316801, Rational(1,10), 0).to_i) assert_equal(1476316801, Timestamp.new(1476316801, 0, :utc).to_i) assert_equal(1476316801, Timestamp.new(1476316801, Rational(1,10), :utc).to_i) assert_equal(1476316801, Timestamp.new(1476316801, 0, 3600).to_i) assert_equal(1476316801, Timestamp.new(1476316801, Rational(1,10), 3600).to_i) end def test_to_datetime_returns_gregorian # 1582-10-15 is the start of the Gregorian calendar. The previous day was 1582-10-04 in the Julian calendar). # TZInfo will always use the proleptic Gregorian calendar to return dates prior to 1582-10-15. dt = Timestamp.new(-12219379200).to_datetime # assert_equal_with_offset (assert_equal) will consider the Julian result 1582-10-04 to be equal to the Gregorian result 1582-10-14. assert_equal_with_offset(DateTime.new(1582, 10, 14, 0, 0, 0, 0, Date::GREGORIAN), dt) assert_equal(1582, dt.year) assert_equal(10, dt.month) assert_equal(14, dt.day) assert(dt.gregorian?) end def test_strftime # Timestamp#strftime calls Time#strftime. No need to test formats exhaustively. assert_equal('2016-10-13 00:00:00.100 +0000 %', Timestamp.new(1476316800, Rational(1,10) ).strftime('%Y-%m-%d %H:%M:%S.%L %z %%')) assert_equal('2016-10-13 00:00:00.100 +0000 %', Timestamp.new(1476316800, Rational(1,10), :utc).strftime('%Y-%m-%d %H:%M:%S.%L %z %%')) assert_equal('2016-10-13 00:00:00.100 +0000 %', Timestamp.new(1476316800, Rational(1,10), 0).strftime('%Y-%m-%d %H:%M:%S.%L %z %%')) assert_equal('2016-10-13 01:00:00.100 +0100 %', Timestamp.new(1476316800, Rational(1,10), 3600).strftime('%Y-%m-%d %H:%M:%S.%L %z %%')) assert_equal('2016-10-12 23:00:00.100 -0100 %', Timestamp.new(1476316800, Rational(1,10), -3600).strftime('%Y-%m-%d %H:%M:%S.%L %z %%')) end def test_strftime_nil_format t = Timestamp.new(1476316800, Rational(1,10)) error = assert_raises(ArgumentError) { t.strftime(nil) } assert_equal('format must be specified', error.message) end def test_to_s_without_offset assert_equal('1476316800', Timestamp.new(1476316800).to_s) end def test_to_s_utc assert_equal('1476316800 UTC', Timestamp.new(1476316800, 0, :utc).to_s) end def test_to_s_offset assert_equal('1476316800 +00:00', Timestamp.new(1476316800, 0, 0).to_s) assert_equal('1476320400 +01:00 (1476316800 UTC)', Timestamp.new(1476316800, 0, 3600).to_s) assert_equal('1476313200 -01:00 (1476316800 UTC)', Timestamp.new(1476316800, 0, -3600).to_s) assert_equal('1476318300 +00:25 (1476316800 UTC)', Timestamp.new(1476316800, 0, 1500).to_s) assert_equal('1476315300 -00:25 (1476316800 UTC)', Timestamp.new(1476316800, 0, -1500).to_s) assert_equal('1476318303 +00:25:03 (1476316800 UTC)', Timestamp.new(1476316800, 0, 1503).to_s) assert_equal('1476315297 -00:25:03 (1476316800 UTC)', Timestamp.new(1476316800, 0, -1503).to_s) assert_equal('1476406800 +25:00 (1476316800 UTC)', Timestamp.new(1476316800, 0, 90000).to_s) assert_equal('1476226800 -25:00 (1476316800 UTC)', Timestamp.new(1476316800, 0, -90000).to_s) end def test_to_s_sub_second assert_equal('1476316800 1/5', Timestamp.new(1476316800, Rational(2, 10)).to_s) end def test_to_s_utc_sub_second assert_equal('1476316800 1/5 UTC', Timestamp.new(1476316800, Rational(2, 10), :utc).to_s) end def test_to_s_offset_sub_second assert_equal('1476316800 1/5 +00:00', Timestamp.new(1476316800, Rational(2, 10), 0).to_s) assert_equal('1476320400 1/5 +01:00 (1476316800 1/5 UTC)', Timestamp.new(1476316800, Rational(2, 10), 3600).to_s) end def test_compare assert_equal(-1, Timestamp.new(1476313200) <=> Timestamp.new(1476316800)) assert_equal(0, Timestamp.new(1476316800) <=> Timestamp.new(1476316800)) assert_equal(1, Timestamp.new(1476316800) <=> Timestamp.new(1476313200)) assert_equal(-1, Timestamp.new(1476316800, Rational(100_000_000, 1_000_000_000)) <=> Timestamp.new(1476316800, Rational(100_000_001, 1_000_000_000))) assert_equal(0, Timestamp.new(1476316800, Rational(100_000_001, 1_000_000_000)) <=> Timestamp.new(1476316800, Rational(100_000_001, 1_000_000_000))) assert_equal(1, Timestamp.new(1476316800, Rational(100_000_001, 1_000_000_000)) <=> Timestamp.new(1476316800, Rational(100_000_000, 1_000_000_000))) assert_equal(-1, Timestamp.new(1476313200, 0, 3600) <=> Timestamp.new(1476316800, 0, 0)) assert_equal(0, Timestamp.new(1476316800, 0, 3600) <=> Timestamp.new(1476316800, 0, 0)) assert_equal(1, Timestamp.new(1476316800, 0, 0) <=> Timestamp.new(1476313200, 0, 3600)) assert_equal(-1, Timestamp.new(1476313200, 0, 3600) <=> Timestamp.new(1476316800, 0, :utc)) assert_equal(0, Timestamp.new(1476316800, 0, 3600) <=> Timestamp.new(1476316800, 0, :utc)) assert_equal(1, Timestamp.new(1476316800, 0, :utc) <=> Timestamp.new(1476313200, 0, 3600)) assert_equal(-1, Timestamp.new(1476316800, Rational(100_000_000, 1_000_000_000), 3600) <=> Timestamp.new(1476316800, Rational(100_000_001, 1_000_000_000), 0)) assert_equal(0, Timestamp.new(1476316800, Rational(100_000_001, 1_000_000_000), 3600) <=> Timestamp.new(1476316800, Rational(100_000_001, 1_000_000_000), 0)) assert_equal(1, Timestamp.new(1476316800, Rational(100_000_001, 1_000_000_000), 0) <=> Timestamp.new(1476316800, Rational(100_000_000, 1_000_000_000), 3600)) assert_equal(-1, Timestamp.new(1476316800, Rational(100_000_000, 1_000_000_000), 3600) <=> Timestamp.new(1476316800, Rational(100_000_001, 1_000_000_000), :utc)) assert_equal(0, Timestamp.new(1476316800, Rational(100_000_001, 1_000_000_000), 3600) <=> Timestamp.new(1476316800, Rational(100_000_001, 1_000_000_000), :utc)) assert_equal(1, Timestamp.new(1476316800, Rational(100_000_001, 1_000_000_000), :utc) <=> Timestamp.new(1476316800, Rational(100_000_000, 1_000_000_000), 3600)) assert_nil(Timestamp.new(1476316800) <=> Timestamp.new(1476316800, 0, 0)) assert_nil(Timestamp.new(1476316800, 0, 0) <=> Timestamp.new(1476316800)) assert_nil(Timestamp.new(1476316800) <=> Timestamp.new(1476316800, 0, :utc)) assert_nil(Timestamp.new(1476316800, 0, :utc) <=> Timestamp.new(1476316800)) assert_nil(Timestamp.new(1476316800) <=> Object.new) assert_nil(Timestamp.new(1476316800) <=> 1476316800) end def test_eql assert_equal(false, Timestamp.new(1476313200).eql?(Timestamp.new(1476316800))) assert_equal(true, Timestamp.new(1476316800).eql?(Timestamp.new(1476316800))) assert_equal(false, Timestamp.new(1476316800).eql?(Timestamp.new(1476313200))) assert_equal(false, Timestamp.new(1476316800, Rational(100_000_000, 1_000_000_000)).eql?(Timestamp.new(1476316800, Rational(100_000_001, 1_000_000_000)))) assert_equal(true, Timestamp.new(1476316800, Rational(100_000_001, 1_000_000_000)).eql?(Timestamp.new(1476316800, Rational(100_000_001, 1_000_000_000)))) assert_equal(false, Timestamp.new(1476316800, Rational(100_000_001, 1_000_000_000)).eql?(Timestamp.new(1476316800, Rational(100_000_000, 1_000_000_000)))) assert_equal(false, Timestamp.new(1476313200, 0, 3600).eql?(Timestamp.new(1476316800, 0, 0))) assert_equal(true, Timestamp.new(1476316800, 0, 3600).eql?(Timestamp.new(1476316800, 0, 0))) assert_equal(false, Timestamp.new(1476316800, 0, 0).eql?(Timestamp.new(1476313200, 0, 3600))) assert_equal(false, Timestamp.new(1476313200, 0, 3600).eql?(Timestamp.new(1476316800, 0, :utc))) assert_equal(true, Timestamp.new(1476316800, 0, 3600).eql?(Timestamp.new(1476316800, 0, :utc))) assert_equal(false, Timestamp.new(1476316800, 0, :utc).eql?(Timestamp.new(1476313200, 0, 3600))) assert_equal(false, Timestamp.new(1476316800, Rational(100_000_000, 1_000_000_000), 3600).eql?(Timestamp.new(1476316800, Rational(100_000_001, 1_000_000_000), 0))) assert_equal(true, Timestamp.new(1476316800, Rational(100_000_001, 1_000_000_000), 3600).eql?(Timestamp.new(1476316800, Rational(100_000_001, 1_000_000_000), 0))) assert_equal(false, Timestamp.new(1476316800, Rational(100_000_001, 1_000_000_000), 0).eql?(Timestamp.new(1476316800, Rational(100_000_000, 1_000_000_000), 3600))) assert_equal(false, Timestamp.new(1476316800, Rational(100_000_000, 1_000_000_000), 3600).eql?(Timestamp.new(1476316800, Rational(100_000_001, 1_000_000_000), :utc))) assert_equal(true, Timestamp.new(1476316800, Rational(100_000_001, 1_000_000_000), 3600).eql?(Timestamp.new(1476316800, Rational(100_000_001, 1_000_000_000), :utc))) assert_equal(false, Timestamp.new(1476316800, Rational(100_000_001, 1_000_000_000), :utc).eql?(Timestamp.new(1476316800, Rational(100_000_000, 1_000_000_000), 3600))) assert_equal(false, Timestamp.new(1476316800).eql?(Timestamp.new(1476316800, 0, 0))) assert_equal(false, Timestamp.new(1476316800, 0, 0).eql?(Timestamp.new(1476316800))) assert_equal(false, Timestamp.new(1476316800).eql?(Timestamp.new(1476316800, 0, :utc))) assert_equal(false, Timestamp.new(1476316800, 0, :utc).eql?(Timestamp.new(1476316800))) assert_equal(false, Timestamp.new(1476316800).eql?(Object.new)) assert_equal(false, Timestamp.new(1476316800).eql?(1476316800)) end def test_hash assert_equal([1476316800, 0, false].hash, Timestamp.new(1476316800).hash) assert_equal([1476316800, 0, true].hash, Timestamp.new(1476316800, 0, 0).hash) assert_equal([1476316800, 0, true].hash, Timestamp.new(1476316800, 0, :utc).hash) assert_equal([1476316800, 0, true].hash, Timestamp.new(1476316800, Rational(0, 1), 0).hash) assert_equal([1476316800, Rational(1, 10), true].hash, Timestamp.new(1476316800, Rational(1, 10), 3600).hash) end def test_inspect assert_equal('#', Timestamp.new(1476316800, 0, 0).inspect) assert_equal('#', Timestamp.new(1476316800, Rational(0, 1), :utc).inspect) assert_equal('#', Timestamp.new(1476316800, Rational(1, 10), 3600).inspect) assert_equal('#', Timestamp.new(1476316800, Rational(1, 10), nil).inspect) end def test_create_unspecified_offset t = Timestamp.create(2018, 1, 10, 12, 0, 0, 0, nil) assert_equal(1515585600, t.value) assert_nil(t.utc_offset) assert_nil(t.utc?) end def test_create_utc t = Timestamp.create(2018, 1, 10, 12, 0, 0, 0, :utc) assert_equal(1515585600, t.value) assert_equal(0, t.utc_offset) assert_equal(true, t.utc?) end def test_create_zero_offset t = Timestamp.create(2018, 1, 10, 12, 0, 0, 0, 0) assert_equal(1515585600, t.value) assert_equal(0, t.utc_offset) assert_equal(false, t.utc?) end def test_create_local_offset_positive t = Timestamp.create(2018, 1, 10, 12, 0, 0, 0, 3600) assert_equal(1515582000, t.value) assert_equal(3600, t.utc_offset) assert_equal(false, t.utc?) end def test_create_local_offset_negative t = Timestamp.create(2018, 1, 10, 12, 0, 0, 0, -3600) assert_equal(1515589200, t.value) assert_equal(-3600, t.utc_offset) assert_equal(false, t.utc?) end def test_create_local_offset_zero_sub_second t = Timestamp.create(2018, 1, 10, 12, 0, 0, 0) assert_equal(1515585600, t.value) assert_equal(0, t.sub_second) end def test_create_local_offset_non_zero_sub_second t = Timestamp.create(2018, 1, 10, 12, 0, 0, Rational(1, 10)) assert_equal(1515585600, t.value) assert_equal(Rational(1, 10), t.sub_second) end def test_create_valid assert_equal(-76350405973, Timestamp.create(-450, 7, 21, 17, 53, 47).value) assert_equal(-62198755200, Timestamp.create( -1, 1, 1, 0, 0, 0).value) assert_equal(-62162035200, Timestamp.create( 0, 3, 1, 0, 0, 0).value) assert_equal( -1, Timestamp.create(1969, 12, 31, 23, 59, 59).value) assert_equal( 0, Timestamp.create(1970, 1, 1, 0, 0, 0).value) assert_equal( 1, Timestamp.create(1970, 1, 1, 0, 0, 1).value) assert_equal( 47843, Timestamp.create(1970, 1, 1, 13, 17, 23).value) assert_equal( 951782400, Timestamp.create(2000, 2, 29, 0, 0, 0).value) assert_equal( 951868800, Timestamp.create(2000, 3, 1, 0, 0, 0).value) assert_equal( 954547200, Timestamp.create(2000, 4, 1, 0, 0, 0).value) assert_equal( 957139200, Timestamp.create(2000, 5, 1, 0, 0, 0).value) assert_equal( 959817600, Timestamp.create(2000, 6, 1, 0, 0, 0).value) assert_equal( 962409600, Timestamp.create(2000, 7, 1, 0, 0, 0).value) assert_equal( 965088000, Timestamp.create(2000, 8, 1, 0, 0, 0).value) assert_equal( 967766400, Timestamp.create(2000, 9, 1, 0, 0, 0).value) assert_equal( 970358400, Timestamp.create(2000, 10, 1, 0, 0, 0).value) assert_equal( 973036800, Timestamp.create(2000, 11, 1, 0, 0, 0).value) assert_equal( 975628800, Timestamp.create(2000, 12, 1, 0, 0, 0).value) assert_equal( 978307200, Timestamp.create(2001, 1, 1, 0, 0, 0).value) assert_equal( 980985600, Timestamp.create(2001, 2, 1, 0, 0, 0).value) assert_equal( 983404800, Timestamp.create(2001, 3, 1, 0, 0, 0).value) assert_equal( 4107456000, Timestamp.create(2100, 2, 28, 0, 0, 0).value) assert_equal( 4107542400, Timestamp.create(2100, 3, 1, 0, 0, 0).value) end def test_create_invalid_days_for_specific_month assert_equal(1519862400, Timestamp.create(2018, 2, 29).value) assert_equal(1525132800, Timestamp.create(2018, 4, 31).value) end def test_create_month_out_of_range [0, 13].each do |month| error = assert_raises(RangeError) { Timestamp.create(2018, month) } assert_equal('month must be between 1 and 12', error.message) end end def test_create_day_out_of_range [0, 32].each do |day| error = assert_raises(RangeError) { Timestamp.create(2018, 1, day) } assert_equal('day must be between 1 and 31', error.message) end end def test_create_hour_out_of_range [-1, 24].each do |hour| error = assert_raises(RangeError) { Timestamp.create(2018, 1, 1, hour) } assert_equal('hour must be between 0 and 23', error.message) end end def test_create_minute_out_of_range [-1, 60].each do |minute| error = assert_raises(RangeError) { Timestamp.create(2018, 1, 1, 0, minute) } assert_equal('minute must be between 0 and 59', error.message) end end def test_create_second_out_of_range [-1, 60].each do |second| error = assert_raises(RangeError) { Timestamp.create(2018, 1, 1, 0, 0, second) } assert_equal('second must be between 0 and 59', error.message) end end def test_create_year_not_integer error = assert_raises(ArgumentError) { Timestamp.create(2018.0) } assert_equal('year must be an Integer', error.message) end def test_create_month_not_integer error = assert_raises(ArgumentError) { Timestamp.create(2018, 1.0) } assert_equal('month must be an Integer', error.message) end def test_create_day_not_integer error = assert_raises(ArgumentError) { Timestamp.create(2018, 1, 1.0) } assert_equal('day must be an Integer', error.message) end def test_create_hour_not_integer error = assert_raises(ArgumentError) { Timestamp.create(2018, 1, 1, 0.0) } assert_equal('hour must be an Integer', error.message) end def test_create_minute_not_integer error = assert_raises(ArgumentError) { Timestamp.create(2018, 1, 1, 0, 0.0) } assert_equal('minute must be an Integer', error.message) end def test_create_second_not_integer error = assert_raises(ArgumentError) { Timestamp.create(2018, 1, 1, 0, 0, 0.0) } assert_equal('second must be an Integer', error.message) end def test_create_sub_second_not_zero_integer_or_rational [nil, 0.1, 1].each do |sub_second| error = assert_raises(ArgumentError) { Timestamp.create(2018, 1, 1, 0, 0, 0, sub_second) } assert_equal('sub_second must be a Rational or the Integer 0', error.message) end end def test_create_sub_second_out_of_range [Rational(-1, 10), Rational(1, 1)].each do |sub_second| error = assert_raises(RangeError) { Timestamp.create(2018, 1, 1, 0, 0, 0, sub_second) } assert_equal('sub_second must be >= 0 and < 1', error.message) end end def test_create_utc_offset_not_integer_or_utc [1.0, :zero].each do |utc_offset| error = assert_raises(ArgumentError) { Timestamp.create(2018, 1, 1, 0, 0, 0, 0, utc_offset) } assert_equal('utc_offset must be an Integer, :utc or nil', error.message) end end # Test Timestamp.for with and without a block. def for_test(*args) t = Timestamp.for(*args) assert_kind_of(Timestamp, t) yield t block_called = 0 block_result = Timestamp.for(*args) do |t2| block_called += 1 assert_kind_of(Timestamp, t2) yield t2 t2 end assert_equal(1, block_called) expected_class = case args[0] when TestTimestampSubclass Timestamp when TestUtils::TimeLike Time else args[0].class end assert_kind_of(expected_class, block_result) end def test_for_timestamp_ignore_offset_utc for_test(Timestamp.new(1476316800, 0, :utc), :ignore) do |t| assert_equal(1476316800, t.value) assert_equal(0, t.sub_second) assert_nil(t.utc_offset) assert_nil(t.utc?) end end def test_for_timestamp_ignore_offset_with_zero_offset for_test(Timestamp.new(1476316800, 0, 0), :ignore) do |t| assert_equal(1476316800, t.value) assert_equal(0, t.sub_second) assert_nil(t.utc_offset) assert_nil(t.utc?) end end def test_for_timestamp_ignore_offset_with_offset for_test(Timestamp.new(1476316800, 0, 3600), :ignore) do |t| assert_equal(1476320400, t.value) assert_equal(0, t.sub_second) assert_nil(t.utc_offset) assert_nil(t.utc?) end end def test_for_timestamp_ignore_offset_sub_second for_test(Timestamp.new(1476316800, Rational(1, 10), 3600), :ignore) do |t| assert_equal(1476320400, t.value) assert_equal(Rational(1, 10), t.sub_second) assert_nil(t.utc_offset) assert_nil(t.utc?) end end def test_for_timestamp_ignore_offset_no_offset orig = Timestamp.new(1476316800) for_test(orig, :ignore) {|t| assert_same(orig, t) } end def test_for_timestamp_ignore_offset_subclass_no_offset for_test(TestTimestampSubclass.new(1476316800, Rational(1, 10)), :ignore) do |t| assert_equal(Timestamp, t.class) assert_equal(1476316800, t.value) assert_equal(Rational(1, 10), t.sub_second) assert_nil(t.utc_offset) assert_nil(t.utc?) end end def test_for_timestamp_treat_offset_as_utc_utc orig = Timestamp.new(1476316800, 0, :utc) for_test(orig, :treat_as_utc) {|t| assert_same(orig, t) } end def test_for_timestamp_treat_offset_as_utc_with_zero_offset for_test(Timestamp.new(1476316800, 0, 0), :treat_as_utc) do |t| assert_equal(1476316800, t.value) assert_equal(0, t.sub_second) assert_equal(0, t.utc_offset) assert_equal(true, t.utc?) end end def test_for_timestamp_treat_offset_as_utc_with_offset for_test(Timestamp.new(1476316800, 0, 3600), :treat_as_utc) do |t| assert_equal(1476320400, t.value) assert_equal(0, t.sub_second) assert_equal(0, t.utc_offset) assert_equal(true, t.utc?) end end def test_for_timestamp_treat_offset_as_utc_sub_second for_test(Timestamp.new(1476316800, Rational(1, 10), 3600), :treat_as_utc) do |t| assert_equal(1476320400, t.value) assert_equal(Rational(1, 10), t.sub_second) assert_equal(0, t.utc_offset) assert_equal(true, t.utc?) end end def test_for_timestamp_treat_offset_as_utc_no_offset for_test(Timestamp.new(1476316800), :treat_as_utc) do |t| assert_equal(1476316800, t.value) assert_equal(0, t.sub_second) assert_equal(0, t.utc_offset) assert_equal(true, t.utc?) end end def test_for_timestamp_treat_offset_as_utc_subclass_utc for_test(TestTimestampSubclass.new(1476316800, Rational(1, 10), :utc), :treat_as_utc) do |t| assert_equal(Timestamp, t.class) assert_equal(1476316800, t.value) assert_equal(Rational(1, 10), t.sub_second) assert_equal(0, t.utc_offset) assert_equal(true, t.utc?) end end def test_for_timestamp_preserve_offset_utc orig = Timestamp.new(1476316800, 0, :utc) for_test(orig, :preserve) {|t| assert_same(orig, t) } end def test_for_timestamp_preserve_offset_with_zero_offset orig = Timestamp.new(1476316800, 0, 0) for_test(orig, :preserve) {|t| assert_same(orig, t) } end def test_for_timestamp_preserve_offset_with_offset orig = Timestamp.new(1476316800, 0, 3600) for_test(orig, :preserve) {|t| assert_same(orig, t) } end def test_for_timestamp_preserve_offset_by_default_with_offset orig = Timestamp.new(1476316800, 0, 3600) for_test(orig) {|t| assert_same(orig, t) } end def test_for_timestamp_preserve_offset_no_offset orig = Timestamp.new(1476316800) for_test(orig, :preserve) {|t| assert_same(orig, t) } end def test_for_timestamp_preserve_offset_sub_second orig = Timestamp.new(1476316800, Rational(1, 10), 0) for_test(orig, :preserve) {|t| assert_same(orig, t) } end def test_for_timestamp_preserve_offset_subclass_utc for_test(TestTimestampSubclass.new(1476316800, Rational(1, 10), :utc)) do |t| assert_equal(Timestamp, t.class) assert_equal(1476316800, t.value) assert_equal(Rational(1, 10), t.sub_second) assert_equal(0, t.utc_offset) assert_equal(true, t.utc?) end end def test_for_timestamp_preserve_offset_subclass_with_zero_offset for_test(TestTimestampSubclass.new(1476316800, Rational(1, 10), 0)) do |t| assert_equal(Timestamp, t.class) assert_equal(1476316800, t.value) assert_equal(Rational(1, 10), t.sub_second) assert_equal(0, t.utc_offset) assert_equal(false, t.utc?) end end def test_for_timestamp_preserve_offset_subclass_with_offset for_test(TestTimestampSubclass.new(1476316800, Rational(1, 10), 3600)) do |t| assert_equal(Timestamp, t.class) assert_equal(1476316800, t.value) assert_equal(Rational(1, 10), t.sub_second) assert_equal(3600, t.utc_offset) assert_equal(false, t.utc?) end end def test_for_timestamp_preserve_offset_subclass_no_offset for_test(TestTimestampSubclass.new(1476316800, Rational(1, 10))) do |t| assert_equal(Timestamp, t.class) assert_equal(1476316800, t.value) assert_equal(Rational(1, 10), t.sub_second) assert_nil(t.utc_offset) assert_nil(t.utc?) end end def test_for_time_ignore_offset_utc for_test(Time.utc(2016,10,13,0,0,0), :ignore) do |t| assert_equal(1476316800, t.value) assert_nil(t.utc_offset) assert_nil(t.utc?) end end def test_for_time_ignore_offset_with_zero_offset for_test(Time.new(2016,10,13,0,0,0,0), :ignore) do |t| assert_equal(1476316800, t.value) assert_nil(t.utc_offset) assert_nil(t.utc?) end end def test_for_time_ignore_offset_with_offset for_test(Time.new(2016,10,13,0,0,0,3600), :ignore) do |t| assert_equal(1476316800, t.value) assert_nil(t.utc_offset) assert_nil(t.utc?) end end def test_for_time_treat_offset_as_utc_utc for_test(Time.utc(2016,10,13,0,0,0), :treat_as_utc) do |t| assert_equal(1476316800, t.value) assert_equal(0, t.utc_offset) assert_equal(true, t.utc?) end end def test_for_time_treat_offset_as_utc_with_zero_offset for_test(Time.new(2016,10,13,0,0,0,0), :treat_as_utc) do |t| assert_equal(1476316800, t.value) assert_equal(0, t.utc_offset) assert_equal(true, t.utc?) end end def test_for_time_treat_offset_as_utc_with_offset for_test(Time.new(2016,10,13,0,0,0,3600), :treat_as_utc) do |t| assert_equal(1476316800, t.value) assert_equal(0, t.utc_offset) assert_equal(true, t.utc?) end end def test_for_time_preserve_offset_utc for_test(Time.utc(2016,10,13,0,0,0), :preserve) do |t| assert_equal(1476316800, t.value) assert_equal(0, t.utc_offset) assert_equal(true, t.utc?) end end def test_for_time_preserve_offset_zero_offset for_test(Time.new(2016,10,13,0,0,0,0), :preserve) do |t| assert_equal(1476316800, t.value) assert_equal(0, t.utc_offset) assert_equal(!TestUtils::TIME_SUPPORTS_DISTINCT_UTC, t.utc?) end end def test_for_time_preserve_offset_with_offset for_test(Time.new(2016,10,13,1,0,0,3600), :preserve) do |t| assert_equal(1476316800, t.value) assert_equal(3600, t.utc_offset) assert_equal(false, t.utc?) end end def test_for_time_preserve_offset_by_default_with_offset for_test(Time.new(2016,10,13,1,0,0,3600)) do |t| assert_equal(1476316800, t.value) assert_equal(3600, t.utc_offset) assert_equal(false, t.utc?) end end def test_for_time_zero_sub_second for_test(Time.utc(2016,10,13,0,0,1)) do |t| assert_equal(1476316801, t.value) assert_equal(0, t.sub_second) end end def test_for_time_sub_second for_test(Time.utc(2016,10,13,0,0,1,Rational(100_000,1))) do |t| assert_equal(1476316801, t.value) assert_equal(Rational(1,10), t.sub_second) end end def test_for_datetime_ignore_offset_utc for_test(DateTime.new(2016,10,13,0,0,0), :ignore) do |t| assert_equal(1476316800, t.value) assert_nil(t.utc_offset) assert_nil(t.utc?) end end def test_for_datetime_ignore_offset_with_offset for_test(DateTime.new(2016,10,13,0,0,0,Rational(1,24)), :ignore) do |t| assert_equal(1476316800, t.value) assert_nil(t.utc_offset) assert_nil(t.utc?) end end def test_for_datetime_treat_offset_as_utc_utc for_test(DateTime.new(2016,10,13,0,0,0), :treat_as_utc) do |t| assert_equal(1476316800, t.value) assert_equal(0, t.utc_offset) assert_equal(true, t.utc?) end end def test_for_datetime_treat_offset_as_utc_with_offset for_test(DateTime.new(2016,10,13,0,0,0,Rational(1,24)), :treat_as_utc) do |t| assert_equal(1476316800, t.value) assert_equal(0, t.utc_offset) assert_equal(true, t.utc?) end end def test_for_datetime_preserve_offset_with_zero_offset for_test(DateTime.new(2016,10,13,0,0,0), :preserve) do |t| assert_equal(1476316800, t.value) assert_equal(0, t.utc_offset) assert_equal(false, t.utc?) end end def test_for_datetime_preserve_offset_with_offset for_test(DateTime.new(2016,10,13,1,0,0,Rational(1,24)), :preserve) do |t| assert_equal(1476316800, t.value) assert_equal(3600, t.utc_offset) assert_equal(false, t.utc?) end end def test_for_datetime_preserve_offset_by_default_with_offset for_test(DateTime.new(2016,10,13,1,0,0,Rational(1,24))) do |t| assert_equal(1476316800, t.value) assert_equal(3600, t.utc_offset) assert_equal(false, t.utc?) end end def test_for_datetime_zero_sub_second for_test(DateTime.new(2016,10,13,0,0,1)) do |t| assert_equal(1476316801, t.value) assert_equal(0, t.sub_second) end end def test_for_datetime_sub_second for_test(DateTime.new(2016,10,13,0,0,Rational(11,10))) do |t| assert_equal(1476316801, t.value) assert_equal(Rational(1,10), t.sub_second) end end def test_for_datetime_julian # 1582-10-04 in the Julian calendar was followed by 1582-10-15 in the Gregorian calendar. # TZInfo will interpret it as the equivalent day in the proleptic Gregorian calendar (1582-10-14). for_test(DateTime.new(1582,10,4,0,0,0,0,Date::ITALY)) do |t| assert_equal(-12219379200, t.value) end end def test_for_datetime_gregorian # The Gregorian calendar starts on 1582-10-15. Iterpret the day before using the proleptic Gregorian calendar. for_test(DateTime.new(1582,10,14,0,0,0,0,Date::GREGORIAN)) do |t| assert_equal(-12219379200, t.value) end end def test_for_time_like_ignore_offset for_test(TestUtils::TimeLike.new(1476316800, 0), :ignore) do |t| assert_equal(1476316800, t.value) assert_nil(t.utc_offset) assert_nil(t.utc?) end end def test_for_time_like_treat_offset_as_utc for_test(TestUtils::TimeLike.new(1476316800, 0), :treat_as_utc) do |t| assert_equal(1476316800, t.value) assert_equal(0, t.utc_offset) assert_equal(true, t.utc?) end end def test_for_time_like_preserve_offset for_test(TestUtils::TimeLike.new(1476316800, 0), :preserve) do |t| assert_equal(1476316800, t.value) assert_equal(0, t.utc_offset) assert_equal(false, t.utc?) end end def test_for_time_like_preserve_offset_by_default for_test(TestUtils::TimeLike.new(1476316800, 0)) do |t| assert_equal(1476316800, t.value) assert_equal(0, t.utc_offset) assert_equal(false, t.utc?) end end def test_for_time_like_zero_sub_second for_test(TestUtils::TimeLike.new(1476316801, 0)) do |t| assert_equal(1476316801, t.value) assert_equal(0, t.sub_second) end end def test_for_time_like_rational_sub_second for_test(TestUtils::TimeLike.new(1476316801, Rational(1,10))) do |t| assert_equal(1476316801, t.value) assert_equal(Rational(1,10), t.sub_second) end end def test_for_time_like_float_sub_second for_test(TestUtils::TimeLike.new(1476316801, 0.1)) do |t| assert_equal(1476316801, t.value) assert_kind_of(Rational, t.sub_second) assert_equal(0.1.to_r, t.sub_second) end end def test_for_time_like_nil_sub_second for_test(TestUtils::TimeLike.new(1476316801, nil)) do |t| assert_equal(1476316801, t.value) assert_equal(0, t.sub_second) end end def test_for_time_like_with_offset_ignore_offset_with_zero_offset for_test(TestUtils::TimeLikeWithOffset.new(1476316800, 0, 0), :ignore) do |t| assert_equal(1476316800, t.value) assert_nil(t.utc_offset) assert_nil(t.utc?) end end def test_for_time_like_with_offset_ignore_offset_with_offset for_test(TestUtils::TimeLikeWithOffset.new(1476316800, 0, 3600), :ignore) do |t| assert_equal(1476320400, t.value) assert_nil(t.utc_offset) assert_nil(t.utc?) end end def test_for_time_like_with_offset_treat_offset_as_utc_with_zero_offset for_test(TestUtils::TimeLikeWithOffset.new(1476316800, 0, 0), :treat_as_utc) do |t| assert_equal(1476316800, t.value) assert_equal(0, t.utc_offset) assert_equal(true, t.utc?) end end def test_for_time_like_with_offset_treat_offset_as_utc_with_offset for_test(TestUtils::TimeLikeWithOffset.new(1476316800, 0, 3600), :treat_as_utc) do |t| assert_equal(1476320400, t.value) assert_equal(0, t.utc_offset) assert_equal(true, t.utc?) end end def test_for_time_like_with_offset_preserve_offset_zero_offset for_test(TestUtils::TimeLikeWithOffset.new(1476316800, 0, 0), :preserve) do |t| assert_equal(1476316800, t.value) assert_equal(0, t.utc_offset) assert_equal(false, t.utc?) end end def test_for_time_like_with_offset_preserve_offset_with_offset for_test(TestUtils::TimeLikeWithOffset.new(1476316800, 0, 3600), :preserve) do |t| assert_equal(1476316800, t.value) assert_equal(3600, t.utc_offset) assert_equal(false, t.utc?) end end def test_for_time_like_with_offset_preserve_offset_by_default_with_offset for_test(TestUtils::TimeLikeWithOffset.new(1476316800, 0, 3600)) do |t| assert_equal(1476316800, t.value) assert_equal(3600, t.utc_offset) assert_equal(false, t.utc?) end end def test_for_time_like_with_offset_preserve_float_offset for_test(TestUtils::TimeLikeWithOffset.new(1476316800, 0, 3600.1), :preserve) do |t| assert_equal(1476316800, t.value) assert_kind_of(Integer, t.utc_offset) assert_equal(3600, t.utc_offset) end end def test_for_time_like_with_offset_preserve_nil_offset for_test(TestUtils::TimeLikeWithOffset.new(1476316800, 0, nil), :preserve) do |t| assert_equal(1476316800, t.value) assert_kind_of(Integer, t.utc_offset) assert_equal(0, t.utc_offset) end end def test_for_time_like_with_offset_treat_float_offset_as_utc for_test(TestUtils::TimeLikeWithOffset.new(1476316800, 0, 3600.1), :treat_as_utc) do |t| assert_kind_of(Integer, t.value) assert_equal(1476320400, t.value) assert_equal(0, t.utc_offset) end end def test_for_time_like_with_offset_treat_nil_offset_as_utc for_test(TestUtils::TimeLikeWithOffset.new(1476316800, 0, nil), :treat_as_utc) do |t| assert_kind_of(Integer, t.value) assert_equal(1476316800, t.value) assert_equal(0, t.utc_offset) end end def for_raises_test(exception, message, *args) error = assert_raises(exception) { Timestamp.for(*args) } assert_equal(message, error.message) error = assert_raises(exception) do Timestamp.for(*args) do |t| flunk('block should not have been called') end end assert_equal(message, error.message) end def test_for_nil_value for_raises_test(ArgumentError, 'value must be specified', nil) end def test_for_invalid_value for_raises_test(ArgumentError, 'Object values are not supported', Object.new) for_raises_test(ArgumentError, "#{Time.utc(2016,10,13,0,0,0).to_i.class} values are not supported", Time.utc(2016,10,13,0,0,0).to_i) end def test_for_invalid_offset for_raises_test(ArgumentError, 'offset must be :preserve, :ignore or :treat_as_utc', Time.utc(2016,10,13,0,0,0), :invalid) end def test_for_time_like_to_i_returns_nil for_raises_test(ArgumentError, 'value must be an Integer', TestUtils::TimeLike.new(nil, 0)) end def test_for_time_like_to_i_returns_non_integer for_raises_test(ArgumentError, 'value must be an Integer', TestUtils::TimeLike.new(1476316800.1, 0)) end def test_for_time_like_subsec_out_of_range [Rational(-1, 10), 1].each do |subsec| for_raises_test(RangeError, 'sub_second must be >= 0 and < 1', TestUtils::TimeLike.new(1476316800, subsec)) end end def test_for_block_result_timestamp block_result = Timestamp.new(1476316801) assert_same(block_result, Timestamp.for(Timestamp.new(1476316800)) {|t| block_result }) end [[:time, Time.utc(2016,10,13,0,0,0)], [:time_like, TestUtils::TimeLike.new(1476316800, 0)], [:time_like_with_offset, TestUtils::TimeLikeWithOffset.new(1476316800, 0, 3600)]].each do |type, input| define_method("test_for_block_result_to_time_for_#{type}") do assert_equal_with_offset(Time.utc(2016,10,13,0,0,1), Timestamp.for(input) { Timestamp.new(1476316801) }) assert_equal_with_offset(Time.utc(2016,10,13,0,0,1,Rational(100_000,1)), Timestamp.for(input) { Timestamp.new(1476316801, Rational(1,10)) }) assert_equal_with_offset(Time.utc(2016,10,13,0,0,1), Timestamp.for(input) { Timestamp.new(1476316801, 0, :utc) }) assert_equal_with_offset(Time.utc(2016,10,13,0,0,1,Rational(100_000,1)), Timestamp.for(input) { Timestamp.new(1476316801, Rational(1,10), :utc) }) assert_equal_with_offset(Time.new(2016,10,13,0,0,1,0), Timestamp.for(input) { Timestamp.new(1476316801, 0, 0) }) assert_equal_with_offset(Time.new(2016,10,13,0,0,1+Rational(1,10),0), Timestamp.for(input) { Timestamp.new(1476316801, Rational(1,10), 0) }) assert_equal_with_offset(Time.new(2016,10,13,1,0,1,3600), Timestamp.for(input) { Timestamp.new(1476316801, 0, 3600) }) assert_equal_with_offset(Time.new(2016,10,13,1,0,Rational(11,10),3600), Timestamp.for(input) { Timestamp.new(1476316801, Rational(1,10), 3600) }) end end def test_for_block_result_to_datetime assert_equal_with_offset(DateTime.new(2016,10,13,0,0,1), Timestamp.for(DateTime.new(2016,10,13,0,0,0)) { Timestamp.new(1476316801) }) assert_equal_with_offset(DateTime.new(2016,10,13,0,0,Rational(11,10)), Timestamp.for(DateTime.new(2016,10,13,0,0,0)) { Timestamp.new(1476316801, Rational(1,10)) }) assert_equal_with_offset(DateTime.new(2016,10,13,0,0,1), Timestamp.for(DateTime.new(2016,10,13,0,0,0)) { Timestamp.new(1476316801, 0, :utc) }) assert_equal_with_offset(DateTime.new(2016,10,13,0,0,Rational(11,10)), Timestamp.for(DateTime.new(2016,10,13,0,0,0)) { Timestamp.new(1476316801, Rational(1,10), :utc) }) assert_equal_with_offset(DateTime.new(2016,10,13,0,0,1), Timestamp.for(DateTime.new(2016,10,13,0,0,0)) { Timestamp.new(1476316801, 0, 0) }) assert_equal_with_offset(DateTime.new(2016,10,13,0,0,Rational(11,10)), Timestamp.for(DateTime.new(2016,10,13,0,0,0)) { Timestamp.new(1476316801, Rational(1,10), 0) }) assert_equal_with_offset(DateTime.new(2016,10,13,1,0,1,Rational(1,24)), Timestamp.for(DateTime.new(2016,10,13,0,0,0)) { Timestamp.new(1476316801, 0, 3600) }) assert_equal_with_offset(DateTime.new(2016,10,13,1,0,Rational(11,10),Rational(1,24)), Timestamp.for(DateTime.new(2016,10,13,0,0,0)) { Timestamp.new(1476316801, Rational(1,10), 3600) }) end def test_for_block_result_to_datetime_is_gregorian # 1582-10-15 is the start of the Gregorian calendar. The previous day was 1582-10-04 in the Julian calendar). # TZInfo will always use the proleptic Gregorian calendar to return dates prior to 1582-10-15. dt = Timestamp.for(DateTime.new(2016,10,13,0,0,0)) { Timestamp.new(-12219379200) } # assert_equal_with_offset (assert_equal) will consider the Julian result 1582-10-04 to be equal to the Gregorian result 1582-10-14. assert_equal_with_offset(DateTime.new(1582,10,14,0,0,0,0,Date::GREGORIAN), dt) assert_equal(1582, dt.year) assert_equal(10, dt.month) assert_equal(14, dt.day) assert(dt.gregorian?) end def test_for_block_result_timestamp_subclass block_result = TestTimestampSubclass.new(1476316801) assert_same(block_result, Timestamp.for(Timestamp.new(1476316800)) {|t| block_result }) end def test_for_block_result_to_time_subclass assert_equal_with_offset(Time.new(2016,10,13,1,0,Rational(11,10),3600), Timestamp.for(Time.utc(2016,10,13,0,0,0)) { TestTimestampSubclass.new(1476316801, Rational(1,10), 3600) }) end def test_for_block_result_to_datetime_subclass assert_equal_with_offset(DateTime.new(2016,10,13,1,0,Rational(11,10),Rational(1,24)), Timestamp.for(DateTime.new(2016,10,13,0,0,0)) { TestTimestampSubclass.new(1476316801, Rational(1,10), 3600) }) end def for_block_invalid_result_test(block_result) block_called = false error = assert_raises(ArgumentError) do Timestamp.for(Timestamp.new(1476316800)) do |t| block_called = true block_result end end assert_equal('block must return a Timestamp', error.message) assert(block_called, 'block was not called') end def test_for_block_result_nil for_block_invalid_result_test(nil) end def test_for_block_result_non_timestamp for_block_invalid_result_test(Time.utc(2016,10,13,0,0,0)) end def test_class_utc t = Timestamp.utc(1476316800) assert_kind_of(Timestamp, t) assert_equal(1476316800, t.value) assert_equal(0, t.sub_second) assert_equal(0, t.utc_offset) assert_equal(true, t.utc?) end def test_class_utc_sub_second t = Timestamp.utc(1476316800, Rational(1, 10)) assert_kind_of(Timestamp, t) assert_equal(1476316800, t.value) assert_equal(Rational(1, 10), t.sub_second) assert_equal(0, t.utc_offset) assert_equal(true, t.utc?) end def test_class_utc_value_nil error = assert_raises(ArgumentError) { Timestamp.utc(nil) } assert_equal('value must be an Integer', error.message) end def test_class_utc_value_not_integer error = assert_raises(ArgumentError) { Timestamp.utc(1476316800.1) } assert_equal('value must be an Integer', error.message) end def test_class_utc_sub_second_nil error = assert_raises(ArgumentError) { Timestamp.utc(1476316800, nil) } assert_equal('sub_second must be a Rational or the Integer 0', error.message) end def test_class_utc_sub_second_not_integer_or_rational error = assert_raises(ArgumentError) { Timestamp.utc(1476316800, 0.1) } assert_equal('sub_second must be a Rational or the Integer 0', error.message) end def test_class_utc_sub_second_integer_not_zero error = assert_raises(ArgumentError) { Timestamp.utc(1476316800, 1) } assert_equal('sub_second must be a Rational or the Integer 0', error.message) end def test_class_utc_sub_second_less_than_zero error = assert_raises(RangeError) { Timestamp.utc(1476316800, Rational(-1, 10)) } assert_equal('sub_second must be >= 0 and < 1', error.message) end def test_class_utc_sub_second_greater_than_or_equal_to_one error = assert_raises(RangeError) { Timestamp.utc(1476316800, Rational(1, 1)) } assert_equal('sub_second must be >= 0 and < 1', error.message) end end tzinfo-2.0.6/test/tc_timestamp_with_offset.rb000066400000000000000000000176351436527530500214540ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true require_relative 'test_utils' class TCTimestampWithOffset < Minitest::Test include TZInfo def new_timestamp(year, month, day, hour, minute, second, offset, klass = Timestamp) time = Time.new(year, month, day, hour, minute, second, offset == :utc ? 0 : offset) klass.new(time.to_i, time.subsec, offset) end def timestamp_with_offset(year, month, day, hour, minute, second, tz_offset) new_timestamp(year, month, day, hour, minute, second, tz_offset.observed_utc_offset, TimestampWithOffset).set_timezone_offset(tz_offset) end def test_class_set_timezone_offset o = TimezoneOffset.new(7200, 0, 'TEST') [new_timestamp(2017,1,15,23,0,0,nil), new_timestamp(2017,1,15,23,0,0,:utc), new_timestamp(2017,1,15,23,0,0,0), new_timestamp(2017,1,15,23,0,Rational(11,10),0), new_timestamp(2017,1,15,23,0,Rational(11,10),3600)].each do |t| two = TimestampWithOffset.set_timezone_offset(t, o) assert_kind_of(TimestampWithOffset, two) assert_equal(t.value, two.value) assert_equal(t.sub_second, two.sub_second) assert_equal(7200, two.utc_offset) assert_same(o, two.timezone_offset) end end def test_class_set_timezone_offset_timestamp_nil o = TimezoneOffset.new(7200, 0, 'TEST') error = assert_raises(ArgumentError) { TimestampWithOffset.set_timezone_offset(nil, o) } assert_match(/\btimestamp\b/, error.message) end def test_class_set_timezone_offset_timezone_offset_nil t = new_timestamp(2017,1,15,23,0,0,0) error = assert_raises(ArgumentError) { TimestampWithOffset.set_timezone_offset(t, nil) } assert_match(/\btimezone_offset\b/, error.message) end def test_set_timezone_offset [new_timestamp(2017,1,15,23,0,Rational(11,10),0,TimestampWithOffset), new_timestamp(2017,1,15,23,0,Rational(11,10),3600,TimestampWithOffset)].each do |two| o1 = TimezoneOffset.new(two.utc_offset, 0, 'TEST') o2 = TimezoneOffset.new(0, two.utc_offset, 'TEST') assert_nil(two.timezone_offset) assert_same(two, two.set_timezone_offset(o1)) assert_same(o1, two.timezone_offset) assert_same(two, two.set_timezone_offset(o2)) assert_same(o2, two.timezone_offset) end end def test_set_timezone_offset_utc two = TimestampWithOffset.create(2017,1,15,23,0,1,Rational(1,10),:utc) o = TimezoneOffset.new(0, 0, 'TEST') error = assert_raises(ArgumentError) { two.set_timezone_offset(o) } assert_match(/\bmatch\b/, error.message) end def test_set_timezone_offset_unspecified_offset two = TimestampWithOffset.create(2017,1,15,23,0,1,Rational(1,10)) o = TimezoneOffset.new(0, 0, 'TEST') error = assert_raises(ArgumentError) { two.set_timezone_offset(o) } assert_match(/\bmatch\b/, error.message) end def test_set_timezone_offset_offset_mismatch two1 = new_timestamp(2017,1,15,23,0,Rational(11,10),0,TimestampWithOffset) o1a = TimezoneOffset.new(3600, 0, 'TEST') o1b = TimezoneOffset.new( 0, 3600, 'TEST') two2 = new_timestamp(2017,1,15,23,0,Rational(11,10),3600,TimestampWithOffset) o2a = TimezoneOffset.new(3600, 3600, 'TEST') o2b = TimezoneOffset.new( 0, 0, 'TEST') [[two1, [o1a, o1b]], [two2, [o2a, o2b]]].each do |two, offsets| offsets.each do |o| error = assert_raises(ArgumentError) { two.set_timezone_offset(o) } assert_match(/\bmatch\b/, error.message) end end end def test_set_timezone_offset_nil_timezone_offset two = new_timestamp(2017,1,15,23,0,Rational(11,10),0,TimestampWithOffset) error = assert_raises(ArgumentError) { two.set_timezone_offset(nil) } assert_match(/\btimezone_offset\b/, error.message) end def test_strftime two = timestamp_with_offset(2017,1,15,23,0,1,TimezoneOffset.new(0, 3600, 'TEST')) assert_equal('23:00:01 TEST', two.strftime('%H:%M:%S %Z')) assert_equal('TEST', two.strftime('%Z')) assert_equal('%ZTEST', two.strftime('%%Z%Z')) assert_equal('TEST TEST', two.strftime('%Z %Z')) assert_equal('TEST %Z %TEST %%Z %%TEST', two.strftime('%Z %%Z %%%Z %%%%Z %%%%%Z')) end def test_strftime_handles_percent_in_abbreviation two = timestamp_with_offset(2017,1,15,23,0,1,TimezoneOffset.new(0, 0, '%H:%M:%S')) assert_equal('%H:%M:%S', two.strftime('%Z')) end def test_strftime_nil_timezone_offset t = new_timestamp(2017,1,15,23,0,1,3600) two = new_timestamp(2017,1,15,23,0,1,3600,TimestampWithOffset) assert_nil(two.timezone_offset) # JRuby 1.7 returns '+01:00' instead of empty string. assert_equal(t.strftime('%Z'), two.strftime('%Z')) end def test_strftime_nil_format two = timestamp_with_offset(2017,1,15,23,0,1,TimezoneOffset.new(0, 3600, 'TEST')) error = assert_raises(ArgumentError) { two.strftime(nil) } assert_match(/\bformat\b/, error.message) end def test_utc two = timestamp_with_offset(2017,1,15,23,0,1,TimezoneOffset.new(0, 0, 'TEST')) assert_equal(Timestamp, two.utc.class) end def test_to_time o = TimezoneOffset.new(0, 3600, 'TEST') two = timestamp_with_offset(2017,1,15,23,0,Rational(11,10),o) t = two.to_time assert_kind_of(TimeWithOffset, t) assert_same(o, t.timezone_offset) assert_equal_with_offset(Time.new(2017,1,15,23,0,Rational(11,10),3600), t) end def test_to_time_nil_timezone_offset two = new_timestamp(2017,1,15,23,0,Rational(11,10),3600,TimestampWithOffset) assert_nil(two.timezone_offset) t = two.to_time assert_equal(Time, t.class) assert_equal_with_offset(Time.new(2017,1,15,23,0,Rational(11,10),3600), t) end def test_to_datetime o = TimezoneOffset.new(0, 3600, 'TEST') two = timestamp_with_offset(2017,1,15,23,0,Rational(11,10),o) dt = two.to_datetime assert_kind_of(DateTimeWithOffset, dt) assert_same(o, dt.timezone_offset) assert_equal_with_offset(DateTime.new(2017,1,15,23,0,Rational(11,10),Rational(1,24)), dt) end def test_to_datetime_nil_timezone_offset two = new_timestamp(2017,1,15,23,0,Rational(11,10),3600,TimestampWithOffset) assert_nil(two.timezone_offset) dt = two.to_datetime assert_equal(DateTime, dt.class) assert_equal_with_offset(DateTime.new(2017,1,15,23,0,Rational(11,10),Rational(1,24)), dt) end def test_compare o = TimezoneOffset.new(0, 0, 'TEST') t1 = new_timestamp(2017,1,15,23,0,1,0) t2 = new_timestamp(2017,1,15,23,0,2,0) two1 = timestamp_with_offset(2017,1,15,23,0,1,o) two2 = timestamp_with_offset(2017,1,15,23,0,2,o) assert_equal(0, two1 <=> two1) assert_equal(0, two1 <=> t1) assert_equal(0, t1 <=> two1) assert_equal(-1, two1 <=> two2) assert_equal(-1, two1 <=> t2) assert_equal(-1, t1 <=> two2) assert_equal(1, two2 <=> two1) assert_equal(1, two2 <=> t1) assert_equal(1, t2 <=> two1) end def test_inspect assert_equal('#', timestamp_with_offset(2016,10,13,0,0,0,TimezoneOffset.new(0, 0, 'TEST')).inspect) assert_equal('#', timestamp_with_offset(2016,10,13,1,0,Rational(1,10),TimezoneOffset.new(3600, 0, 'TEST')).inspect) assert_equal('#', TimestampWithOffset.new(1476316800, Rational(0, 1), :utc).inspect) end def test_class_create_returns_local_timestamp two = TimestampWithOffset.create(2016, 10, 13, 1, 0, 0, 0, 3600) assert_kind_of(TimestampWithOffset, two) assert_nil(two.timezone_offset) assert_equal(1476316800, two.value) assert_equal(0, two.sub_second) assert_equal(3600, two.utc_offset) end def test_class_new_returns_local_timestamp two = TimestampWithOffset.new(1476316800, 0, 3600) assert_kind_of(TimestampWithOffset, two) assert_nil(two.timezone_offset) assert_equal(1476316800, two.value) assert_equal(0, two.sub_second) assert_equal(3600, two.utc_offset) end end tzinfo-2.0.6/test/tc_timezone.rb000066400000000000000000002375111436527530500166770ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true require_relative 'test_utils' class TCTimezone < Minitest::Test include TZInfo class << self include TZInfo private def time_with_unspecified_offset_test(method) define_method("test_#{method}_time_with_unspecified_offset") do tz = Timezone.get('Europe/London') time_types_test(:unspecified_offset) do |h| t = h.time(2006, 7, 15, 22, 12, 2, 0, nil) error = assert_raises(ArgumentError) { tz.public_send(method, t) } assert_equal('time must have a specified utc_offset', error.message) end end end def nil_time_test(method) define_method("test_#{method}_nil_time") do tz = Timezone.get('Europe/London') error = assert_raises(ArgumentError) { tz.public_send(method, nil) } assert_equal('time must be specified', error.message) end end end class BlockCalled < StandardError end class BaseTestTimezone < Timezone protected def times_equal(t1, t2) return false unless t1.class == t2.class return false unless t1 == t2 if t1.respond_to?(:utc_offset) return false unless t1.utc_offset == t2.utc_offset elsif t1.respond_to?(:offset) return false unless t1.offset == t2.offset end if t1.respond_to?(:utc?) return false unless t1.utc? == t2.utc? end true end end class TestTimezone < BaseTestTimezone def initialize(identifier, period_for_result = nil, periods_for_local_result = nil, expected = nil) super() @identifier = identifier @period_for_result = period_for_result @periods_for_local_result = periods_for_local_result || [] @expected = expected end def identifier @identifier end def period_for(time) raise "Unexpected time #{time} in period_for (expecting #{@expected})" unless times_equal(@expected, time) @period_for_result end def periods_for_local(local_time) raise "Unexpected local_time #{local_time} in periods_for_local (expecting #{@expected})" unless times_equal(@expected, local_time) @periods_for_local_result.clone end def transitions_up_to(utc_to, utc_from = nil) raise 'transitions_up_to called' end end class OffsetsUpToTestTimezone < BaseTestTimezone def initialize(identifier, expected_to, expected_from, transitions_up_to_result) super() @identifier = identifier @expected_to = expected_to @expected_from = expected_from @transitions_up_to_result = transitions_up_to_result end def identifier @identifier end def period_for(time) raise 'period_for called' end def periods_for_local(local_time) raise 'periods_for_local called' end def transitions_up_to(to, from = nil) raise ArgumentError, 'to must be specified' unless to raise "Unexpected to #{to || 'nil'} in transitions_up_to (expecting #{@expected_to})" unless times_equal(@expected_to, to) raise "Unexpected from #{from || 'nil'} in transitions_up_to (expecting #{@expected_from})" unless (!@expected_from && !from) || times_equal(@expected_from, from) raise ArgumentError, 'to must have a specified utc_offset' unless to.utc_offset if from raise ArgumentError, 'from must have a specified utc_offset' unless from.utc_offset end raise ArgumentError, 'to must be greater than from' if from && to <= from @transitions_up_to_result end end class OffsetsUpToNoTransitionsTestTimezone < BaseTestTimezone def initialize(identifier, expected_to, expected_from, period_for_result) super() @identifier = identifier @expected_to = expected_to @expected_from = expected_from @period_for_result = period_for_result end def identifier @identifier end def period_for(time) raise "Unexpected time #{time} in period_for (should be #{@expected_from})" if @expected_from && !times_equal(@expected_from, time) raise "Unexpected time #{time} in period_for (should be < #{@expected_to})" if !@expected_from && @expected_to <= time @period_for_result end def periods_for_local(local_time) raise 'periods_for_local called' end def transitions_up_to(to, from = nil) raise "Unexpected to #{to || 'nil'} in transitions_up_to (expecting #{@expected_to})" unless times_equal(@expected_to, to) raise "Unexpected from #{from || 'nil'} in transitions_up_to (expecting #{@expected_from})" unless (!@expected_from && !from) || times_equal(@expected_from, from) if from && to <= from raise ArgumentError, 'to must be greater than from' end [] end end def setup @orig_default_dst = Timezone.default_dst @orig_data_source = DataSource.get end def teardown Timezone.default_dst = @orig_default_dst DataSource.set(@orig_data_source) end def test_default_dst_initial_value assert_nil(Timezone.default_dst) end def test_set_default_dst Timezone.default_dst = true assert_equal(true, Timezone.default_dst) Timezone.default_dst = false assert_equal(false, Timezone.default_dst) Timezone.default_dst = nil assert_nil(Timezone.default_dst) Timezone.default_dst = 0 assert_equal(true, Timezone.default_dst) end test_encodings('ISO-8859-1', 'UTF-8', 'UTF-16').each do |encoding| define_method("test_get_valid_data_with_#{encoding.to_method}_encoded_identifier") do tz = Timezone.get('Europe/London'.encode(encoding.name)) assert_kind_of(DataTimezone, tz) assert_equal('Europe/London', tz.identifier) end define_method("test_get_valid_linked_with_#{encoding.to_method}_encoded_identifier") do tz = Timezone.get('UTC'.encode(encoding.name)) # ZoneinfoDataSource doesn't return DataSources::LinkedTimezoneInfo for any timezone. if DataSource.get.get_timezone_info('UTC').kind_of?(DataSources::LinkedTimezoneInfo) assert_kind_of(LinkedTimezone, tz) else assert_kind_of(DataTimezone, tz) end assert_equal('UTC', tz.identifier) end define_method("test_get_valid_three_levels_with_#{encoding.to_method}_encoded_identifier") do tz = Timezone.get('America/Argentina/Buenos_Aires'.encode(encoding.name)) assert_kind_of(DataTimezone, tz) assert_equal('America/Argentina/Buenos_Aires', tz.identifier) end define_method("test_get_not_exist_with_#{encoding.to_method}_encoded_identifier") do error = assert_raises(InvalidTimezoneIdentifier) { Timezone.get('Nowhere/Special'.encode(encoding.name)) } assert_match(/\bNowhere\/Special/, error.message) end define_method("test_get_invalid_with_#{encoding.to_method}_encoded_identifier") do error = assert_raises(InvalidTimezoneIdentifier) { Timezone.get('../Definitions/UTC'.encode(encoding.name)) } assert_match(/\W\.\.\/Definitions\/UTC\b/, error.message) end define_method("test_get_case_with_#{encoding.to_method}_encoded_identifier") do Timezone.get('Europe/Prague') error = assert_raises(InvalidTimezoneIdentifier) { Timezone.get('Europe/prague'.encode(encoding.name)) } assert_match(/\bEurope\/prague\b/, error.message) end end def test_get_nil error = assert_raises(InvalidTimezoneIdentifier) { Timezone.get(nil) } assert_match(/\bnil\b/, error.message) end test_encodings('ISO-8859-1', 'UTF-8', 'UTF-16').each do |encoding| define_method("test_get_proxy_valid_with_#{encoding.to_method}_encoded_identifier") do identifier = 'Europe/London'.encode(encoding.name) proxy = Timezone.get_proxy(identifier) assert_kind_of(TimezoneProxy, proxy) assert_same(identifier, proxy.identifier) end define_method("test_get_proxy_not_exist_with_#{encoding.to_method}_encoded_identifier") do identifier = 'Not/There'.encode(encoding.name) proxy = Timezone.get_proxy(identifier) assert_kind_of(TimezoneProxy, proxy) assert_same(identifier, proxy.identifier) end define_method("test_get_proxy_invalid_with_#{encoding.to_method}_encoded_identifier") do identifier = '../Invalid/Identifier'.encode(encoding.name) proxy = Timezone.get_proxy(identifier) assert_kind_of(TimezoneProxy, proxy) assert_same(identifier, proxy.identifier) end end def test_get_tainted_loaded skip_if_taint_is_undefined_or_no_op Timezone.get('Europe/Andorra') safe_test(unavailable: :skip) do identifier = 'Europe/Andorra'.dup.taint assert(identifier.tainted?) tz = Timezone.get(identifier) assert_equal('Europe/Andorra', tz.identifier) assert(identifier.tainted?) end end def test_get_tainted_and_frozen_loaded skip_if_taint_is_undefined_or_no_op Timezone.get('Europe/Andorra') safe_test do tz = Timezone.get('Europe/Andorra'.dup.taint.freeze) assert_equal('Europe/Andorra', tz.identifier) end end def test_get_tainted_not_previously_loaded skip_if_taint_is_undefined_or_no_op safe_test(unavailable: :skip) do identifier = 'Europe/Andorra'.dup.taint assert(identifier.tainted?) tz = Timezone.get(identifier) assert_equal('Europe/Andorra', tz.identifier) assert(identifier.tainted?) end end def test_get_tainted_and_frozen_not_previously_loaded skip_if_taint_is_undefined_or_no_op safe_test do tz = Timezone.get('Europe/Amsterdam'.dup.taint.freeze) assert_equal('Europe/Amsterdam', tz.identifier) end end def test_new_no_args tz = Timezone.new assert_raises_unknown_timezone { tz.identifier } assert_raises_unknown_timezone { tz.friendly_identifier } assert_raises_unknown_timezone { tz.now } assert_raises_unknown_timezone { tz.current_period_and_time } assert_raises_unknown_timezone { tz.canonical_identifier } assert_raises_unknown_timezone { tz.canonical_zone } time_types_test do |h| time = h.time(2006,1,1,1,0,0) assert_raises_unknown_timezone { tz.utc_to_local(time) } assert_raises_unknown_timezone { tz.to_local(time) } assert_raises_unknown_timezone { tz.local_to_utc(time) } assert_raises_unknown_timezone { tz.period_for(time) } assert_raises_unknown_timezone { tz.period_for_utc(time) } assert_raises_unknown_timezone { tz.periods_for_local(time) } assert_raises_unknown_timezone { tz.period_for_local(time) } assert_raises_unknown_timezone { tz.transitions_up_to(time) } assert_raises_unknown_timezone { tz.offsets_up_to(time) } end end def test_all all = Timezone.all expected = DataSource.get.timezone_identifiers.collect {|identifier| Timezone.get_proxy(identifier)} assert_equal(expected, all) end def test_all_identifiers all = Timezone.all_identifiers assert_equal(DataSource.get.timezone_identifiers, all) end def test_all_data_zones all_data = Timezone.all_data_zones expected = DataSource.get.data_timezone_identifiers.collect {|identifier| Timezone.get_proxy(identifier)} assert_equal(expected, all_data) end def test_all_data_zone_identifiers all_data = Timezone.all_data_zone_identifiers assert_equal(DataSource.get.data_timezone_identifiers, all_data) end def test_all_linked_zones all_linked = Timezone.all_linked_zones expected = DataSource.get.linked_timezone_identifiers.collect {|identifier| Timezone.get_proxy(identifier)} assert_equal(expected, all_linked) end def test_all_linked_zone_identifiers all_linked = Timezone.all_linked_zone_identifiers assert_equal(DataSource.get.linked_timezone_identifiers, all_linked) end def test_all_country_zones # Probably should relax this test - just need all the zones, don't care # about order. expected = Country.all.inject([]) do |result,country| result += country.zones end expected.uniq! all_country_zones = Timezone.all_country_zones assert_equal(expected, all_country_zones) all_country_zone_identifiers = Timezone.all_country_zone_identifiers assert_equal(all_country_zone_identifiers.length, all_country_zones.length) all_country_zones.each do |zone| assert_kind_of(TimezoneProxy, zone) assert(all_country_zone_identifiers.include?(zone.identifier)) end end def test_all_country_zone_identifiers # Probably should relax this test - just need all the zones, don't care # about order. expected = Country.all.inject([]) do |result,country| result += country.zone_identifiers end expected.uniq! assert_equal(expected, Timezone.all_country_zone_identifiers) end def test_identifier assert_raises_unknown_timezone { Timezone.new.identifier } assert_equal('Europe/Paris', TestTimezone.new('Europe/Paris').identifier) end def test_name assert_raises_unknown_timezone { Timezone.new.name } assert_equal('Europe/Paris', TestTimezone.new('Europe/Paris').name) end def test_friendly_identifier assert_equal('Paris', TestTimezone.new('Europe/Paris').friendly_identifier(true)) assert_equal('Europe - Paris', TestTimezone.new('Europe/Paris').friendly_identifier(false)) assert_equal('Europe - Paris', TestTimezone.new('Europe/Paris').friendly_identifier) assert_equal('Knox, Indiana', TestTimezone.new('America/Indiana/Knox').friendly_identifier(true)) assert_equal('America - Knox, Indiana', TestTimezone.new('America/Indiana/Knox').friendly_identifier(false)) assert_equal('America - Knox, Indiana', TestTimezone.new('America/Indiana/Knox').friendly_identifier) assert_equal('Dumont D\'Urville', TestTimezone.new('Antarctica/DumontDUrville').friendly_identifier(true)) assert_equal('Antarctica - Dumont D\'Urville', TestTimezone.new('Antarctica/DumontDUrville').friendly_identifier(false)) assert_equal('Antarctica - Dumont D\'Urville', TestTimezone.new('Antarctica/DumontDUrville').friendly_identifier) assert_equal('McMurdo', TestTimezone.new('Antarctica/McMurdo').friendly_identifier(true)) assert_equal('Antarctica - McMurdo', TestTimezone.new('Antarctica/McMurdo').friendly_identifier(false)) assert_equal('Antarctica - McMurdo', TestTimezone.new('Antarctica/McMurdo').friendly_identifier) assert_equal('GMT+1', TestTimezone.new('Etc/GMT+1').friendly_identifier(true)) assert_equal('Etc - GMT+1', TestTimezone.new('Etc/GMT+1').friendly_identifier(false)) assert_equal('Etc - GMT+1', TestTimezone.new('Etc/GMT+1').friendly_identifier) assert_equal('UTC', TestTimezone.new('UTC').friendly_identifier(true)) assert_equal('UTC', TestTimezone.new('UTC').friendly_identifier(false)) assert_equal('UTC', TestTimezone.new('UTC').friendly_identifier) assert_equal('', TestTimezone.new('').friendly_identifier(true)) assert_equal('', TestTimezone.new('').friendly_identifier(false)) assert_equal('', TestTimezone.new('').friendly_identifier) end test_encodings('ISO-8859-1', 'UTF-8', 'UTF-16').each do |encoding| define_method("test_friendly_identifier_with_#{encoding.to_method}_encoded_identifier") do tz = TestTimezone.new('Europe/Paris'.encode(encoding.name).freeze) assert_equal('Paris', tz.friendly_identifier(true)) assert_equal('Europe - Paris', tz.friendly_identifier(false)) end end def test_friendly_identifier_non_binary_encoding refute_equal(Encoding::ASCII_8BIT, TestTimezone.new('Europe/Paris').friendly_identifier(true).encoding) refute_equal(Encoding::ASCII_8BIT, TestTimezone.new('Europe/Paris').friendly_identifier(false).encoding) end def test_to_s assert_equal('Europe - Paris', TestTimezone.new('Europe/Paris').to_s) assert_equal('America - Knox, Indiana', TestTimezone.new('America/Indiana/Knox').to_s) assert_equal('Antarctica - Dumont D\'Urville', TestTimezone.new('Antarctica/DumontDUrville').to_s) assert_equal('Antarctica - McMurdo', TestTimezone.new('Antarctica/McMurdo').to_s) assert_equal('Etc - GMT+1', TestTimezone.new('Etc/GMT+1').to_s) assert_equal('UTC', TestTimezone.new('UTC').to_s) end def test_period_for_local o1 = TimezoneOffset.new(0, 0, 'GMT') o2 = TimezoneOffset.new(0, 3600, 'BST') period = TransitionsTimezonePeriod.new( TimezoneTransition.new(o1, o2, Time.utc(2004,10,31,1,0,0).to_i), TimezoneTransition.new(o2, o1, Time.utc(2005,03,27,1,0,0).to_i)) time_types_test(:unspecified_offset) do |h| t = h.time(2005,2,18,16,24,23) assert_equal(period, TestTimezone.new('Europe/London', nil, [period], Timestamp.for(t, :ignore)).period_for_local(t)) end time_types_test(:utc) do |h| t = h.time(2005,2,18,16,24,23,0,:utc) assert_equal(period, TestTimezone.new('Europe/London', nil, [period], Timestamp.for(t, :ignore)).period_for_local(t)) end time_types_test(:offset) do |h| t = h.time(2005,2,18,16,24,23,0,18000) assert_equal(period, TestTimezone.new('Europe/London', nil, [period], Timestamp.for(t, :ignore)).period_for_local(t)) end time_types_test do |h| t1 = h.time(2005,2,18,16,24,23,0,0) t2 = h.time(2005,2,18,16,24,23,Rational(789,1000), 0) assert_equal(period, TestTimezone.new('Europe/London', nil, [period], Timestamp.for(t1, :ignore)).period_for_local(t1)) assert_equal(period, TestTimezone.new('Europe/London', nil, [period], Timestamp.for(t2, :ignore)).period_for_local(t2)) end end def test_period_for_local_not_found time_types_test do |h| t = h.time(2004,4,4,2,30,0) tz = TestTimezone.new('America/New_York', nil, [], Timestamp.for(t, :ignore)) assert_raises_period_not_found(t) { tz.period_for_local(t) } end end def test_period_for_local_ambiguous o1 = TimezoneOffset.new(-18000, 0, 'EST') o2 = TimezoneOffset.new(-18000, 3600, 'EDT') t1 = TimezoneTransition.new(o2, o1, Time.utc(2004,4,4,8,0,0).to_i) t2 = TimezoneTransition.new(o1, o2, Time.utc(2004,10,31,6,0,0).to_i) t3 = TimezoneTransition.new(o2, o1, Time.utc(2005,4,3,8,0,0).to_i) p1 = TransitionsTimezonePeriod.new(t1, t2) p2 = TransitionsTimezonePeriod.new(t2, t3) time_types_test do |h| t = h.time(2004,10,31,1,30,0) tz = TestTimezone.new('America/New_York', nil, [p1, p2], Timestamp.for(t, :ignore)) assert_raises_ambiguous_time(t) { tz.period_for_local(t) } end end def test_period_for_local_default_dst_set_true Timezone.default_dst = true o1 = TimezoneOffset.new(-18000, 0, 'EST') o2 = TimezoneOffset.new(-18000, 3600, 'EDT') t1 = TimezoneTransition.new(o2, o1, Time.utc(2004,4,4,8,0,0).to_i) t2 = TimezoneTransition.new(o1, o2, Time.utc(2004,10,31,6,0,0).to_i) t3 = TimezoneTransition.new(o2, o1, Time.utc(2005,4,3,8,0,0).to_i) p1 = TransitionsTimezonePeriod.new(t1, t2) p2 = TransitionsTimezonePeriod.new(t2, t3) time_types_test do |h| t = h.time(2004,10,31,1,30,0) tz = TestTimezone.new('America/New_York', nil, [p1, p2], Timestamp.for(t, :ignore)) assert_equal(p1, tz.period_for_local(t)) assert_equal(p1, tz.period_for_local(t, true)) assert_equal(p2, tz.period_for_local(t, false)) assert_raises_ambiguous_time(t) { tz.period_for_local(t, nil) } end end def test_period_for_local_default_dst_set_false Timezone.default_dst = false o1 = TimezoneOffset.new(-18000, 0, 'EST') o2 = TimezoneOffset.new(-18000, 3600, 'EDT') t1 = TimezoneTransition.new(o2, o1, Time.utc(2004,4,4,8,0,0).to_i) t2 = TimezoneTransition.new(o1, o2, Time.utc(2004,10,31,6,0,0).to_i) t3 = TimezoneTransition.new(o2, o1, Time.utc(2005,4,3,8,0,0).to_i) p1 = TransitionsTimezonePeriod.new(t1, t2) p2 = TransitionsTimezonePeriod.new(t2, t3) time_types_test do |h| t = h.time(2004,10,31,1,30,0) tz = TestTimezone.new('America/New_York', nil, [p1, p2], Timestamp.for(t, :ignore)) assert_equal(p2, tz.period_for_local(t)) assert_equal(p1, tz.period_for_local(t, true)) assert_equal(p2, tz.period_for_local(t, false)) assert_raises_ambiguous_time(t) { tz.period_for_local(t, nil) } end end def test_period_for_local_dst_flag_resolved o1 = TimezoneOffset.new(-18000, 0, 'EST') o2 = TimezoneOffset.new(-18000, 3600, 'EDT') t1 = TimezoneTransition.new(o2, o1, Time.utc(2004,4,4,8,0,0).to_i) t2 = TimezoneTransition.new(o1, o2, Time.utc(2004,10,31,6,0,0).to_i) t3 = TimezoneTransition.new(o2, o1, Time.utc(2005,4,3,8,0,0).to_i) p1 = TransitionsTimezonePeriod.new(t1, t2) p2 = TransitionsTimezonePeriod.new(t2, t3) t = Time.utc(2004,10,31,1,30,0) tz = TestTimezone.new('America/New_York', nil, [p1, p2], Timestamp.for(t, :ignore)) assert_equal(p1, tz.period_for_local(t, true)) assert_equal(p2, tz.period_for_local(t, false)) assert_equal(p1, tz.period_for_local(t, true) {|periods| raise BlockCalled, 'should not be called' }) assert_equal(p2, tz.period_for_local(t, false) {|periods| raise BlockCalled, 'should not be called' }) end def test_period_for_local_dst_block_called o1 = TimezoneOffset.new(-18000, 0, 'EST') o2 = TimezoneOffset.new(-18000, 3600, 'EDT') t1 = TimezoneTransition.new(o2, o1, Time.utc(2004,4,4,8,0,0).to_i) t2 = TimezoneTransition.new(o1, o2, Time.utc(2004,10,31,6,0,0).to_i) t3 = TimezoneTransition.new(o2, o1, Time.utc(2005,4,3,8,0,0).to_i) p1 = TransitionsTimezonePeriod.new(t1, t2) p2 = TransitionsTimezonePeriod.new(t2, t3) t = Time.utc(2004,10,31,1,30,0) tz = TestTimezone.new('America/New_York', nil, [p1, p2], Timestamp.for(t, :ignore)) assert_raises(BlockCalled) do tz.period_for_local(t) do |periods| assert_equal([p1, p2], periods) # raise exception to test that the block was called raise BlockCalled, 'should be raised' end end assert_equal(p1, tz.period_for_local(t) {|periods| periods.first}) assert_equal(p2, tz.period_for_local(t) {|periods| periods.last}) assert_equal(p1, tz.period_for_local(t) {|periods| [periods.first]}) assert_equal(p2, tz.period_for_local(t) {|periods| [periods.last]}) end def test_period_for_local_dst_cannot_resolve # At midnight local time on Aug 5 1915 in Warsaw, the clocks were put back # 24 minutes and both periods were non-DST. Hence the block should be # called regardless of the value of the Boolean dst parameter. o0 = TimezoneOffset.new(5040, 0, 'LMT') o1 = TimezoneOffset.new(5040, 0, 'WMT') o2 = TimezoneOffset.new(3600, 0, 'CET') o3 = TimezoneOffset.new(3600, 3600, 'CEST') t1 = TimezoneTransition.new(o1, o0, Time.utc(1879, 12, 31, 22, 36, 0).to_i) t2 = TimezoneTransition.new(o2, o1, Time.utc(1915, 8, 4, 22, 36, 0).to_i) t3 = TimezoneTransition.new(o3, o2, Time.utc(1916, 4, 30, 22, 0, 0).to_i) p1 = TransitionsTimezonePeriod.new(t1, t2) p2 = TransitionsTimezonePeriod.new(t2, t3) t = Time.utc(1915,8,4,23,40,0) tz = TestTimezone.new('Europe/Warsaw', nil, [p1, p2], Timestamp.for(t, :ignore)) assert_raises(BlockCalled) do tz.period_for_local(t, true) do |periods| assert_equal([p1, p2], periods) raise BlockCalled, 'should be raised' end end assert_raises(BlockCalled) do tz.period_for_local(t, false) do |periods| assert_equal([p1, p2], periods) raise BlockCalled, 'should be raised' end end end def test_period_for_local_block_ambiguous o1 = TimezoneOffset.new(-18000, 0, 'EST') o2 = TimezoneOffset.new(-18000, 3600, 'EDT') t1 = TimezoneTransition.new(o2, o1, Time.utc(2004,4,4,8,0,0).to_i) t2 = TimezoneTransition.new(o1, o2, Time.utc(2004,10,31,6,0,0).to_i) t3 = TimezoneTransition.new(o2, o1, Time.utc(2005,4,3,8,0,0).to_i) p1 = TransitionsTimezonePeriod.new(t1, t2) p2 = TransitionsTimezonePeriod.new(t2, t3) t = Time.utc(2004,10,31,1,30,0) tz = TestTimezone.new('America/New_York', nil, [p1, p2], Timestamp.for(t, :ignore)) assert_raises_ambiguous_time(t) do tz.period_for_local(t) {|periods| nil } end assert_raises_ambiguous_time(t) do tz.period_for_local(t) {|periods| periods } end assert_raises_ambiguous_time(t) do tz.period_for_local(t) {|periods| [] } end error = assert_raises(AmbiguousTime) do tz.period_for_local(t) {|periods| raise AmbiguousTime, 'Custom ambiguous time message' } end assert_equal('Custom ambiguous time message', error.message) end def test_period_for_local_nil tz = Timezone.get('Europe/London') error = assert_raises(ArgumentError) { tz.period_for_local(nil) } assert_match(/\blocal_time\b/, error.message) end def test_period_for_local_unsupported tz = Timezone.get('Europe/London') t = Time.utc(2004,10,31,1,30,0).to_i error = assert_raises(ArgumentError) { tz.period_for_local(t) } assert_match(Regexp.new("\\b#{Regexp.escape(t.class.name)}\\b"), error.message) end def test_period_for_utc o1 = TimezoneOffset.new(0, 0, 'GMT') o2 = TimezoneOffset.new(0, 3600, 'BST') period = TransitionsTimezonePeriod.new( TimezoneTransition.new(o1, o2, Time.utc(2004,10,31,1,0,0).to_i), TimezoneTransition.new(o2, o1, Time.utc(2005,3,27,2,0,0).to_i)) tz = TestTimezone.new('Europe/London', period, nil, Timestamp.create(2005,2,18,16,24,23,Rational(1,10),:utc)) time_types_test(:unspecified_offset) do |h| assert_equal(period, tz.period_for_utc(h.time(2005,2,18,16,24,23,Rational(1,10)))) end time_types_test(:utc) do |h| assert_equal(period, tz.period_for_utc(h.time(2005,2,18,16,24,23,Rational(1,10),:utc))) end time_types_test(:offset) do |h| assert_equal(period, tz.period_for_utc(h.time(2005,2,18,16,24,23,Rational(1,10),3600))) end time_types_test do |h| assert_equal(period, tz.period_for_utc(h.time(2005,2,18,16,24,23,Rational(1,10),0))) end end def test_period_for_utc_nil tz = Timezone.get('Europe/London') error = assert_raises(ArgumentError) { tz.period_for_utc(nil) } assert_match(/\butc_time\b/, error.message) end def test_period_for_utc_unsupported tz = Timezone.get('Europe/London') t = Time.utc(2004,10,31,1,30,0).to_i error = assert_raises(ArgumentError) { tz.period_for_utc(t) } assert_match(Regexp.new("\\b#{Regexp.escape(t.class.name)}\\b"), error.message) end def test_utc_to_local o1 = TimezoneOffset.new(0, 0, 'GMT') o2 = TimezoneOffset.new(0, 3600, 'BST') period = TransitionsTimezonePeriod.new( TimezoneTransition.new(o2, o1, Time.utc(2005,3,27,2,0,0).to_i), TimezoneTransition.new(o1, o2, Time.utc(2005,10,30,1,0,0).to_i)) time_types_test(:unspecified_offset) do |h| assert_equal_with_offset_and_timezone_offset(h.time_with_offset(o2,2005,6,18,17,24,23,0), TestTimezone.new('Europe/London', period, [], Timestamp.create(2005,6,18,16,24,23,0,:utc)).utc_to_local(h.time(2005,6,18,16,24,23,0))) end time_types_test(:utc) do |h| assert_equal_with_offset_and_timezone_offset(h.time_with_offset(o2,2005,6,18,17,24,23,0), TestTimezone.new('Europe/London', period, [], Timestamp.create(2005,6,18,16,24,23,0,:utc)).utc_to_local(h.time(2005,6,18,16,24,23,0,:utc))) end time_types_test(:offset) do |h| assert_equal_with_offset_and_timezone_offset(h.time_with_offset(o2,2005,6,18,17,24,23,0), TestTimezone.new('Europe/London', period, [], Timestamp.create(2005,6,18,16,24,23,0,:utc)).utc_to_local(h.time(2005,6,18,16,24,23,0,10800))) end time_types_test do |h| assert_equal_with_offset_and_timezone_offset(h.time_with_offset(o2,2005,6,18,17,24,23,0), TestTimezone.new('Europe/London', period, [], Timestamp.create(2005,6,18,16,24,23,0,:utc)).utc_to_local(h.time(2005,6,18,16,24,23,0,0))) assert_equal_with_offset_and_timezone_offset(h.time_with_offset(o2,2005,6,18,17,24,23,Rational(567,1000)), TestTimezone.new('Europe/London', period, [], Timestamp.create(2005,6,18,16,24,23,Rational(567,1000),:utc)).utc_to_local(h.time(2005,6,18,16,24,23,Rational(567,1000),0))) end end def test_utc_to_local_zero_offset_not_utc o1 = TimezoneOffset.new(0, 0, 'GMT') o2 = TimezoneOffset.new(0, 3600, 'BST') period = TransitionsTimezonePeriod.new( TimezoneTransition.new(o1, o2, Time.utc(2016,10,30,1,0,0).to_i), TimezoneTransition.new(o2, o1, Time.utc(2017, 3,26,1,0,0).to_i)) time_types_test(:utc) do |h| # test that the result doesn't have utc? set to true assert_equal_with_offset_and_timezone_offset(h.time_with_offset(o1,2016,12,31,0,0,0,0), TestTimezone.new('Europe/London', period, [], Timestamp.create(2016,12,31,0,0,0,0,:utc)).utc_to_local(h.time(2016,12,31,0,0,0,0,:utc))) end end def test_utc_to_local_local_time_input o1 = TimezoneOffset.new(0, 0, 'GMT') o2 = TimezoneOffset.new(0, 3600, 'BST') period = TransitionsTimezonePeriod.new( TimezoneTransition.new(o2, o1, Time.utc(2005,3,27,2,0,0).to_i), TimezoneTransition.new(o1, o2, Time.utc(2005,10,30,1,0,0).to_i)) time_types_test do |h| assert_equal_with_offset_and_timezone_offset(h.time_with_offset(o2,2005,6,18,17,24,23,0), TestTimezone.new('Europe/London', period, [], Timestamp.create(2005,6,18,16,24,23,0,:utc)).utc_to_local( h.time_with_offset(TimezoneOffset.new(10800, 0, 'TEST'),2005,6,18,16,24,23,0))) end end def test_utc_to_local_nil tz = Timezone.get('Europe/London') error = assert_raises(ArgumentError) { tz.utc_to_local(nil) } assert_match(/\butc_time\b/, error.message) end def test_utc_to_local_unsupported tz = Timezone.get('Europe/London') t = Time.utc(2004,10,31,1,30,0).to_i error = assert_raises(ArgumentError) { tz.utc_to_local(t) } assert_match(Regexp.new("\\b#{Regexp.escape(t.class.name)}\\b"), error.message) end def test_to_local o1 = TimezoneOffset.new(0, 0, 'GMT') o2 = TimezoneOffset.new(0, 3600, 'BST') period = TransitionsTimezonePeriod.new( TimezoneTransition.new(o2, o1, Time.utc(2005,3,27,2,0,0).to_i), TimezoneTransition.new(o1, o2, Time.utc(2005,10,30,1,0,0).to_i)) time_types_test(:utc) do |h| assert_equal_with_offset_and_timezone_offset(h.time_with_offset(o2,2005,6,18,17,24,23,0), TestTimezone.new('Europe/London', period, [], Timestamp.create(2005,6,18,16,24,23,0,:utc)).to_local(h.time(2005,6,18,16,24,23,0,:utc))) end time_types_test(:offset) do |h| assert_equal_with_offset_and_timezone_offset(h.time_with_offset(o2,2005,6,18,14,24,23,0), TestTimezone.new('Europe/London', period, [], Timestamp.create(2005,6,18,16,24,23,0,10800)).to_local(h.time(2005,6,18,16,24,23,0,10800))) end time_types_test do |h| assert_equal_with_offset_and_timezone_offset(h.time_with_offset(o2,2005,6,18,17,24,23,0), TestTimezone.new('Europe/London', period, [], Timestamp.create(2005,6,18,16,24,23,0,h.expected_zero_offset)).to_local(h.time(2005,6,18,16,24,23,0,0))) assert_equal_with_offset_and_timezone_offset(h.time_with_offset(o2,2005,6,18,17,24,23,Rational(567,1000)), TestTimezone.new('Europe/London', period, [], Timestamp.create(2005,6,18,16,24,23,Rational(567,1000),h.expected_zero_offset)).to_local(h.time(2005,6,18,16,24,23,Rational(567,1000),0))) end end def test_to_local_zero_offset_not_utc o1 = TimezoneOffset.new(0, 0, 'GMT') o2 = TimezoneOffset.new(0, 3600, 'BST') period = TransitionsTimezonePeriod.new( TimezoneTransition.new(o1, o2, Time.utc(2016,10,30,1,0,0).to_i), TimezoneTransition.new(o2, o1, Time.utc(2017, 3,26,1,0,0).to_i)) time_types_test(:utc) do |h| # test that the result doesn't have utc? set to true assert_equal_with_offset_and_timezone_offset(h.time_with_offset(o1,2016,12,31,0,0,0,0), TestTimezone.new('Europe/London', period, [], Timestamp.create(2016,12,31,0,0,0,0,:utc)).to_local(h.time(2016,12,31,0,0,0,0,:utc))) end end def test_to_local_local_time_input o1 = TimezoneOffset.new(0, 0, 'GMT') o2 = TimezoneOffset.new(0, 3600, 'BST') period = TransitionsTimezonePeriod.new( TimezoneTransition.new(o2, o1, Time.utc(2005,3,27,2,0,0).to_i), TimezoneTransition.new(o1, o2, Time.utc(2005,10,30,1,0,0).to_i)) time_types_test do |h| assert_equal_with_offset_and_timezone_offset(h.time_with_offset(o2,2005,6,18,14,24,23,0), TestTimezone.new('Europe/London', period, [], Timestamp.create(2005,6,18,16,24,23,0,10800)).to_local( h.time_with_offset(TimezoneOffset.new(10800, 0, 'TEST'),2005,6,18,16,24,23,0))) end end time_with_unspecified_offset_test(:to_local) nil_time_test(:to_local) def test_to_local_unsupported tz = Timezone.get('Europe/London') t = Time.utc(2004,10,31,1,30,0).to_i error = assert_raises(ArgumentError) { tz.to_local(t) } assert_match(Regexp.new("\\b#{Regexp.escape(t.class.name)}\\b"), error.message) end def test_local_to_utc o1 = TimezoneOffset.new(0, 0, 'GMT') o2 = TimezoneOffset.new(0, 3600, 'BST') period = TransitionsTimezonePeriod.new( TimezoneTransition.new(o2, o1, Time.utc(2005,3,27,2,0,0).to_i), TimezoneTransition.new(o1, o2, Time.utc(2005,10,30,1,0,0).to_i)) time_types_test(:unspecified_offset) do |h| assert_equal_with_offset_and_class(h.output_time(2005,6,18,15,24,23,0,:utc), TestTimezone.new('Europe/London', nil, [period], Timestamp.create(2005,6,18,16,24,23,0)).local_to_utc(h.time(2005,6,18,16,24,23,0))) end time_types_test(:utc) do |h| assert_equal_with_offset_and_class(h.output_time(2005,6,18,15,24,23,0,:utc), TestTimezone.new('Europe/London', nil, [period], Timestamp.create(2005,6,18,16,24,23,0)).local_to_utc(h.time(2005,6,18,16,24,23,0,:utc))) end time_types_test(:offset) do |h| assert_equal_with_offset_and_class(h.output_time(2005,6,18,15,24,23,0,:utc), TestTimezone.new('Europe/London', nil, [period], Timestamp.create(2005,6,18,16,24,23,0)).local_to_utc(h.time(2005,6,18,16,24,23,0,10800))) end time_types_test do |h| assert_equal_with_offset_and_class(h.output_time(2005,6,18,15,24,23,0,:utc), TestTimezone.new('Europe/London', nil, [period], Timestamp.create(2005,6,18,16,24,23,0)).local_to_utc(h.time(2005,6,18,16,24,23,0,0))) assert_equal_with_offset_and_class(h.output_time(2005,6,18,15,24,23,Rational(567,1000),:utc), TestTimezone.new('Europe/London', nil, [period], Timestamp.create(2005,6,18,16,24,23,Rational(567,1000))).local_to_utc(h.time(2005,6,18,16,24,23,Rational(567,1000)))) end end def test_local_to_utc_local_time_input o1 = TimezoneOffset.new(0, 0, 'GMT') o2 = TimezoneOffset.new(0, 3600, 'BST') period = TransitionsTimezonePeriod.new( TimezoneTransition.new(o2, o1, Time.utc(2005,3,27,2,0,0).to_i), TimezoneTransition.new(o1, o2, Time.utc(2005,10,30,1,0,0).to_i)) time_types_test do |h| assert_equal_with_offset_and_class(h.output_time(2005,6,18,15,24,23,0,:utc), TestTimezone.new('Europe/London', nil, [period], Timestamp.create(2005,6,18,16,24,23,0)).local_to_utc( h.time_with_offset(TimezoneOffset.new(10800,0,'TEST'),2005,6,18,16,24,23,0))) end end def test_local_to_utc_local_timestamp_without_offset_input o1 = TimezoneOffset.new(0, 0, 'GMT') o2 = TimezoneOffset.new(0, 3600, 'BST') period = TransitionsTimezonePeriod.new( TimezoneTransition.new(o2, o1, Time.utc(2005,3,27,2,0,0).to_i), TimezoneTransition.new(o1, o2, Time.utc(2005,10,30,1,0,0).to_i)) assert_equal_with_offset_and_class(Timestamp.create(2005,6,18,15,24,23,0,:utc), TestTimezone.new('Europe/London', nil, [period], Timestamp.create(2005,6,18,16,24,23,0)).local_to_utc( TimestampWithOffset.create(2005,6,18,16,24,23))) end def test_local_to_utc_ambiguous o1 = TimezoneOffset.new(-18000, 0, 'EST') o2 = TimezoneOffset.new(-18000, 3600, 'EDT') tt1 = TimezoneTransition.new(o2, o1, Time.utc(2004,4,4,8,0,0).to_i) tt2 = TimezoneTransition.new(o1, o2, Time.utc(2004,10,31,6,0,0).to_i) tt3 = TimezoneTransition.new(o2, o1, Time.utc(2005,4,3,8,0,0).to_i) p1 = TransitionsTimezonePeriod.new(tt1, tt2) p2 = TransitionsTimezonePeriod.new(tt2, tt3) time_types_test do |h| t1 = h.time(2004,10,31,1,30,0) t2 = h.time(2004,10,31,1,30,0,Rational(501,1000000)) tz1 = TestTimezone.new('America/New_York', nil, [p1, p2], Timestamp.create(2004,10,31,1,30,0)) tz2 = TestTimezone.new('America/New_York', nil, [p1, p2], Timestamp.create(2004,10,31,1,30,0,Rational(501,1000000))) assert_raises_ambiguous_time(t1) { tz1.local_to_utc(t1) } assert_raises_ambiguous_time(t2) { tz2.local_to_utc(t2) } end end def test_local_to_utc_not_found time_types_test do |h| t = h.time(2004,4,4,2,0,0) tz = TestTimezone.new('America/New_York', nil, [], Timestamp.create(2004,4,4,2,0,0)) assert_raises_period_not_found(t) { tz.local_to_utc(t) } end end def test_local_to_utc_default_dst_set_true Timezone.default_dst = true o1 = TimezoneOffset.new(-18000, 0, 'EST') o2 = TimezoneOffset.new(-18000, 3600, 'EDT') t1 = TimezoneTransition.new(o2, o1, Time.utc(2004,4,4,8,0,0).to_i) t2 = TimezoneTransition.new(o1, o2, Time.utc(2004,10,31,6,0,0).to_i) t3 = TimezoneTransition.new(o2, o1, Time.utc(2005,4,3,8,0,0).to_i) p1 = TransitionsTimezonePeriod.new(t1, t2) p2 = TransitionsTimezonePeriod.new(t2, t3) time_types_test do |h| t = h.time(2004,10,31,1,30,0) tz = TestTimezone.new('America/New_York', nil, [p1, p2], Timestamp.create(2004,10,31,1,30,0)) assert_equal_with_offset_and_class(h.output_time(2004,10,31,5,30,0,0,:utc), tz.local_to_utc(t)) assert_equal_with_offset_and_class(h.output_time(2004,10,31,5,30,0,0,:utc), tz.local_to_utc(t, true)) assert_equal_with_offset_and_class(h.output_time(2004,10,31,6,30,0,0,:utc), tz.local_to_utc(t, false)) assert_raises_ambiguous_time(t) { tz.local_to_utc(t, nil) } assert_equal_with_offset_and_class(h.output_time(2004,10,31,5,30,0,0,:utc), tz.local_to_utc(t) {|periods| raise BlockCalled, 'should not be called' }) end end def test_local_to_utc_default_dst_set_false Timezone.default_dst = false o1 = TimezoneOffset.new(-18000, 0, 'EST') o2 = TimezoneOffset.new(-18000, 3600, 'EDT') t1 = TimezoneTransition.new(o2, o1, Time.utc(2004,4,4,8,0,0).to_i) t2 = TimezoneTransition.new(o1, o2, Time.utc(2004,10,31,6,0,0).to_i) t3 = TimezoneTransition.new(o2, o1, Time.utc(2005,4,3,8,0,0).to_i) p1 = TransitionsTimezonePeriod.new(t1, t2) p2 = TransitionsTimezonePeriod.new(t2, t3) time_types_test do |h| t = h.time(2004,10,31,1,30,0) tz = TestTimezone.new('America/New_York', nil, [p1, p2], Timestamp.create(2004,10,31,1,30,0)) assert_equal_with_offset_and_class(h.output_time(2004,10,31,6,30,0,0,:utc), tz.local_to_utc(t)) assert_equal_with_offset_and_class(h.output_time(2004,10,31,6,30,0,0,:utc), tz.local_to_utc(t, false)) assert_equal_with_offset_and_class(h.output_time(2004,10,31,5,30,0,0,:utc), tz.local_to_utc(t, true)) assert_raises_ambiguous_time(t) { tz.local_to_utc(t, nil) } assert_equal_with_offset_and_class(h.output_time(2004,10,31,6,30,0,0,:utc), tz.local_to_utc(t) {|periods| raise BlockCalled, 'should not be called' }) end end def test_local_to_utc_dst_flag_resolved o1 = TimezoneOffset.new(-18000, 0, 'EST') o2 = TimezoneOffset.new(-18000, 3600, 'EDT') t1 = TimezoneTransition.new(o2, o1, Time.utc(2004,4,4,8,0,0).to_i) t2 = TimezoneTransition.new(o1, o2, Time.utc(2004,10,31,6,0,0).to_i) t3 = TimezoneTransition.new(o2, o1, Time.utc(2005,4,3,8,0,0).to_i) p1 = TransitionsTimezonePeriod.new(t1, t2) p2 = TransitionsTimezonePeriod.new(t2, t3) time_types_test do |h| t = h.time(2004,10,31,1,30,0) tz = TestTimezone.new('America/New_York', nil, [p1, p2], Timestamp.create(2004,10,31,1,30,0)) assert_equal_with_offset_and_class(h.output_time(2004,10,31,5,30,0,0,:utc), tz.local_to_utc(t, true)) assert_equal_with_offset_and_class(h.output_time(2004,10,31,6,30,0,0,:utc), tz.local_to_utc(t, false)) assert_equal_with_offset_and_class(h.output_time(2004,10,31,5,30,0,0,:utc), tz.local_to_utc(t, true) {|periods| raise BlockCalled, 'should not be called' }) assert_equal_with_offset_and_class(h.output_time(2004,10,31,6,30,0,0,:utc), tz.local_to_utc(t, false) {|periods| raise BlockCalled, 'should not be called' }) end end def test_local_to_utc_dst_block_called o1 = TimezoneOffset.new(-18000, 0, 'EST') o2 = TimezoneOffset.new(-18000, 3600, 'EDT') t1 = TimezoneTransition.new(o2, o1, Time.utc(2004,4,4,8,0,0).to_i) t2 = TimezoneTransition.new(o1, o2, Time.utc(2004,10,31,6,0,0).to_i) t3 = TimezoneTransition.new(o2, o1, Time.utc(2005,4,3,8,0,0).to_i) p1 = TransitionsTimezonePeriod.new(t1, t2) p2 = TransitionsTimezonePeriod.new(t2, t3) time_types_test do |h| t = h.time(2004,10,31,1,30,0) tz = TestTimezone.new('America/New_York', nil, [p1, p2], Timestamp.create(2004,10,31,1,30,0)) assert_raises(BlockCalled) do tz.local_to_utc(t) do |periods| assert_equal([p1, p2], periods) # raise exception to test that the block was called raise BlockCalled, 'should be raised' end end assert_equal_with_offset_and_class(h.output_time(2004,10,31,5,30,0,0,:utc), tz.local_to_utc(t) {|periods| periods.first}) assert_equal_with_offset_and_class(h.output_time(2004,10,31,6,30,0,0,:utc), tz.local_to_utc(t) {|periods| periods.last}) assert_equal_with_offset_and_class(h.output_time(2004,10,31,5,30,0,0,:utc), tz.local_to_utc(t) {|periods| [periods.first]}) assert_equal_with_offset_and_class(h.output_time(2004,10,31,6,30,0,0,:utc), tz.local_to_utc(t) {|periods| [periods.last]}) end end def test_local_to_utc_dst_cannot_resolve # At midnight local time on Aug 5 1915 in Warsaw, the clocks were put back # 24 minutes and both periods were non-DST. Hence the block should be # called regardless of the value of the Boolean dst parameter. o0 = TimezoneOffset.new(5040, 0, 'LMT') o1 = TimezoneOffset.new(5040, 0, 'WMT') o2 = TimezoneOffset.new(3600, 0, 'CET') o3 = TimezoneOffset.new(3600, 3600, 'CEST') t1 = TimezoneTransition.new(o1, o0, Time.utc(1879, 12, 31, 22, 36, 0).to_i) t2 = TimezoneTransition.new(o2, o1, Time.utc(1915, 8, 4, 22, 36, 0).to_i) t3 = TimezoneTransition.new(o3, o2, Time.utc(1916, 4, 30, 22, 0, 0).to_i) p1 = TransitionsTimezonePeriod.new(t1, t2) p2 = TransitionsTimezonePeriod.new(t2, t3) time_types_test do |h| t = h.time(1915,8,4,23,40,0) tz = TestTimezone.new('Europe/Warsaw', nil, [p1, p2], Timestamp.create(1915,8,4,23,40,0)) assert_raises(BlockCalled) do tz.local_to_utc(t, true) do |periods| assert_equal([p1, p2], periods) raise BlockCalled, 'should be raised' end end assert_raises(BlockCalled) do tz.local_to_utc(t, false) do |periods| assert_equal([p1, p2], periods) raise BlockCalled, 'should be raised' end end assert_equal_with_offset_and_class(h.output_time(1915,8,4,22,16,0,0,:utc), tz.local_to_utc(t) {|periods| periods.first}) assert_equal_with_offset_and_class(h.output_time(1915,8,4,22,40,0,0,:utc), tz.local_to_utc(t) {|periods| periods.last}) assert_equal_with_offset_and_class(h.output_time(1915,8,4,22,16,0,0,:utc), tz.local_to_utc(t) {|periods| [periods.first]}) assert_equal_with_offset_and_class(h.output_time(1915,8,4,22,40,0,0,:utc), tz.local_to_utc(t) {|periods| [periods.last]}) end end def test_local_to_utc_block_ambiguous o1 = TimezoneOffset.new(-18000, 0, 'EST') o2 = TimezoneOffset.new(-18000, 3600, 'EDT') t1 = TimezoneTransition.new(o2, o1, Time.utc(2004,4,4,8,0,0).to_i) t2 = TimezoneTransition.new(o1, o2, Time.utc(2004,10,31,6,0,0).to_i) t3 = TimezoneTransition.new(o2, o1, Time.utc(2005,4,3,8,0,0).to_i) p1 = TransitionsTimezonePeriod.new(t1, t2) p2 = TransitionsTimezonePeriod.new(t2, t3) time_types_test do |h| t = h.time(2004,10,31,1,30,0) tz = TestTimezone.new('America/New_York', nil, [p1, p2], Timestamp.create(2004,10,31,1,30,0)) assert_raises_ambiguous_time(t) { tz.local_to_utc(t) {|periods| nil} } assert_raises_ambiguous_time(t) { tz.local_to_utc(t) {|periods| periods} } assert_raises_ambiguous_time(t) { tz.local_to_utc(t) {|periods| []} } error = assert_raises(AmbiguousTime) { tz.local_to_utc(t) {|periods| raise AmbiguousTime, 'Custom ambiguous time message'} } assert_equal('Custom ambiguous time message', error.message) end end def test_local_to_utc_nil tz = Timezone.get('Europe/London') error = assert_raises(ArgumentError) { tz.local_to_utc(nil) } assert_match(/\blocal_time\b/, error.message) end def test_local_to_utc_unsupported tz = Timezone.get('Europe/London') t = Time.utc(2004,10,31,1,30,0).to_i error = assert_raises(ArgumentError) { tz.local_to_utc(t) } assert_match(Regexp.new("\\b#{Regexp.escape(t.class.name)}\\b"), error.message) end time_types_helpers(:output) do |h| method = "local_#{h.type}" define_method("test_#{method}") do o1 = TimezoneOffset.new(0, 0, 'GMT') o2 = TimezoneOffset.new(0, 3600, 'BST') period = TransitionsTimezonePeriod.new( TimezoneTransition.new(o2, o1, Time.utc(2005,3,27,2,0,0).to_i), TimezoneTransition.new(o1, o2, Time.utc(2005,10,30,1,0,0).to_i)) assert_equal_with_offset_and_class(h.time_with_offset(o2,2005,6,18,16,24,23,0), TestTimezone.new('Europe/London', nil, [period], Timestamp.create(2005,6,18,16,24,23,0)).public_send(method,2005,6,18,16,24,23,0)) assert_equal_with_offset_and_class(h.time_with_offset(o2,2005,6,18,16,24,23,Rational(567,1000)), TestTimezone.new('Europe/London', nil, [period], Timestamp.create(2005,6,18,16,24,23,Rational(567,1000))).public_send(method,2005,6,18,16,24,23,Rational(567,1000))) end define_method("test_#{method}_not_found") do ts = Timestamp.create(2004,4,4,2,30,0) tz = TestTimezone.new('America/New_York', nil, [], ts) assert_raises_period_not_found(ts) { tz.public_send(method,2004,4,4,2,30,0) } end define_method("test_#{method}_ambiguous") do o1 = TimezoneOffset.new(-18000, 0, 'EST') o2 = TimezoneOffset.new(-18000, 3600, 'EDT') t1 = TimezoneTransition.new(o2, o1, Time.utc(2004,4,4,8,0,0).to_i) t2 = TimezoneTransition.new(o1, o2, Time.utc(2004,10,31,6,0,0).to_i) t3 = TimezoneTransition.new(o2, o1, Time.utc(2005,4,3,8,0,0).to_i) p1 = TransitionsTimezonePeriod.new(t1, t2) p2 = TransitionsTimezonePeriod.new(t2, t3) ts = Timestamp.create(2004,10,31,1,30,0) tz = TestTimezone.new('America/New_York', nil, [p1, p2], ts) assert_raises_ambiguous_time(ts) { tz.public_send(method,2004,10,31,1,30,0) } end define_method("test_#{method}_default_dst_set_true") do Timezone.default_dst = true o1 = TimezoneOffset.new(-18000, 0, 'EST') o2 = TimezoneOffset.new(-18000, 3600, 'EDT') t1 = TimezoneTransition.new(o2, o1, Time.utc(2004,4,4,8,0,0).to_i) t2 = TimezoneTransition.new(o1, o2, Time.utc(2004,10,31,6,0,0).to_i) t3 = TimezoneTransition.new(o2, o1, Time.utc(2005,4,3,8,0,0).to_i) p1 = TransitionsTimezonePeriod.new(t1, t2) p2 = TransitionsTimezonePeriod.new(t2, t3) ts = Timestamp.create(2004,10,31,1,30,0) tz = TestTimezone.new('America/New_York', nil, [p1, p2], ts) assert_equal_with_offset_and_class(h.time_with_offset(o2,2004,10,31,1,30,0,0), tz.public_send(method,2004,10,31,1,30,0,0)) assert_equal_with_offset_and_class(h.time_with_offset(o2,2004,10,31,1,30,0,0), tz.public_send(method,2004,10,31,1,30,0,0,true)) assert_equal_with_offset_and_class(h.time_with_offset(o1,2004,10,31,1,30,0,0), tz.public_send(method,2004,10,31,1,30,0,0,false)) assert_raises_ambiguous_time(ts) { tz.public_send(method,2004,10,31,1,30,0,0,nil) } assert_equal_with_offset_and_class(h.time_with_offset(o2,2004,10,31,1,30,0,0), tz.public_send(method,2004,10,31,1,30,0,0) {|periods| raise BlockCalled, 'should not be called' }) end define_method("test_#{method}_default_dst_set_false") do Timezone.default_dst = false o1 = TimezoneOffset.new(-18000, 0, 'EST') o2 = TimezoneOffset.new(-18000, 3600, 'EDT') t1 = TimezoneTransition.new(o2, o1, Time.utc(2004,4,4,8,0,0).to_i) t2 = TimezoneTransition.new(o1, o2, Time.utc(2004,10,31,6,0,0).to_i) t3 = TimezoneTransition.new(o2, o1, Time.utc(2005,4,3,8,0,0).to_i) p1 = TransitionsTimezonePeriod.new(t1, t2) p2 = TransitionsTimezonePeriod.new(t2, t3) ts = Timestamp.create(2004,10,31,1,30,0) tz = TestTimezone.new('America/New_York', nil, [p1, p2], ts) assert_equal_with_offset_and_class(h.time_with_offset(o1,2004,10,31,1,30,0,0), tz.public_send(method,2004,10,31,1,30,0,0)) assert_equal_with_offset_and_class(h.time_with_offset(o1,2004,10,31,1,30,0,0), tz.public_send(method,2004,10,31,1,30,0,0,false)) assert_equal_with_offset_and_class(h.time_with_offset(o2,2004,10,31,1,30,0,0), tz.public_send(method,2004,10,31,1,30,0,0,true)) assert_raises_ambiguous_time(ts) { tz.public_send(method,2004,10,31,1,30,0,0,nil) } assert_equal_with_offset_and_class(h.time_with_offset(o1,2004,10,31,1,30,0,0), tz.public_send(method,2004,10,31,1,30,0,0) {|periods| raise BlockCalled, 'should not be called' }) end define_method("test_#{method}_default_dst_flag_resolved") do o1 = TimezoneOffset.new(-18000, 0, 'EST') o2 = TimezoneOffset.new(-18000, 3600, 'EDT') t1 = TimezoneTransition.new(o2, o1, Time.utc(2004,4,4,8,0,0).to_i) t2 = TimezoneTransition.new(o1, o2, Time.utc(2004,10,31,6,0,0).to_i) t3 = TimezoneTransition.new(o2, o1, Time.utc(2005,4,3,8,0,0).to_i) p1 = TransitionsTimezonePeriod.new(t1, t2) p2 = TransitionsTimezonePeriod.new(t2, t3) tz = TestTimezone.new('America/New_York', nil, [p1, p2], Timestamp.create(2004,10,31,1,30,0)) assert_equal_with_offset_and_class(h.time_with_offset(o2,2004,10,31,1,30,0,0), tz.public_send(method,2004,10,31,1,30,0,0,true)) assert_equal_with_offset_and_class(h.time_with_offset(o1,2004,10,31,1,30,0,0), tz.public_send(method,2004,10,31,1,30,0,0,false)) assert_equal_with_offset_and_class(h.time_with_offset(o2,2004,10,31,1,30,0,0), tz.public_send(method,2004,10,31,1,30,0,0,true) {|periods| raise BlockCalled, 'should not be called' }) assert_equal_with_offset_and_class(h.time_with_offset(o1,2004,10,31,1,30,0,0), tz.public_send(method,2004,10,31,1,30,0,0,false) {|periods| raise BlockCalled, 'should not be called' }) end define_method("test_#{method}_default_dst_block_called") do o1 = TimezoneOffset.new(-18000, 0, 'EST') o2 = TimezoneOffset.new(-18000, 3600, 'EDT') t1 = TimezoneTransition.new(o2, o1, Time.utc(2004,4,4,8,0,0).to_i) t2 = TimezoneTransition.new(o1, o2, Time.utc(2004,10,31,6,0,0).to_i) t3 = TimezoneTransition.new(o2, o1, Time.utc(2005,4,3,8,0,0).to_i) p1 = TransitionsTimezonePeriod.new(t1, t2) p2 = TransitionsTimezonePeriod.new(t2, t3) tz = TestTimezone.new('America/New_York', nil, [p1, p2], Timestamp.create(2004,10,31,1,30,0)) assert_raises(BlockCalled) do tz.public_send(method,2004,10,31,1,30,0) do |periods| assert_equal([p1, p2], periods) # raise exception to test that the block was called raise BlockCalled, 'should be raised' end end assert_equal_with_offset_and_class(h.time_with_offset(o2,2004,10,31,1,30,0,0), tz.public_send(method,2004,10,31,1,30,0) {|periods| periods.first }) assert_equal_with_offset_and_class(h.time_with_offset(o1,2004,10,31,1,30,0,0), tz.public_send(method,2004,10,31,1,30,0) {|periods| periods.last }) assert_equal_with_offset_and_class(h.time_with_offset(o2,2004,10,31,1,30,0,0), tz.public_send(method,2004,10,31,1,30,0) {|periods| [periods.first] }) assert_equal_with_offset_and_class(h.time_with_offset(o1,2004,10,31,1,30,0,0), tz.public_send(method,2004,10,31,1,30,0) {|periods| [periods.last] }) end define_method("test_#{method}_default_dst_cannot_resolve") do # At midnight local time on Aug 5 1915 in Warsaw, the clocks were put back # 24 minutes and both periods were non-DST. Hence the block should be # called regardless of the value of the Boolean dst parameter. o0 = TimezoneOffset.new(5040, 0, 'LMT') o1 = TimezoneOffset.new(5040, 0, 'WMT') o2 = TimezoneOffset.new(3600, 0, 'CET') o3 = TimezoneOffset.new(3600, 3600, 'CEST') t1 = TimezoneTransition.new(o1, o0, Time.utc(1879, 12, 31, 22, 36, 0).to_i) t2 = TimezoneTransition.new(o2, o1, Time.utc(1915, 8, 4, 22, 36, 0).to_i) t3 = TimezoneTransition.new(o3, o2, Time.utc(1916, 4, 30, 22, 0, 0).to_i) p1 = TransitionsTimezonePeriod.new(t1, t2) p2 = TransitionsTimezonePeriod.new(t2, t3) tz = TestTimezone.new('Europe/Warsaw', nil, [p1, p2], Timestamp.create(1915,8,4,23,40,0)) assert_raises(BlockCalled) do tz.public_send(method,1915,8,4,23,40,0,0,true) do |periods| assert_equal([p1, p2], periods) raise BlockCalled, 'should be raised' end end assert_raises(BlockCalled) do tz.public_send(method,1915,8,4,23,40,0,0,false) do |periods| assert_equal([p1, p2], periods) raise BlockCalled, 'should be raised' end end assert_equal_with_offset_and_class(h.time_with_offset(o1,1915,8,4,23,40,0,0), tz.public_send(method,1915,8,4,23,40,0) {|periods| periods.first}) assert_equal_with_offset_and_class(h.time_with_offset(o2,1915,8,4,23,40,0,0), tz.public_send(method,1915,8,4,23,40,0) {|periods| periods.last}) assert_equal_with_offset_and_class(h.time_with_offset(o1,1915,8,4,23,40,0,0), tz.public_send(method,1915,8,4,23,40,0) {|periods| [periods.first]}) assert_equal_with_offset_and_class(h.time_with_offset(o2,1915,8,4,23,40,0,0), tz.public_send(method,1915,8,4,23,40,0) {|periods| [periods.last]}) end define_method("test_#{method}_block_ambiguous") do o1 = TimezoneOffset.new(-18000, 0, 'EST') o2 = TimezoneOffset.new(-18000, 3600, 'EDT') t1 = TimezoneTransition.new(o2, o1, Time.utc(2004,4,4,8,0,0).to_i) t2 = TimezoneTransition.new(o1, o2, Time.utc(2004,10,31,6,0,0).to_i) t3 = TimezoneTransition.new(o2, o1, Time.utc(2005,4,3,8,0,0).to_i) p1 = TransitionsTimezonePeriod.new(t1, t2) p2 = TransitionsTimezonePeriod.new(t2, t3) ts = Timestamp.create(2004,10,31,1,30,0) tz = TestTimezone.new('America/New_York', nil, [p1, p2], ts) assert_raises_ambiguous_time(ts) { tz.public_send(method,2004,10,31,1,30,0) {|periods| nil } } assert_raises_ambiguous_time(ts) { tz.public_send(method,2004,10,31,1,30,0) {|periods| periods } } assert_raises_ambiguous_time(ts) { tz.public_send(method,2004,10,31,1,30,0) {|periods| [] } } error = assert_raises(AmbiguousTime) { tz.public_send(method,2004,10,31,1,30,0) {|periods| raise AmbiguousTime, 'Custom ambiguous time message' } } assert_equal('Custom ambiguous time message', error.message) end define_method("test_#{method}_invalid_days_for_specific_month") do o = TimezoneOffset.new(18000, 0, 'TEST') p = OffsetTimezonePeriod.new(o) [[2018,2,29],[2018,11,31]].each do |time_args| tz = TestTimezone.new('Test', nil, [p], Timestamp.create(*time_args)) assert_equal_with_offset_and_class(h.time_with_offset(o,time_args[0],time_args[1]+1,1,0,0,0,0), tz.public_send(method,*time_args)) end end define_method("test_#{method}_month_out_of_range") do tz = Timezone.get('Europe/London') [0, 13].each do |month| error = assert_raises(RangeError) { tz.public_send(method, 2018, month) } assert_equal('month must be between 1 and 12', error.message) end end define_method("test_#{method}_day_out_of_range") do tz = Timezone.get('Europe/London') [0, 32].each do |day| error = assert_raises(RangeError) { tz.public_send(method, 2018, 1, day) } assert_equal('day must be between 1 and 31', error.message) end end define_method("test_#{method}_hour_out_of_range") do tz = Timezone.get('Europe/London') [-1, 24].each do |hour| error = assert_raises(RangeError) { tz.public_send(method, 2018, 1, 1, hour) } assert_equal('hour must be between 0 and 23', error.message) end end define_method("test_#{method}_minute_out_of_range") do tz = Timezone.get('Europe/London') [-1, 60].each do |minute| error = assert_raises(RangeError) { tz.public_send(method, 2018, 1, 1, 0, minute) } assert_equal('minute must be between 0 and 59', error.message) end end define_method("test_#{method}_second_out_of_range") do tz = Timezone.get('Europe/London') [-1, 60].each do |second| error = assert_raises(RangeError) { tz.public_send(method, 2018, 1, 1, 0, 0, second) } assert_equal('second must be between 0 and 59', error.message) end end define_method("test_#{method}_sub_second_out_of_range") do tz = Timezone.get('Europe/London') [Rational(-1, 10), Rational(11, 10)].each do |sub_second| error = assert_raises(RangeError) { tz.public_send(method, 2018, 1, 1, 0, 0, 0, sub_second) } assert_equal('sub_second must be >= 0 and < 1', error.message) end end define_method("test_#{method}_year_not_integer") do tz = Timezone.get('Europe/London') error = assert_raises(ArgumentError) { tz.public_send(method, 2018.0) } assert_equal('year must be an Integer', error.message) end define_method("test_#{method}_month_not_integer") do tz = Timezone.get('Europe/London') error = assert_raises(ArgumentError) { tz.public_send(method, 2018, 1.0) } assert_equal('month must be an Integer', error.message) end define_method("test_#{method}_day_not_integer") do tz = Timezone.get('Europe/London') error = assert_raises(ArgumentError) { tz.public_send(method, 2018, 1, 1.0) } assert_equal('day must be an Integer', error.message) end define_method("test_#{method}_hour_not_integer") do tz = Timezone.get('Europe/London') error = assert_raises(ArgumentError) { tz.public_send(method, 2018, 1, 1, 0.0) } assert_equal('hour must be an Integer', error.message) end define_method("test_#{method}_minute_not_integer") do tz = Timezone.get('Europe/London') error = assert_raises(ArgumentError) { tz.public_send(method, 2018, 1, 1, 0, 0.0) } assert_equal('minute must be an Integer', error.message) end define_method("test_#{method}_second_not_integer") do tz = Timezone.get('Europe/London') error = assert_raises(ArgumentError) { tz.public_send(method, 2018, 1, 1, 0, 0, 0.0) } assert_equal('second must be an Integer', error.message) end define_method("test_#{method}_sub_second_not_zero_integer_or_rational") do tz = Timezone.get('Europe/London') [nil, 0.1, 1].each do |sub_second| error = assert_raises(ArgumentError) { tz.public_send(method, 2018, 1, 1, 0, 0, 0, sub_second) } assert_equal('sub_second must be a Rational or the Integer 0', error.message) end end end def test_offsets_up_to_utc_and_zero_offset o1 = TimezoneOffset.new(-17900, 0, 'TESTLMT') o2 = TimezoneOffset.new(-18000, 3600, 'TESTD') o3 = TimezoneOffset.new(-18000, 0, 'TESTS') o4 = TimezoneOffset.new(-21600, 3600, 'TESTD') o5 = TimezoneOffset.new(-21600, 0, 'TESTS') t1 = TimezoneTransition.new(o2, o1, Time.utc(2010, 4,1,1,0,0).to_i) t2 = TimezoneTransition.new(o3, o2, Time.utc(2010,10,1,1,0,0).to_i) t3 = TimezoneTransition.new(o2, o3, Time.utc(2011, 3,1,1,0,0).to_i) t4 = TimezoneTransition.new(o4, o2, Time.utc(2011, 4,1,1,0,0).to_i) t5 = TimezoneTransition.new(o3, o4, Time.utc(2011,10,1,1,0,0).to_i) t6 = TimezoneTransition.new(o5, o3, Time.utc(2012, 3,1,1,0,0).to_i) time_types_test(:utc) do |h| assert_array_same_items([o1, o2, o3, o4, o5], OffsetsUpToTestTimezone.new('Test/Zone', Timestamp.create(2012,3,1,1,0,1,0,:utc), nil, [t1, t2, t3, t4, t5, t6]). offsets_up_to(h.time(2012,3,1,1,0,1,0,:utc))) assert_array_same_items([o2, o3, o4, o5], OffsetsUpToTestTimezone.new('Test/Zone', Timestamp.create(2012,3,1,1,0,1,0,:utc), Timestamp.create(2010,4,1,1,0,0,0,:utc), [t1, t2, t3, t4, t5, t6]). offsets_up_to(h.time(2012,3,1,1,0,1,0,:utc), h.time(2010,4,1,1,0,0,0,:utc))) assert_array_same_items([o1, o2, o3, o4], OffsetsUpToTestTimezone.new('Test/Zone', Timestamp.create(2012,3,1,1,0,0,0,:utc), nil, [t1, t2, t3, t4, t5]). offsets_up_to(h.time(2012,3,1,1,0,0,0,:utc))) assert_array_same_items([o2, o3, o4, o5], OffsetsUpToTestTimezone.new('Test/Zone', Timestamp.create(2012,3,1,1,0,1,0,:utc), Timestamp.create(2010,4,1,1,0,1,0,:utc), [t2, t3, t4, t5, t6]). offsets_up_to(h.time(2012,3,1,1,0,1,0,:utc), h.time(2010,4,1,1,0,1,0,:utc))) assert_array_same_items([o2, o3], OffsetsUpToTestTimezone.new('Test/Zone', Timestamp.create(2011,3,1,2,0,0,0,:utc), Timestamp.create(2011,3,1,0,0,0,0,:utc), [t3]). offsets_up_to(h.time(2011,3,1,2,0,0,0,:utc), h.time(2011,3,1,0,0,0,0,:utc))) assert_array_same_items([o3, o4], OffsetsUpToTestTimezone.new('Test/Zone', Timestamp.create(2012,3,1,1,0,0, 0, :utc), Timestamp.create(2011,4,1,1,0,0,0,:utc), [t4, t5]). offsets_up_to(h.time(2012,3,1,1,0,0,0,:utc), h.time(2011,4,1,1,0,0,0,:utc))) end time_types_test do |h| assert_array_same_items([o1, o2, o3, o4, o5], OffsetsUpToTestTimezone.new('Test/Zone', Timestamp.create(2012,3,1,1,0,1,0,h.expected_zero_offset), nil, [t1, t2, t3, t4, t5, t6]). offsets_up_to(h.time(2012,3,1,1,0,1,0,0))) assert_array_same_items([o2, o3, o4, o5], OffsetsUpToTestTimezone.new('Test/Zone', Timestamp.create(2012,3,1,1,0,1,0,h.expected_zero_offset), Timestamp.create(2010,4,1,1,0,0,0,h.expected_zero_offset), [t1, t2, t3, t4, t5, t6]). offsets_up_to(h.time(2012,3,1,1,0,1,0,0), h.time(2010,4,1,1,0,0,0,0))) assert_array_same_items([o1, o2, o3, o4], OffsetsUpToTestTimezone.new('Test/Zone', Timestamp.create(2012,3,1,1,0,0,0,h.expected_zero_offset), nil, [t1, t2, t3, t4, t5]). offsets_up_to(h.time(2012,3,1,1,0,0,0,0))) assert_array_same_items([o2, o3, o4, o5], OffsetsUpToTestTimezone.new('Test/Zone', Timestamp.create(2012,3,1,1,0,1,0,h.expected_zero_offset), Timestamp.create(2010,4,1,1,0,1,0, h.expected_zero_offset), [t2, t3, t4, t5, t6]). offsets_up_to(h.time(2012,3,1,1,0,1,0,0), h.time(2010,4,1,1,0,1,0,0))) assert_array_same_items([o2, o3], OffsetsUpToTestTimezone.new('Test/Zone', Timestamp.create(2011,3,1,2,0,0,0,h.expected_zero_offset), Timestamp.create(2011,3,1,0,0,0,0,h.expected_zero_offset), [t3]). offsets_up_to(h.time(2011,3,1,2,0,0,0,0), h.time(2011,3,1,0,0,0,0,0))) assert_array_same_items([o3, o4], OffsetsUpToTestTimezone.new('Test/Zone', Timestamp.create(2012,3,1,1,0,0,0,h.expected_zero_offset), Timestamp.create(2011,4,1,1,0,0,0,h.expected_zero_offset), [t4, t5]). offsets_up_to(h.time(2012,3,1,1,0,0,0,0), h.time(2011,4,1,1,0,0,0,0))) end end def test_offsets_up_to_offset o1 = TimezoneOffset.new(-17900, 0, 'TESTLMT') o2 = TimezoneOffset.new(-18000, 0, 'TESTS') o3 = TimezoneOffset.new(-18000, 3600, 'TESTD') t1 = TimezoneTransition.new(o2, o1, Time.utc(2009,12,31,23,59,59).to_i) t2 = TimezoneTransition.new(o3, o2, Time.utc(2010, 7, 1, 0, 0, 0).to_i) time_types_test(:offset) do |h| assert_array_same_items([o1, o2, o3], OffsetsUpToTestTimezone.new('Test/Zone', Timestamp.create(2010,6,30,23,0,1,0,-3600), nil, [t1, t2]). offsets_up_to(h.time(2010,6,30,23,0,1,0,-3600))) assert_array_same_items([o1, o2], OffsetsUpToTestTimezone.new('Test/Zone', Timestamp.create(2010,7,1,1,0,0,0,3600), nil, [t1]). offsets_up_to(h.time(2010,7,1,1,0,0,0,3600))) assert_array_same_items([o2, o3], OffsetsUpToTestTimezone.new('Test/Zone', Timestamp.create(2011,1,1,0,0,0,0,h.expected_zero_offset), Timestamp.create(2010,1,1,0,59,59,0,3600), [t1, t2]). offsets_up_to(h.time(2011,1,1,0,0,0,0,0), h.time(2010,1,1,0,59,59,0,3600))) assert_array_same_items([o2, o3], OffsetsUpToTestTimezone.new('Test/Zone', Timestamp.create(2011,1,1,0,0,0,0,h.expected_zero_offset), Timestamp.create(2009,12,31,23,0,0,0,-3600), [t2]). offsets_up_to(h.time(2011,1,1,0,0,0,0,0), h.time(2009,12,31,23,0,0,0,-3600))) end end def test_offsets_up_to_no_transitions o = TimezoneOffset.new(600, 0, 'LMT') p = OffsetTimezonePeriod.new(o) time_types_test(:utc) do |h| assert_array_same_items([o], OffsetsUpToNoTransitionsTestTimezone.new('Test/Zone', Timestamp.create(2000,1,1,1,0,0,0,:utc), nil, p). offsets_up_to(h.time(2000,1,1,1,0,0,0,:utc))) assert_array_same_items([o], OffsetsUpToNoTransitionsTestTimezone.new('Test/Zone', Timestamp.create(2000,1,1,1,0,0,0,:utc), Timestamp.create(1990,1,1,1,0,0,0,:utc), p). offsets_up_to(h.time(2000,1,1,1,0,0,0,:utc), h.time(1990,1,1,1,0,0,0,:utc))) end time_types_test(:utc) do |h| assert_array_same_items([o], OffsetsUpToNoTransitionsTestTimezone.new('Test/Zone', Timestamp.create(2000,1,1,1,0,0,0,h.expected_zero_offset), nil, p). offsets_up_to(h.time(2000,1,1,1,0,0,0,0))) assert_array_same_items([o], OffsetsUpToNoTransitionsTestTimezone.new('Test/Zone', Timestamp.create(2000,1,1,1,0,0,0,h.expected_zero_offset), Timestamp.create(1990,1,1,1,0,0,0,h.expected_zero_offset), p). offsets_up_to(h.time(2000,1,1,1,0,0,0,0), h.time(1990,1,1,1,0,0,0,0))) assert_array_same_items([o], OffsetsUpToNoTransitionsTestTimezone.new('Test/Zone', Timestamp.create(2000,1,1,2,0,0,0,3600), nil, p). offsets_up_to(h.time(2000,1,1,2,0,0,0,3600))) assert_array_same_items([o], OffsetsUpToNoTransitionsTestTimezone.new('Test/Zone', Timestamp.create(2000,1,1,2,0,0,0,3600), Timestamp.create(1990,1,1,2,0,0,0,3600), p). offsets_up_to(h.time(2000,1,1,2,0,0,0,3600), h.time(1990,1,1,2,0,0,0,3600))) end end def test_offsets_up_to_utc_to_not_greater_than_utc_from time_types_test do |h| ts = Timestamp.create(2012,8,1,0,0,0,0,h.expected_zero_offset) tz = OffsetsUpToTestTimezone.new('Test/Zone', ts, ts, []) to = h.time(2012,8,1,0,0,0,0,0) from = h.time(2012,8,1,0,0,0,0,0) error = assert_raises(ArgumentError) { tz.offsets_up_to(to, from) } assert_equal('to must be greater than from', error.message) end end def test_offsets_up_to_unspecified_offset_to tz = OffsetsUpToTestTimezone.new('Test/Zone', Timestamp.create(2012,8,1,0,0,0), nil, []) time_types_test(:unspecified_offset) do |h| to = h.time(2012,8,1,0,0,0,0,nil) error = assert_raises(ArgumentError) { tz.offsets_up_to(to) } assert_equal('to must have a specified utc_offset', error.message) end end def test_offsets_up_to_unspecified_offset_from tz = OffsetsUpToTestTimezone.new('Test/Zone', Timestamp.create(2012,8,1,0,0,0,0,0), Timestamp.create(2012,1,1,0,0,0), []) time_types_test(:unspecified_offset) do |h| to = h.time(2012,8,1,0,0,0,0,0) from = h.time(2012,1,1,0,0,0,0,nil) error = assert_raises(ArgumentError) { tz.offsets_up_to(to, from) } assert_equal('from must have a specified utc_offset', error.message) end end def test_offsets_up_to_nil_to tz = OffsetsUpToTestTimezone.new('Test/Zone', nil, nil, []) error = assert_raises(ArgumentError) { tz.offsets_up_to(nil) } assert_equal('to must be specified', error.message) end def test_offsets_up_to_unsupported_to tz = Timezone.get('Europe/London') to = Time.utc(2012,8,1,0,0,0).to_i error = assert_raises(ArgumentError) { tz.offsets_up_to(to) } assert_match(Regexp.new("\\b#{Regexp.escape(to.class.name)}\\b"), error.message) end def test_offsets_up_to_unsupported_from tz = Timezone.get('Europe/London') to = Time.utc(2012,8,1,0,0,0) from = Time.utc(2012,1,1,0,0,0).to_i error = assert_raises(ArgumentError) { tz.offsets_up_to(to, from) } assert_match(Regexp.new("\\b#{Regexp.escape(from.class.name)}\\b"), error.message) end def test_now o1 = TimezoneOffset.new(0, 0, 'GMT') o2 = TimezoneOffset.new(0, 3600, 'BST') period = TransitionsTimezonePeriod.new( TimezoneTransition.new(o2, o1, Time.utc(2005,3,27,2,0,0).to_i), TimezoneTransition.new(o1, o2, Time.utc(2005,10,30,1,0,0).to_i)) now = Time.utc(2005,6,18,16,24,23).localtime tz = TestTimezone.new('Europe/London', period, [], Timestamp.for(now)) Time.stub(:now, now) do assert_equal_with_offset_and_timezone_offset(TimeWithOffset.new(2005,6,18,17,24,23,3600).set_timezone_offset(o2), tz.now) end end def test_current_period o1 = TimezoneOffset.new(0, 0, 'GMT') o2 = TimezoneOffset.new(0, 3600, 'BST') period = TransitionsTimezonePeriod.new( TimezoneTransition.new(o2, o1, Time.utc(2005,3,27,2,0,0).to_i), TimezoneTransition.new(o1, o2, Time.utc(2005,10,30,1,0,0).to_i)) now = Time.utc(2005,6,18,16,24,23).localtime tz = TestTimezone.new('Europe/London', period, [], now) Time.stub(:now, now) do assert_same(period, tz.current_period) end end [:current_period_and_time, :current_time_and_period].each do |method| define_method("test_#{method}") do o1 = TimezoneOffset.new(0, 0, 'GMT') o2 = TimezoneOffset.new(0, 3600, 'BST') period = TransitionsTimezonePeriod.new( TimezoneTransition.new(o2, o1, Time.utc(2005,3,27,2,0,0).to_i), TimezoneTransition.new(o1, o2, Time.utc(2005,10,30,1,0,0).to_i)) now = Time.utc(2005,6,18,16,24,23).localtime tz = TestTimezone.new('Europe/London', period, [], Timestamp.for(now)) Time.stub(:now, now) do current = tz.public_send(method) assert_equal(2, current.length) assert_equal_with_offset_and_timezone_offset(TimeWithOffset.new(2005,6,18,17,24,23,3600).set_timezone_offset(o2), current.first) assert_same(period, current.last) end end end def test_compare assert_equal(0, TestTimezone.new('Europe/London') <=> TestTimezone.new('Europe/London')) assert_equal(-1, TestTimezone.new('Europe/London') <=> TestTimezone.new('Europe/london')) assert_equal(-1, TestTimezone.new('Europe/London') <=> TestTimezone.new('Europe/Paris')) assert_equal(1, TestTimezone.new('Europe/Paris') <=> TestTimezone.new('Europe/London')) assert_equal(-1, TestTimezone.new('America/New_York') <=> TestTimezone.new('Europe/Paris')) assert_equal(1, TestTimezone.new('Europe/Paris') <=> TestTimezone.new('America/New_York')) end def test_compare_non_comparable assert_nil(TestTimezone.new('Europe/London') <=> Object.new) end def test_equality assert_equal(true, TestTimezone.new('Europe/London') == TestTimezone.new('Europe/London')) assert_equal(false, TestTimezone.new('Europe/London') == TestTimezone.new('Europe/london')) assert_equal(false, TestTimezone.new('Europe/London') == TestTimezone.new('Europe/Paris')) assert(!(TestTimezone.new('Europe/London') == Object.new)) end def test_eql assert_equal(true, TestTimezone.new('Europe/London').eql?(TestTimezone.new('Europe/London'))) assert_equal(false, TestTimezone.new('Europe/London').eql?(TestTimezone.new('Europe/london'))) assert_equal(false, TestTimezone.new('Europe/London').eql?(TestTimezone.new('Europe/Paris'))) assert(!TestTimezone.new('Europe/London').eql?(Object.new)) end def test_hash assert_equal('Europe/London'.hash, TestTimezone.new('Europe/London').hash) assert_equal('America/New_York'.hash, TestTimezone.new('America/New_York').hash) end define_method("test_=~_operator_matches_against_identifier") do tz = TestTimezone.new('Europe/London') assert_equal(0, tz =~ /\AEurope\/London\z/) assert_equal(6, tz =~ /\/London/) end define_method("test_=~_operator_returns_nil_when_regexp_does_not_match") do tz = TestTimezone.new('Europe/London') assert_nil(tz =~ /America\/New_York/) end def test_marshal_data tz = Timezone.get('Europe/London') marshalled_tz = Marshal.load(Marshal.dump(tz)) assert_kind_of(DataTimezone, marshalled_tz) assert_equal('Europe/London', marshalled_tz.identifier) end def test_marshal_linked tz = Timezone.get('UTC') marshalled_tz = Marshal.load(Marshal.dump(tz)) # ZoneinfoDataSource doesn't return DataSources::LinkedTimezoneInfo for any timezone. if DataSource.get.get_timezone_info('UTC').kind_of?(DataSources::LinkedTimezoneInfo) assert_kind_of(LinkedTimezone, marshalled_tz) else assert_kind_of(DataTimezone, marshalled_tz) end assert_equal('UTC', marshalled_tz.identifier) end def strftime_assertions(tz, time) assert_equal('23:12:02 BST', tz.strftime('%H:%M:%S %Z', time)) assert_equal('BST', tz.strftime('%Z', time)) assert_equal('%ZBST', tz.strftime('%%Z%Z', time)) assert_equal('BST BST', tz.strftime('%Z %Z', time)) assert_equal('BST %Z %BST %%Z %%BST', tz.strftime('%Z %%Z %%%Z %%%%Z %%%%%Z', time)) end def test_strftime tz = Timezone.get('Europe/London') time_types_test(:utc) do |h| strftime_assertions(tz, h.time(2006, 7, 15, 22, 12, 2, 0, :utc)) end time_types_test(:offset) do |h| strftime_assertions(tz, h.time(2006, 7, 15, 23, 12, 2, 0, 3600)) strftime_assertions(tz, h.time(2006, 7, 15, 21, 12, 2, 0, -3600)) end time_types_test do |h| strftime_assertions(tz, h.time(2006, 7, 15, 22, 12, 2, 0, 0)) end end def test_strftime_handles_percent_in_abbreviation o1 = TimezoneOffset.new(0, 0, 'GMT') o2 = TimezoneOffset.new(0, 0, '%H:%M:%S') tz = TestTimezone.new('Test/Zone', TransitionsTimezonePeriod.new(TimezoneTransition.new(o2, o1, Time.utc(2017,1,1,0,0,0).to_i), nil), nil, Timestamp.create(2017,1,15,15,50,0,0,:utc)) assert_equal('%H:%M:%S', tz.strftime('%Z', Time.utc(2017,1,15,15,50,0))) end def test_strftime_unspecified_offset tz = Timezone.get('Europe/London') time_types_test(:unspecified_offset) do |h| t = h.time(2006, 7, 15, 22, 12, 2, 0, nil) error = assert_raises(ArgumentError) { tz.strftime('%Z', t) } assert_match(/\btime\b/, error.message) end end def test_strftime_nil_format tz = Timezone.get('Europe/London') t = Time.utc(2006, 7, 15, 22, 12, 2) error = assert_raises(ArgumentError) { tz.strftime(nil, t) } assert_match(/\bformat\b/, error.message) end def test_strftime_nil_time tz = Timezone.get('Europe/London') error = assert_raises(ArgumentError) { tz.strftime('%Z', nil) } assert_match(/\btime\b/, error.message) end def test_get_missing_data_source DataSource.set(DataSource.new) error = assert_raises(InvalidDataSource) do Timezone.get('Europe/London') end assert_equal('load_timezone_info not defined', error.message) end def test_all_missing_data_source DataSource.set(DataSource.new) error = assert_raises(InvalidDataSource) do Timezone.all end assert_match(/\A(data|linked)_timezone_identifiers not defined\z/, error.message) end def test_all_identifiers_missing_data_source DataSource.set(DataSource.new) error = assert_raises(InvalidDataSource) do Timezone.all_identifiers end assert_match(/\A(data|linked)_timezone_identifiers not defined\z/, error.message) end def test_all_data_zones_missing_data_source DataSource.set(DataSource.new) error = assert_raises(InvalidDataSource) do Timezone.all_data_zones end assert_equal('data_timezone_identifiers not defined', error.message) end def test_all_data_zone_identifiers_missing_data_source DataSource.set(DataSource.new) error = assert_raises(InvalidDataSource) do Timezone.all_data_zone_identifiers end assert_equal('data_timezone_identifiers not defined', error.message) end def test_all_linked_zones_missing_data_source DataSource.set(DataSource.new) error = assert_raises(InvalidDataSource) do Timezone.all_linked_zones end assert_equal('linked_timezone_identifiers not defined', error.message) end def test_all_linked_zone_identifiers_missing_data_source DataSource.set(DataSource.new) error = assert_raises(InvalidDataSource) do Timezone.all_linked_zone_identifiers end assert_equal('linked_timezone_identifiers not defined', error.message) end def test_inspect tz = TestTimezone.new('Europe/London') assert_equal('#', tz.inspect) end %w(abbreviation abbr).each do |method| define_method("test_#{method}") do tz = Timezone.get('America/New_York') time_types_test do |h| assert_equal('EST', tz.public_send(method, h.time(2017,1,1,0,0,0,0,:utc))) assert_equal('EST', tz.public_send(method, h.time(2017,1,1,0,0,0,0,0))) assert_equal('EDT', tz.public_send(method, h.time(2017,7,1,0,0,0,0,:utc))) assert_equal('EDT', tz.public_send(method, h.time(2017,7,1,0,0,0,0,0))) end time_types_test(:offset) do |h| assert_equal('EST', tz.public_send(method, h.time(2016,12,31,19,0,0,0,-18000))) assert_equal('EDT', tz.public_send(method, h.time(2017, 6,30,20,0,0,0,-14400))) end end time_with_unspecified_offset_test(method) nil_time_test(method) end def test_dst? tz = Timezone.get('America/New_York') time_types_test do |h| assert_equal(false, tz.dst?(h.time(2017,1,1,0,0,0,0,:utc))) assert_equal(false, tz.dst?(h.time(2017,1,1,0,0,0,0,0))) assert_equal(true, tz.dst?(h.time(2017,7,1,0,0,0,0,:utc))) assert_equal(true, tz.dst?(h.time(2017,7,1,0,0,0,0,0))) end time_types_test(:offset) do |h| assert_equal(false, tz.dst?(h.time(2016,12,31,19,0,0,0,-18000))) assert_equal(true, tz.dst?(h.time(2017, 6,30,20,0,0,0,-14400))) end end time_with_unspecified_offset_test(:dst?) nil_time_test(:dst?) def test_base_utc_offset tz = Timezone.get('America/New_York') time_types_test do |h| assert_equal(-18000, tz.base_utc_offset(h.time(2017,1,1,0,0,0,0,:utc))) assert_equal(-18000, tz.base_utc_offset(h.time(2017,1,1,0,0,0,0,0))) assert_equal(-18000, tz.base_utc_offset(h.time(2017,7,1,0,0,0,0,:utc))) assert_equal(-18000, tz.base_utc_offset(h.time(2017,7,1,0,0,0,0,0))) end time_types_test(:offset) do |h| assert_equal(-18000, tz.base_utc_offset(h.time(2016,12,31,19,0,0,0,-18000))) assert_equal(-18000, tz.base_utc_offset(h.time(2017, 6,30,20,0,0,0,-14400))) end end time_with_unspecified_offset_test(:base_utc_offset) nil_time_test(:base_utc_offset) %w(observed_utc_offset utc_offset).each do |method| define_method("test_#{method}") do tz = Timezone.get('America/New_York') time_types_test do |h| assert_equal(-18000, tz.public_send(method, h.time(2017,1,1,0,0,0,0,:utc))) assert_equal(-18000, tz.public_send(method, h.time(2017,1,1,0,0,0,0,0))) assert_equal(-14400, tz.public_send(method, h.time(2017,7,1,0,0,0,0,:utc))) assert_equal(-14400, tz.public_send(method, h.time(2017,7,1,0,0,0,0,0))) end time_types_test(:offset) do |h| assert_equal(-18000, tz.public_send(method, h.time(2016,12,31,19,0,0,0,-18000))) assert_equal(-14400, tz.public_send(method, h.time(2017, 6,30,20,0,0,0,-14400))) end end time_with_unspecified_offset_test(method) nil_time_test(method) end private def assert_raises_unknown_timezone(&block) error = assert_raises(UnknownTimezone, &block) assert_equal('TZInfo::Timezone should not be constructed directly (use TZInfo::Timezone.get instead)', error.message) end def assert_raises_ambiguous_time(time, &block) error = assert_raises(AmbiguousTime, &block) assert_equal("#{strftime(time, '%Y-%m-%d %H:%M:%S')} is an ambiguous local time.", error.message) end def assert_raises_period_not_found(time, &block) error = assert_raises(PeriodNotFound, &block) assert_equal("#{strftime(time, '%Y-%m-%d %H:%M:%S')} is an invalid local time.", error.message) end def strftime(time, format) return time.strftime(format) if time.respond_to?(:strftime) Timestamp.for(time).strftime(format) end end tzinfo-2.0.6/test/tc_timezone_london.rb000066400000000000000000000302161436527530500202410ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true require_relative 'test_utils' class TCTimezoneLondon < Minitest::Test include TZInfo def test_2004 #Europe/London Sun Mar 28 00:59:59 2004 UTC = Sun Mar 28 00:59:59 2004 GMT isdst=0 gmtoff=0 #Europe/London Sun Mar 28 01:00:00 2004 UTC = Sun Mar 28 02:00:00 2004 BST isdst=1 gmtoff=3600 #Europe/London Sun Oct 31 00:59:59 2004 UTC = Sun Oct 31 01:59:59 2004 BST isdst=1 gmtoff=3600 #Europe/London Sun Oct 31 01:00:00 2004 UTC = Sun Oct 31 01:00:00 2004 GMT isdst=0 gmtoff=0 tz = Timezone.get('Europe/London') time_types_test(:offset) do |h| assert_equal_with_offset(h.output_time(2004, 3,28,0,59,59,0, 0), tz.to_local(h.time(2004, 3,28,0,59,59,0,0))) assert_equal_with_offset(h.output_time(2004, 3,28,2, 0, 0,0,3600), tz.to_local(h.time(2004, 3,28,1, 0, 0,0,0))) assert_equal_with_offset(h.output_time(2004,10,31,1,59,59,0,3600), tz.to_local(h.time(2004,10,31,0,59,59,0,0))) assert_equal_with_offset(h.output_time(2004,10,31,1, 0, 0,0, 0), tz.to_local(h.time(2004,10,31,1, 0, 0,0,0))) assert_equal_with_offset(h.output_time(2004, 3,28,0,59,59,0, 0), tz.utc_to_local(h.time(2004, 3,28,0,59,59))) assert_equal_with_offset(h.output_time(2004, 3,28,2, 0, 0,0,3600), tz.utc_to_local(h.time(2004, 3,28,1, 0, 0))) assert_equal_with_offset(h.output_time(2004,10,31,1,59,59,0,3600), tz.utc_to_local(h.time(2004,10,31,0,59,59))) assert_equal_with_offset(h.output_time(2004,10,31,1, 0, 0,0, 0), tz.utc_to_local(h.time(2004,10,31,1, 0, 0))) assert_equal_with_offset(h.output_time(2004, 3,28,0,59,59,0,:utc), tz.local_to_utc(h.time(2004, 3,28,0,59,59))) assert_equal_with_offset(h.output_time(2004, 3,28,1, 0, 0,0,:utc), tz.local_to_utc(h.time(2004, 3,28,2, 0, 0))) assert_equal_with_offset(h.output_time(2004,10,31,0,59,59,0,:utc), tz.local_to_utc(h.time(2004,10,31,1,59,59), true)) assert_equal_with_offset(h.output_time(2004,10,31,1,59,59,0,:utc), tz.local_to_utc(h.time(2004,10,31,1,59,59), false)) assert_equal_with_offset(h.output_time(2004,10,31,0, 0, 0,0,:utc), tz.local_to_utc(h.time(2004,10,31,1, 0, 0), true)) assert_equal_with_offset(h.output_time(2004,10,31,1, 0, 0,0,:utc), tz.local_to_utc(h.time(2004,10,31,1, 0, 0), false)) assert_raises(PeriodNotFound) { tz.local_to_utc(h.time(2004, 3,28,1,0,0)) } assert_raises(AmbiguousTime) { tz.local_to_utc(h.time(2004,10,31,1,0,0)) } assert_equal('GMT', tz.period_for(h.time(2004, 3,28,0,59,59,0,0)).zone_identifier) assert_equal('BST', tz.period_for(h.time(2004, 3,28,1, 0, 0,0,0)).zone_identifier) assert_equal('BST', tz.period_for(h.time(2004,10,31,0,59,59,0,0)).zone_identifier) assert_equal('GMT', tz.period_for(h.time(2004,10,31,1, 0, 0,0,0)).zone_identifier) assert_equal('GMT', tz.period_for_utc(h.time(2004, 3,28,0,59,59)).zone_identifier) assert_equal('BST', tz.period_for_utc(h.time(2004, 3,28,1, 0, 0)).zone_identifier) assert_equal('BST', tz.period_for_utc(h.time(2004,10,31,0,59,59)).zone_identifier) assert_equal('GMT', tz.period_for_utc(h.time(2004,10,31,1, 0, 0)).zone_identifier) assert_equal('GMT', tz.period_for_local(h.time(2004, 3,28,0,59,59)).zone_identifier) assert_equal('BST', tz.period_for_local(h.time(2004, 3,28,2, 0, 0)).zone_identifier) assert_equal('BST', tz.period_for_local(h.time(2004,10,31,1,59,59), true).zone_identifier) assert_equal('GMT', tz.period_for_local(h.time(2004,10,31,1,59,59), false).zone_identifier) assert_equal('BST', tz.period_for_local(h.time(2004,10,31,1, 0, 0), true).zone_identifier) assert_equal('GMT', tz.period_for_local(h.time(2004,10,31,1, 0, 0), false).zone_identifier) assert_equal( 0, tz.period_for(h.time(2004, 3,28,0,59,59,0,0)).observed_utc_offset) assert_equal(3600, tz.period_for(h.time(2004, 3,28,1, 0, 0,0,0)).observed_utc_offset) assert_equal(3600, tz.period_for(h.time(2004,10,31,0,59,59,0,0)).observed_utc_offset) assert_equal( 0, tz.period_for(h.time(2004,10,31,1, 0, 0,0,0)).observed_utc_offset) assert_equal( 0, tz.period_for_utc(h.time(2004, 3,28,0,59,59)).observed_utc_offset) assert_equal(3600, tz.period_for_utc(h.time(2004, 3,28,1, 0, 0)).observed_utc_offset) assert_equal(3600, tz.period_for_utc(h.time(2004,10,31,0,59,59)).observed_utc_offset) assert_equal( 0, tz.period_for_utc(h.time(2004,10,31,1, 0, 0)).observed_utc_offset) assert_equal( 0, tz.period_for_local(h.time(2004, 3,28,0,59,59)).observed_utc_offset) assert_equal(3600, tz.period_for_local(h.time(2004, 3,28,2, 0, 0)).observed_utc_offset) assert_equal(3600, tz.period_for_local(h.time(2004,10,31,1,59,59), true).observed_utc_offset) assert_equal( 0, tz.period_for_local(h.time(2004,10,31,1,59,59), false).observed_utc_offset) assert_equal(3600, tz.period_for_local(h.time(2004,10,31,1, 0, 0), true).observed_utc_offset) assert_equal( 0, tz.period_for_local(h.time(2004,10,31,1, 0, 0), false).observed_utc_offset) transitions = tz.transitions_up_to(h.time(2005,1,1,0,0,0,0,0), h.time(2004,1,1,0,0,0,0,0)) assert_equal(2, transitions.length) assert_equal_with_offset(Timestamp.for(Time.utc(2004,3,28,1,0,0)), transitions[0].at) assert_equal(TimezoneOffset.new(0, 0, 'GMT'), transitions[0].previous_offset) assert_equal(TimezoneOffset.new(0, 3600, 'BST'), transitions[0].offset) assert_equal_with_offset(Timestamp.for(Time.utc(2004,10,31,1,0,0)), transitions[1].at) assert_equal(TimezoneOffset.new(0, 3600, 'BST'), transitions[1].previous_offset) assert_equal(TimezoneOffset.new(0, 0, 'GMT'), transitions[1].offset) offsets = tz.offsets_up_to(h.time(2005,1,1,0,0,0,0,0), h.time(2004,1,1,0,0,0,0,0)) assert_array_same_items([TimezoneOffset.new(0, 0, 'GMT'), TimezoneOffset.new(0, 3600, 'BST')], offsets) end end def test_1961 #Europe/London Sun Mar 26 01:59:59 1961 UTC = Sun Mar 26 01:59:59 1961 GMT isdst=0 gmtoff=0 #Europe/London Sun Mar 26 02:00:00 1961 UTC = Sun Mar 26 03:00:00 1961 BST isdst=1 gmtoff=3600 #Europe/London Sun Oct 29 01:59:59 1961 UTC = Sun Oct 29 02:59:59 1961 BST isdst=1 gmtoff=3600 #Europe/London Sun Oct 29 02:00:00 1961 UTC = Sun Oct 29 02:00:00 1961 GMT isdst=0 gmtoff=0 tz = Timezone.get('Europe/London') time_types_test do |h| assert_equal_with_offset(h.output_time(1961, 3,26,1,59,59,0, 0), tz.to_local(h.time(1961, 3,26,1,59,59,0,0))) assert_equal_with_offset(h.output_time(1961, 3,26,3, 0, 0,0,3600), tz.to_local(h.time(1961, 3,26,2, 0, 0,0,0))) assert_equal_with_offset(h.output_time(1961,10,29,2,59,59,0,3600), tz.to_local(h.time(1961,10,29,1,59,59,0,0))) assert_equal_with_offset(h.output_time(1961,10,29,2, 0, 0,0, 0), tz.to_local(h.time(1961,10,29,2, 0, 0,0,0))) assert_equal_with_offset(h.output_time(1961, 3,26,1,59,59,0, 0), tz.utc_to_local(h.time(1961, 3,26,1,59,59))) assert_equal_with_offset(h.output_time(1961, 3,26,3, 0, 0,0,3600), tz.utc_to_local(h.time(1961, 3,26,2, 0, 0))) assert_equal_with_offset(h.output_time(1961,10,29,2,59,59,0,3600), tz.utc_to_local(h.time(1961,10,29,1,59,59))) assert_equal_with_offset(h.output_time(1961,10,29,2, 0, 0,0, 0), tz.utc_to_local(h.time(1961,10,29,2, 0, 0))) assert_equal_with_offset(h.output_time(1961, 3,26,1,59,59,0,:utc), tz.local_to_utc(h.time(1961, 3,26,1,59,59))) assert_equal_with_offset(h.output_time(1961, 3,26,2, 0, 0,0,:utc), tz.local_to_utc(h.time(1961, 3,26,3, 0, 0))) assert_equal_with_offset(h.output_time(1961,10,29,1,59,59,0,:utc), tz.local_to_utc(h.time(1961,10,29,2,59,59), true)) assert_equal_with_offset(h.output_time(1961,10,29,2,59,59,0,:utc), tz.local_to_utc(h.time(1961,10,29,2,59,59), false)) assert_equal_with_offset(h.output_time(1961,10,29,1, 0, 0,0,:utc), tz.local_to_utc(h.time(1961,10,29,2, 0, 0), true)) assert_equal_with_offset(h.output_time(1961,10,29,2, 0, 0,0,:utc), tz.local_to_utc(h.time(1961,10,29,2, 0, 0), false)) assert_raises(PeriodNotFound) { tz.local_to_utc(h.time(1961, 3,26,2,0,0)) } assert_raises(AmbiguousTime) { tz.local_to_utc(h.time(1961,10,29,2,0,0)) } assert_equal('GMT', tz.period_for(h.time(1961, 3,26,1,59,59,0,0)).zone_identifier) assert_equal('BST', tz.period_for(h.time(1961, 3,26,2, 0, 0,0,0)).zone_identifier) assert_equal('BST', tz.period_for(h.time(1961,10,29,1,59,59,0,0)).zone_identifier) assert_equal('GMT', tz.period_for(h.time(1961,10,29,2, 0, 0,0,0)).zone_identifier) assert_equal('GMT', tz.period_for_utc(h.time(1961, 3,26,1,59,59)).zone_identifier) assert_equal('BST', tz.period_for_utc(h.time(1961, 3,26,2, 0, 0)).zone_identifier) assert_equal('BST', tz.period_for_utc(h.time(1961,10,29,1,59,59)).zone_identifier) assert_equal('GMT', tz.period_for_utc(h.time(1961,10,29,2, 0, 0)).zone_identifier) assert_equal('GMT', tz.period_for_local(h.time(1961, 3,26,1,59,59)).zone_identifier) assert_equal('BST', tz.period_for_local(h.time(1961, 3,26,3, 0, 0)).zone_identifier) assert_equal('BST', tz.period_for_local(h.time(1961,10,29,2,59,59), true).zone_identifier) assert_equal('GMT', tz.period_for_local(h.time(1961,10,29,2,59,59), false).zone_identifier) assert_equal('BST', tz.period_for_local(h.time(1961,10,29,2, 0, 0), true).zone_identifier) assert_equal('GMT', tz.period_for_local(h.time(1961,10,29,2, 0, 0), false).zone_identifier) assert_equal( 0, tz.period_for(h.time(1961, 3,26,1,59,59,0,0)).observed_utc_offset) assert_equal(3600, tz.period_for(h.time(1961, 3,26,2, 0, 0,0,0)).observed_utc_offset) assert_equal(3600, tz.period_for(h.time(1961,10,29,1,59,59,0,0)).observed_utc_offset) assert_equal( 0, tz.period_for(h.time(1961,10,29,2, 0, 0,0,0)).observed_utc_offset) assert_equal( 0, tz.period_for_utc(h.time(1961, 3,26,1,59,59)).observed_utc_offset) assert_equal(3600, tz.period_for_utc(h.time(1961, 3,26,2, 0, 0)).observed_utc_offset) assert_equal(3600, tz.period_for_utc(h.time(1961,10,29,1,59,59)).observed_utc_offset) assert_equal( 0, tz.period_for_utc(h.time(1961,10,29,2, 0, 0)).observed_utc_offset) assert_equal( 0, tz.period_for_local(h.time(1961, 3,26,1,59,59)).observed_utc_offset) assert_equal(3600, tz.period_for_local(h.time(1961, 3,26,3, 0, 0)).observed_utc_offset) assert_equal(3600, tz.period_for_local(h.time(1961,10,29,2,59,59), true).observed_utc_offset) assert_equal( 0, tz.period_for_local(h.time(1961,10,29,2,59,59), false).observed_utc_offset) assert_equal(3600, tz.period_for_local(h.time(1961,10,29,2, 0, 0), true).observed_utc_offset) assert_equal( 0, tz.period_for_local(h.time(1961,10,29,2, 0, 0), false).observed_utc_offset) transitions = tz.transitions_up_to(h.time(1962,1,1,0,0,0,0,0), h.time(1961,1,1,0,0,0,0,0)) assert_equal(2, transitions.length) assert_equal_with_offset(Timestamp.for(Time.utc(1961,3,26,2,0,0)), transitions[0].at) assert_equal(TimezoneOffset.new(0, 0, 'GMT'), transitions[0].previous_offset) assert_equal(TimezoneOffset.new(0, 3600, 'BST'), transitions[0].offset) assert_equal_with_offset(Timestamp.for(Time.utc(1961,10,29,2,0,0)), transitions[1].at) assert_equal(TimezoneOffset.new(0, 3600, 'BST'), transitions[1].previous_offset) assert_equal(TimezoneOffset.new(0, 0, 'GMT'), transitions[1].offset) offsets = tz.offsets_up_to(h.time(1962,1,1,0,0,0,0,0), h.time(1961,1,1,0,0,0,0,0)) assert_array_same_items([TimezoneOffset.new(0, 0, 'GMT'), TimezoneOffset.new(0, 3600, 'BST')], offsets) end end def test_time_boundary #Europe/London Sat Oct 26 23:00:00 1968 UTC = Sun Oct 27 00:00:00 1968 GMT isdst=0 gmtoff=3600 #Europe/London Sun Oct 31 01:59:59 1971 UTC = Sun Oct 31 02:59:59 1971 GMT isdst=0 gmtoff=3600 tz = Timezone.get('Europe/London') time_types_test(:offset) do |h| assert_equal_with_offset(h.output_time(1970,1,1,1,0,0,0,3600), tz.to_local(h.time(1970,1,1,0,0,0,0,0))) assert_equal_with_offset(h.output_time(1970,1,1,1,0,0,0,3600), tz.utc_to_local(h.time(1970,1,1,0,0,0))) assert_equal_with_offset(h.output_time(1970,1,1,0,0,0,0,:utc), tz.local_to_utc(h.time(1970,1,1,1,0,0))) end end end tzinfo-2.0.6/test/tc_timezone_melbourne.rb000066400000000000000000000306331436527530500207430ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true require_relative 'test_utils' class TCTimezoneMelbourne < Minitest::Test include TZInfo def test_2004 #Australia/Melbourne Sat Mar 27 15:59:59 2004 UTC = Sun Mar 28 02:59:59 2004 AEDT isdst=1 gmtoff=39600 #Australia/Melbourne Sat Mar 27 16:00:00 2004 UTC = Sun Mar 28 02:00:00 2004 AEST isdst=0 gmtoff=36000 #Australia/Melbourne Sat Oct 30 15:59:59 2004 UTC = Sun Oct 31 01:59:59 2004 AEST isdst=0 gmtoff=36000 #Australia/Melbourne Sat Oct 30 16:00:00 2004 UTC = Sun Oct 31 03:00:00 2004 AEDT isdst=1 gmtoff=39600 tz = Timezone.get('Australia/Melbourne') time_types_test(:offset) do |h| assert_equal_with_offset(h.output_time(2004, 3,28,2,59,59,0,39600), tz.to_local(h.time(2004, 3,27,15,59,59,0,0))) assert_equal_with_offset(h.output_time(2004, 3,28,2, 0, 0,0,36000), tz.to_local(h.time(2004, 3,27,16, 0, 0,0,0))) assert_equal_with_offset(h.output_time(2004,10,31,1,59,59,0,36000), tz.to_local(h.time(2004,10,30,15,59,59,0,0))) assert_equal_with_offset(h.output_time(2004,10,31,3, 0, 0,0,39600), tz.to_local(h.time(2004,10,30,16, 0, 0,0,0))) assert_equal_with_offset(h.output_time(2004, 3,28,2,59,59,0,39600), tz.utc_to_local(h.time(2004, 3,27,15,59,59))) assert_equal_with_offset(h.output_time(2004, 3,28,2, 0, 0,0,36000), tz.utc_to_local(h.time(2004, 3,27,16, 0, 0))) assert_equal_with_offset(h.output_time(2004,10,31,1,59,59,0,36000), tz.utc_to_local(h.time(2004,10,30,15,59,59))) assert_equal_with_offset(h.output_time(2004,10,31,3, 0, 0,0,39600), tz.utc_to_local(h.time(2004,10,30,16, 0, 0))) assert_equal_with_offset(h.output_time(2004, 3,27,15,59,59,0,:utc), tz.local_to_utc(h.time(2004, 3,28,2,59,59), true)) assert_equal_with_offset(h.output_time(2004, 3,27,16,59,59,0,:utc), tz.local_to_utc(h.time(2004, 3,28,2,59,59), false)) assert_equal_with_offset(h.output_time(2004, 3,27,15, 0, 0,0,:utc), tz.local_to_utc(h.time(2004, 3,28,2, 0, 0), true)) assert_equal_with_offset(h.output_time(2004, 3,27,16, 0, 0,0,:utc), tz.local_to_utc(h.time(2004, 3,28,2, 0, 0), false)) assert_equal_with_offset(h.output_time(2004,10,30,15,59,59,0,:utc), tz.local_to_utc(h.time(2004,10,31,1,59,59))) assert_equal_with_offset(h.output_time(2004,10,30,16, 0, 0,0,:utc), tz.local_to_utc(h.time(2004,10,31,3, 0, 0))) assert_raises(PeriodNotFound) { tz.local_to_utc(h.time(2004,10,31,2,0,0)) } assert_raises(AmbiguousTime) { tz.local_to_utc(h.time(2004, 3,28,2,0,0)) } assert_equal('AEDT', tz.period_for(h.time(2004, 3,27,15,59,59,0,0)).zone_identifier) assert_equal('AEST', tz.period_for(h.time(2004, 3,27,16, 0, 0,0,0)).zone_identifier) assert_equal('AEST', tz.period_for(h.time(2004,10,30,15,59,59,0,0)).zone_identifier) assert_equal('AEDT', tz.period_for(h.time(2004,10,30,16, 0, 0,0,0)).zone_identifier) assert_equal('AEDT', tz.period_for_utc(h.time(2004, 3,27,15,59,59)).zone_identifier) assert_equal('AEST', tz.period_for_utc(h.time(2004, 3,27,16, 0, 0)).zone_identifier) assert_equal('AEST', tz.period_for_utc(h.time(2004,10,30,15,59,59)).zone_identifier) assert_equal('AEDT', tz.period_for_utc(h.time(2004,10,30,16, 0, 0)).zone_identifier) assert_equal('AEDT', tz.period_for_local(h.time(2004, 3,28,2,59,59), true).zone_identifier) assert_equal('AEST', tz.period_for_local(h.time(2004, 3,28,2,59,59), false).zone_identifier) assert_equal('AEDT', tz.period_for_local(h.time(2004, 3,28,2, 0, 0), true).zone_identifier) assert_equal('AEST', tz.period_for_local(h.time(2004, 3,28,2, 0, 0), false).zone_identifier) assert_equal('AEST', tz.period_for_local(h.time(2004,10,31,1,59,59)).zone_identifier) assert_equal('AEDT', tz.period_for_local(h.time(2004,10,31,3, 0, 0)).zone_identifier) assert_equal(39600, tz.period_for(h.time(2004, 3,27,15,59,59,0,0)).observed_utc_offset) assert_equal(36000, tz.period_for(h.time(2004, 3,27,16, 0, 0,0,0)).observed_utc_offset) assert_equal(36000, tz.period_for(h.time(2004,10,30,15,59,59,0,0)).observed_utc_offset) assert_equal(39600, tz.period_for(h.time(2004,10,30,16, 0, 0,0,0)).observed_utc_offset) assert_equal(39600, tz.period_for_utc(h.time(2004, 3,27,15,59,59)).observed_utc_offset) assert_equal(36000, tz.period_for_utc(h.time(2004, 3,27,16, 0, 0)).observed_utc_offset) assert_equal(36000, tz.period_for_utc(h.time(2004,10,30,15,59,59)).observed_utc_offset) assert_equal(39600, tz.period_for_utc(h.time(2004,10,30,16, 0, 0)).observed_utc_offset) assert_equal(39600, tz.period_for_local(h.time(2004, 3,28,2,59,59), true).observed_utc_offset) assert_equal(36000, tz.period_for_local(h.time(2004, 3,28,2,59,59), false).observed_utc_offset) assert_equal(39600, tz.period_for_local(h.time(2004, 3,28,2, 0, 0), true).observed_utc_offset) assert_equal(36000, tz.period_for_local(h.time(2004, 3,28,2, 0, 0), false).observed_utc_offset) assert_equal(36000, tz.period_for_local(h.time(2004,10,31,1,59,59)).observed_utc_offset) assert_equal(39600, tz.period_for_local(h.time(2004,10,31,3, 0, 0)).observed_utc_offset) transitions = tz.transitions_up_to(h.time(2005,1,1,0,0,0,0,0), h.time(2004,1,1,0,0,0,0,0)) assert_equal(2, transitions.length) assert_equal_with_offset(Timestamp.for(Time.utc(2004,3,27,16,0,0)), transitions[0].at) assert_equal(TimezoneOffset.new(36000, 3600, 'AEDT'), transitions[0].previous_offset) assert_equal(TimezoneOffset.new(36000, 0, 'AEST'), transitions[0].offset) assert_equal_with_offset(Timestamp.for(Time.utc(2004,10,30,16,0,0)), transitions[1].at) assert_equal(TimezoneOffset.new(36000, 0, 'AEST'), transitions[1].previous_offset) assert_equal(TimezoneOffset.new(36000, 3600, 'AEDT'), transitions[1].offset) offsets = tz.offsets_up_to(h.time(2005,1,1,0,0,0,0,0), h.time(2004,1,1,0,0,0,0,0)) assert_array_same_items([TimezoneOffset.new(36000, 0, 'AEST'), TimezoneOffset.new(36000, 3600, 'AEDT')], offsets) end end def test_1942 #Australia/Melbourne Sat Mar 28 14:59:59 1942 UTC = Sun Mar 29 01:59:59 1942 AEDT isdst=1 gmtoff=39600 #Australia/Melbourne Sat Mar 28 15:00:00 1942 UTC = Sun Mar 29 01:00:00 1942 AEST isdst=0 gmtoff=36000 #Australia/Melbourne Sat Sep 26 15:59:59 1942 UTC = Sun Sep 27 01:59:59 1942 AEST isdst=0 gmtoff=36000 #Australia/Melbourne Sat Sep 26 16:00:00 1942 UTC = Sun Sep 27 03:00:00 1942 AEDT isdst=1 gmtoff=39600 tz = Timezone.get('Australia/Melbourne') time_types_test(:offset) do |h| assert_equal_with_offset(h.output_time(1942,3,29,1,59,59,0,39600), tz.to_local(h.time(1942,3,28,14,59,59,0,0))) assert_equal_with_offset(h.output_time(1942,3,29,1, 0, 0,0,36000), tz.to_local(h.time(1942,3,28,15, 0, 0,0,0))) assert_equal_with_offset(h.output_time(1942,9,27,1,59,59,0,36000), tz.to_local(h.time(1942,9,26,15,59,59,0,0))) assert_equal_with_offset(h.output_time(1942,9,27,3, 0, 0,0,39600), tz.to_local(h.time(1942,9,26,16, 0, 0,0,0))) assert_equal_with_offset(h.output_time(1942,3,29,1,59,59,0,39600), tz.utc_to_local(h.time(1942,3,28,14,59,59))) assert_equal_with_offset(h.output_time(1942,3,29,1, 0, 0,0,36000), tz.utc_to_local(h.time(1942,3,28,15, 0, 0))) assert_equal_with_offset(h.output_time(1942,9,27,1,59,59,0,36000), tz.utc_to_local(h.time(1942,9,26,15,59,59))) assert_equal_with_offset(h.output_time(1942,9,27,3, 0, 0,0,39600), tz.utc_to_local(h.time(1942,9,26,16, 0, 0))) assert_equal_with_offset(h.output_time(1942,3,28,14,59,59,0,:utc), tz.local_to_utc(h.time(1942,3,29,1,59,59), true)) assert_equal_with_offset(h.output_time(1942,3,28,15,59,59,0,:utc), tz.local_to_utc(h.time(1942,3,29,1,59,59), false)) assert_equal_with_offset(h.output_time(1942,3,28,14, 0, 0,0,:utc), tz.local_to_utc(h.time(1942,3,29,1, 0, 0), true)) assert_equal_with_offset(h.output_time(1942,3,28,15, 0, 0,0,:utc), tz.local_to_utc(h.time(1942,3,29,1, 0, 0), false)) assert_equal_with_offset(h.output_time(1942,9,26,15,59,59,0,:utc), tz.local_to_utc(h.time(1942,9,27,1,59,59))) assert_equal_with_offset(h.output_time(1942,9,26,16, 0, 0,0,:utc), tz.local_to_utc(h.time(1942,9,27,3, 0, 0))) assert_raises(PeriodNotFound) { tz.local_to_utc(h.time(1942,9,27,2,0,0)) } assert_raises(AmbiguousTime) { tz.local_to_utc(h.time(1942,3,29,1,0,0)) } assert_equal('AEDT', tz.period_for(h.time(1942,3,28,14,59,59,0,0)).zone_identifier) assert_equal('AEST', tz.period_for(h.time(1942,3,28,15, 0, 0,0,0)).zone_identifier) assert_equal('AEST', tz.period_for(h.time(1942,9,26,15,59,59,0,0)).zone_identifier) assert_equal('AEDT', tz.period_for(h.time(1942,9,26,16, 0, 0,0,0)).zone_identifier) assert_equal('AEDT', tz.period_for_utc(h.time(1942,3,28,14,59,59)).zone_identifier) assert_equal('AEST', tz.period_for_utc(h.time(1942,3,28,15, 0, 0)).zone_identifier) assert_equal('AEST', tz.period_for_utc(h.time(1942,9,26,15,59,59)).zone_identifier) assert_equal('AEDT', tz.period_for_utc(h.time(1942,9,26,16, 0, 0)).zone_identifier) assert_equal('AEDT', tz.period_for_local(h.time(1942,3,29,1,59,59), true).zone_identifier) assert_equal('AEST', tz.period_for_local(h.time(1942,3,29,1,59,59), false).zone_identifier) assert_equal('AEDT', tz.period_for_local(h.time(1942,3,29,1, 0, 0), true).zone_identifier) assert_equal('AEST', tz.period_for_local(h.time(1942,3,29,1, 0, 0), false).zone_identifier) assert_equal('AEST', tz.period_for_local(h.time(1942,9,27,1,59,59)).zone_identifier) assert_equal('AEDT', tz.period_for_local(h.time(1942,9,27,3, 0, 0)).zone_identifier) assert_equal(39600, tz.period_for(h.time(1942,3,28,14,59,59,0,0)).observed_utc_offset) assert_equal(36000, tz.period_for(h.time(1942,3,28,15, 0, 0,0,0)).observed_utc_offset) assert_equal(36000, tz.period_for(h.time(1942,9,26,15,59,59,0,0)).observed_utc_offset) assert_equal(39600, tz.period_for(h.time(1942,9,26,16, 0, 0,0,0)).observed_utc_offset) assert_equal(39600, tz.period_for_utc(h.time(1942,3,28,14,59,59)).observed_utc_offset) assert_equal(36000, tz.period_for_utc(h.time(1942,3,28,15, 0, 0)).observed_utc_offset) assert_equal(36000, tz.period_for_utc(h.time(1942,9,26,15,59,59)).observed_utc_offset) assert_equal(39600, tz.period_for_utc(h.time(1942,9,26,16, 0, 0)).observed_utc_offset) assert_equal(39600, tz.period_for_local(h.time(1942,3,29,1,59,59), true).observed_utc_offset) assert_equal(36000, tz.period_for_local(h.time(1942,3,29,1,59,59), false).observed_utc_offset) assert_equal(39600, tz.period_for_local(h.time(1942,3,29,1, 0, 0), true).observed_utc_offset) assert_equal(36000, tz.period_for_local(h.time(1942,3,29,1, 0, 0), false).observed_utc_offset) assert_equal(36000, tz.period_for_local(h.time(1942,9,27,1,59,59)).observed_utc_offset) assert_equal(39600, tz.period_for_local(h.time(1942,9,27,3, 0, 0)).observed_utc_offset) transitions = tz.transitions_up_to(h.time(1943,1,1,0,0,0,0,0), h.time(1942,1,1,0,0,0,0,0)) assert_equal(2, transitions.length) assert_equal_with_offset(Timestamp.for(Time.utc(1942,3,28,15,0,0)), transitions[0].at) assert_equal(TimezoneOffset.new(36000, 3600, 'AEDT'), transitions[0].previous_offset) assert_equal(TimezoneOffset.new(36000, 0, 'AEST'), transitions[0].offset) assert_equal_with_offset(Timestamp.for(Time.utc(1942,9,26,16,0,0)), transitions[1].at) assert_equal(TimezoneOffset.new(36000, 0, 'AEST'), transitions[1].previous_offset) assert_equal(TimezoneOffset.new(36000, 3600, 'AEDT'), transitions[1].offset) offsets = tz.offsets_up_to(h.time(1943,1,1,0,0,0,0,0), h.time(1942,1,1,0,0,0,0,0)) assert_array_same_items([TimezoneOffset.new(36000, 0, 'AEST'), TimezoneOffset.new(36000, 3600, 'AEDT')], offsets) end end def test_time_boundary #Australia/Melbourne Sat Mar 25 15:00:00 1944 UTC = Sun Mar 26 01:00:00 1944 AEST isdst=0 gmtoff=36000 #Australia/Melbourne Sat Oct 30 15:59:59 1971 UTC = Sun Oct 31 01:59:59 1971 AEST isdst=0 gmtoff=36000 tz = Timezone.get('Australia/Melbourne') time_types_test(:offset) do |h| assert_equal_with_offset(h.output_time(1970,1,1,10,0,0,0,36000), tz.to_local(h.time(1970,1,1, 0,0,0,0,0))) assert_equal_with_offset(h.output_time(1970,1,1,10,0,0,0,36000), tz.utc_to_local(h.time(1970,1,1, 0,0,0))) assert_equal_with_offset(h.output_time(1970,1,1, 0,0,0,0, :utc), tz.local_to_utc(h.time(1970,1,1,10,0,0))) end end end tzinfo-2.0.6/test/tc_timezone_new_york.rb000066400000000000000000000306311436527530500206060ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true require_relative 'test_utils' class TCTimezoneNewYork < Minitest::Test include TZInfo def test_2004 #America/New_York Sun Apr 4 06:59:59 2004 UTC = Sun Apr 4 01:59:59 2004 EST isdst=0 gmtoff=-18000 #America/New_York Sun Apr 4 07:00:00 2004 UTC = Sun Apr 4 03:00:00 2004 EDT isdst=1 gmtoff=-14400 #America/New_York Sun Oct 31 05:59:59 2004 UTC = Sun Oct 31 01:59:59 2004 EDT isdst=1 gmtoff=-14400 #America/New_York Sun Oct 31 06:00:00 2004 UTC = Sun Oct 31 01:00:00 2004 EST isdst=0 gmtoff=-18000 tz = Timezone.get('America/New_York') time_types_test(:offset) do |h| assert_equal_with_offset(h.output_time(2004, 4, 4,1,59,59,0,-18000), tz.utc_to_local(h.time(2004, 4, 4,6,59,59,0,0))) assert_equal_with_offset(h.output_time(2004, 4, 4,3, 0, 0,0,-14400), tz.utc_to_local(h.time(2004, 4, 4,7, 0, 0,0,0))) assert_equal_with_offset(h.output_time(2004,10,31,1,59,59,0,-14400), tz.utc_to_local(h.time(2004,10,31,5,59,59,0,0))) assert_equal_with_offset(h.output_time(2004,10,31,1, 0, 0,0,-18000), tz.utc_to_local(h.time(2004,10,31,6, 0, 0,0,0))) assert_equal_with_offset(h.output_time(2004, 4, 4,1,59,59,0,-18000), tz.utc_to_local(h.time(2004, 4, 4,6,59,59))) assert_equal_with_offset(h.output_time(2004, 4, 4,3, 0, 0,0,-14400), tz.utc_to_local(h.time(2004, 4, 4,7, 0, 0))) assert_equal_with_offset(h.output_time(2004,10,31,1,59,59,0,-14400), tz.utc_to_local(h.time(2004,10,31,5,59,59))) assert_equal_with_offset(h.output_time(2004,10,31,1, 0, 0,0,-18000), tz.utc_to_local(h.time(2004,10,31,6, 0, 0))) assert_equal_with_offset(h.output_time(2004, 4, 4,6,59,59,0,:utc), tz.local_to_utc(h.time(2004, 4, 4,1,59,59))) assert_equal_with_offset(h.output_time(2004, 4, 4,7, 0, 0,0,:utc), tz.local_to_utc(h.time(2004, 4, 4,3, 0, 0))) assert_equal_with_offset(h.output_time(2004,10,31,5,59,59,0,:utc), tz.local_to_utc(h.time(2004,10,31,1,59,59), true)) assert_equal_with_offset(h.output_time(2004,10,31,6,59,59,0,:utc), tz.local_to_utc(h.time(2004,10,31,1,59,59), false)) assert_equal_with_offset(h.output_time(2004,10,31,5, 0, 0,0,:utc), tz.local_to_utc(h.time(2004,10,31,1, 0, 0), true)) assert_equal_with_offset(h.output_time(2004,10,31,6, 0, 0,0,:utc), tz.local_to_utc(h.time(2004,10,31,1, 0, 0), false)) assert_raises(PeriodNotFound) { tz.local_to_utc(h.time(2004, 4, 4,2,0,0)) } assert_raises(AmbiguousTime) { tz.local_to_utc(h.time(2004,10,31,1,0,0)) } assert_equal('EST', tz.period_for(h.time(2004, 4, 4,6,59,59,0,0)).zone_identifier) assert_equal('EDT', tz.period_for(h.time(2004, 4, 4,7, 0, 0,0,0)).zone_identifier) assert_equal('EDT', tz.period_for(h.time(2004,10,31,5,59,59,0,0)).zone_identifier) assert_equal('EST', tz.period_for(h.time(2004,10,31,6, 0, 0,0,0)).zone_identifier) assert_equal('EST', tz.period_for_utc(h.time(2004, 4, 4,6,59,59)).zone_identifier) assert_equal('EDT', tz.period_for_utc(h.time(2004, 4, 4,7, 0, 0)).zone_identifier) assert_equal('EDT', tz.period_for_utc(h.time(2004,10,31,5,59,59)).zone_identifier) assert_equal('EST', tz.period_for_utc(h.time(2004,10,31,6, 0, 0)).zone_identifier) assert_equal('EST', tz.period_for_local(h.time(2004, 4, 4,1,59,59)).zone_identifier) assert_equal('EDT', tz.period_for_local(h.time(2004, 4, 4,3, 0, 0)).zone_identifier) assert_equal('EDT', tz.period_for_local(h.time(2004,10,31,1,59,59), true).zone_identifier) assert_equal('EST', tz.period_for_local(h.time(2004,10,31,1,59,59), false).zone_identifier) assert_equal('EDT', tz.period_for_local(h.time(2004,10,31,1, 0, 0), true).zone_identifier) assert_equal('EST', tz.period_for_local(h.time(2004,10,31,1, 0, 0), false).zone_identifier) assert_equal(-18000, tz.period_for(h.time(2004, 4, 4,6,59,59,0,0)).observed_utc_offset) assert_equal(-14400, tz.period_for(h.time(2004, 4, 4,7, 0, 0,0,0)).observed_utc_offset) assert_equal(-14400, tz.period_for(h.time(2004,10,31,5,59,59,0,0)).observed_utc_offset) assert_equal(-18000, tz.period_for(h.time(2004,10,31,6, 0, 0,0,0)).observed_utc_offset) assert_equal(-18000, tz.period_for_utc(h.time(2004, 4, 4,6,59,59)).observed_utc_offset) assert_equal(-14400, tz.period_for_utc(h.time(2004, 4, 4,7, 0, 0)).observed_utc_offset) assert_equal(-14400, tz.period_for_utc(h.time(2004,10,31,5,59,59)).observed_utc_offset) assert_equal(-18000, tz.period_for_utc(h.time(2004,10,31,6, 0, 0)).observed_utc_offset) assert_equal(-18000, tz.period_for_local(h.time(2004, 4, 4,1,59,59)).observed_utc_offset) assert_equal(-14400, tz.period_for_local(h.time(2004, 4, 4,3, 0, 0)).observed_utc_offset) assert_equal(-14400, tz.period_for_local(h.time(2004,10,31,1,59,59), true).observed_utc_offset) assert_equal(-18000, tz.period_for_local(h.time(2004,10,31,1,59,59), false).observed_utc_offset) assert_equal(-14400, tz.period_for_local(h.time(2004,10,31,1, 0, 0), true).observed_utc_offset) assert_equal(-18000, tz.period_for_local(h.time(2004,10,31,1, 0, 0), false).observed_utc_offset) transitions = tz.transitions_up_to(h.time(2005,1,1,0,0,0,0,0), h.time(2004,1,1,0,0,0,0,0)) assert_equal(2, transitions.length) assert_equal_with_offset(Timestamp.for(Time.utc(2004,4,4,7,0,0)), transitions[0].at) assert_equal(TimezoneOffset.new(-18000, 0, 'EST'), transitions[0].previous_offset) assert_equal(TimezoneOffset.new(-18000, 3600, 'EDT'), transitions[0].offset) assert_equal_with_offset(Timestamp.for(Time.utc(2004,10,31,6,0,0)), transitions[1].at) assert_equal(TimezoneOffset.new(-18000, 3600, 'EDT'), transitions[1].previous_offset) assert_equal(TimezoneOffset.new(-18000, 0, 'EST'), transitions[1].offset) offsets = tz.offsets_up_to(h.time(2005,1,1,0,0,0,0,0), h.time(2004,1,1,0,0,0,0,0)) assert_array_same_items([TimezoneOffset.new(-18000, 0, 'EST'), TimezoneOffset.new(-18000, 3600, 'EDT')], offsets) end end def test_1957 #America/New_York Sun Apr 28 06:59:59 1957 UTC = Sun Apr 28 01:59:59 1957 EST isdst=0 gmtoff=-18000 #America/New_York Sun Apr 28 07:00:00 1957 UTC = Sun Apr 28 03:00:00 1957 EDT isdst=1 gmtoff=-14400 #America/New_York Sun Oct 27 05:59:59 1957 UTC = Sun Oct 27 01:59:59 1957 EDT isdst=1 gmtoff=-14400 #America/New_York Sun Oct 27 06:00:00 1957 UTC = Sun Oct 27 01:00:00 1957 EST isdst=0 gmtoff=-18000 tz = Timezone.get('America/New_York') time_types_test(:offset) do |h| assert_equal_with_offset(h.output_time(1957, 4,28,1,59,59,0,-18000), tz.utc_to_local(h.time(1957, 4,28,6,59,59,0,0))) assert_equal_with_offset(h.output_time(1957, 4,28,3, 0, 0,0,-14400), tz.utc_to_local(h.time(1957, 4,28,7, 0, 0,0,0))) assert_equal_with_offset(h.output_time(1957,10,27,1,59,59,0,-14400), tz.utc_to_local(h.time(1957,10,27,5,59,59,0,0))) assert_equal_with_offset(h.output_time(1957,10,27,1, 0, 0,0,-18000), tz.utc_to_local(h.time(1957,10,27,6, 0, 0,0,0))) assert_equal_with_offset(h.output_time(1957, 4,28,1,59,59,0,-18000), tz.utc_to_local(h.time(1957, 4,28,6,59,59))) assert_equal_with_offset(h.output_time(1957, 4,28,3, 0, 0,0,-14400), tz.utc_to_local(h.time(1957, 4,28,7, 0, 0))) assert_equal_with_offset(h.output_time(1957,10,27,1,59,59,0,-14400), tz.utc_to_local(h.time(1957,10,27,5,59,59))) assert_equal_with_offset(h.output_time(1957,10,27,1, 0, 0,0,-18000), tz.utc_to_local(h.time(1957,10,27,6, 0, 0))) assert_equal_with_offset(h.output_time(1957, 4,28,6,59,59,0,:utc), tz.local_to_utc(h.time(1957, 4,28,1,59,59))) assert_equal_with_offset(h.output_time(1957, 4,28,7, 0, 0,0,:utc), tz.local_to_utc(h.time(1957, 4,28,3, 0, 0))) assert_equal_with_offset(h.output_time(1957,10,27,5,59,59,0,:utc), tz.local_to_utc(h.time(1957,10,27,1,59,59), true)) assert_equal_with_offset(h.output_time(1957,10,27,6,59,59,0,:utc), tz.local_to_utc(h.time(1957,10,27,1,59,59), false)) assert_equal_with_offset(h.output_time(1957,10,27,5, 0, 0,0,:utc), tz.local_to_utc(h.time(1957,10,27,1, 0, 0), true)) assert_equal_with_offset(h.output_time(1957,10,27,6, 0, 0,0,:utc), tz.local_to_utc(h.time(1957,10,27,1, 0, 0), false)) assert_raises(PeriodNotFound) { tz.local_to_utc(h.time(1957, 4,28,2,0,0)) } assert_raises(AmbiguousTime) { tz.local_to_utc(h.time(1957,10,27,1,0,0)) } assert_equal('EST', tz.period_for(h.time(1957, 4,28,6,59,59,0,0)).zone_identifier) assert_equal('EDT', tz.period_for(h.time(1957, 4,28,7, 0, 0,0,0)).zone_identifier) assert_equal('EDT', tz.period_for(h.time(1957,10,27,5,59,59,0,0)).zone_identifier) assert_equal('EST', tz.period_for(h.time(1957,10,27,6, 0, 0,0,0)).zone_identifier) assert_equal('EST', tz.period_for_utc(h.time(1957, 4,28,6,59,59)).zone_identifier) assert_equal('EDT', tz.period_for_utc(h.time(1957, 4,28,7, 0, 0)).zone_identifier) assert_equal('EDT', tz.period_for_utc(h.time(1957,10,27,5,59,59)).zone_identifier) assert_equal('EST', tz.period_for_utc(h.time(1957,10,27,6, 0, 0)).zone_identifier) assert_equal('EST', tz.period_for_local(h.time(1957, 4,28,1,59,59)).zone_identifier) assert_equal('EDT', tz.period_for_local(h.time(1957, 4,28,3, 0, 0)).zone_identifier) assert_equal('EDT', tz.period_for_local(h.time(1957,10,27,1,59,59), true).zone_identifier) assert_equal('EST', tz.period_for_local(h.time(1957,10,27,1,59,59), false).zone_identifier) assert_equal('EDT', tz.period_for_local(h.time(1957,10,27,1, 0, 0), true).zone_identifier) assert_equal('EST', tz.period_for_local(h.time(1957,10,27,1, 0, 0), false).zone_identifier) assert_equal(-18000, tz.period_for(h.time(1957, 4,28,6,59,59,0,0)).observed_utc_offset) assert_equal(-14400, tz.period_for(h.time(1957, 4,28,7, 0, 0,0,0)).observed_utc_offset) assert_equal(-14400, tz.period_for(h.time(1957,10,27,5,59,59,0,0)).observed_utc_offset) assert_equal(-18000, tz.period_for(h.time(1957,10,27,6, 0, 0,0,0)).observed_utc_offset) assert_equal(-18000, tz.period_for_utc(h.time(1957, 4,28,6,59,59)).observed_utc_offset) assert_equal(-14400, tz.period_for_utc(h.time(1957, 4,28,7, 0, 0)).observed_utc_offset) assert_equal(-14400, tz.period_for_utc(h.time(1957,10,27,5,59,59)).observed_utc_offset) assert_equal(-18000, tz.period_for_utc(h.time(1957,10,27,6, 0, 0)).observed_utc_offset) assert_equal(-18000, tz.period_for_local(h.time(1957, 4,28,1,59,59)).observed_utc_offset) assert_equal(-14400, tz.period_for_local(h.time(1957, 4,28,3, 0, 0)).observed_utc_offset) assert_equal(-14400, tz.period_for_local(h.time(1957,10,27,1,59,59), true).observed_utc_offset) assert_equal(-18000, tz.period_for_local(h.time(1957,10,27,1,59,59), false).observed_utc_offset) assert_equal(-14400, tz.period_for_local(h.time(1957,10,27,1, 0, 0), true).observed_utc_offset) assert_equal(-18000, tz.period_for_local(h.time(1957,10,27,1, 0, 0), false).observed_utc_offset) transitions = tz.transitions_up_to(h.time(1958,1,1,0,0,0,0,0), h.time(1957,1,1,0,0,0,0,0)) assert_equal(2, transitions.length) assert_equal_with_offset(Timestamp.for(Time.utc(1957,4,28,7,0,0)), transitions[0].at) assert_equal(TimezoneOffset.new(-18000, 0, 'EST'), transitions[0].previous_offset) assert_equal(TimezoneOffset.new(-18000, 3600, 'EDT'), transitions[0].offset) assert_equal_with_offset(Timestamp.for(Time.utc(1957,10,27,6,0,0)), transitions[1].at) assert_equal(TimezoneOffset.new(-18000, 3600, 'EDT'), transitions[1].previous_offset) assert_equal(TimezoneOffset.new(-18000, 0, 'EST'), transitions[1].offset) offsets = tz.offsets_up_to(h.time(1958,1,1,0,0,0,0,0), h.time(1957,1,1,0,0,0,0,0)) assert_array_same_items([TimezoneOffset.new(-18000, 0, 'EST'), TimezoneOffset.new(-18000, 3600, 'EDT')], offsets) end end def test_time_boundary #America/New_York Sun Oct 26 06:00:00 1969 UTC = Sun Oct 26 01:00:00 1969 EST isdst=0 gmtoff=-18000 #America/New_York Sun Apr 26 06:59:59 1970 UTC = Sun Apr 26 01:59:59 1970 EST isdst=0 gmtoff=-18000 tz = Timezone.get('America/New_York') time_types_test(:offset) do |h| assert_equal_with_offset(h.output_time(1970,1,1,0,0,0,0,-18000), tz.to_local(h.time(1970,1,1,5,0,0,0,0))) assert_equal_with_offset(h.output_time(1970,1,1,0,0,0,0,-18000), tz.utc_to_local(h.time(1970,1,1,5,0,0))) assert_equal_with_offset(h.output_time(1970,1,1,5,0,0,0, :utc), tz.local_to_utc(h.time(1970,1,1,0,0,0))) end end end tzinfo-2.0.6/test/tc_timezone_offset.rb000066400000000000000000000060071436527530500202370ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true require_relative 'test_utils' class TCTimezoneOffset < Minitest::Test include TZInfo [:base_utc_offset, :utc_offset].each do |method| define_method("test_#{method}") do o1 = TimezoneOffset.new(18000, 0, 'TEST') o2 = TimezoneOffset.new(-3600, 3600, 'TEST2') assert_equal(18000, o1.public_send(method)) assert_equal(-3600, o2.public_send(method)) end end def test_std_offset o1 = TimezoneOffset.new(18000, 0, 'TEST') o2 = TimezoneOffset.new(-3600, 3600, 'TEST2') assert_equal(0, o1.std_offset) assert_equal(3600, o2.std_offset) end [:observed_utc_offset, :utc_total_offset].each do |method| define_method("test_#{method}") do o1 = TimezoneOffset.new(18000, 0, 'TEST') o2 = TimezoneOffset.new(-3600, 3600, 'TEST2') assert_equal(18000, o1.public_send(method)) assert_equal(0, o2.public_send(method)) end end %w(abbreviation abbr).each do |method| define_method("test_#{method}") do o1 = TimezoneOffset.new(18000, 0, 'TEST') o2 = TimezoneOffset.new(-3600, 3600, 'TEST2') assert_equal('TEST', o1.public_send(method)) assert_equal('TEST2', o2.public_send(method)) end define_method("test_#{method}_frozen") do abbreviation = 'TEST'.dup refute(abbreviation.frozen?) o = TimezoneOffset.new(18000, 0, abbreviation) assert_same(abbreviation, o.public_send(method)) assert(o.public_send(method).frozen?) end end def test_dst o1 = TimezoneOffset.new(18000, 0, 'TEST') o2 = TimezoneOffset.new(-3600, 3600, 'TEST2') assert_equal(false, o1.dst?) assert_equal(true, o2.dst?) end def test_equality o1 = TimezoneOffset.new(18000, 0, 'TEST') o2 = TimezoneOffset.new(18000, 0, 'TEST') o3 = TimezoneOffset.new(18001, 0, 'TEST') o4 = TimezoneOffset.new(18000, 1, 'TEST') o5 = TimezoneOffset.new(18000, 0, 'TEST2') assert_equal(true, o1 == o1) assert_equal(true, o1 == o2) assert_equal(false, o1 == o3) assert_equal(false, o1 == o4) assert_equal(false, o1 == o5) assert_equal(false, o1 == Object.new) end def test_eql o1 = TimezoneOffset.new(18000, 0, 'TEST') o2 = TimezoneOffset.new(18000, 0, 'TEST') o3 = TimezoneOffset.new(18001, 0, 'TEST') o4 = TimezoneOffset.new(18000, 1, 'TEST') o5 = TimezoneOffset.new(18000, 0, 'TEST2') assert_equal(true, o1.eql?(o1)) assert_equal(true, o1.eql?(o2)) assert_equal(false, o1.eql?(o3)) assert_equal(false, o1.eql?(o4)) assert_equal(false, o1.eql?(o5)) assert_equal(false, o1.eql?(Object.new)) end def test_hash o1 = TimezoneOffset.new(18000, 0, 'TEST') o2 = TimezoneOffset.new(-3600, 3600, 'TEST2') assert_equal([18000, 0, 'TEST'].hash, o1.hash) assert_equal([-3600, 3600, 'TEST2'].hash, o2.hash) end def test_inspect o = TimezoneOffset.new(18000, 0, 'TEST') assert_equal('#', o.inspect) end end tzinfo-2.0.6/test/tc_timezone_period.rb000066400000000000000000000104231436527530500202300ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true require_relative 'test_utils' class TCTimezonePeriod < Minitest::Test include TZInfo class TestTimezonePeriod < TimezonePeriod attr_reader :start_transition attr_reader :end_transition def initialize(start_transition, end_transition, offset) super(offset) @start_transition = start_transition @end_transition = end_transition end end def test_initialize offset = TimezoneOffset.new(-7200, 3600, 'SPECIAL') p = TimezonePeriod.new(offset) assert_same(offset, p.offset) end def test_initialize_nil error = assert_raises(ArgumentError) { TimezonePeriod.new(nil) } assert_match(/\boffset\b/, error.message) end def test_start_transition p = TimezonePeriod.new(TimezoneOffset.new(-7200, 3600, 'SPECIAL')) error = assert_raises(NotImplementedError) { p.start_transition } assert_match(/\bstart_transition\b/, error.message) end def test_end_transition p = TimezonePeriod.new(TimezoneOffset.new(-7200, 3600, 'SPECIAL')) error = assert_raises(NotImplementedError) { p.end_transition } assert_match(/\bend_transition\b/, error.message) end [:base_utc_offset, :utc_offset].each do |method| define_method("test_#{method}") do p = TimezonePeriod.new(TimezoneOffset.new(-14400, 3600, 'TEST')) assert_equal(-14400, p.public_send(method)) end end def test_std_offset p = TimezonePeriod.new(TimezoneOffset.new(-14400, 3600, 'TEST')) assert_equal(3600, p.std_offset) end %w(abbreviation abbr).each do |method| define_method("test_#{method}") do p = TimezonePeriod.new(TimezoneOffset.new(-14400, 3600, 'TEST')) assert_equal('TEST', p.public_send(method)) end end def test_zone_identifier p = TimezonePeriod.new(TimezoneOffset.new(-14400, 3600, 'TEST')) assert_equal('TEST', p.zone_identifier) end [:observed_utc_offset, :utc_total_offset].each do |method| define_method("test_#{method}") do p = TimezonePeriod.new(TimezoneOffset.new(-14400, 3600, 'TEST')) assert_equal(-10800, p.public_send(method)) end end def test_dst p1 = TimezonePeriod.new(TimezoneOffset.new(-14400, 3600, 'TEST')) p2 = TimezonePeriod.new(TimezoneOffset.new(-14400, 0, 'TEST')) assert_equal(true, p1.dst?) assert_equal(false, p2.dst?) end def test_starts_at_bounded std = TimezoneOffset.new(-7200, 0, 'TEST') dst = TimezoneOffset.new(-7200, 3600, 'TEST') p = TestTimezonePeriod.new(TimezoneTransition.new(dst, std, 1136073600), nil, dst) assert_equal_with_offset_and_class(Timestamp.utc(1136073600), p.starts_at) end def test_starts_at_unbounded dst = TimezoneOffset.new(-7200, 3600, 'TEST') p = TestTimezonePeriod.new(nil, nil, dst) assert_nil(p.starts_at) end def test_ends_at_bounded std = TimezoneOffset.new(-7200, 0, 'TEST') dst = TimezoneOffset.new(-7200, 3600, 'TEST') p = TestTimezonePeriod.new(nil, TimezoneTransition.new(std, dst, 1136160000), dst) assert_equal_with_offset_and_class(Timestamp.utc(1136160000), p.ends_at) end def test_ends_at_unbounded dst = TimezoneOffset.new(-7200, 3600, 'TEST') p = TestTimezonePeriod.new(nil, nil, dst) assert_nil(p.ends_at) end def test_local_starts_at_bounded std = TimezoneOffset.new(-7200, 0, 'TEST') dst = TimezoneOffset.new(-7200, 3600, 'TEST') p = TestTimezonePeriod.new(TimezoneTransition.new(dst, std, 1136073600), nil, dst) assert_equal_with_offset_and_timezone_offset(TimestampWithOffset.new(1136073600, 0, -3600).set_timezone_offset(dst), p.local_starts_at) end def test_local_starts_at_unbounded dst = TimezoneOffset.new(-7200, 3600, 'TEST') p = TestTimezonePeriod.new(nil, nil, dst) assert_nil(p.local_starts_at) end def test_local_ends_at_bounded std = TimezoneOffset.new(-7200, 0, 'TEST') dst = TimezoneOffset.new(-7200, 3600, 'TEST') p = TestTimezonePeriod.new(nil, TimezoneTransition.new(std, dst, 1136160000), dst) assert_equal_with_offset_and_class(TimestampWithOffset.new(1136160000, 0, -3600).set_timezone_offset(dst), p.local_ends_at) end def test_local_ends_at_unbounded dst = TimezoneOffset.new(-7200, 3600, 'TEST') p = TestTimezonePeriod.new(nil, nil, dst) assert_nil(p.local_ends_at) end end tzinfo-2.0.6/test/tc_timezone_proxy.rb000066400000000000000000000172211436527530500201320ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true require_relative 'test_utils' class TCTimezoneProxy < Minitest::Test include TZInfo def assert_raises_invalid_timezone_identifier(identifier) error = assert_raises(InvalidTimezoneIdentifier) { yield } assert_match(Regexp.new('\b' + Regexp.escape(identifier) + '\b'), error.message) end test_encodings('ISO-8859-1', 'UTF-8', 'UTF-16').each do |encoding| define_method("test_not_exist_with_#{encoding.to_method}_encoded_identifier") do identifier = 'Nothing/Special'.encode(encoding.name) proxy = TimezoneProxy.new(identifier) t = Time.utc(2006,1,1,0,0,0) assert_same(identifier, proxy.identifier) assert_same(identifier, proxy.name) assert_equal('Nothing - Special', proxy.friendly_identifier) assert_equal('Nothing - Special', proxy.to_s) assert_raises_invalid_timezone_identifier('Nothing/Special') { proxy.canonical_identifier } assert_raises_invalid_timezone_identifier('Nothing/Special') { proxy.canonical_zone } assert_raises_invalid_timezone_identifier('Nothing/Special') { proxy.current_period } assert_raises_invalid_timezone_identifier('Nothing/Special') { proxy.current_period_and_time } assert_raises_invalid_timezone_identifier('Nothing/Special') { proxy.current_time_and_period } assert_raises_invalid_timezone_identifier('Nothing/Special') { proxy.local_to_utc(t) } assert_raises_invalid_timezone_identifier('Nothing/Special') { proxy.now } assert_raises_invalid_timezone_identifier('Nothing/Special') { proxy.offsets_up_to(t) } assert_raises_invalid_timezone_identifier('Nothing/Special') { proxy.period_for(t) } assert_raises_invalid_timezone_identifier('Nothing/Special') { proxy.period_for_local(t) } assert_raises_invalid_timezone_identifier('Nothing/Special') { proxy.period_for_utc(t) } assert_raises_invalid_timezone_identifier('Nothing/Special') { proxy.periods_for_local(t) } assert_raises_invalid_timezone_identifier('Nothing/Special') { proxy.strftime('%Z', t) } assert_raises_invalid_timezone_identifier('Nothing/Special') { proxy.to_local(t) } assert_raises_invalid_timezone_identifier('Nothing/Special') { proxy.transitions_up_to(t) } assert_raises_invalid_timezone_identifier('Nothing/Special') { proxy.utc_to_local(t) } end define_method("test_valid_with_#{encoding.to_method}_encoded_identifier") do proxy = TimezoneProxy.new('Europe/London'.encode(encoding.name)) real = Timezone.get('Europe/London') t1 = Time.utc(2005,8,1,0,0,0) t2 = Time.utc(2004,8,1,0,0,0) assert_equal(real.canonical_identifier, proxy.canonical_identifier) assert_equal(real.canonical_zone, proxy.canonical_zone) assert_nothing_raised { proxy.current_period } assert_nothing_raised { proxy.current_period_and_time } assert_nothing_raised { proxy.current_time_and_period } assert_equal(real.friendly_identifier(true), proxy.friendly_identifier(true)) assert_equal(real.friendly_identifier(false), proxy.friendly_identifier(false)) assert_equal(real.friendly_identifier, proxy.friendly_identifier) assert_equal(real.identifier, proxy.identifier) assert_equal_with_offset(real.local_to_utc(t1), proxy.local_to_utc(t1)) assert_equal(real.name, proxy.name) assert_nothing_raised { proxy.now } assert_equal(real.offsets_up_to(t1), proxy.offsets_up_to(t1)) assert_equal(real.offsets_up_to(t1, t2), proxy.offsets_up_to(t1, t2)) assert_equal(real.period_for(t1), proxy.period_for(t1)) assert_equal(real.period_for_local(t1), proxy.period_for_local(t1)) assert_equal(real.period_for_utc(t1), proxy.period_for_utc(t1)) assert_equal(real.periods_for_local(t1), proxy.periods_for_local(t1)) assert_equal(real.strftime('%Z', t1), proxy.strftime('%Z', t1)) assert_equal_with_offset(real.to_local(t1), proxy.to_local(t1)) assert_equal(real.to_s, proxy.to_s) assert_equal(real.transitions_up_to(t1), proxy.transitions_up_to(t1)) assert_equal(real.transitions_up_to(t1, t2), proxy.transitions_up_to(t1, t2)) assert_equal_with_offset(real.utc_to_local(t1), proxy.utc_to_local(t1)) assert(real == proxy) assert(proxy == real) assert_equal(0, real <=> proxy) assert_equal(0, proxy <=> real) end end def test_canonical_linked # Test that the implementation of canonical_zone and canonical_identifier # are actually calling the real timezone and not just returning it and # its identifier. real = Timezone.get('UTC') proxy = TimezoneProxy.new('UTC') assert_kind_of(DataTimezone, proxy.canonical_zone) # ZoneinfoDataSource doesn't return LinkedTimezoneInfo instances for any # timezone. if real.kind_of?(LinkedTimezone) assert_equal('Etc/UTC', proxy.canonical_identifier) assert_equal('Etc/UTC', proxy.canonical_zone.identifier) else if DataSource.get.kind_of?(DataSources::RubyDataSource) # Not got a LinkedTimezone despite using a DataSource that supports it. # Raise an exception as this shouldn't happen. raise 'Non-LinkedTimezone instance returned for UTC using RubyDataSource' end assert_equal('UTC', proxy.canonical_identifier) assert_equal('UTC', proxy.canonical_zone.identifier) end end def test_after_freeze proxy = TimezoneProxy.new('Europe/London') real = Timezone.get('Europe/London') t = Time.utc(2017, 6, 1) proxy.freeze assert_equal('Europe/London', proxy.identifier) assert_equal(real.utc_to_local(t), proxy.utc_to_local(t)) end def test_equals assert_equal(true, TimezoneProxy.new('Europe/London') == TimezoneProxy.new('Europe/London')) assert_equal(false, TimezoneProxy.new('Europe/London') == TimezoneProxy.new('Europe/Paris')) assert(!(TimezoneProxy.new('Europe/London') == Object.new)) end def test_compare assert_equal(0, TimezoneProxy.new('Europe/London') <=> TimezoneProxy.new('Europe/London')) assert_equal(0, Timezone.get('Europe/London') <=> TimezoneProxy.new('Europe/London')) assert_equal(0, TimezoneProxy.new('Europe/London') <=> Timezone.get('Europe/London')) assert_equal(-1, TimezoneProxy.new('Europe/London') <=> TimezoneProxy.new('Europe/Paris')) assert_equal(-1, Timezone.get('Europe/London') <=> TimezoneProxy.new('Europe/Paris')) assert_equal(-1, TimezoneProxy.new('Europe/London') <=> Timezone.get('Europe/Paris')) assert_equal(1, TimezoneProxy.new('Europe/Paris') <=> TimezoneProxy.new('Europe/London')) assert_equal(1, Timezone.get('Europe/Paris') <=> TimezoneProxy.new('Europe/London')) assert_equal(1, TimezoneProxy.new('Europe/Paris') <=> Timezone.get('Europe/London')) assert_equal(-1, TimezoneProxy.new('America/New_York') <=> TimezoneProxy.new('Europe/Paris')) assert_equal(-1, Timezone.get('America/New_York') <=> TimezoneProxy.new('Europe/Paris')) assert_equal(-1, TimezoneProxy.new('America/New_York') <=> Timezone.get('Europe/Paris')) assert_equal(1, TimezoneProxy.new('Europe/Paris') <=> TimezoneProxy.new('America/New_York')) assert_equal(1, Timezone.get('Europe/Paris') <=> TimezoneProxy.new('America/New_York')) assert_equal(1, TimezoneProxy.new('Europe/Paris') <=> Timezone.get('America/New_York')) end def test_kind assert_kind_of(Timezone, TimezoneProxy.new('America/New_York')) end def test_marshal tp = TimezoneProxy.new('Europe/London') tp2 = Marshal.load(Marshal.dump(tp)) assert_kind_of(TimezoneProxy, tp2) assert_equal('Europe/London', tp2.identifier) end def test_inspect tp = TimezoneProxy.new('Europe/London') assert_equal('#', tp.inspect) end end tzinfo-2.0.6/test/tc_timezone_transition.rb000066400000000000000000000100171436527530500211370ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true require_relative 'test_utils' require 'date' class TCTimezoneTransition < Minitest::Test include TZInfo def test_offset t = TimezoneTransition.new(TimezoneOffset.new(3600, 3600, 'TDT'), TimezoneOffset.new(3600, 0, 'TST'), 1148949080) assert_equal(TimezoneOffset.new(3600, 3600, 'TDT'), t.offset) end def test_previous_offset t = TimezoneTransition.new(TimezoneOffset.new(3600, 3600, 'TDT'), TimezoneOffset.new(3600, 0, 'TST'), 1148949080) assert_equal(TimezoneOffset.new(3600, 0, 'TST'), t.previous_offset) end def test_timestamp_value t = TimezoneTransition.new(TimezoneOffset.new(3600, 3600, 'TDT'), TimezoneOffset.new(3600, 0, 'TST'), 1148949080) assert_equal(1148949080, t.timestamp_value) end def test_at t = TimezoneTransition.new(TimezoneOffset.new(3600, 3600, 'TDT'), TimezoneOffset.new(3600, 0, 'TST'), 1148949080) assert_equal_with_offset(Timestamp.utc(1148949080), t.at) end def test_local_end_at t1 = TimezoneTransition.new(TimezoneOffset.new(3600, 3600, 'TDT'), TimezoneOffset.new(3600, 0, 'TST'), 1148949080) t2 = TimezoneTransition.new(TimezoneOffset.new(7200, 0, 'TST'), TimezoneOffset.new(7200, 3600, 'TDT'), 1148949080) t3 = TimezoneTransition.new(TimezoneOffset.new(-3600, 3600, 'TDT'), TimezoneOffset.new(-3600, 0, 'TST'), 1148949080) assert_equal_with_offset_and_timezone_offset(TimestampWithOffset.new(1148949080, 0, 3600).set_timezone_offset(t1.previous_offset), t1.local_end_at) assert_equal_with_offset_and_timezone_offset(TimestampWithOffset.new(1148949080, 0, 10800).set_timezone_offset(t2.previous_offset), t2.local_end_at) assert_equal_with_offset_and_timezone_offset(TimestampWithOffset.new(1148949080, 0, -3600).set_timezone_offset(t3.previous_offset), t3.local_end_at) end def test_local_start_at t1 = TimezoneTransition.new(TimezoneOffset.new(3600, 3600, 'TDT'), TimezoneOffset.new(3600, 0, 'TST'), 1148949080) t2 = TimezoneTransition.new(TimezoneOffset.new(7200, 0, 'TST'), TimezoneOffset.new(7200, 3600, 'TDT'), 1148949080) t3 = TimezoneTransition.new(TimezoneOffset.new(-3600, 3600, 'TDT'), TimezoneOffset.new(-3600, 0, 'TST'), 1148949080) assert_equal_with_offset_and_timezone_offset(TimestampWithOffset.new(1148949080, 0, 7200).set_timezone_offset(t1.offset), t1.local_start_at) assert_equal_with_offset_and_timezone_offset(TimestampWithOffset.new(1148949080, 0, 7200).set_timezone_offset(t2.offset), t2.local_start_at) assert_equal_with_offset_and_timezone_offset(TimestampWithOffset.new(1148949080, 0, 0).set_timezone_offset(t3.offset), t3.local_start_at) end def test_equality t1 = TimezoneTransition.new(TimezoneOffset.new(3600, 3600, 'TDT'), TimezoneOffset.new(3600, 0, 'TST'), 1148949080) t2 = TimezoneTransition.new(TimezoneOffset.new(3600, 3600, 'TDT'), TimezoneOffset.new(3600, 0, 'TST'), 1148949080) t3 = TimezoneTransition.new(TimezoneOffset.new(3600, 3600, 'TDT'), TimezoneOffset.new(3600, 0, 'TST'), 1148949081) t4 = TimezoneTransition.new(TimezoneOffset.new(3601, 3600, 'TDT'), TimezoneOffset.new(3600, 0, 'TST'), 1148949080) t5 = TimezoneTransition.new(TimezoneOffset.new(3600, 3600, 'TDT'), TimezoneOffset.new(3601, 0, 'TST'), 1148949080) assert_equal(true, t1 == t1) assert_equal(true, t1 == t2) assert_equal(false, t1 == t3) assert_equal(false, t1 == t4) assert_equal(false, t1 == t5) assert_equal(false, t1 == Object.new) assert_equal(true, t1.eql?(t1)) assert_equal(true, t1.eql?(t2)) assert_equal(false, t1.eql?(t3)) assert_equal(false, t1.eql?(t4)) assert_equal(false, t1.eql?(t5)) assert_equal(false, t1.eql?(Object.new)) end def test_hash t = TimezoneTransition.new(TimezoneOffset.new(3600, 3600, 'TDTA'), TimezoneOffset.new(3600, 0, 'TSTA'), 1148949080) assert_equal([TimezoneOffset.new(3600, 3600, 'TDTA'), TimezoneOffset.new(3600, 0, 'TSTA'), 1148949080].hash, t.hash) end end tzinfo-2.0.6/test/tc_timezone_utc.rb000066400000000000000000000044341436527530500175460ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true require_relative 'test_utils' class TCTimezoneUTC < Minitest::Test include TZInfo def test_2004 tz = Timezone.get('UTC') time_types_test(:offset) do |h| assert_equal_with_offset(h.output_time(2004, 1, 1, 0, 0, 0,0,0), tz.to_local(h.time(2004, 1, 1, 0, 0, 0,0,0))) assert_equal_with_offset(h.output_time(2004,12,31,23,59,59,0,0), tz.to_local(h.time(2004,12,31,23,59,59,0,0))) assert_equal_with_offset(h.output_time(2004, 1, 1, 0, 0, 0,0,0), tz.utc_to_local(h.time(2004, 1, 1, 0, 0, 0))) assert_equal_with_offset(h.output_time(2004,12,31,23,59,59,0,0), tz.utc_to_local(h.time(2004,12,31,23,59,59))) assert_equal_with_offset(h.output_time(2004, 1, 1, 0, 0, 0,0,:utc), tz.local_to_utc(h.time(2004, 1, 1, 0, 0, 0))) assert_equal_with_offset(h.output_time(2004,12,31,23,59,59,0,:utc), tz.local_to_utc(h.time(2004,12,31,23,59,59))) assert_equal('UTC', tz.period_for(h.time(2004, 1, 1, 0, 0, 0,0,0)).zone_identifier) assert_equal('UTC', tz.period_for(h.time(2004,12,31,23,59,59,0,0)).zone_identifier) assert_equal('UTC', tz.period_for_utc(h.time(2004, 1, 1, 0, 0, 0)).zone_identifier) assert_equal('UTC', tz.period_for_utc(h.time(2004,12,31,23,59,59)).zone_identifier) assert_equal('UTC', tz.period_for_local(h.time(2004, 1, 1, 0, 0, 0)).zone_identifier) assert_equal('UTC', tz.period_for_local(h.time(2004,12,31,23,59,59)).zone_identifier) assert_equal(0, tz.period_for(h.time(2004, 1, 1, 0, 0, 0,0,0)).observed_utc_offset) assert_equal(0, tz.period_for(h.time(2004,12,31,23,59,59,0,0)).observed_utc_offset) assert_equal(0, tz.period_for_utc(h.time(2004, 1, 1, 0, 0, 0)).observed_utc_offset) assert_equal(0, tz.period_for_utc(h.time(2004,12,31,23,59,59)).observed_utc_offset) assert_equal(0, tz.period_for_local(h.time(2004, 1, 1, 0, 0, 0)).observed_utc_offset) assert_equal(0, tz.period_for_local(h.time(2004,12,31,23,59,59)).observed_utc_offset) transitions = tz.transitions_up_to(h.time(2005,1,1,0,0,0,0,0), h.time(2004,1,1,0,0,0,0,0)) assert_equal(0, transitions.length) offsets = tz.offsets_up_to(h.time(2005,1,1,0,0,0,0,0), h.time(2004,1,1,0,0,0,0,0)) assert_equal([TimezoneOffset.new(0, 0, 'UTC')], offsets) end end end tzinfo-2.0.6/test/tc_transition_rule.rb000066400000000000000000000444761436527530500202740ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true require_relative 'test_utils' class TCTransitionRule < Minitest::Test include TZInfo [-1, 0, 1].each do |transition_at| define_method "test_transition_at_#{transition_at}" do rule = TestTransitionRule.new(transition_at) assert_equal(transition_at, rule.transition_at) end end [ [-1, 19, 23, 59, 59], [0, 20, 0, 0, 0], [1, 20, 0, 0, 1], [60, 20, 0, 1, 0], [86399, 20, 23, 59, 59], [86400, 21, 0, 0, 0] ].each do |(transition_at, expected_day, expected_hour, expected_minute, expected_second)| define_method "test_at_with_transition_at_#{transition_at}" do offset = TimezoneOffset.new(0, 0, 'TEST') rule = TestTransitionRule.new(transition_at) do |o, y| assert_same(offset, o) assert_equal(2020, y) Time.new(2020, 3, 20, 0, 0, 0, 0) end result = rule.at(offset, 2020) # Construct Timestamp from a value instead of using Timestamp.for. # JRuby would consider a Time with a 0 offset to be UTC. assert_equal_with_offset(Timestamp.new(Time.new(2020, 3, expected_day, expected_hour, expected_minute, expected_second, 0).to_i, 0, 0), result) assert_same(offset, result.timezone_offset) end end [-7200, 0, 7200].each do |offset_seconds| define_method "test_at_with_offset_#{offset_seconds}" do offset = TimezoneOffset.new(offset_seconds, 0, 'TEST') rule = TestTransitionRule.new(3600) do |o, y| assert_same(offset, o) assert_equal(2020, y) Time.new(2020, 3, 20, 0, 0, 0, offset_seconds) end result = rule.at(offset, 2020) # Construct Timestamp from a value instead of using Timestamp.for. # JRuby would consider a Time with a 0 offset to be UTC. assert_equal_with_offset(Timestamp.new(Time.new(2020, 3, 20, 1, 0, 0, offset_seconds).to_i, 0, offset_seconds), result) assert_same(offset, result.timezone_offset) end end [2020, 2021].each do |year| define_method "test_at_with_year_#{year}" do offset = TimezoneOffset.new(0, 0, 'TEST') rule = TestTransitionRule.new(3600) do |o, y| assert_same(offset, o) assert_equal(year, y) Time.new(year, 3, 20, 0, 0, 0, 0) end result = rule.at(offset, year) # Construct Timestamp from a value instead of using Timestamp.for. # JRuby would consider a Time with a 0 offset to be UTC. assert_equal_with_offset(Timestamp.new(Time.new(year, 3, 20, 1, 0, 0, 0).to_i, 0, 0), result) assert_same(offset, result.timezone_offset) end end class TestTransitionRule < TransitionRule def initialize(transition_at, &block) super(transition_at) @get_day = block end protected def get_day(offset, year) @get_day.call(offset, year) end end end module BaseTransitionRuleTestHelper def test_invalid_transition_at error = assert_raises(ArgumentError) { create_with_transition_at('0') } assert_match(/\btransition_at(\b.*)?/, error.message) end [:==, :eql?].each do |method| define_method "test_not_equal_by_transition_at_with_#{method}" do rule1 = create_with_transition_at(0) rule2 = create_with_transition_at(1) assert_equal(false, rule1.public_send(method, rule2)) assert_equal(false, rule2.public_send(method, rule1)) end define_method "test_not_equal_to_other_with_#{method}" do rule = create_with_transition_at(0) assert_equal(false, rule.public_send(method, Object.new)) end end end class TCAbsoluteDayOfYearTransitionRule < Minitest::Test include TZInfo include BaseTransitionRuleTestHelper [-1, 366, '0'].each do |value| define_method "test_invalid_day_#{value}" do error = assert_raises(ArgumentError) { AbsoluteDayOfYearTransitionRule.new(value) } assert_match(/\bday\b/, error.message) end end [ [2020, 0, 1, 1], [2020, 58, 2, 28], [2020, 59, 2, 29], [2020, 365, 12, 31], [2021, 59, 3, 1], [2021, 365, 13, 1], [2100, 59, 3, 1], [2100, 365, 13, 1], [2000, 59, 2, 29], [2000, 365, 12, 31] ].each do |(year, day, expected_month, expected_day)| define_method "test_day_#{day}_of_year_#{year}" do rule = AbsoluteDayOfYearTransitionRule.new(day, 3600) offset = TimezoneOffset.new(7200, 0, 'TEST') result = rule.at(offset, year) expected_year = year if expected_month == 13 expected_year += 1 expected_month = 1 end assert_equal_with_offset(Timestamp.for(Time.new(expected_year, expected_month, expected_day, 1, 0, 0, 7200)), result) assert_same(offset, result.timezone_offset) end end def test_day_0_is_always_first_day_of_year rule = AbsoluteDayOfYearTransitionRule.new(0) assert_equal(true, rule.is_always_first_day_of_year?) end [1, 365].each do |day| define_method "test_day_#{day}_is_not_always_first_day_of_year" do rule = AbsoluteDayOfYearTransitionRule.new(day) assert_equal(false, rule.is_always_first_day_of_year?) end define_method "test_day_#{day}_is_not_always_last_day_of_year" do rule = AbsoluteDayOfYearTransitionRule.new(day) assert_equal(false, rule.is_always_last_day_of_year?) end end [:==, :eql?].each do |method| [ [0, 0], [0, 3600], [365, 0] ].each do |(day, transition_at)| define_method "test_equal_for_day_#{day}_and_transition_at_#{transition_at}_with_#{method}" do rule1 = AbsoluteDayOfYearTransitionRule.new(day, transition_at) rule2 = AbsoluteDayOfYearTransitionRule.new(day, transition_at) assert_equal(true, rule1.public_send(method, rule2)) assert_equal(true, rule2.public_send(method, rule1)) end end define_method "test_not_equal_by_day_with_#{method}" do rule1 = AbsoluteDayOfYearTransitionRule.new(0, 3600) rule2 = AbsoluteDayOfYearTransitionRule.new(1, 3600) assert_equal(false, rule1.public_send(method, rule2)) assert_equal(false, rule2.public_send(method, rule1)) end define_method "test_not_equal_to_julian_with_#{method}" do rule1 = AbsoluteDayOfYearTransitionRule.new(1, 0) rule2 = JulianDayOfYearTransitionRule.new(1, 0) assert_equal(false, rule1.public_send(method, rule2)) assert_equal(false, rule2.public_send(method, rule1)) end end [ [0, 0], [0, 3600], [365, 0] ].each do |(day, transition_at)| define_method "test_hash_for_day_#{day}_and_transition_at_#{transition_at}" do rule = AbsoluteDayOfYearTransitionRule.new(day, transition_at) expected = [AbsoluteDayOfYearTransitionRule, day * 86400, transition_at].hash assert_equal(expected, rule.hash) end end protected def create_with_transition_at(transition_at) AbsoluteDayOfYearTransitionRule.new(1, transition_at) end end class TCJulianDayOfYearTransitionRule < Minitest::Test include TZInfo include BaseTransitionRuleTestHelper [0, 366, '1'].each do |value| define_method "test_invalid_day_#{value}" do error = assert_raises(ArgumentError) { JulianDayOfYearTransitionRule.new(value) } assert_match(/\bday\b/, error.message) end end [2020, 2021, 2100, 2000].each do |year| [ [1, 1, 1], [59, 2, 28], [60, 3, 1], [365, 12, 31] ].each do |(day, expected_month, expected_day)| define_method "test_day_#{day}_of_year_#{year}" do rule = JulianDayOfYearTransitionRule.new(day, 3600) offset = TimezoneOffset.new(7200, 0, 'TEST') result = rule.at(offset, year) assert_equal_with_offset(Timestamp.for(Time.new(year, expected_month, expected_day, 1, 0, 0, 7200)), result) assert_same(offset, result.timezone_offset) end end end def test_day_1_is_always_first_day_of_year rule = JulianDayOfYearTransitionRule.new(1) assert_equal(true, rule.is_always_first_day_of_year?) end [2, 365].each do |day| define_method "test_day_#{day}_is_not_always_first_day_of_year" do rule = JulianDayOfYearTransitionRule.new(day) assert_equal(false, rule.is_always_first_day_of_year?) end end def test_day_365_is_always_last_day_of_year rule = JulianDayOfYearTransitionRule.new(365) assert_equal(true, rule.is_always_last_day_of_year?) end [1, 364].each do |day| define_method "test_day_#{day}_is_not_always_last_day_of_year" do rule = JulianDayOfYearTransitionRule.new(day) assert_equal(false, rule.is_always_last_day_of_year?) end end [:==, :eql?].each do |method| [ [1, 0], [1, 3600], [365, 0] ].each do |(day, transition_at)| define_method "test_equal_for_day_#{day}_and_transition_at_#{transition_at}_with_#{method}" do rule1 = JulianDayOfYearTransitionRule.new(day, transition_at) rule2 = JulianDayOfYearTransitionRule.new(day, transition_at) assert_equal(true, rule1.public_send(method, rule2)) assert_equal(true, rule2.public_send(method, rule1)) end end define_method "test_not_equal_by_day_with_#{method}" do rule1 = JulianDayOfYearTransitionRule.new(1, 0) rule2 = JulianDayOfYearTransitionRule.new(2, 0) assert_equal(false, rule1.public_send(method, rule2)) assert_equal(false, rule2.public_send(method, rule1)) end define_method "test_not_equal_to_absolute_with_#{method}" do rule1 = JulianDayOfYearTransitionRule.new(1, 0) rule2 = AbsoluteDayOfYearTransitionRule.new(1, 0) assert_equal(false, rule1.public_send(method, rule2)) assert_equal(false, rule2.public_send(method, rule1)) end end [ [1, 0], [1, 3600], [365, 0] ].each do |(day, transition_at)| define_method "test_hash_for_day_#{day}_and_transition_at_#{transition_at}" do rule = JulianDayOfYearTransitionRule.new(day, transition_at) expected = [JulianDayOfYearTransitionRule, day * 86400, transition_at].hash assert_equal(expected, rule.hash) end end protected def create_with_transition_at(transition_at) JulianDayOfYearTransitionRule.new(1, transition_at) end end module DayOfWeekTransitionRuleTestHelper [-1, 0, 13, '1'].each do |month| define_method "test_invalid_month_#{month}" do error = assert_raises(ArgumentError) { create_with_month_and_day_of_week(month, 0) } assert_match(/\bmonth\b/, error.message) end end [-1, 7, '0'].each do |day_of_week| define_method "test_invalid_day_of_week_#{day_of_week}" do error = assert_raises(ArgumentError) { create_with_month_and_day_of_week(1, day_of_week) } assert_match(/\bday_of_week\b/, error.message) end end def test_is_not_always_first_day_of_year rule = create_with_month_and_day_of_week(1, 0) assert_equal(false, rule.is_always_first_day_of_year?) end def test_is_not_always_last_day_of_year rule = create_with_month_and_day_of_week(12, 6) assert_equal(false, rule.is_always_last_day_of_year?) end [:==, :eql?].each do |method| define_method "test_not_equal_by_month_with_#{method}" do rule1 = create_with_month_and_day_of_week(1, 0) rule2 = create_with_month_and_day_of_week(2, 0) assert_equal(false, rule1.public_send(method, rule2)) assert_equal(false, rule2.public_send(method, rule1)) end define_method "test_not_equal_by_day_of_week_with_#{method}" do rule1 = create_with_month_and_day_of_week(1, 0) rule2 = create_with_month_and_day_of_week(1, 1) assert_equal(false, rule1.public_send(method, rule2)) assert_equal(false, rule2.public_send(method, rule1)) end end end class TCDayOfMonthTransitionRule < Minitest::Test include TZInfo include BaseTransitionRuleTestHelper include DayOfWeekTransitionRuleTestHelper [-1, 0, 5, '1'].each do |week| define_method "test_invalid_week_#{week}" do error = assert_raises(ArgumentError) { DayOfMonthTransitionRule.new(1, week, 0) } assert_match(/\bweek\b/, error.message) end end [ # All possible first week start days. [2020, 3, [1, 2, 3, 4, 5, 6, 7]], [2021, 3, [7, 1, 2, 3, 4, 5, 6]], [2022, 3, [6, 7, 1, 2, 3, 4, 5]], [2023, 3, [5, 6, 7, 1, 2, 3, 4]], [2018, 3, [4, 5, 6, 7, 1, 2, 3]], [2024, 3, [3, 4, 5, 6, 7, 1, 2]], [2025, 3, [2, 3, 4, 5, 6, 7, 1]], # All possible months. [2019, 1, [6]], [2019, 2, [3]], [2019, 3, [3]], [2019, 4, [7]], [2019, 5, [5]], [2019, 6, [2]], [2019, 7, [7]], [2019, 8, [4]], [2019, 9, [1]], [2019, 10, [6]], [2019, 11, [3]], [2019, 12, [1]] ].each do |(year, month, days)| days.each_with_index do |expected_day, day_of_week| (1..4).each do |week| define_method "test_month_#{month}_week_#{week}_and_day_of_week_#{day_of_week}_year_#{year}" do rule = DayOfMonthTransitionRule.new(month, week, day_of_week, 3600) offset = TimezoneOffset.new(7200, 0, 'TEST') result = rule.at(offset, year) assert_equal_with_offset(Timestamp.for(Time.new(year, month, expected_day + (week - 1) * 7, 1, 0, 0, 7200)), result) assert_same(offset, result.timezone_offset) end end end end [:==, :eql?].each do |method| [ [1, 1, 0, 0], [1, 1, 0, 1], [1, 1, 1, 0], [1, 2, 0, 0], [2, 1, 0, 0] ].each do |(month, week, day_of_week, transition_at)| define_method "test_equal_for_month_#{month}_week_#{week}_day_of_week_#{day_of_week}_and_transition_at_#{transition_at}_with_#{method}" do rule1 = DayOfMonthTransitionRule.new(month, week, day_of_week, transition_at) rule2 = DayOfMonthTransitionRule.new(month, week, day_of_week, transition_at) assert_equal(true, rule1.public_send(method, rule2)) assert_equal(true, rule2.public_send(method, rule1)) end end define_method "test_not_equal_by_week_with_#{method}" do rule1 = DayOfMonthTransitionRule.new(1, 1, 0, 0) rule2 = DayOfMonthTransitionRule.new(1, 2, 0, 0) assert_equal(false, rule1.public_send(method, rule2)) assert_equal(false, rule2.public_send(method, rule1)) end define_method "test_not_equal_to_last_day_of_month_with_#{method}" do rule1 = DayOfMonthTransitionRule.new(1, 1, 0, 0) rule2 = LastDayOfMonthTransitionRule.new(1, 0, 0) assert_equal(false, rule1.public_send(method, rule2)) assert_equal(false, rule2.public_send(method, rule1)) end end [ [1, 1, 0, 0], [1, 1, 0, 1], [1, 1, 1, 0], [1, 2, 0, 0], [2, 1, 0, 0] ].each do |(month, week, day_of_week, transition_at)| define_method "test_hash_for_month_#{month}_week_#{week}_day_of_week_#{day_of_week}_and_transition_at_#{transition_at}" do rule = DayOfMonthTransitionRule.new(month, week, day_of_week, transition_at) expected = [(week - 1) * 7 + 1, month, day_of_week, transition_at].hash assert_equal(expected, rule.hash) end end protected def create_with_transition_at(transition_at) DayOfMonthTransitionRule.new(1, 1, 0, transition_at) end def create_with_month_and_day_of_week(month, day_of_week) DayOfMonthTransitionRule.new(month, 1, day_of_week) end end class TCLastDayOfMonthTransitionRule < Minitest::Test include TZInfo include BaseTransitionRuleTestHelper include DayOfWeekTransitionRuleTestHelper [ # All possible last days. [2021, 10, [31, 25, 26, 27, 28, 29, 30]], [2022, 10, [30, 31, 25, 26, 27, 28, 29]], [2023, 10, [29, 30, 31, 25, 26, 27, 28]], [2018, 10, [28, 29, 30, 31, 25, 26, 27]], [2024, 10, [27, 28, 29, 30, 31, 25, 26]], [2025, 10, [26, 27, 28, 29, 30, 31, 25]], [2026, 10, [25, 26, 27, 28, 29, 30, 31]], # All possible months. [2020, 1, [26]], [2020, 2, [23]], [2020, 3, [29]], [2020, 4, [26]], [2020, 5, [31]], [2020, 6, [28]], [2020, 7, [26]], [2020, 8, [30]], [2020, 9, [27]], [2020, 10, [25]], [2020, 11, [29]], [2020, 12, [27]] ].each do |(year, month, days)| days.each_with_index do |expected_day, day_of_week| define_method "test_month_#{month}_day_of_week_#{day_of_week}_year_#{year}" do rule = LastDayOfMonthTransitionRule.new(month, day_of_week, 7200) offset = TimezoneOffset.new(7200, 3600, 'TEST') result = rule.at(offset, year) assert_equal_with_offset(Timestamp.for(Time.new(year, month, expected_day, 2, 0, 0, 10800)), result) assert_same(offset, result.timezone_offset) end end end [[2020, 6, 29], [2021, 0, 28], [2000, 2, 29], [2100, 0, 28]].each do |(year, day_of_week, expected_day)| define_method "test_#{expected_day == 29 ? '' : 'non_'}leap_year_#{year}" do rule = LastDayOfMonthTransitionRule.new(2, day_of_week, 7200) offset = TimezoneOffset.new(7200, 3600, 'TEST') result = rule.at(offset, year) assert_equal_with_offset(Timestamp.for(Time.new(year, 2, expected_day, 2, 0, 0, 10800)), result) assert_same(offset, result.timezone_offset) end end [:==, :eql?].each do |method| [ [1, 0, 0], [1, 0, 1], [1, 1, 0], [2, 0, 0] ].each do |(month, day_of_week, transition_at)| define_method "test_equal_for_month_#{month}_day_of_week_#{day_of_week}_and_transition_at_#{transition_at}_with_#{method}" do rule1 = LastDayOfMonthTransitionRule.new(month, day_of_week, transition_at) rule2 = LastDayOfMonthTransitionRule.new(month, day_of_week, transition_at) assert_equal(true, rule1.public_send(method, rule2)) assert_equal(true, rule2.public_send(method, rule1)) end end define_method "test_not_equal_to_day_of_month_with_#{method}" do rule1 = LastDayOfMonthTransitionRule.new(1, 0, 0) rule2 = DayOfMonthTransitionRule.new(1, 1, 0, 0) assert_equal(false, rule1.public_send(method, rule2)) assert_equal(false, rule2.public_send(method, rule1)) end end [ [1, 0, 0], [1, 0, 1], [1, 1, 0], [2, 0, 0] ].each do |(month, day_of_week, transition_at)| define_method "test_hash_for_month_#{month}_day_of_week_#{day_of_week}_and_transition_at_#{transition_at}" do rule = LastDayOfMonthTransitionRule.new(month, day_of_week, transition_at) expected = [month, day_of_week, transition_at].hash assert_equal(expected, rule.hash) end end protected def create_with_transition_at(transition_at) LastDayOfMonthTransitionRule.new(1, 0, transition_at) end def create_with_month_and_day_of_week(month, day_of_week) LastDayOfMonthTransitionRule.new(month, day_of_week) end end tzinfo-2.0.6/test/tc_transitions_timezone_period.rb000066400000000000000000000127041436527530500226710ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true require_relative 'test_utils' class TCTransitionsTimezonePeriod < Minitest::Test include TZInfo def test_initialize_start_end std = TimezoneOffset.new(-7200, 0, 'TEST') dst = TimezoneOffset.new(-7200, 3600, 'TEST') start_t = TimezoneTransition.new(dst, std, 1136073600) end_t = TimezoneTransition.new(std, dst, 1136160000) p = TransitionsTimezonePeriod.new(start_t, end_t) assert_same(start_t, p.start_transition) assert_same(end_t, p.end_transition) assert_same(dst, p.offset) end def test_initialize_start std = TimezoneOffset.new(-7200, 0, 'TEST') dst = TimezoneOffset.new(-7200, 3600, 'TEST') start_t = TimezoneTransition.new(dst, std, 1136073600) p = TransitionsTimezonePeriod.new(start_t, nil) assert_same(start_t, p.start_transition) assert_nil(p.end_transition) assert_same(dst, p.offset) end def test_initialize_end std = TimezoneOffset.new(-7200, 0, 'TEST') dst = TimezoneOffset.new(-7200, 3600, 'TEST') end_t = TimezoneTransition.new(std, dst, 1136160000) p = TransitionsTimezonePeriod.new(nil, end_t) assert_nil(p.start_transition) assert_same(end_t, p.end_transition) assert_same(dst, p.offset) end def test_initialize_start_and_end_nil error = assert_raises(ArgumentError) { TransitionsTimezonePeriod.new(nil, nil) } assert_match(/\bstart_transition\b/, error.message) assert_match(/\bend_transition\b/, error.message) end def test_equality o1 = TimezoneOffset.new(0, 3600, 'TEST') o2 = TimezoneOffset.new(0, 0, 'TEST') t1 = TimezoneTransition.new(o1, o2, 1149368400) t2 = TimezoneTransition.new(o1, o2, 1149454800) t3 = TimezoneTransition.new(o1, o2, 1149541200) p1 = TransitionsTimezonePeriod.new(t1, t2) p2 = TransitionsTimezonePeriod.new(t1, t2) p3 = TransitionsTimezonePeriod.new(t2, nil) p4 = TransitionsTimezonePeriod.new(t2, nil) p5 = TransitionsTimezonePeriod.new(t3, nil) p6 = TransitionsTimezonePeriod.new(nil, t2) p7 = TransitionsTimezonePeriod.new(nil, t2) p8 = TransitionsTimezonePeriod.new(nil, t3) p9 = TimezonePeriod.new(o1) assert_equal(true, p1 == p1) assert_equal(true, p1 == p2) assert_equal(false, p1 == p3) assert_equal(false, p1 == p4) assert_equal(false, p1 == p5) assert_equal(false, p1 == p6) assert_equal(false, p1 == p7) assert_equal(false, p1 == p8) assert_equal(false, p1 == p9) assert_equal(false, p1 == Object.new) assert_equal(true, p3 == p3) assert_equal(true, p3 == p4) assert_equal(false, p3 == p5) assert_equal(false, p3 == p9) assert_equal(false, p3 == Object.new) assert_equal(true, p6 == p6) assert_equal(true, p6 == p7) assert_equal(false, p6 == p8) assert_equal(false, p6 == p9) assert_equal(false, p6 == Object.new) end def test_eql o1 = TimezoneOffset.new(0, 3600, 'TEST') o2 = TimezoneOffset.new(0, 0, 'TEST') t1 = TimezoneTransition.new(o1, o2, 1149368400) t2 = TimezoneTransition.new(o1, o2, 1149454800) t3 = TimezoneTransition.new(o1, o2, 1149541200) p1 = TransitionsTimezonePeriod.new(t1, t2) p2 = TransitionsTimezonePeriod.new(t1, t2) p3 = TransitionsTimezonePeriod.new(t2, nil) p4 = TransitionsTimezonePeriod.new(t2, nil) p5 = TransitionsTimezonePeriod.new(t3, nil) p6 = TransitionsTimezonePeriod.new(nil, t2) p7 = TransitionsTimezonePeriod.new(nil, t2) p8 = TransitionsTimezonePeriod.new(nil, t3) p9 = TimezonePeriod.new(o1) assert_equal(true, p1.eql?(p1)) assert_equal(true, p1.eql?(p2)) assert_equal(false, p1.eql?(p3)) assert_equal(false, p1.eql?(p4)) assert_equal(false, p1.eql?(p5)) assert_equal(false, p1.eql?(p6)) assert_equal(false, p1.eql?(p7)) assert_equal(false, p1.eql?(p8)) assert_equal(false, p1.eql?(p9)) assert_equal(false, p1.eql?(Object.new)) assert_equal(true, p3.eql?(p3)) assert_equal(true, p3.eql?(p4)) assert_equal(false, p3.eql?(p5)) assert_equal(false, p3.eql?(p9)) assert_equal(false, p3.eql?(Object.new)) assert_equal(true, p6.eql?(p6)) assert_equal(true, p6.eql?(p7)) assert_equal(false, p6.eql?(p8)) assert_equal(false, p6.eql?(p9)) assert_equal(false, p6.eql?(Object.new)) end def test_hash o1 = TimezoneOffset.new(0, 3600, 'TEST') o2 = TimezoneOffset.new(0, 0, 'TEST') t1 = TimezoneTransition.new(o1, o2, 1149368400) t2 = TimezoneTransition.new(o1, o2, 1149454800) p1 = TransitionsTimezonePeriod.new(t1, t2) p2 = TransitionsTimezonePeriod.new(t1, nil) p3 = TransitionsTimezonePeriod.new(nil, t2) assert_equal([t1, t2].hash, p1.hash) assert_equal([t1, nil].hash, p2.hash) assert_equal([nil, t2].hash, p3.hash) end def test_inspect o1 = TimezoneOffset.new(0, 3600, 'TESTD') o2 = TimezoneOffset.new(0, 0, 'TEST') t1 = TimezoneTransition.new(o1, o2, 1149368400) t2 = TimezoneTransition.new(o2, o1, 1149454800) p1 = TransitionsTimezonePeriod.new(t1, t2) p2 = TransitionsTimezonePeriod.new(t1, nil) p3 = TransitionsTimezonePeriod.new(nil, t2) assert_equal("#", p1.inspect) assert_equal("#", p2.inspect) assert_equal("#", p3.inspect) end end tzinfo-2.0.6/test/tc_tzinfo.rb000066400000000000000000000010111436527530500163360ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true require_relative 'test_utils' class TCTZInfo < Minitest::Test include TZInfo def test_eager_load test_data_source = Minitest::Mock.new test_data_source.expect(:kind_of?, true, [DataSource]) test_data_source.expect(:eager_load!, nil) orig_data_source = DataSource.get DataSource.set(test_data_source) begin assert_nil(TZInfo.eager_load!) test_data_source.verify ensure DataSource.set(orig_data_source) end end end tzinfo-2.0.6/test/tc_version.rb000066400000000000000000000003171436527530500165220ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true require_relative 'test_utils' class TCVersion < Minitest::Test def test_version assert(TZInfo::VERSION =~ /\A\d+(\.\d+){2}(\.[a-z]+\d*)?\z/) end end tzinfo-2.0.6/test/tc_with_offset.rb000066400000000000000000000042111436527530500173530ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true require_relative 'test_utils' class TCWithOffset < Minitest::Test include TZInfo class TestBaseClass attr_reader :format attr_accessor :strftime_result def strftime(format) @format = format @strftime_result end end class TestClass < TestBaseClass include TZInfo::WithOffset attr_accessor :timezone_offset def if_timezone_offset_test(value) if_timezone_offset(value) {|p,v| yield(p, v) } end end def strftime_test(expected_super_format, format, abbreviation) t = TestClass.new t.timezone_offset = abbreviation ? TimezoneOffset.new(0, 0, abbreviation) : nil expected_result = 'super_result' t.strftime_result = expected_result assert_same(expected_result, t.strftime(format)) assert_equal(expected_super_format, t.format) end def test_strftime strftime_test('%H:%M:%S BST', '%H:%M:%S %Z', 'BST') strftime_test('BST', '%Z', 'BST') strftime_test('%%ZBST', '%%Z%Z', 'BST') strftime_test('BST BST', '%Z %Z', 'BST') strftime_test('BST %%Z %%BST %%%%Z %%%%BST', '%Z %%Z %%%Z %%%%Z %%%%%Z', 'BST') end def test_strftime_handles_percent_in_abbreviation strftime_test('%%H:%%M:%%S', '%Z', '%H:%M:%S') end def test_strftime_nil_timezone_offset strftime_test('%Z', '%Z', nil) end def test_strftime_nil_format t = TestClass.new t.timezone_offset = TimezoneOffset.new(0, 0, 'BST') error = assert_raises(ArgumentError) { t.strftime(nil) } assert_match(/\bformat\b/, error.message) end def test_if_timezone_offset o = TimezoneOffset.new(0, 0, 'BST') t = TestClass.new t.timezone_offset = o v = Object.new r = Object.new block_called = 0 result = t.if_timezone_offset_test(v) do |bo,bv| block_called += 1 assert_same(o, bo) assert_same(v, bv) r end assert_same(r, result) assert_equal(1, block_called) end def test_if_timezone_offset_nil_timezone_offset t = TestClass.new v = Object.new result = t.if_timezone_offset_test(v) {|bo,bv| raise 'block called unexpectedly' } assert_same(result, v) end end tzinfo-2.0.6/test/test_utils.rb000066400000000000000000000441131436527530500165500ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true raise 'Tests must be run with bundler, e.g. bundle exec rake test' unless defined?(Bundler) # Workaround an issue on JRuby where the stdlib directory can end up before the # minitest gem in the load path. This causes an old built-in version of minitest # to be loaded instead of the gem. https://github.com/jruby/jruby/issues/5038 if RUBY_ENGINE == 'jruby' stdlib_index = $:.find_index(RbConfig::CONFIG['rubylibdir']) minitest_index = $:.find_index(File.join(Bundler.rubygems.find_name('minitest').first.full_gem_path, 'lib')) if stdlib_index < minitest_index # The stdlib directory is before the minitest gem. Move stdlib to the end of # the load path. $:.push($:.delete_at(stdlib_index)) end end COVERAGE_ENABLED = ENV['TEST_COVERAGE'] == '1' if COVERAGE_ENABLED && defined?(COVERAGE_TYPE) string_unary_minus_does_dedupe = if '0'.respond_to?(:-@) s1 = -('0'.dup) s2 = -('0'.dup) s1.object_id == s2.object_id else false end untaint_is_functional = Object.new.respond_to?(:untaint) && RUBY_VERSION < '2.7' feature_support = [ ['deduping_string_unary_minus', string_unary_minus_does_dedupe], ['functional_untaint', untaint_is_functional] ].map do |feature, available| "#{available ? '' : 'no_'}#{feature}" end method_support = [[[], :bsearch], [[], :bsearch_index], ['', :-@]].map do |object, method| "#{object.respond_to?(method) ? '' : 'no_'}#{Regexp.escape(object.class.name.downcase)}_#{Regexp.escape(method)}" end COVERAGE_NOCOV_TOKEN = "nocov_(#{(feature_support + method_support).join('|')})" require 'simplecov' SimpleCov.start do command_name COVERAGE_TYPE add_filter 'test' nocov_token COVERAGE_NOCOV_TOKEN project_name 'TZInfo' self.formatters = [SimpleCov::Formatter::HTMLFormatter] end end tests_dir = File.expand_path(File.dirname(__FILE__)) tests_dir.untaint if RUBY_VERSION < '2.7' TESTS_DIR = tests_dir TZINFO_TEST_ZONEINFO_DIR = File.join(TESTS_DIR, 'zoneinfo') unless defined? TZINFO_TEST_DATA_DIR TZINFO_TEST_DATA_DIR = File.join(TESTS_DIR, "tzinfo-data#{(defined? TZINFO_TEST_DATA_FORMAT) ? TZINFO_TEST_DATA_FORMAT : 2}") $:.unshift(TZINFO_TEST_DATA_DIR) unless $:.include?(TZINFO_TEST_DATA_DIR) end def nil.freeze warn('nil is being frozen') super end require 'minitest/autorun' require 'tzinfo' require 'date' require 'fileutils' require 'rbconfig' module TestUtils ZONEINFO_SYMLINKS = [ ['localtime', File.join('America', 'New_York')], ['UTC', File.join('Etc', 'UTC')]] def self.prepare_test_zoneinfo_dir ZONEINFO_SYMLINKS.each do |file, target| path = File.join(TZINFO_TEST_ZONEINFO_DIR, file) File.delete(path) if File.exist?(path) begin FileUtils.ln_s(target, path) rescue NotImplementedError, Errno::EACCES # Symlinks not supported on this platform, or permission denied # (administrative rights are required on Windows). Copy instead. target_path = File.join(TZINFO_TEST_ZONEINFO_DIR, target) FileUtils.cp(target_path, path) end end end # A helper class used to define test methods for different encodings. class TestEncoding attr_reader :name def initialize(name) @name = name end def find Encoding.find(@name) end def to_method @name.downcase.gsub('-', '_') end end # With MRI and Rubinius, a Time constructed with a zero offset will have # Time#utc? == false. utc? only returns true for Times explicitly initialized # as UTC (e.g with Time.utc). JRuby's Time#utc? returns true when the offset # is zero. TIME_SUPPORTS_DISTINCT_UTC = !Time.new(2017,1,1,0,0,0,0).utc? # Test class to simulate Ruby 2.6's internal Time::TM. # Timestamp.for will accept objects that have value, subsec and optionally # utc_offset methods and return Time results. class TimeLike attr_reader :subsec def initialize(value, subsec) @value = value @subsec = subsec end def to_i @value end end # An extended version of TimeLike that adds a utc_offset attribute. class TimeLikeWithOffset < TimeLike attr_reader :utc_offset def initialize(value, subsec, utc_offset) super(value, subsec) @utc_offset = utc_offset end end class TimeTypesHelper def supports?(feature) self.class.supports?(feature) end def expected_zero_offset # On JRuby Time#utc? is always true when utc_offset is 0 (but not on MRI or Rubinius). supports?(:utc) && !supports?(:distinct_utc) ? :utc : 0 end end class TimeTypesOutputHelper < TimeTypesHelper def self.supports?(feature) feature == :output || feature == :offset end def output_time(*args) time(*args) end end class TimeTypesTimeHelper < TimeTypesOutputHelper def self.supports?(feature) super(feature) || (feature == :distinct_utc && TIME_SUPPORTS_DISTINCT_UTC) || feature == :utc end def type :time end def time(year, month, day, hour, minute, second, sub_second = 0, utc_offset = 0) if utc_offset == :utc Time.utc(year, month, day, hour, minute, second + sub_second) else Time.new(year, month, day, hour, minute, second + sub_second, utc_offset) end end def time_with_offset(period, year, month, day, hour, minute, second, sub_second = 0) TZInfo::TimeWithOffset.new(year, month, day, hour, minute, second + sub_second, period.observed_utc_offset).set_timezone_offset(period) end end class TimeTypesDateTimeHelper < TimeTypesOutputHelper def type :datetime end def time(year, month, day, hour, minute, second, sub_second = 0, utc_offset = 0) utc_offset = 0 if utc_offset == :utc DateTime.new(year, month, day, hour, minute, second + sub_second, utc_offset.to_r / 86400) end def time_with_offset(offset, year, month, day, hour, minute, second, sub_second = 0) TZInfo::DateTimeWithOffset.new(year, month, day, hour, minute, second + sub_second, offset.observed_utc_offset.to_r / 86400).set_timezone_offset(offset) end end class TimeTypesTimestampHelper < TimeTypesOutputHelper def self.supports?(feature) super(feature) || feature == :distinct_utc || feature == :unspecified_offset || feature == :utc end def type :timestamp end def time(year, month, day, hour, minute, second, sub_second = 0, utc_offset = nil) TZInfo::Timestamp.create(year, month, day, hour, minute, second, sub_second, utc_offset) end def time_with_offset(offset, year, month, day, hour, minute, second, sub_second = 0) TZInfo::TimestampWithOffset.create(year, month, day, hour, minute, second, sub_second, offset.observed_utc_offset).set_timezone_offset(offset) end end class TimeTypesBaseTimeLikeHelper < TimeTypesHelper def initialize @time_helper = TimeTypesTimeHelper.new end def output_time(*args) @time_helper.time(*args) end def time_with_offset(*args) @time_helper.time_with_offset(*args) end end class TimeTypesTimeLikeHelper < TimeTypesBaseTimeLikeHelper def self.supports?(feature) false end def type :time_like end def time(year, month, day, hour, minute, second, sub_second = 0, utc_offset = 0) raise 'TimeLike does not support non-zero/non-UTC offsets' unless utc_offset == 0 || utc_offset == :utc TimeLike.new(Time.utc(year, month, day, hour, minute, second).to_i, sub_second) end end class TimeTypesTimeLikeWithOffsetHelper < TimeTypesBaseTimeLikeHelper def self.supports?(feature) feature == :offset end def type :time_like_with_offset end def time(year, month, day, hour, minute, second, sub_second = 0, utc_offset = 0) utc_offset = 0 if utc_offset == :utc TimeLikeWithOffset.new(Time.new(year, month, day, hour, minute, second, utc_offset).to_i, sub_second, utc_offset) end end module Helpers def self.append_features(base) super base.extend(ClassMethods) end # Runs tests with each of the supported time representation types (DateTime, # Time or Timestamp). Types can be restricted by requiring features # (:distinct_utc, :unspecified_offset or :utc). def time_types_test(*required_features, &block) self.class.time_types_helpers(*required_features, &block) end # Suppresses any warnings raised in a specified block. def without_warnings old_verbose = $VERBOSE begin $VERBOSE = nil yield ensure $-v = old_verbose end end # Runs a test with safe mode enabled ($SAFE = 1). def safe_test(options = {}) # Ruby >= 2.7, JRuby, Rubinius and TruffleRuby don't support SAFE levels. available = RUBY_VERSION < '2.7' && !%w(jruby rbx truffleruby).include?(RUBY_ENGINE) if !available && options[:unavailable] == :skip skip('Ruby >= 2.7, JRuby, Rubinius and TruffleRuby don\'t support SAFE levels') end thread = Thread.new do orig_diff = Minitest::Assertions.diff if available orig_safe = $SAFE $SAFE = options[:level] || 1 end begin # Disable the use of external diff tools during safe mode tests (since # safe mode will prevent their use). The initial value is retrieved # before activating safe mode because the first time # Minitest::Assertions.diff is called, it will attempt to find a diff # tool. Finding the diff tool will also fail in safe mode. Minitest::Assertions.diff = nil begin yield ensure Minitest::Assertions.diff = orig_diff end ensure if available # On Ruby < 2.6, setting $SAFE affects only the current thread # and the $SAFE level cannot be downgraded. Catch and ignore the # SecurityError. # On Ruby >= 2.6, setting $SAFE is global, and the $SAFE level # can be downgraded. Restore $SAFE back to the original level. begin $SAFE = orig_safe rescue SecurityError end end end end thread.join end module ClassMethods # Yields instances of the TimeTypesHelper subclasses. Types can be # restricted by requiring features (:distinct_utc, :unspecified_offset or # :utc). def time_types_helpers(*required_features) [ TestUtils::TimeTypesTimeHelper, TestUtils::TimeTypesDateTimeHelper, TestUtils::TimeTypesTimestampHelper, TestUtils::TimeTypesTimeLikeHelper, TestUtils::TimeTypesTimeLikeWithOffsetHelper ].each do |helper_class| if required_features.all? {|f| helper_class.supports?(f) } yield helper_class.new end end end # Gets instances of TestEncoding for the given names. def test_encodings(*names) names.map {|n| TestEncoding.new(n) } end end end module Assertions # Assert that an array contains the same items independent of ordering. def assert_array_same_items(expected, actual, msg = nil) full_message = message(msg, '') { diff(expected, actual) } condition = (expected.size == actual.size) && (expected - actual == []) assert(condition, full_message) end # Keeps track of the number of times assert_sub_process_returns has been # called in order to name each SimpleCov run. @@assert_sub_process_returns_count = 0 # Assert that starting a Ruby sub process to run code returns the output # contained in the expected_lines array. Directories in load_path are added # to the start of the load path before running requires. Each item in # required is passed to require before running the specified code. def assert_sub_process_returns(expected_lines, code, load_path = [], required = ['tzinfo']) if RUBY_ENGINE == 'jruby' && JRUBY_VERSION.start_with?('9.0.') && RbConfig::CONFIG['host_os'] =~ /mswin/ skip('JRuby 9.0 on Windows cannot handle writing to the IO instance returned by popen') end ruby = File.join(RbConfig::CONFIG['bindir'], RbConfig::CONFIG['ruby_install_name'] + RbConfig::CONFIG['EXEEXT']) if RUBY_ENGINE == 'rbx' # Stop Rubinius from operating as irb. args = ' -' else args = '' end @@assert_sub_process_returns_count += 1 IO.popen("\"#{ruby}\"#{args} 2>&1", 'r+') do |process| load_path.each do |p| process.puts("$:.unshift('#{p.gsub("'", "\\\\'")}')") end if RUBY_ENGINE == 'rbx' # Bundler doesn't get set up automatically on Rubinius. process.puts("require 'bundler/setup'") end if COVERAGE_ENABLED && defined?(COVERAGE_TYPE) process.puts("require 'simplecov'") process.puts('SimpleCov.start do') process.puts(" command_name '#{COVERAGE_TYPE.gsub("'", "\\\\'")}:sp#{@@assert_sub_process_returns_count}'") process.puts(" add_filter 'test'") process.puts(" nocov_token '#{COVERAGE_NOCOV_TOKEN.gsub("'", "\\\\'")}'") process.puts(" project_name 'TZInfo'") process.puts(' self.formatters = []') process.puts('end') end required.each do |r| process.puts("require '#{r.gsub("'", "\\\\'")}'") end process.puts(code) process.flush process.close_write actual_lines = process.readlines actual_lines = actual_lines.collect(&:chomp) # Ignore warnings from RubyGems >= 3.1.0 that cause test failures with # JRuby 9.2.9.0: # https://travis-ci.org/tzinfo/tzinfo/jobs/628170481#L2437 # # Ignore warnings from JRuby 1.7 and 9.0 on modern versions of Java: # https://github.com/tzinfo/tzinfo/runs/1664655982#step:8:1893 # # Ignore untaint deprecation warnings from Bundler 1 on Ruby 3.0. actual_lines = actual_lines.reject do |l| l.start_with?('Gem::Specification#rubyforge_project= called from') || l.start_with?('NOTE: Gem::Specification#rubyforge_project= is deprecated with no replacement.') || l.end_with?('warning: constant Gem::ConfigMap is deprecated') || l.start_with?('unsupported Java version') || l.start_with?('WARNING: An illegal reflective access operation has occurred') || l.start_with?('WARNING: Illegal reflective access by') || l.start_with?('WARNING: Please consider reporting this to the maintainers of') || l.start_with?('WARNING: All illegal access operations will be denied in a future release') || l.start_with?('WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations') || l.start_with?('io/console on JRuby shells out to stty for most operations') || l =~ /\/bundler-1\..*\/lib\/bundler\/.*\.rb:\d+: warning: (Object|Pathname)#untaint is deprecated and will be removed in Ruby 3\.2\.\z/ end if RUBY_ENGINE == 'jruby' && ENV['_JAVA_OPTIONS'] && actual_lines.first == "Picked up _JAVA_OPTIONS: #{ENV['_JAVA_OPTIONS']}" actual_lines.shift end assert_equal(expected_lines, actual_lines) end end # Asserts that a block does not raise an exception. def assert_nothing_raised(msg = nil) begin yield rescue => e full_message = message(msg) { exception_details(e, 'Exception raised: ') } assert(false, full_message) end end # If expected is nil, asserts that actual is nil, otherwise asserts that # expected equals actual. def assert_nil_or_equal(expected, actual, msg = nil) if expected.nil? assert_nil(actual, msg) else assert_equal(expected, actual, msg) end end # Asserts that Time, DateTime or Timestamp instances are equal and that # their offsets are equal. The actual instance is allowed to be a subclass # of the expected class. def assert_equal_with_offset(expected, actual) assert_kind_of(expected.class, actual) assert_equal(expected, actual) # Time, DateTime and Timestamp don't require identical offsets for equality. # Test the offsets explicitly. if expected.respond_to?(:utc_offset) assert_nil_or_equal(expected.utc_offset, actual.utc_offset, 'utc_offset') elsif expected.respond_to?(:offset) assert_nil_or_equal(expected.offset, actual.offset, 'offset') end # Time (on MRI and Rubinius, but not JRuby) and Timestamp distinguish between # UTC and a local time with 0 offset from UTC. if expected.respond_to?(:utc?) assert_nil_or_equal(expected.utc?, actual.utc?, 'utc?') end end # Asserts that TimeWithOffset, DateTimeWithOffset or TimestampWithOffset # instances are equal and that their associated TimezoneOffsets are also # equal. def assert_equal_with_offset_and_timezone_offset(expected, actual) assert_equal_with_offset(expected, actual) assert_kind_of(TZInfo::TimezoneOffset, actual.timezone_offset) assert_equal(expected.timezone_offset, actual.timezone_offset) end # Asserts that Time, DateTime or Timestamp instances are equal and that # their classes are identical. def assert_equal_with_offset_and_class(expected, actual) assert_equal_with_offset(expected, actual) assert_equal(expected.class, actual.class) end # Object#taint is deprecated in Ruby >= 2.7 and will be removed in 3.2. # 2.7 makes it a no-op with a warning. # Define a method that will skip for use in tests that deal with tainted # objects. if Object.respond_to?(:taint) if RUBY_VERSION >= '2.7' def skip_if_taint_is_undefined_or_no_op skip('Object#taint is a no-op') end else def skip_if_taint_is_undefined_or_no_op end end else def skip_if_taint_is_undefined_or_no_op skip('Object#taint is not defined') end end end end TestUtils.prepare_test_zoneinfo_dir class Minitest::Test include TestUtils::Helpers include TestUtils::Assertions end tzinfo-2.0.6/test/ts_all.rb000066400000000000000000000005261436527530500156270ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true # Force a particular timezone to be local (helps find issues when local # timezone isn't GMT). This won't work on Windows. ENV['TZ'] = 'America/Los_Angeles' Dir[File.join(File.expand_path(File.dirname(__FILE__)), '**', 'tc_*.rb')].each {|t| require t} puts "Using #{TZInfo::DataSource.get}" tzinfo-2.0.6/test/ts_all_ruby_format1.rb000066400000000000000000000003061436527530500203150ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true TZINFO_TEST_DATA_FORMAT = 1 COVERAGE_TYPE = 'ruby_format_1' require_relative 'test_utils' TZInfo::DataSource.set(:ruby) require_relative 'ts_all' tzinfo-2.0.6/test/ts_all_ruby_format2.rb000066400000000000000000000003061436527530500203160ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true TZINFO_TEST_DATA_FORMAT = 2 COVERAGE_TYPE = 'ruby_format_2' require_relative 'test_utils' TZInfo::DataSource.set(:ruby) require_relative 'ts_all' tzinfo-2.0.6/test/ts_all_zoneinfo.rb000066400000000000000000000007021436527530500175320ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true COVERAGE_TYPE = 'zoneinfo' require_relative 'test_utils' # Use a zoneinfo directory containing files needed by the tests. # The symlinks in this directory are set up in test_utils.rb. zoneinfo_path = File.join(File.expand_path(File.dirname(__FILE__)), 'zoneinfo') TZInfo::const_get(:RubyCoreSupport).untaint(zoneinfo_path) TZInfo::DataSource.set(:zoneinfo, zoneinfo_path) require_relative 'ts_all' tzinfo-2.0.6/test/tzinfo-data1/000077500000000000000000000000001436527530500163225ustar00rootroot00000000000000tzinfo-2.0.6/test/tzinfo-data1/tzinfo/000077500000000000000000000000001436527530500176335ustar00rootroot00000000000000tzinfo-2.0.6/test/tzinfo-data1/tzinfo/data.rb000066400000000000000000000002131436527530500210650ustar00rootroot00000000000000# Top level module for TZInfo. module TZInfo # Top level module for TZInfo::Data. module Data end end require 'tzinfo/data/version' tzinfo-2.0.6/test/tzinfo-data1/tzinfo/data/000077500000000000000000000000001436527530500205445ustar00rootroot00000000000000tzinfo-2.0.6/test/tzinfo-data1/tzinfo/data/definitions/000077500000000000000000000000001436527530500230575ustar00rootroot00000000000000tzinfo-2.0.6/test/tzinfo-data1/tzinfo/data/definitions/America/000077500000000000000000000000001436527530500244205ustar00rootroot00000000000000tzinfo-2.0.6/test/tzinfo-data1/tzinfo/data/definitions/America/Argentina/000077500000000000000000000000001436527530500263305ustar00rootroot00000000000000tzinfo-2.0.6/test/tzinfo-data1/tzinfo/data/definitions/America/Argentina/Buenos_Aires.rb000066400000000000000000000106761436527530500312450ustar00rootroot00000000000000# encoding: UTF-8 # This file contains data derived from the IANA Time Zone Database # (https://www.iana.org/time-zones). module TZInfo module Data module Definitions module America module Argentina module Buenos_Aires include TimezoneDefinition timezone 'America/Argentina/Buenos_Aires' do |tz| tz.offset :o0, -14028, 0, :LMT tz.offset :o1, -15408, 0, :CMT tz.offset :o2, -14400, 0, :'-04' tz.offset :o3, -14400, 3600, :'-03' tz.offset :o4, -10800, 0, :'-03' tz.offset :o5, -10800, 3600, :'-02' tz.transition 1894, 10, :o1, -2372097972, 17374555169, 7200 tz.transition 1920, 5, :o2, -1567453392, 1453467407, 600 tz.transition 1930, 12, :o3, -1233432000, 7278935, 3 tz.transition 1931, 4, :o2, -1222981200, 19411461, 8 tz.transition 1931, 10, :o3, -1205956800, 7279889, 3 tz.transition 1932, 3, :o2, -1194037200, 19414141, 8 tz.transition 1932, 11, :o3, -1172865600, 7281038, 3 tz.transition 1933, 3, :o2, -1162501200, 19417061, 8 tz.transition 1933, 11, :o3, -1141329600, 7282133, 3 tz.transition 1934, 3, :o2, -1130965200, 19419981, 8 tz.transition 1934, 11, :o3, -1109793600, 7283228, 3 tz.transition 1935, 3, :o2, -1099429200, 19422901, 8 tz.transition 1935, 11, :o3, -1078257600, 7284323, 3 tz.transition 1936, 3, :o2, -1067806800, 19425829, 8 tz.transition 1936, 11, :o3, -1046635200, 7285421, 3 tz.transition 1937, 3, :o2, -1036270800, 19428749, 8 tz.transition 1937, 11, :o3, -1015099200, 7286516, 3 tz.transition 1938, 3, :o2, -1004734800, 19431669, 8 tz.transition 1938, 11, :o3, -983563200, 7287611, 3 tz.transition 1939, 3, :o2, -973198800, 19434589, 8 tz.transition 1939, 11, :o3, -952027200, 7288706, 3 tz.transition 1940, 3, :o2, -941576400, 19437517, 8 tz.transition 1940, 7, :o3, -931032000, 7289435, 3 tz.transition 1941, 6, :o2, -900882000, 19441285, 8 tz.transition 1941, 10, :o3, -890337600, 7290848, 3 tz.transition 1943, 8, :o2, -833749200, 19447501, 8 tz.transition 1943, 10, :o3, -827265600, 7293038, 3 tz.transition 1946, 3, :o2, -752274000, 19455045, 8 tz.transition 1946, 10, :o3, -733780800, 7296284, 3 tz.transition 1963, 10, :o2, -197326800, 19506429, 8 tz.transition 1963, 12, :o3, -190843200, 7315136, 3 tz.transition 1964, 3, :o2, -184194000, 19507645, 8 tz.transition 1964, 10, :o3, -164491200, 7316051, 3 tz.transition 1965, 3, :o2, -152658000, 19510565, 8 tz.transition 1965, 10, :o3, -132955200, 7317146, 3 tz.transition 1966, 3, :o2, -121122000, 19513485, 8 tz.transition 1966, 10, :o3, -101419200, 7318241, 3 tz.transition 1967, 4, :o2, -86821200, 19516661, 8 tz.transition 1967, 10, :o3, -71092800, 7319294, 3 tz.transition 1968, 4, :o2, -54766800, 19519629, 8 tz.transition 1968, 10, :o3, -39038400, 7320407, 3 tz.transition 1969, 4, :o2, -23317200, 19522541, 8 tz.transition 1969, 10, :o4, -7588800, 7321499, 3 tz.transition 1974, 1, :o5, 128142000 tz.transition 1974, 5, :o4, 136605600 tz.transition 1988, 12, :o5, 596948400 tz.transition 1989, 3, :o4, 605066400 tz.transition 1989, 10, :o5, 624423600 tz.transition 1990, 3, :o4, 636516000 tz.transition 1990, 10, :o5, 656478000 tz.transition 1991, 3, :o4, 667965600 tz.transition 1991, 10, :o5, 687927600 tz.transition 1992, 3, :o4, 699415200 tz.transition 1992, 10, :o5, 719377200 tz.transition 1993, 3, :o4, 731469600 tz.transition 1999, 10, :o3, 938919600 tz.transition 2000, 3, :o4, 952052400 tz.transition 2007, 12, :o5, 1198983600 tz.transition 2008, 3, :o4, 1205632800 tz.transition 2008, 10, :o5, 1224385200 tz.transition 2009, 3, :o4, 1237082400 end end end end end end end tzinfo-2.0.6/test/tzinfo-data1/tzinfo/data/definitions/America/New_York.rb000066400000000000000000000435141436527530500265110ustar00rootroot00000000000000# encoding: UTF-8 # This file contains data derived from the IANA Time Zone Database # (https://www.iana.org/time-zones). module TZInfo module Data module Definitions module America module New_York include TimezoneDefinition timezone 'America/New_York' do |tz| tz.offset :o0, -17762, 0, :LMT tz.offset :o1, -18000, 0, :EST tz.offset :o2, -18000, 3600, :EDT tz.offset :o3, -18000, 3600, :EWT tz.offset :o4, -18000, 3600, :EPT tz.transition 1883, 11, :o1, -2717650800, 57819197, 24 tz.transition 1918, 3, :o2, -1633280400, 58120411, 24 tz.transition 1918, 10, :o1, -1615140000, 9687575, 4 tz.transition 1919, 3, :o2, -1601830800, 58129147, 24 tz.transition 1919, 10, :o1, -1583690400, 9689031, 4 tz.transition 1920, 3, :o2, -1570381200, 58137883, 24 tz.transition 1920, 10, :o1, -1551636000, 9690515, 4 tz.transition 1921, 4, :o2, -1536512400, 58147291, 24 tz.transition 1921, 9, :o1, -1523210400, 9691831, 4 tz.transition 1922, 4, :o2, -1504458000, 58156195, 24 tz.transition 1922, 9, :o1, -1491760800, 9693287, 4 tz.transition 1923, 4, :o2, -1473008400, 58164931, 24 tz.transition 1923, 9, :o1, -1459706400, 9694771, 4 tz.transition 1924, 4, :o2, -1441558800, 58173667, 24 tz.transition 1924, 9, :o1, -1428256800, 9696227, 4 tz.transition 1925, 4, :o2, -1410109200, 58182403, 24 tz.transition 1925, 9, :o1, -1396807200, 9697683, 4 tz.transition 1926, 4, :o2, -1378659600, 58191139, 24 tz.transition 1926, 9, :o1, -1365357600, 9699139, 4 tz.transition 1927, 4, :o2, -1347210000, 58199875, 24 tz.transition 1927, 9, :o1, -1333908000, 9700595, 4 tz.transition 1928, 4, :o2, -1315155600, 58208779, 24 tz.transition 1928, 9, :o1, -1301853600, 9702079, 4 tz.transition 1929, 4, :o2, -1283706000, 58217515, 24 tz.transition 1929, 9, :o1, -1270404000, 9703535, 4 tz.transition 1930, 4, :o2, -1252256400, 58226251, 24 tz.transition 1930, 9, :o1, -1238954400, 9704991, 4 tz.transition 1931, 4, :o2, -1220806800, 58234987, 24 tz.transition 1931, 9, :o1, -1207504800, 9706447, 4 tz.transition 1932, 4, :o2, -1189357200, 58243723, 24 tz.transition 1932, 9, :o1, -1176055200, 9707903, 4 tz.transition 1933, 4, :o2, -1157302800, 58252627, 24 tz.transition 1933, 9, :o1, -1144605600, 9709359, 4 tz.transition 1934, 4, :o2, -1125853200, 58261363, 24 tz.transition 1934, 9, :o1, -1112551200, 9710843, 4 tz.transition 1935, 4, :o2, -1094403600, 58270099, 24 tz.transition 1935, 9, :o1, -1081101600, 9712299, 4 tz.transition 1936, 4, :o2, -1062954000, 58278835, 24 tz.transition 1936, 9, :o1, -1049652000, 9713755, 4 tz.transition 1937, 4, :o2, -1031504400, 58287571, 24 tz.transition 1937, 9, :o1, -1018202400, 9715211, 4 tz.transition 1938, 4, :o2, -1000054800, 58296307, 24 tz.transition 1938, 9, :o1, -986752800, 9716667, 4 tz.transition 1939, 4, :o2, -968000400, 58305211, 24 tz.transition 1939, 9, :o1, -955303200, 9718123, 4 tz.transition 1940, 4, :o2, -936550800, 58313947, 24 tz.transition 1940, 9, :o1, -923248800, 9719607, 4 tz.transition 1941, 4, :o2, -905101200, 58322683, 24 tz.transition 1941, 9, :o1, -891799200, 9721063, 4 tz.transition 1942, 2, :o3, -880218000, 58329595, 24 tz.transition 1945, 8, :o4, -769395600, 58360379, 24 tz.transition 1945, 9, :o1, -765396000, 9726915, 4 tz.transition 1946, 4, :o2, -747248400, 58366531, 24 tz.transition 1946, 9, :o1, -733946400, 9728371, 4 tz.transition 1947, 4, :o2, -715798800, 58375267, 24 tz.transition 1947, 9, :o1, -702496800, 9729827, 4 tz.transition 1948, 4, :o2, -684349200, 58384003, 24 tz.transition 1948, 9, :o1, -671047200, 9731283, 4 tz.transition 1949, 4, :o2, -652899600, 58392739, 24 tz.transition 1949, 9, :o1, -639597600, 9732739, 4 tz.transition 1950, 4, :o2, -620845200, 58401643, 24 tz.transition 1950, 9, :o1, -608148000, 9734195, 4 tz.transition 1951, 4, :o2, -589395600, 58410379, 24 tz.transition 1951, 9, :o1, -576093600, 9735679, 4 tz.transition 1952, 4, :o2, -557946000, 58419115, 24 tz.transition 1952, 9, :o1, -544644000, 9737135, 4 tz.transition 1953, 4, :o2, -526496400, 58427851, 24 tz.transition 1953, 9, :o1, -513194400, 9738591, 4 tz.transition 1954, 4, :o2, -495046800, 58436587, 24 tz.transition 1954, 9, :o1, -481744800, 9740047, 4 tz.transition 1955, 4, :o2, -463597200, 58445323, 24 tz.transition 1955, 10, :o1, -447271200, 9741643, 4 tz.transition 1956, 4, :o2, -431542800, 58454227, 24 tz.transition 1956, 10, :o1, -415821600, 9743099, 4 tz.transition 1957, 4, :o2, -400093200, 58462963, 24 tz.transition 1957, 10, :o1, -384372000, 9744555, 4 tz.transition 1958, 4, :o2, -368643600, 58471699, 24 tz.transition 1958, 10, :o1, -352922400, 9746011, 4 tz.transition 1959, 4, :o2, -337194000, 58480435, 24 tz.transition 1959, 10, :o1, -321472800, 9747467, 4 tz.transition 1960, 4, :o2, -305744400, 58489171, 24 tz.transition 1960, 10, :o1, -289418400, 9748951, 4 tz.transition 1961, 4, :o2, -273690000, 58498075, 24 tz.transition 1961, 10, :o1, -257968800, 9750407, 4 tz.transition 1962, 4, :o2, -242240400, 58506811, 24 tz.transition 1962, 10, :o1, -226519200, 9751863, 4 tz.transition 1963, 4, :o2, -210790800, 58515547, 24 tz.transition 1963, 10, :o1, -195069600, 9753319, 4 tz.transition 1964, 4, :o2, -179341200, 58524283, 24 tz.transition 1964, 10, :o1, -163620000, 9754775, 4 tz.transition 1965, 4, :o2, -147891600, 58533019, 24 tz.transition 1965, 10, :o1, -131565600, 9756259, 4 tz.transition 1966, 4, :o2, -116442000, 58541755, 24 tz.transition 1966, 10, :o1, -100116000, 9757715, 4 tz.transition 1967, 4, :o2, -84387600, 58550659, 24 tz.transition 1967, 10, :o1, -68666400, 9759171, 4 tz.transition 1968, 4, :o2, -52938000, 58559395, 24 tz.transition 1968, 10, :o1, -37216800, 9760627, 4 tz.transition 1969, 4, :o2, -21488400, 58568131, 24 tz.transition 1969, 10, :o1, -5767200, 9762083, 4 tz.transition 1970, 4, :o2, 9961200 tz.transition 1970, 10, :o1, 25682400 tz.transition 1971, 4, :o2, 41410800 tz.transition 1971, 10, :o1, 57736800 tz.transition 1972, 4, :o2, 73465200 tz.transition 1972, 10, :o1, 89186400 tz.transition 1973, 4, :o2, 104914800 tz.transition 1973, 10, :o1, 120636000 tz.transition 1974, 1, :o2, 126687600 tz.transition 1974, 10, :o1, 152085600 tz.transition 1975, 2, :o2, 162370800 tz.transition 1975, 10, :o1, 183535200 tz.transition 1976, 4, :o2, 199263600 tz.transition 1976, 10, :o1, 215589600 tz.transition 1977, 4, :o2, 230713200 tz.transition 1977, 10, :o1, 247039200 tz.transition 1978, 4, :o2, 262767600 tz.transition 1978, 10, :o1, 278488800 tz.transition 1979, 4, :o2, 294217200 tz.transition 1979, 10, :o1, 309938400 tz.transition 1980, 4, :o2, 325666800 tz.transition 1980, 10, :o1, 341388000 tz.transition 1981, 4, :o2, 357116400 tz.transition 1981, 10, :o1, 372837600 tz.transition 1982, 4, :o2, 388566000 tz.transition 1982, 10, :o1, 404892000 tz.transition 1983, 4, :o2, 420015600 tz.transition 1983, 10, :o1, 436341600 tz.transition 1984, 4, :o2, 452070000 tz.transition 1984, 10, :o1, 467791200 tz.transition 1985, 4, :o2, 483519600 tz.transition 1985, 10, :o1, 499240800 tz.transition 1986, 4, :o2, 514969200 tz.transition 1986, 10, :o1, 530690400 tz.transition 1987, 4, :o2, 544604400 tz.transition 1987, 10, :o1, 562140000 tz.transition 1988, 4, :o2, 576054000 tz.transition 1988, 10, :o1, 594194400 tz.transition 1989, 4, :o2, 607503600 tz.transition 1989, 10, :o1, 625644000 tz.transition 1990, 4, :o2, 638953200 tz.transition 1990, 10, :o1, 657093600 tz.transition 1991, 4, :o2, 671007600 tz.transition 1991, 10, :o1, 688543200 tz.transition 1992, 4, :o2, 702457200 tz.transition 1992, 10, :o1, 719992800 tz.transition 1993, 4, :o2, 733906800 tz.transition 1993, 10, :o1, 752047200 tz.transition 1994, 4, :o2, 765356400 tz.transition 1994, 10, :o1, 783496800 tz.transition 1995, 4, :o2, 796806000 tz.transition 1995, 10, :o1, 814946400 tz.transition 1996, 4, :o2, 828860400 tz.transition 1996, 10, :o1, 846396000 tz.transition 1997, 4, :o2, 860310000 tz.transition 1997, 10, :o1, 877845600 tz.transition 1998, 4, :o2, 891759600 tz.transition 1998, 10, :o1, 909295200 tz.transition 1999, 4, :o2, 923209200 tz.transition 1999, 10, :o1, 941349600 tz.transition 2000, 4, :o2, 954658800 tz.transition 2000, 10, :o1, 972799200 tz.transition 2001, 4, :o2, 986108400 tz.transition 2001, 10, :o1, 1004248800 tz.transition 2002, 4, :o2, 1018162800 tz.transition 2002, 10, :o1, 1035698400 tz.transition 2003, 4, :o2, 1049612400 tz.transition 2003, 10, :o1, 1067148000 tz.transition 2004, 4, :o2, 1081062000 tz.transition 2004, 10, :o1, 1099202400 tz.transition 2005, 4, :o2, 1112511600 tz.transition 2005, 10, :o1, 1130652000 tz.transition 2006, 4, :o2, 1143961200 tz.transition 2006, 10, :o1, 1162101600 tz.transition 2007, 3, :o2, 1173596400 tz.transition 2007, 11, :o1, 1194156000 tz.transition 2008, 3, :o2, 1205046000 tz.transition 2008, 11, :o1, 1225605600 tz.transition 2009, 3, :o2, 1236495600 tz.transition 2009, 11, :o1, 1257055200 tz.transition 2010, 3, :o2, 1268550000 tz.transition 2010, 11, :o1, 1289109600 tz.transition 2011, 3, :o2, 1299999600 tz.transition 2011, 11, :o1, 1320559200 tz.transition 2012, 3, :o2, 1331449200 tz.transition 2012, 11, :o1, 1352008800 tz.transition 2013, 3, :o2, 1362898800 tz.transition 2013, 11, :o1, 1383458400 tz.transition 2014, 3, :o2, 1394348400 tz.transition 2014, 11, :o1, 1414908000 tz.transition 2015, 3, :o2, 1425798000 tz.transition 2015, 11, :o1, 1446357600 tz.transition 2016, 3, :o2, 1457852400 tz.transition 2016, 11, :o1, 1478412000 tz.transition 2017, 3, :o2, 1489302000 tz.transition 2017, 11, :o1, 1509861600 tz.transition 2018, 3, :o2, 1520751600 tz.transition 2018, 11, :o1, 1541311200 tz.transition 2019, 3, :o2, 1552201200 tz.transition 2019, 11, :o1, 1572760800 tz.transition 2020, 3, :o2, 1583650800 tz.transition 2020, 11, :o1, 1604210400 tz.transition 2021, 3, :o2, 1615705200 tz.transition 2021, 11, :o1, 1636264800 tz.transition 2022, 3, :o2, 1647154800 tz.transition 2022, 11, :o1, 1667714400 tz.transition 2023, 3, :o2, 1678604400 tz.transition 2023, 11, :o1, 1699164000 tz.transition 2024, 3, :o2, 1710054000 tz.transition 2024, 11, :o1, 1730613600 tz.transition 2025, 3, :o2, 1741503600 tz.transition 2025, 11, :o1, 1762063200 tz.transition 2026, 3, :o2, 1772953200 tz.transition 2026, 11, :o1, 1793512800 tz.transition 2027, 3, :o2, 1805007600 tz.transition 2027, 11, :o1, 1825567200 tz.transition 2028, 3, :o2, 1836457200 tz.transition 2028, 11, :o1, 1857016800 tz.transition 2029, 3, :o2, 1867906800 tz.transition 2029, 11, :o1, 1888466400 tz.transition 2030, 3, :o2, 1899356400 tz.transition 2030, 11, :o1, 1919916000 tz.transition 2031, 3, :o2, 1930806000 tz.transition 2031, 11, :o1, 1951365600 tz.transition 2032, 3, :o2, 1962860400 tz.transition 2032, 11, :o1, 1983420000 tz.transition 2033, 3, :o2, 1994310000 tz.transition 2033, 11, :o1, 2014869600 tz.transition 2034, 3, :o2, 2025759600 tz.transition 2034, 11, :o1, 2046319200 tz.transition 2035, 3, :o2, 2057209200 tz.transition 2035, 11, :o1, 2077768800 tz.transition 2036, 3, :o2, 2088658800 tz.transition 2036, 11, :o1, 2109218400 tz.transition 2037, 3, :o2, 2120108400 tz.transition 2037, 11, :o1, 2140668000 tz.transition 2038, 3, :o2, 2152162800, 59171923, 24 tz.transition 2038, 11, :o1, 2172722400, 9862939, 4 tz.transition 2039, 3, :o2, 2183612400, 59180659, 24 tz.transition 2039, 11, :o1, 2204172000, 9864395, 4 tz.transition 2040, 3, :o2, 2215062000, 59189395, 24 tz.transition 2040, 11, :o1, 2235621600, 9865851, 4 tz.transition 2041, 3, :o2, 2246511600, 59198131, 24 tz.transition 2041, 11, :o1, 2267071200, 9867307, 4 tz.transition 2042, 3, :o2, 2277961200, 59206867, 24 tz.transition 2042, 11, :o1, 2298520800, 9868763, 4 tz.transition 2043, 3, :o2, 2309410800, 59215603, 24 tz.transition 2043, 11, :o1, 2329970400, 9870219, 4 tz.transition 2044, 3, :o2, 2341465200, 59224507, 24 tz.transition 2044, 11, :o1, 2362024800, 9871703, 4 tz.transition 2045, 3, :o2, 2372914800, 59233243, 24 tz.transition 2045, 11, :o1, 2393474400, 9873159, 4 tz.transition 2046, 3, :o2, 2404364400, 59241979, 24 tz.transition 2046, 11, :o1, 2424924000, 9874615, 4 tz.transition 2047, 3, :o2, 2435814000, 59250715, 24 tz.transition 2047, 11, :o1, 2456373600, 9876071, 4 tz.transition 2048, 3, :o2, 2467263600, 59259451, 24 tz.transition 2048, 11, :o1, 2487823200, 9877527, 4 tz.transition 2049, 3, :o2, 2499318000, 59268355, 24 tz.transition 2049, 11, :o1, 2519877600, 9879011, 4 tz.transition 2050, 3, :o2, 2530767600, 59277091, 24 tz.transition 2050, 11, :o1, 2551327200, 9880467, 4 tz.transition 2051, 3, :o2, 2562217200, 59285827, 24 tz.transition 2051, 11, :o1, 2582776800, 9881923, 4 tz.transition 2052, 3, :o2, 2593666800, 59294563, 24 tz.transition 2052, 11, :o1, 2614226400, 9883379, 4 tz.transition 2053, 3, :o2, 2625116400, 59303299, 24 tz.transition 2053, 11, :o1, 2645676000, 9884835, 4 tz.transition 2054, 3, :o2, 2656566000, 59312035, 24 tz.transition 2054, 11, :o1, 2677125600, 9886291, 4 tz.transition 2055, 3, :o2, 2688620400, 59320939, 24 tz.transition 2055, 11, :o1, 2709180000, 9887775, 4 tz.transition 2056, 3, :o2, 2720070000, 59329675, 24 tz.transition 2056, 11, :o1, 2740629600, 9889231, 4 tz.transition 2057, 3, :o2, 2751519600, 59338411, 24 tz.transition 2057, 11, :o1, 2772079200, 9890687, 4 tz.transition 2058, 3, :o2, 2782969200, 59347147, 24 tz.transition 2058, 11, :o1, 2803528800, 9892143, 4 tz.transition 2059, 3, :o2, 2814418800, 59355883, 24 tz.transition 2059, 11, :o1, 2834978400, 9893599, 4 tz.transition 2060, 3, :o2, 2846473200, 59364787, 24 tz.transition 2060, 11, :o1, 2867032800, 9895083, 4 tz.transition 2061, 3, :o2, 2877922800, 59373523, 24 tz.transition 2061, 11, :o1, 2898482400, 9896539, 4 tz.transition 2062, 3, :o2, 2909372400, 59382259, 24 tz.transition 2062, 11, :o1, 2929932000, 9897995, 4 tz.transition 2063, 3, :o2, 2940822000, 59390995, 24 tz.transition 2063, 11, :o1, 2961381600, 9899451, 4 tz.transition 2064, 3, :o2, 2972271600, 59399731, 24 tz.transition 2064, 11, :o1, 2992831200, 9900907, 4 tz.transition 2065, 3, :o2, 3003721200, 59408467, 24 tz.transition 2065, 11, :o1, 3024280800, 9902363, 4 tz.transition 2066, 3, :o2, 3035775600, 59417371, 24 tz.transition 2066, 11, :o1, 3056335200, 9903847, 4 tz.transition 2067, 3, :o2, 3067225200, 59426107, 24 tz.transition 2067, 11, :o1, 3087784800, 9905303, 4 tz.transition 2068, 3, :o2, 3098674800, 59434843, 24 tz.transition 2068, 11, :o1, 3119234400, 9906759, 4 tz.transition 2069, 3, :o2, 3130124400, 59443579, 24 tz.transition 2069, 11, :o1, 3150684000, 9908215, 4 tz.transition 2070, 3, :o2, 3161574000, 59452315, 24 tz.transition 2070, 11, :o1, 3182133600, 9909671, 4 end end end end end end tzinfo-2.0.6/test/tzinfo-data1/tzinfo/data/definitions/Australia/000077500000000000000000000000001436527530500250045ustar00rootroot00000000000000tzinfo-2.0.6/test/tzinfo-data1/tzinfo/data/definitions/Australia/Melbourne.rb000066400000000000000000000274621436527530500272740ustar00rootroot00000000000000# encoding: UTF-8 # This file contains data derived from the IANA Time Zone Database # (https://www.iana.org/time-zones). module TZInfo module Data module Definitions module Australia module Melbourne include TimezoneDefinition timezone 'Australia/Melbourne' do |tz| tz.offset :o0, 34792, 0, :LMT tz.offset :o1, 36000, 0, :AEST tz.offset :o2, 36000, 3600, :AEDT tz.transition 1895, 1, :o1, -2364111592, 26062831051, 10800 tz.transition 1916, 12, :o2, -1672567140, 3486569881, 1440 tz.transition 1917, 3, :o1, -1665392400, 19370497, 8 tz.transition 1941, 12, :o2, -883641600, 14582161, 6 tz.transition 1942, 3, :o1, -876128400, 19443577, 8 tz.transition 1942, 9, :o2, -860400000, 14583775, 6 tz.transition 1943, 3, :o1, -844678800, 19446489, 8 tz.transition 1943, 10, :o2, -828345600, 14586001, 6 tz.transition 1944, 3, :o1, -813229200, 19449401, 8 tz.transition 1971, 10, :o2, 57686400 tz.transition 1972, 2, :o1, 67968000 tz.transition 1972, 10, :o2, 89136000 tz.transition 1973, 3, :o1, 100022400 tz.transition 1973, 10, :o2, 120585600 tz.transition 1974, 3, :o1, 131472000 tz.transition 1974, 10, :o2, 152035200 tz.transition 1975, 3, :o1, 162921600 tz.transition 1975, 10, :o2, 183484800 tz.transition 1976, 3, :o1, 194976000 tz.transition 1976, 10, :o2, 215539200 tz.transition 1977, 3, :o1, 226425600 tz.transition 1977, 10, :o2, 246988800 tz.transition 1978, 3, :o1, 257875200 tz.transition 1978, 10, :o2, 278438400 tz.transition 1979, 3, :o1, 289324800 tz.transition 1979, 10, :o2, 309888000 tz.transition 1980, 3, :o1, 320774400 tz.transition 1980, 10, :o2, 341337600 tz.transition 1981, 2, :o1, 352224000 tz.transition 1981, 10, :o2, 372787200 tz.transition 1982, 3, :o1, 384278400 tz.transition 1982, 10, :o2, 404841600 tz.transition 1983, 3, :o1, 415728000 tz.transition 1983, 10, :o2, 436291200 tz.transition 1984, 3, :o1, 447177600 tz.transition 1984, 10, :o2, 467740800 tz.transition 1985, 3, :o1, 478627200 tz.transition 1985, 10, :o2, 499190400 tz.transition 1986, 3, :o1, 511286400 tz.transition 1986, 10, :o2, 530035200 tz.transition 1987, 3, :o1, 542736000 tz.transition 1987, 10, :o2, 561484800 tz.transition 1988, 3, :o1, 574790400 tz.transition 1988, 10, :o2, 594144000 tz.transition 1989, 3, :o1, 606240000 tz.transition 1989, 10, :o2, 625593600 tz.transition 1990, 3, :o1, 637689600 tz.transition 1990, 10, :o2, 657043200 tz.transition 1991, 3, :o1, 667929600 tz.transition 1991, 10, :o2, 688492800 tz.transition 1992, 2, :o1, 699379200 tz.transition 1992, 10, :o2, 719942400 tz.transition 1993, 3, :o1, 731433600 tz.transition 1993, 10, :o2, 751996800 tz.transition 1994, 3, :o1, 762883200 tz.transition 1994, 10, :o2, 783446400 tz.transition 1995, 3, :o1, 796147200 tz.transition 1995, 10, :o2, 814896000 tz.transition 1996, 3, :o1, 828201600 tz.transition 1996, 10, :o2, 846345600 tz.transition 1997, 3, :o1, 859651200 tz.transition 1997, 10, :o2, 877795200 tz.transition 1998, 3, :o1, 891100800 tz.transition 1998, 10, :o2, 909244800 tz.transition 1999, 3, :o1, 922550400 tz.transition 1999, 10, :o2, 941299200 tz.transition 2000, 3, :o1, 954000000 tz.transition 2000, 8, :o2, 967305600 tz.transition 2001, 3, :o1, 985449600 tz.transition 2001, 10, :o2, 1004198400 tz.transition 2002, 3, :o1, 1017504000 tz.transition 2002, 10, :o2, 1035648000 tz.transition 2003, 3, :o1, 1048953600 tz.transition 2003, 10, :o2, 1067097600 tz.transition 2004, 3, :o1, 1080403200 tz.transition 2004, 10, :o2, 1099152000 tz.transition 2005, 3, :o1, 1111852800 tz.transition 2005, 10, :o2, 1130601600 tz.transition 2006, 4, :o1, 1143907200 tz.transition 2006, 10, :o2, 1162051200 tz.transition 2007, 3, :o1, 1174752000 tz.transition 2007, 10, :o2, 1193500800 tz.transition 2008, 4, :o1, 1207411200 tz.transition 2008, 10, :o2, 1223136000 tz.transition 2009, 4, :o1, 1238860800 tz.transition 2009, 10, :o2, 1254585600 tz.transition 2010, 4, :o1, 1270310400 tz.transition 2010, 10, :o2, 1286035200 tz.transition 2011, 4, :o1, 1301760000 tz.transition 2011, 10, :o2, 1317484800 tz.transition 2012, 3, :o1, 1333209600 tz.transition 2012, 10, :o2, 1349539200 tz.transition 2013, 4, :o1, 1365264000 tz.transition 2013, 10, :o2, 1380988800 tz.transition 2014, 4, :o1, 1396713600 tz.transition 2014, 10, :o2, 1412438400 tz.transition 2015, 4, :o1, 1428163200 tz.transition 2015, 10, :o2, 1443888000 tz.transition 2016, 4, :o1, 1459612800 tz.transition 2016, 10, :o2, 1475337600 tz.transition 2017, 4, :o1, 1491062400 tz.transition 2017, 9, :o2, 1506787200 tz.transition 2018, 3, :o1, 1522512000 tz.transition 2018, 10, :o2, 1538841600 tz.transition 2019, 4, :o1, 1554566400 tz.transition 2019, 10, :o2, 1570291200 tz.transition 2020, 4, :o1, 1586016000 tz.transition 2020, 10, :o2, 1601740800 tz.transition 2021, 4, :o1, 1617465600 tz.transition 2021, 10, :o2, 1633190400 tz.transition 2022, 4, :o1, 1648915200 tz.transition 2022, 10, :o2, 1664640000 tz.transition 2023, 4, :o1, 1680364800 tz.transition 2023, 9, :o2, 1696089600 tz.transition 2024, 4, :o1, 1712419200 tz.transition 2024, 10, :o2, 1728144000 tz.transition 2025, 4, :o1, 1743868800 tz.transition 2025, 10, :o2, 1759593600 tz.transition 2026, 4, :o1, 1775318400 tz.transition 2026, 10, :o2, 1791043200 tz.transition 2027, 4, :o1, 1806768000 tz.transition 2027, 10, :o2, 1822492800 tz.transition 2028, 4, :o1, 1838217600 tz.transition 2028, 9, :o2, 1853942400 tz.transition 2029, 3, :o1, 1869667200 tz.transition 2029, 10, :o2, 1885996800 tz.transition 2030, 4, :o1, 1901721600 tz.transition 2030, 10, :o2, 1917446400 tz.transition 2031, 4, :o1, 1933171200 tz.transition 2031, 10, :o2, 1948896000 tz.transition 2032, 4, :o1, 1964620800 tz.transition 2032, 10, :o2, 1980345600 tz.transition 2033, 4, :o1, 1996070400 tz.transition 2033, 10, :o2, 2011795200 tz.transition 2034, 4, :o1, 2027520000 tz.transition 2034, 9, :o2, 2043244800 tz.transition 2035, 3, :o1, 2058969600 tz.transition 2035, 10, :o2, 2075299200 tz.transition 2036, 4, :o1, 2091024000 tz.transition 2036, 10, :o2, 2106748800 tz.transition 2037, 4, :o1, 2122473600 tz.transition 2037, 10, :o2, 2138198400 tz.transition 2038, 4, :o1, 2153923200, 14793103, 6 tz.transition 2038, 10, :o2, 2169648000, 14794195, 6 tz.transition 2039, 4, :o1, 2185372800, 14795287, 6 tz.transition 2039, 10, :o2, 2201097600, 14796379, 6 tz.transition 2040, 3, :o1, 2216822400, 14797471, 6 tz.transition 2040, 10, :o2, 2233152000, 14798605, 6 tz.transition 2041, 4, :o1, 2248876800, 14799697, 6 tz.transition 2041, 10, :o2, 2264601600, 14800789, 6 tz.transition 2042, 4, :o1, 2280326400, 14801881, 6 tz.transition 2042, 10, :o2, 2296051200, 14802973, 6 tz.transition 2043, 4, :o1, 2311776000, 14804065, 6 tz.transition 2043, 10, :o2, 2327500800, 14805157, 6 tz.transition 2044, 4, :o1, 2343225600, 14806249, 6 tz.transition 2044, 10, :o2, 2358950400, 14807341, 6 tz.transition 2045, 4, :o1, 2374675200, 14808433, 6 tz.transition 2045, 9, :o2, 2390400000, 14809525, 6 tz.transition 2046, 3, :o1, 2406124800, 14810617, 6 tz.transition 2046, 10, :o2, 2422454400, 14811751, 6 tz.transition 2047, 4, :o1, 2438179200, 14812843, 6 tz.transition 2047, 10, :o2, 2453904000, 14813935, 6 tz.transition 2048, 4, :o1, 2469628800, 14815027, 6 tz.transition 2048, 10, :o2, 2485353600, 14816119, 6 tz.transition 2049, 4, :o1, 2501078400, 14817211, 6 tz.transition 2049, 10, :o2, 2516803200, 14818303, 6 tz.transition 2050, 4, :o1, 2532528000, 14819395, 6 tz.transition 2050, 10, :o2, 2548252800, 14820487, 6 tz.transition 2051, 4, :o1, 2563977600, 14821579, 6 tz.transition 2051, 9, :o2, 2579702400, 14822671, 6 tz.transition 2052, 4, :o1, 2596032000, 14823805, 6 tz.transition 2052, 10, :o2, 2611756800, 14824897, 6 tz.transition 2053, 4, :o1, 2627481600, 14825989, 6 tz.transition 2053, 10, :o2, 2643206400, 14827081, 6 tz.transition 2054, 4, :o1, 2658931200, 14828173, 6 tz.transition 2054, 10, :o2, 2674656000, 14829265, 6 tz.transition 2055, 4, :o1, 2690380800, 14830357, 6 tz.transition 2055, 10, :o2, 2706105600, 14831449, 6 tz.transition 2056, 4, :o1, 2721830400, 14832541, 6 tz.transition 2056, 9, :o2, 2737555200, 14833633, 6 tz.transition 2057, 3, :o1, 2753280000, 14834725, 6 tz.transition 2057, 10, :o2, 2769609600, 14835859, 6 tz.transition 2058, 4, :o1, 2785334400, 14836951, 6 tz.transition 2058, 10, :o2, 2801059200, 14838043, 6 tz.transition 2059, 4, :o1, 2816784000, 14839135, 6 tz.transition 2059, 10, :o2, 2832508800, 14840227, 6 tz.transition 2060, 4, :o1, 2848233600, 14841319, 6 tz.transition 2060, 10, :o2, 2863958400, 14842411, 6 tz.transition 2061, 4, :o1, 2879683200, 14843503, 6 tz.transition 2061, 10, :o2, 2895408000, 14844595, 6 tz.transition 2062, 4, :o1, 2911132800, 14845687, 6 tz.transition 2062, 9, :o2, 2926857600, 14846779, 6 tz.transition 2063, 3, :o1, 2942582400, 14847871, 6 tz.transition 2063, 10, :o2, 2958912000, 14849005, 6 tz.transition 2064, 4, :o1, 2974636800, 14850097, 6 tz.transition 2064, 10, :o2, 2990361600, 14851189, 6 tz.transition 2065, 4, :o1, 3006086400, 14852281, 6 tz.transition 2065, 10, :o2, 3021811200, 14853373, 6 tz.transition 2066, 4, :o1, 3037536000, 14854465, 6 tz.transition 2066, 10, :o2, 3053260800, 14855557, 6 tz.transition 2067, 4, :o1, 3068985600, 14856649, 6 tz.transition 2067, 10, :o2, 3084710400, 14857741, 6 tz.transition 2068, 3, :o1, 3100435200, 14858833, 6 tz.transition 2068, 10, :o2, 3116764800, 14859967, 6 tz.transition 2069, 4, :o1, 3132489600, 14861059, 6 tz.transition 2069, 10, :o2, 3148214400, 14862151, 6 tz.transition 2070, 4, :o1, 3163939200, 14863243, 6 end end end end end end tzinfo-2.0.6/test/tzinfo-data1/tzinfo/data/definitions/EST.rb000066400000000000000000000005471436527530500240450ustar00rootroot00000000000000# encoding: UTF-8 # This file contains data derived from the IANA Time Zone Database # (https://www.iana.org/time-zones). module TZInfo module Data module Definitions module EST include TimezoneDefinition timezone 'EST' do |tz| tz.offset :o0, -18000, 0, :EST end end end end end tzinfo-2.0.6/test/tzinfo-data1/tzinfo/data/definitions/Etc/000077500000000000000000000000001436527530500235725ustar00rootroot00000000000000tzinfo-2.0.6/test/tzinfo-data1/tzinfo/data/definitions/Etc/GMT__m__1.rb000066400000000000000000000006361436527530500256050ustar00rootroot00000000000000# encoding: UTF-8 # This file contains data derived from the IANA Time Zone Database # (https://www.iana.org/time-zones). module TZInfo module Data module Definitions module Etc module GMT__m__1 include TimezoneDefinition timezone 'Etc/GMT-1' do |tz| tz.offset :o0, 3600, 0, :'+01' end end end end end end tzinfo-2.0.6/test/tzinfo-data1/tzinfo/data/definitions/Etc/GMT__p__1.rb000066400000000000000000000006371436527530500256110ustar00rootroot00000000000000# encoding: UTF-8 # This file contains data derived from the IANA Time Zone Database # (https://www.iana.org/time-zones). module TZInfo module Data module Definitions module Etc module GMT__p__1 include TimezoneDefinition timezone 'Etc/GMT+1' do |tz| tz.offset :o0, -3600, 0, :'-01' end end end end end end tzinfo-2.0.6/test/tzinfo-data1/tzinfo/data/definitions/Etc/UTC.rb000066400000000000000000000006211436527530500245510ustar00rootroot00000000000000# encoding: UTF-8 # This file contains data derived from the IANA Time Zone Database # (https://www.iana.org/time-zones). module TZInfo module Data module Definitions module Etc module UTC include TimezoneDefinition timezone 'Etc/UTC' do |tz| tz.offset :o0, 0, 0, :UTC end end end end end end tzinfo-2.0.6/test/tzinfo-data1/tzinfo/data/definitions/Europe/000077500000000000000000000000001436527530500243165ustar00rootroot00000000000000tzinfo-2.0.6/test/tzinfo-data1/tzinfo/data/definitions/Europe/Amsterdam.rb000066400000000000000000000357531436527530500265750ustar00rootroot00000000000000# encoding: UTF-8 # This file contains data derived from the IANA Time Zone Database # (https://www.iana.org/time-zones). module TZInfo module Data module Definitions module Europe module Amsterdam include TimezoneDefinition timezone 'Europe/Amsterdam' do |tz| tz.offset :o0, 1172, 0, :LMT tz.offset :o1, 1172, 0, :AMT tz.offset :o2, 1172, 3600, :NST tz.offset :o3, 1200, 3600, :'+0120' tz.offset :o4, 1200, 0, :'+0020' tz.offset :o5, 3600, 3600, :CEST tz.offset :o6, 3600, 0, :CET tz.transition 1834, 12, :o1, -4260212372, 51651636907, 21600 tz.transition 1916, 4, :o2, -1693700372, 52293264907, 21600 tz.transition 1916, 9, :o1, -1680484772, 52296568807, 21600 tz.transition 1917, 4, :o2, -1663453172, 52300826707, 21600 tz.transition 1917, 9, :o1, -1650147572, 52304153107, 21600 tz.transition 1918, 4, :o2, -1633213172, 52308386707, 21600 tz.transition 1918, 9, :o1, -1617488372, 52312317907, 21600 tz.transition 1919, 4, :o2, -1601158772, 52316400307, 21600 tz.transition 1919, 9, :o1, -1586038772, 52320180307, 21600 tz.transition 1920, 4, :o2, -1569709172, 52324262707, 21600 tz.transition 1920, 9, :o1, -1554589172, 52328042707, 21600 tz.transition 1921, 4, :o2, -1538259572, 52332125107, 21600 tz.transition 1921, 9, :o1, -1523139572, 52335905107, 21600 tz.transition 1922, 3, :o2, -1507501172, 52339814707, 21600 tz.transition 1922, 10, :o1, -1490566772, 52344048307, 21600 tz.transition 1923, 6, :o2, -1470176372, 52349145907, 21600 tz.transition 1923, 10, :o1, -1459117172, 52351910707, 21600 tz.transition 1924, 3, :o2, -1443997172, 52355690707, 21600 tz.transition 1924, 10, :o1, -1427667572, 52359773107, 21600 tz.transition 1925, 6, :o2, -1406672372, 52365021907, 21600 tz.transition 1925, 10, :o1, -1396217972, 52367635507, 21600 tz.transition 1926, 5, :o2, -1376950772, 52372452307, 21600 tz.transition 1926, 10, :o1, -1364768372, 52375497907, 21600 tz.transition 1927, 5, :o2, -1345414772, 52380336307, 21600 tz.transition 1927, 10, :o1, -1333318772, 52383360307, 21600 tz.transition 1928, 5, :o2, -1313792372, 52388241907, 21600 tz.transition 1928, 10, :o1, -1301264372, 52391373907, 21600 tz.transition 1929, 5, :o2, -1282256372, 52396125907, 21600 tz.transition 1929, 10, :o1, -1269814772, 52399236307, 21600 tz.transition 1930, 5, :o2, -1250720372, 52404009907, 21600 tz.transition 1930, 10, :o1, -1238365172, 52407098707, 21600 tz.transition 1931, 5, :o2, -1219184372, 52411893907, 21600 tz.transition 1931, 10, :o1, -1206915572, 52414961107, 21600 tz.transition 1932, 5, :o2, -1186957172, 52419950707, 21600 tz.transition 1932, 10, :o1, -1175465972, 52422823507, 21600 tz.transition 1933, 5, :o2, -1156025972, 52427683507, 21600 tz.transition 1933, 10, :o1, -1143411572, 52430837107, 21600 tz.transition 1934, 5, :o2, -1124489972, 52435567507, 21600 tz.transition 1934, 10, :o1, -1111961972, 52438699507, 21600 tz.transition 1935, 5, :o2, -1092953972, 52443451507, 21600 tz.transition 1935, 10, :o1, -1080512372, 52446561907, 21600 tz.transition 1936, 5, :o2, -1061331572, 52451357107, 21600 tz.transition 1936, 10, :o1, -1049062772, 52454424307, 21600 tz.transition 1937, 5, :o2, -1029190772, 52459392307, 21600 tz.transition 1937, 6, :o3, -1025745572, 52460253607, 21600 tz.transition 1937, 10, :o4, -1017613200, 174874289, 72 tz.transition 1938, 5, :o3, -998259600, 174890417, 72 tz.transition 1938, 10, :o4, -986163600, 174900497, 72 tz.transition 1939, 5, :o3, -966723600, 174916697, 72 tz.transition 1939, 10, :o4, -954109200, 174927209, 72 tz.transition 1940, 5, :o5, -935022000, 174943115, 72 tz.transition 1942, 11, :o6, -857257200, 58335973, 24 tz.transition 1943, 3, :o5, -844556400, 58339501, 24 tz.transition 1943, 10, :o6, -828226800, 58344037, 24 tz.transition 1944, 4, :o5, -812502000, 58348405, 24 tz.transition 1944, 10, :o6, -796777200, 58352773, 24 tz.transition 1945, 4, :o5, -781052400, 58357141, 24 tz.transition 1945, 9, :o6, -766623600, 58361149, 24 tz.transition 1977, 4, :o5, 228877200 tz.transition 1977, 9, :o6, 243997200 tz.transition 1978, 4, :o5, 260326800 tz.transition 1978, 10, :o6, 276051600 tz.transition 1979, 4, :o5, 291776400 tz.transition 1979, 9, :o6, 307501200 tz.transition 1980, 4, :o5, 323830800 tz.transition 1980, 9, :o6, 338950800 tz.transition 1981, 3, :o5, 354675600 tz.transition 1981, 9, :o6, 370400400 tz.transition 1982, 3, :o5, 386125200 tz.transition 1982, 9, :o6, 401850000 tz.transition 1983, 3, :o5, 417574800 tz.transition 1983, 9, :o6, 433299600 tz.transition 1984, 3, :o5, 449024400 tz.transition 1984, 9, :o6, 465354000 tz.transition 1985, 3, :o5, 481078800 tz.transition 1985, 9, :o6, 496803600 tz.transition 1986, 3, :o5, 512528400 tz.transition 1986, 9, :o6, 528253200 tz.transition 1987, 3, :o5, 543978000 tz.transition 1987, 9, :o6, 559702800 tz.transition 1988, 3, :o5, 575427600 tz.transition 1988, 9, :o6, 591152400 tz.transition 1989, 3, :o5, 606877200 tz.transition 1989, 9, :o6, 622602000 tz.transition 1990, 3, :o5, 638326800 tz.transition 1990, 9, :o6, 654656400 tz.transition 1991, 3, :o5, 670381200 tz.transition 1991, 9, :o6, 686106000 tz.transition 1992, 3, :o5, 701830800 tz.transition 1992, 9, :o6, 717555600 tz.transition 1993, 3, :o5, 733280400 tz.transition 1993, 9, :o6, 749005200 tz.transition 1994, 3, :o5, 764730000 tz.transition 1994, 9, :o6, 780454800 tz.transition 1995, 3, :o5, 796179600 tz.transition 1995, 9, :o6, 811904400 tz.transition 1996, 3, :o5, 828234000 tz.transition 1996, 10, :o6, 846378000 tz.transition 1997, 3, :o5, 859683600 tz.transition 1997, 10, :o6, 877827600 tz.transition 1998, 3, :o5, 891133200 tz.transition 1998, 10, :o6, 909277200 tz.transition 1999, 3, :o5, 922582800 tz.transition 1999, 10, :o6, 941331600 tz.transition 2000, 3, :o5, 954032400 tz.transition 2000, 10, :o6, 972781200 tz.transition 2001, 3, :o5, 985482000 tz.transition 2001, 10, :o6, 1004230800 tz.transition 2002, 3, :o5, 1017536400 tz.transition 2002, 10, :o6, 1035680400 tz.transition 2003, 3, :o5, 1048986000 tz.transition 2003, 10, :o6, 1067130000 tz.transition 2004, 3, :o5, 1080435600 tz.transition 2004, 10, :o6, 1099184400 tz.transition 2005, 3, :o5, 1111885200 tz.transition 2005, 10, :o6, 1130634000 tz.transition 2006, 3, :o5, 1143334800 tz.transition 2006, 10, :o6, 1162083600 tz.transition 2007, 3, :o5, 1174784400 tz.transition 2007, 10, :o6, 1193533200 tz.transition 2008, 3, :o5, 1206838800 tz.transition 2008, 10, :o6, 1224982800 tz.transition 2009, 3, :o5, 1238288400 tz.transition 2009, 10, :o6, 1256432400 tz.transition 2010, 3, :o5, 1269738000 tz.transition 2010, 10, :o6, 1288486800 tz.transition 2011, 3, :o5, 1301187600 tz.transition 2011, 10, :o6, 1319936400 tz.transition 2012, 3, :o5, 1332637200 tz.transition 2012, 10, :o6, 1351386000 tz.transition 2013, 3, :o5, 1364691600 tz.transition 2013, 10, :o6, 1382835600 tz.transition 2014, 3, :o5, 1396141200 tz.transition 2014, 10, :o6, 1414285200 tz.transition 2015, 3, :o5, 1427590800 tz.transition 2015, 10, :o6, 1445734800 tz.transition 2016, 3, :o5, 1459040400 tz.transition 2016, 10, :o6, 1477789200 tz.transition 2017, 3, :o5, 1490490000 tz.transition 2017, 10, :o6, 1509238800 tz.transition 2018, 3, :o5, 1521939600 tz.transition 2018, 10, :o6, 1540688400 tz.transition 2019, 3, :o5, 1553994000 tz.transition 2019, 10, :o6, 1572138000 tz.transition 2020, 3, :o5, 1585443600 tz.transition 2020, 10, :o6, 1603587600 tz.transition 2021, 3, :o5, 1616893200 tz.transition 2021, 10, :o6, 1635642000 tz.transition 2022, 3, :o5, 1648342800 tz.transition 2022, 10, :o6, 1667091600 tz.transition 2023, 3, :o5, 1679792400 tz.transition 2023, 10, :o6, 1698541200 tz.transition 2024, 3, :o5, 1711846800 tz.transition 2024, 10, :o6, 1729990800 tz.transition 2025, 3, :o5, 1743296400 tz.transition 2025, 10, :o6, 1761440400 tz.transition 2026, 3, :o5, 1774746000 tz.transition 2026, 10, :o6, 1792890000 tz.transition 2027, 3, :o5, 1806195600 tz.transition 2027, 10, :o6, 1824944400 tz.transition 2028, 3, :o5, 1837645200 tz.transition 2028, 10, :o6, 1856394000 tz.transition 2029, 3, :o5, 1869094800 tz.transition 2029, 10, :o6, 1887843600 tz.transition 2030, 3, :o5, 1901149200 tz.transition 2030, 10, :o6, 1919293200 tz.transition 2031, 3, :o5, 1932598800 tz.transition 2031, 10, :o6, 1950742800 tz.transition 2032, 3, :o5, 1964048400 tz.transition 2032, 10, :o6, 1982797200 tz.transition 2033, 3, :o5, 1995498000 tz.transition 2033, 10, :o6, 2014246800 tz.transition 2034, 3, :o5, 2026947600 tz.transition 2034, 10, :o6, 2045696400 tz.transition 2035, 3, :o5, 2058397200 tz.transition 2035, 10, :o6, 2077146000 tz.transition 2036, 3, :o5, 2090451600 tz.transition 2036, 10, :o6, 2108595600 tz.transition 2037, 3, :o5, 2121901200 tz.transition 2037, 10, :o6, 2140045200 tz.transition 2038, 3, :o5, 2153350800, 59172253, 24 tz.transition 2038, 10, :o6, 2172099600, 59177461, 24 tz.transition 2039, 3, :o5, 2184800400, 59180989, 24 tz.transition 2039, 10, :o6, 2203549200, 59186197, 24 tz.transition 2040, 3, :o5, 2216250000, 59189725, 24 tz.transition 2040, 10, :o6, 2234998800, 59194933, 24 tz.transition 2041, 3, :o5, 2248304400, 59198629, 24 tz.transition 2041, 10, :o6, 2266448400, 59203669, 24 tz.transition 2042, 3, :o5, 2279754000, 59207365, 24 tz.transition 2042, 10, :o6, 2297898000, 59212405, 24 tz.transition 2043, 3, :o5, 2311203600, 59216101, 24 tz.transition 2043, 10, :o6, 2329347600, 59221141, 24 tz.transition 2044, 3, :o5, 2342653200, 59224837, 24 tz.transition 2044, 10, :o6, 2361402000, 59230045, 24 tz.transition 2045, 3, :o5, 2374102800, 59233573, 24 tz.transition 2045, 10, :o6, 2392851600, 59238781, 24 tz.transition 2046, 3, :o5, 2405552400, 59242309, 24 tz.transition 2046, 10, :o6, 2424301200, 59247517, 24 tz.transition 2047, 3, :o5, 2437606800, 59251213, 24 tz.transition 2047, 10, :o6, 2455750800, 59256253, 24 tz.transition 2048, 3, :o5, 2469056400, 59259949, 24 tz.transition 2048, 10, :o6, 2487200400, 59264989, 24 tz.transition 2049, 3, :o5, 2500506000, 59268685, 24 tz.transition 2049, 10, :o6, 2519254800, 59273893, 24 tz.transition 2050, 3, :o5, 2531955600, 59277421, 24 tz.transition 2050, 10, :o6, 2550704400, 59282629, 24 tz.transition 2051, 3, :o5, 2563405200, 59286157, 24 tz.transition 2051, 10, :o6, 2582154000, 59291365, 24 tz.transition 2052, 3, :o5, 2595459600, 59295061, 24 tz.transition 2052, 10, :o6, 2613603600, 59300101, 24 tz.transition 2053, 3, :o5, 2626909200, 59303797, 24 tz.transition 2053, 10, :o6, 2645053200, 59308837, 24 tz.transition 2054, 3, :o5, 2658358800, 59312533, 24 tz.transition 2054, 10, :o6, 2676502800, 59317573, 24 tz.transition 2055, 3, :o5, 2689808400, 59321269, 24 tz.transition 2055, 10, :o6, 2708557200, 59326477, 24 tz.transition 2056, 3, :o5, 2721258000, 59330005, 24 tz.transition 2056, 10, :o6, 2740006800, 59335213, 24 tz.transition 2057, 3, :o5, 2752707600, 59338741, 24 tz.transition 2057, 10, :o6, 2771456400, 59343949, 24 tz.transition 2058, 3, :o5, 2784762000, 59347645, 24 tz.transition 2058, 10, :o6, 2802906000, 59352685, 24 tz.transition 2059, 3, :o5, 2816211600, 59356381, 24 tz.transition 2059, 10, :o6, 2834355600, 59361421, 24 tz.transition 2060, 3, :o5, 2847661200, 59365117, 24 tz.transition 2060, 10, :o6, 2866410000, 59370325, 24 tz.transition 2061, 3, :o5, 2879110800, 59373853, 24 tz.transition 2061, 10, :o6, 2897859600, 59379061, 24 tz.transition 2062, 3, :o5, 2910560400, 59382589, 24 tz.transition 2062, 10, :o6, 2929309200, 59387797, 24 tz.transition 2063, 3, :o5, 2942010000, 59391325, 24 tz.transition 2063, 10, :o6, 2960758800, 59396533, 24 tz.transition 2064, 3, :o5, 2974064400, 59400229, 24 tz.transition 2064, 10, :o6, 2992208400, 59405269, 24 tz.transition 2065, 3, :o5, 3005514000, 59408965, 24 tz.transition 2065, 10, :o6, 3023658000, 59414005, 24 tz.transition 2066, 3, :o5, 3036963600, 59417701, 24 tz.transition 2066, 10, :o6, 3055712400, 59422909, 24 tz.transition 2067, 3, :o5, 3068413200, 59426437, 24 tz.transition 2067, 10, :o6, 3087162000, 59431645, 24 tz.transition 2068, 3, :o5, 3099862800, 59435173, 24 tz.transition 2068, 10, :o6, 3118611600, 59440381, 24 tz.transition 2069, 3, :o5, 3131917200, 59444077, 24 tz.transition 2069, 10, :o6, 3150061200, 59449117, 24 tz.transition 2070, 3, :o5, 3163366800, 59452813, 24 tz.transition 2070, 10, :o6, 3181510800, 59457853, 24 end end end end end end tzinfo-2.0.6/test/tzinfo-data1/tzinfo/data/definitions/Europe/Andorra.rb000066400000000000000000000242571436527530500262430ustar00rootroot00000000000000# encoding: UTF-8 # This file contains data derived from the IANA Time Zone Database # (https://www.iana.org/time-zones). module TZInfo module Data module Definitions module Europe module Andorra include TimezoneDefinition timezone 'Europe/Andorra' do |tz| tz.offset :o0, 364, 0, :LMT tz.offset :o1, 0, 0, :WET tz.offset :o2, 3600, 0, :CET tz.offset :o3, 3600, 3600, :CEST tz.transition 1900, 12, :o1, -2177453164, 52172326709, 21600 tz.transition 1946, 9, :o2, -733881600, 4864187, 2 tz.transition 1985, 3, :o3, 481078800 tz.transition 1985, 9, :o2, 496803600 tz.transition 1986, 3, :o3, 512528400 tz.transition 1986, 9, :o2, 528253200 tz.transition 1987, 3, :o3, 543978000 tz.transition 1987, 9, :o2, 559702800 tz.transition 1988, 3, :o3, 575427600 tz.transition 1988, 9, :o2, 591152400 tz.transition 1989, 3, :o3, 606877200 tz.transition 1989, 9, :o2, 622602000 tz.transition 1990, 3, :o3, 638326800 tz.transition 1990, 9, :o2, 654656400 tz.transition 1991, 3, :o3, 670381200 tz.transition 1991, 9, :o2, 686106000 tz.transition 1992, 3, :o3, 701830800 tz.transition 1992, 9, :o2, 717555600 tz.transition 1993, 3, :o3, 733280400 tz.transition 1993, 9, :o2, 749005200 tz.transition 1994, 3, :o3, 764730000 tz.transition 1994, 9, :o2, 780454800 tz.transition 1995, 3, :o3, 796179600 tz.transition 1995, 9, :o2, 811904400 tz.transition 1996, 3, :o3, 828234000 tz.transition 1996, 10, :o2, 846378000 tz.transition 1997, 3, :o3, 859683600 tz.transition 1997, 10, :o2, 877827600 tz.transition 1998, 3, :o3, 891133200 tz.transition 1998, 10, :o2, 909277200 tz.transition 1999, 3, :o3, 922582800 tz.transition 1999, 10, :o2, 941331600 tz.transition 2000, 3, :o3, 954032400 tz.transition 2000, 10, :o2, 972781200 tz.transition 2001, 3, :o3, 985482000 tz.transition 2001, 10, :o2, 1004230800 tz.transition 2002, 3, :o3, 1017536400 tz.transition 2002, 10, :o2, 1035680400 tz.transition 2003, 3, :o3, 1048986000 tz.transition 2003, 10, :o2, 1067130000 tz.transition 2004, 3, :o3, 1080435600 tz.transition 2004, 10, :o2, 1099184400 tz.transition 2005, 3, :o3, 1111885200 tz.transition 2005, 10, :o2, 1130634000 tz.transition 2006, 3, :o3, 1143334800 tz.transition 2006, 10, :o2, 1162083600 tz.transition 2007, 3, :o3, 1174784400 tz.transition 2007, 10, :o2, 1193533200 tz.transition 2008, 3, :o3, 1206838800 tz.transition 2008, 10, :o2, 1224982800 tz.transition 2009, 3, :o3, 1238288400 tz.transition 2009, 10, :o2, 1256432400 tz.transition 2010, 3, :o3, 1269738000 tz.transition 2010, 10, :o2, 1288486800 tz.transition 2011, 3, :o3, 1301187600 tz.transition 2011, 10, :o2, 1319936400 tz.transition 2012, 3, :o3, 1332637200 tz.transition 2012, 10, :o2, 1351386000 tz.transition 2013, 3, :o3, 1364691600 tz.transition 2013, 10, :o2, 1382835600 tz.transition 2014, 3, :o3, 1396141200 tz.transition 2014, 10, :o2, 1414285200 tz.transition 2015, 3, :o3, 1427590800 tz.transition 2015, 10, :o2, 1445734800 tz.transition 2016, 3, :o3, 1459040400 tz.transition 2016, 10, :o2, 1477789200 tz.transition 2017, 3, :o3, 1490490000 tz.transition 2017, 10, :o2, 1509238800 tz.transition 2018, 3, :o3, 1521939600 tz.transition 2018, 10, :o2, 1540688400 tz.transition 2019, 3, :o3, 1553994000 tz.transition 2019, 10, :o2, 1572138000 tz.transition 2020, 3, :o3, 1585443600 tz.transition 2020, 10, :o2, 1603587600 tz.transition 2021, 3, :o3, 1616893200 tz.transition 2021, 10, :o2, 1635642000 tz.transition 2022, 3, :o3, 1648342800 tz.transition 2022, 10, :o2, 1667091600 tz.transition 2023, 3, :o3, 1679792400 tz.transition 2023, 10, :o2, 1698541200 tz.transition 2024, 3, :o3, 1711846800 tz.transition 2024, 10, :o2, 1729990800 tz.transition 2025, 3, :o3, 1743296400 tz.transition 2025, 10, :o2, 1761440400 tz.transition 2026, 3, :o3, 1774746000 tz.transition 2026, 10, :o2, 1792890000 tz.transition 2027, 3, :o3, 1806195600 tz.transition 2027, 10, :o2, 1824944400 tz.transition 2028, 3, :o3, 1837645200 tz.transition 2028, 10, :o2, 1856394000 tz.transition 2029, 3, :o3, 1869094800 tz.transition 2029, 10, :o2, 1887843600 tz.transition 2030, 3, :o3, 1901149200 tz.transition 2030, 10, :o2, 1919293200 tz.transition 2031, 3, :o3, 1932598800 tz.transition 2031, 10, :o2, 1950742800 tz.transition 2032, 3, :o3, 1964048400 tz.transition 2032, 10, :o2, 1982797200 tz.transition 2033, 3, :o3, 1995498000 tz.transition 2033, 10, :o2, 2014246800 tz.transition 2034, 3, :o3, 2026947600 tz.transition 2034, 10, :o2, 2045696400 tz.transition 2035, 3, :o3, 2058397200 tz.transition 2035, 10, :o2, 2077146000 tz.transition 2036, 3, :o3, 2090451600 tz.transition 2036, 10, :o2, 2108595600 tz.transition 2037, 3, :o3, 2121901200 tz.transition 2037, 10, :o2, 2140045200 tz.transition 2038, 3, :o3, 2153350800, 59172253, 24 tz.transition 2038, 10, :o2, 2172099600, 59177461, 24 tz.transition 2039, 3, :o3, 2184800400, 59180989, 24 tz.transition 2039, 10, :o2, 2203549200, 59186197, 24 tz.transition 2040, 3, :o3, 2216250000, 59189725, 24 tz.transition 2040, 10, :o2, 2234998800, 59194933, 24 tz.transition 2041, 3, :o3, 2248304400, 59198629, 24 tz.transition 2041, 10, :o2, 2266448400, 59203669, 24 tz.transition 2042, 3, :o3, 2279754000, 59207365, 24 tz.transition 2042, 10, :o2, 2297898000, 59212405, 24 tz.transition 2043, 3, :o3, 2311203600, 59216101, 24 tz.transition 2043, 10, :o2, 2329347600, 59221141, 24 tz.transition 2044, 3, :o3, 2342653200, 59224837, 24 tz.transition 2044, 10, :o2, 2361402000, 59230045, 24 tz.transition 2045, 3, :o3, 2374102800, 59233573, 24 tz.transition 2045, 10, :o2, 2392851600, 59238781, 24 tz.transition 2046, 3, :o3, 2405552400, 59242309, 24 tz.transition 2046, 10, :o2, 2424301200, 59247517, 24 tz.transition 2047, 3, :o3, 2437606800, 59251213, 24 tz.transition 2047, 10, :o2, 2455750800, 59256253, 24 tz.transition 2048, 3, :o3, 2469056400, 59259949, 24 tz.transition 2048, 10, :o2, 2487200400, 59264989, 24 tz.transition 2049, 3, :o3, 2500506000, 59268685, 24 tz.transition 2049, 10, :o2, 2519254800, 59273893, 24 tz.transition 2050, 3, :o3, 2531955600, 59277421, 24 tz.transition 2050, 10, :o2, 2550704400, 59282629, 24 tz.transition 2051, 3, :o3, 2563405200, 59286157, 24 tz.transition 2051, 10, :o2, 2582154000, 59291365, 24 tz.transition 2052, 3, :o3, 2595459600, 59295061, 24 tz.transition 2052, 10, :o2, 2613603600, 59300101, 24 tz.transition 2053, 3, :o3, 2626909200, 59303797, 24 tz.transition 2053, 10, :o2, 2645053200, 59308837, 24 tz.transition 2054, 3, :o3, 2658358800, 59312533, 24 tz.transition 2054, 10, :o2, 2676502800, 59317573, 24 tz.transition 2055, 3, :o3, 2689808400, 59321269, 24 tz.transition 2055, 10, :o2, 2708557200, 59326477, 24 tz.transition 2056, 3, :o3, 2721258000, 59330005, 24 tz.transition 2056, 10, :o2, 2740006800, 59335213, 24 tz.transition 2057, 3, :o3, 2752707600, 59338741, 24 tz.transition 2057, 10, :o2, 2771456400, 59343949, 24 tz.transition 2058, 3, :o3, 2784762000, 59347645, 24 tz.transition 2058, 10, :o2, 2802906000, 59352685, 24 tz.transition 2059, 3, :o3, 2816211600, 59356381, 24 tz.transition 2059, 10, :o2, 2834355600, 59361421, 24 tz.transition 2060, 3, :o3, 2847661200, 59365117, 24 tz.transition 2060, 10, :o2, 2866410000, 59370325, 24 tz.transition 2061, 3, :o3, 2879110800, 59373853, 24 tz.transition 2061, 10, :o2, 2897859600, 59379061, 24 tz.transition 2062, 3, :o3, 2910560400, 59382589, 24 tz.transition 2062, 10, :o2, 2929309200, 59387797, 24 tz.transition 2063, 3, :o3, 2942010000, 59391325, 24 tz.transition 2063, 10, :o2, 2960758800, 59396533, 24 tz.transition 2064, 3, :o3, 2974064400, 59400229, 24 tz.transition 2064, 10, :o2, 2992208400, 59405269, 24 tz.transition 2065, 3, :o3, 3005514000, 59408965, 24 tz.transition 2065, 10, :o2, 3023658000, 59414005, 24 tz.transition 2066, 3, :o3, 3036963600, 59417701, 24 tz.transition 2066, 10, :o2, 3055712400, 59422909, 24 tz.transition 2067, 3, :o3, 3068413200, 59426437, 24 tz.transition 2067, 10, :o2, 3087162000, 59431645, 24 tz.transition 2068, 3, :o3, 3099862800, 59435173, 24 tz.transition 2068, 10, :o2, 3118611600, 59440381, 24 tz.transition 2069, 3, :o3, 3131917200, 59444077, 24 tz.transition 2069, 10, :o2, 3150061200, 59449117, 24 tz.transition 2070, 3, :o3, 3163366800, 59452813, 24 tz.transition 2070, 10, :o2, 3181510800, 59457853, 24 end end end end end end tzinfo-2.0.6/test/tzinfo-data1/tzinfo/data/definitions/Europe/London.rb000066400000000000000000000446561436527530500261130ustar00rootroot00000000000000# encoding: UTF-8 # This file contains data derived from the IANA Time Zone Database # (https://www.iana.org/time-zones). module TZInfo module Data module Definitions module Europe module London include TimezoneDefinition timezone 'Europe/London' do |tz| tz.offset :o0, -75, 0, :LMT tz.offset :o1, 0, 0, :GMT tz.offset :o2, 0, 3600, :BST tz.offset :o3, 0, 7200, :BDST tz.offset :o4, 3600, 0, :BST tz.transition 1847, 12, :o1, -3852662325, 2760187969, 1152 tz.transition 1916, 5, :o2, -1691964000, 29052055, 12 tz.transition 1916, 10, :o1, -1680472800, 29053651, 12 tz.transition 1917, 4, :o2, -1664143200, 29055919, 12 tz.transition 1917, 9, :o1, -1650146400, 29057863, 12 tz.transition 1918, 3, :o2, -1633903200, 29060119, 12 tz.transition 1918, 9, :o1, -1617487200, 29062399, 12 tz.transition 1919, 3, :o2, -1601848800, 29064571, 12 tz.transition 1919, 9, :o1, -1586037600, 29066767, 12 tz.transition 1920, 3, :o2, -1570399200, 29068939, 12 tz.transition 1920, 10, :o1, -1552168800, 29071471, 12 tz.transition 1921, 4, :o2, -1538344800, 29073391, 12 tz.transition 1921, 10, :o1, -1522533600, 29075587, 12 tz.transition 1922, 3, :o2, -1507500000, 29077675, 12 tz.transition 1922, 10, :o1, -1490565600, 29080027, 12 tz.transition 1923, 4, :o2, -1473631200, 29082379, 12 tz.transition 1923, 9, :o1, -1460930400, 29084143, 12 tz.transition 1924, 4, :o2, -1442786400, 29086663, 12 tz.transition 1924, 9, :o1, -1428876000, 29088595, 12 tz.transition 1925, 4, :o2, -1410732000, 29091115, 12 tz.transition 1925, 10, :o1, -1396216800, 29093131, 12 tz.transition 1926, 4, :o2, -1379282400, 29095483, 12 tz.transition 1926, 10, :o1, -1364767200, 29097499, 12 tz.transition 1927, 4, :o2, -1348437600, 29099767, 12 tz.transition 1927, 10, :o1, -1333317600, 29101867, 12 tz.transition 1928, 4, :o2, -1315778400, 29104303, 12 tz.transition 1928, 10, :o1, -1301263200, 29106319, 12 tz.transition 1929, 4, :o2, -1284328800, 29108671, 12 tz.transition 1929, 10, :o1, -1269813600, 29110687, 12 tz.transition 1930, 4, :o2, -1253484000, 29112955, 12 tz.transition 1930, 10, :o1, -1238364000, 29115055, 12 tz.transition 1931, 4, :o2, -1221429600, 29117407, 12 tz.transition 1931, 10, :o1, -1206914400, 29119423, 12 tz.transition 1932, 4, :o2, -1189980000, 29121775, 12 tz.transition 1932, 10, :o1, -1175464800, 29123791, 12 tz.transition 1933, 4, :o2, -1159135200, 29126059, 12 tz.transition 1933, 10, :o1, -1143410400, 29128243, 12 tz.transition 1934, 4, :o2, -1126476000, 29130595, 12 tz.transition 1934, 10, :o1, -1111960800, 29132611, 12 tz.transition 1935, 4, :o2, -1095631200, 29134879, 12 tz.transition 1935, 10, :o1, -1080511200, 29136979, 12 tz.transition 1936, 4, :o2, -1063576800, 29139331, 12 tz.transition 1936, 10, :o1, -1049061600, 29141347, 12 tz.transition 1937, 4, :o2, -1032127200, 29143699, 12 tz.transition 1937, 10, :o1, -1017612000, 29145715, 12 tz.transition 1938, 4, :o2, -1001282400, 29147983, 12 tz.transition 1938, 10, :o1, -986162400, 29150083, 12 tz.transition 1939, 4, :o2, -969228000, 29152435, 12 tz.transition 1939, 11, :o1, -950479200, 29155039, 12 tz.transition 1940, 2, :o2, -942012000, 29156215, 12 tz.transition 1941, 5, :o3, -904518000, 58322845, 24 tz.transition 1941, 8, :o2, -896050800, 58325197, 24 tz.transition 1942, 4, :o3, -875487600, 58330909, 24 tz.transition 1942, 8, :o2, -864601200, 58333933, 24 tz.transition 1943, 4, :o3, -844038000, 58339645, 24 tz.transition 1943, 8, :o2, -832546800, 58342837, 24 tz.transition 1944, 4, :o3, -812588400, 58348381, 24 tz.transition 1944, 9, :o2, -798073200, 58352413, 24 tz.transition 1945, 4, :o3, -781052400, 58357141, 24 tz.transition 1945, 7, :o2, -772066800, 58359637, 24 tz.transition 1945, 10, :o1, -764805600, 29180827, 12 tz.transition 1946, 4, :o2, -748476000, 29183095, 12 tz.transition 1946, 10, :o1, -733356000, 29185195, 12 tz.transition 1947, 3, :o2, -719445600, 29187127, 12 tz.transition 1947, 4, :o3, -717030000, 58374925, 24 tz.transition 1947, 8, :o2, -706748400, 58377781, 24 tz.transition 1947, 11, :o1, -699487200, 29189899, 12 tz.transition 1948, 3, :o2, -687996000, 29191495, 12 tz.transition 1948, 10, :o1, -668037600, 29194267, 12 tz.transition 1949, 4, :o2, -654732000, 29196115, 12 tz.transition 1949, 10, :o1, -636588000, 29198635, 12 tz.transition 1950, 4, :o2, -622072800, 29200651, 12 tz.transition 1950, 10, :o1, -605743200, 29202919, 12 tz.transition 1951, 4, :o2, -590623200, 29205019, 12 tz.transition 1951, 10, :o1, -574293600, 29207287, 12 tz.transition 1952, 4, :o2, -558568800, 29209471, 12 tz.transition 1952, 10, :o1, -542239200, 29211739, 12 tz.transition 1953, 4, :o2, -527119200, 29213839, 12 tz.transition 1953, 10, :o1, -512604000, 29215855, 12 tz.transition 1954, 4, :o2, -496274400, 29218123, 12 tz.transition 1954, 10, :o1, -481154400, 29220223, 12 tz.transition 1955, 4, :o2, -464220000, 29222575, 12 tz.transition 1955, 10, :o1, -449704800, 29224591, 12 tz.transition 1956, 4, :o2, -432165600, 29227027, 12 tz.transition 1956, 10, :o1, -417650400, 29229043, 12 tz.transition 1957, 4, :o2, -401320800, 29231311, 12 tz.transition 1957, 10, :o1, -386200800, 29233411, 12 tz.transition 1958, 4, :o2, -369266400, 29235763, 12 tz.transition 1958, 10, :o1, -354751200, 29237779, 12 tz.transition 1959, 4, :o2, -337816800, 29240131, 12 tz.transition 1959, 10, :o1, -323301600, 29242147, 12 tz.transition 1960, 4, :o2, -306972000, 29244415, 12 tz.transition 1960, 10, :o1, -291852000, 29246515, 12 tz.transition 1961, 3, :o2, -276732000, 29248615, 12 tz.transition 1961, 10, :o1, -257983200, 29251219, 12 tz.transition 1962, 3, :o2, -245282400, 29252983, 12 tz.transition 1962, 10, :o1, -226533600, 29255587, 12 tz.transition 1963, 3, :o2, -213228000, 29257435, 12 tz.transition 1963, 10, :o1, -195084000, 29259955, 12 tz.transition 1964, 3, :o2, -182383200, 29261719, 12 tz.transition 1964, 10, :o1, -163634400, 29264323, 12 tz.transition 1965, 3, :o2, -150933600, 29266087, 12 tz.transition 1965, 10, :o1, -132184800, 29268691, 12 tz.transition 1966, 3, :o2, -119484000, 29270455, 12 tz.transition 1966, 10, :o1, -100735200, 29273059, 12 tz.transition 1967, 3, :o2, -88034400, 29274823, 12 tz.transition 1967, 10, :o1, -68680800, 29277511, 12 tz.transition 1968, 2, :o2, -59004000, 29278855, 12 tz.transition 1968, 10, :o4, -37242000, 58563755, 24 tz.transition 1971, 10, :o1, 57722400 tz.transition 1972, 3, :o2, 69818400 tz.transition 1972, 10, :o1, 89172000 tz.transition 1973, 3, :o2, 101268000 tz.transition 1973, 10, :o1, 120621600 tz.transition 1974, 3, :o2, 132717600 tz.transition 1974, 10, :o1, 152071200 tz.transition 1975, 3, :o2, 164167200 tz.transition 1975, 10, :o1, 183520800 tz.transition 1976, 3, :o2, 196221600 tz.transition 1976, 10, :o1, 214970400 tz.transition 1977, 3, :o2, 227671200 tz.transition 1977, 10, :o1, 246420000 tz.transition 1978, 3, :o2, 259120800 tz.transition 1978, 10, :o1, 278474400 tz.transition 1979, 3, :o2, 290570400 tz.transition 1979, 10, :o1, 309924000 tz.transition 1980, 3, :o2, 322020000 tz.transition 1980, 10, :o1, 341373600 tz.transition 1981, 3, :o2, 354675600 tz.transition 1981, 10, :o1, 372819600 tz.transition 1982, 3, :o2, 386125200 tz.transition 1982, 10, :o1, 404269200 tz.transition 1983, 3, :o2, 417574800 tz.transition 1983, 10, :o1, 435718800 tz.transition 1984, 3, :o2, 449024400 tz.transition 1984, 10, :o1, 467773200 tz.transition 1985, 3, :o2, 481078800 tz.transition 1985, 10, :o1, 499222800 tz.transition 1986, 3, :o2, 512528400 tz.transition 1986, 10, :o1, 530672400 tz.transition 1987, 3, :o2, 543978000 tz.transition 1987, 10, :o1, 562122000 tz.transition 1988, 3, :o2, 575427600 tz.transition 1988, 10, :o1, 593571600 tz.transition 1989, 3, :o2, 606877200 tz.transition 1989, 10, :o1, 625626000 tz.transition 1990, 3, :o2, 638326800 tz.transition 1990, 10, :o1, 657075600 tz.transition 1991, 3, :o2, 670381200 tz.transition 1991, 10, :o1, 688525200 tz.transition 1992, 3, :o2, 701830800 tz.transition 1992, 10, :o1, 719974800 tz.transition 1993, 3, :o2, 733280400 tz.transition 1993, 10, :o1, 751424400 tz.transition 1994, 3, :o2, 764730000 tz.transition 1994, 10, :o1, 782874000 tz.transition 1995, 3, :o2, 796179600 tz.transition 1995, 10, :o1, 814323600 tz.transition 1996, 3, :o2, 828234000 tz.transition 1996, 10, :o1, 846378000 tz.transition 1997, 3, :o2, 859683600 tz.transition 1997, 10, :o1, 877827600 tz.transition 1998, 3, :o2, 891133200 tz.transition 1998, 10, :o1, 909277200 tz.transition 1999, 3, :o2, 922582800 tz.transition 1999, 10, :o1, 941331600 tz.transition 2000, 3, :o2, 954032400 tz.transition 2000, 10, :o1, 972781200 tz.transition 2001, 3, :o2, 985482000 tz.transition 2001, 10, :o1, 1004230800 tz.transition 2002, 3, :o2, 1017536400 tz.transition 2002, 10, :o1, 1035680400 tz.transition 2003, 3, :o2, 1048986000 tz.transition 2003, 10, :o1, 1067130000 tz.transition 2004, 3, :o2, 1080435600 tz.transition 2004, 10, :o1, 1099184400 tz.transition 2005, 3, :o2, 1111885200 tz.transition 2005, 10, :o1, 1130634000 tz.transition 2006, 3, :o2, 1143334800 tz.transition 2006, 10, :o1, 1162083600 tz.transition 2007, 3, :o2, 1174784400 tz.transition 2007, 10, :o1, 1193533200 tz.transition 2008, 3, :o2, 1206838800 tz.transition 2008, 10, :o1, 1224982800 tz.transition 2009, 3, :o2, 1238288400 tz.transition 2009, 10, :o1, 1256432400 tz.transition 2010, 3, :o2, 1269738000 tz.transition 2010, 10, :o1, 1288486800 tz.transition 2011, 3, :o2, 1301187600 tz.transition 2011, 10, :o1, 1319936400 tz.transition 2012, 3, :o2, 1332637200 tz.transition 2012, 10, :o1, 1351386000 tz.transition 2013, 3, :o2, 1364691600 tz.transition 2013, 10, :o1, 1382835600 tz.transition 2014, 3, :o2, 1396141200 tz.transition 2014, 10, :o1, 1414285200 tz.transition 2015, 3, :o2, 1427590800 tz.transition 2015, 10, :o1, 1445734800 tz.transition 2016, 3, :o2, 1459040400 tz.transition 2016, 10, :o1, 1477789200 tz.transition 2017, 3, :o2, 1490490000 tz.transition 2017, 10, :o1, 1509238800 tz.transition 2018, 3, :o2, 1521939600 tz.transition 2018, 10, :o1, 1540688400 tz.transition 2019, 3, :o2, 1553994000 tz.transition 2019, 10, :o1, 1572138000 tz.transition 2020, 3, :o2, 1585443600 tz.transition 2020, 10, :o1, 1603587600 tz.transition 2021, 3, :o2, 1616893200 tz.transition 2021, 10, :o1, 1635642000 tz.transition 2022, 3, :o2, 1648342800 tz.transition 2022, 10, :o1, 1667091600 tz.transition 2023, 3, :o2, 1679792400 tz.transition 2023, 10, :o1, 1698541200 tz.transition 2024, 3, :o2, 1711846800 tz.transition 2024, 10, :o1, 1729990800 tz.transition 2025, 3, :o2, 1743296400 tz.transition 2025, 10, :o1, 1761440400 tz.transition 2026, 3, :o2, 1774746000 tz.transition 2026, 10, :o1, 1792890000 tz.transition 2027, 3, :o2, 1806195600 tz.transition 2027, 10, :o1, 1824944400 tz.transition 2028, 3, :o2, 1837645200 tz.transition 2028, 10, :o1, 1856394000 tz.transition 2029, 3, :o2, 1869094800 tz.transition 2029, 10, :o1, 1887843600 tz.transition 2030, 3, :o2, 1901149200 tz.transition 2030, 10, :o1, 1919293200 tz.transition 2031, 3, :o2, 1932598800 tz.transition 2031, 10, :o1, 1950742800 tz.transition 2032, 3, :o2, 1964048400 tz.transition 2032, 10, :o1, 1982797200 tz.transition 2033, 3, :o2, 1995498000 tz.transition 2033, 10, :o1, 2014246800 tz.transition 2034, 3, :o2, 2026947600 tz.transition 2034, 10, :o1, 2045696400 tz.transition 2035, 3, :o2, 2058397200 tz.transition 2035, 10, :o1, 2077146000 tz.transition 2036, 3, :o2, 2090451600 tz.transition 2036, 10, :o1, 2108595600 tz.transition 2037, 3, :o2, 2121901200 tz.transition 2037, 10, :o1, 2140045200 tz.transition 2038, 3, :o2, 2153350800, 59172253, 24 tz.transition 2038, 10, :o1, 2172099600, 59177461, 24 tz.transition 2039, 3, :o2, 2184800400, 59180989, 24 tz.transition 2039, 10, :o1, 2203549200, 59186197, 24 tz.transition 2040, 3, :o2, 2216250000, 59189725, 24 tz.transition 2040, 10, :o1, 2234998800, 59194933, 24 tz.transition 2041, 3, :o2, 2248304400, 59198629, 24 tz.transition 2041, 10, :o1, 2266448400, 59203669, 24 tz.transition 2042, 3, :o2, 2279754000, 59207365, 24 tz.transition 2042, 10, :o1, 2297898000, 59212405, 24 tz.transition 2043, 3, :o2, 2311203600, 59216101, 24 tz.transition 2043, 10, :o1, 2329347600, 59221141, 24 tz.transition 2044, 3, :o2, 2342653200, 59224837, 24 tz.transition 2044, 10, :o1, 2361402000, 59230045, 24 tz.transition 2045, 3, :o2, 2374102800, 59233573, 24 tz.transition 2045, 10, :o1, 2392851600, 59238781, 24 tz.transition 2046, 3, :o2, 2405552400, 59242309, 24 tz.transition 2046, 10, :o1, 2424301200, 59247517, 24 tz.transition 2047, 3, :o2, 2437606800, 59251213, 24 tz.transition 2047, 10, :o1, 2455750800, 59256253, 24 tz.transition 2048, 3, :o2, 2469056400, 59259949, 24 tz.transition 2048, 10, :o1, 2487200400, 59264989, 24 tz.transition 2049, 3, :o2, 2500506000, 59268685, 24 tz.transition 2049, 10, :o1, 2519254800, 59273893, 24 tz.transition 2050, 3, :o2, 2531955600, 59277421, 24 tz.transition 2050, 10, :o1, 2550704400, 59282629, 24 tz.transition 2051, 3, :o2, 2563405200, 59286157, 24 tz.transition 2051, 10, :o1, 2582154000, 59291365, 24 tz.transition 2052, 3, :o2, 2595459600, 59295061, 24 tz.transition 2052, 10, :o1, 2613603600, 59300101, 24 tz.transition 2053, 3, :o2, 2626909200, 59303797, 24 tz.transition 2053, 10, :o1, 2645053200, 59308837, 24 tz.transition 2054, 3, :o2, 2658358800, 59312533, 24 tz.transition 2054, 10, :o1, 2676502800, 59317573, 24 tz.transition 2055, 3, :o2, 2689808400, 59321269, 24 tz.transition 2055, 10, :o1, 2708557200, 59326477, 24 tz.transition 2056, 3, :o2, 2721258000, 59330005, 24 tz.transition 2056, 10, :o1, 2740006800, 59335213, 24 tz.transition 2057, 3, :o2, 2752707600, 59338741, 24 tz.transition 2057, 10, :o1, 2771456400, 59343949, 24 tz.transition 2058, 3, :o2, 2784762000, 59347645, 24 tz.transition 2058, 10, :o1, 2802906000, 59352685, 24 tz.transition 2059, 3, :o2, 2816211600, 59356381, 24 tz.transition 2059, 10, :o1, 2834355600, 59361421, 24 tz.transition 2060, 3, :o2, 2847661200, 59365117, 24 tz.transition 2060, 10, :o1, 2866410000, 59370325, 24 tz.transition 2061, 3, :o2, 2879110800, 59373853, 24 tz.transition 2061, 10, :o1, 2897859600, 59379061, 24 tz.transition 2062, 3, :o2, 2910560400, 59382589, 24 tz.transition 2062, 10, :o1, 2929309200, 59387797, 24 tz.transition 2063, 3, :o2, 2942010000, 59391325, 24 tz.transition 2063, 10, :o1, 2960758800, 59396533, 24 tz.transition 2064, 3, :o2, 2974064400, 59400229, 24 tz.transition 2064, 10, :o1, 2992208400, 59405269, 24 tz.transition 2065, 3, :o2, 3005514000, 59408965, 24 tz.transition 2065, 10, :o1, 3023658000, 59414005, 24 tz.transition 2066, 3, :o2, 3036963600, 59417701, 24 tz.transition 2066, 10, :o1, 3055712400, 59422909, 24 tz.transition 2067, 3, :o2, 3068413200, 59426437, 24 tz.transition 2067, 10, :o1, 3087162000, 59431645, 24 tz.transition 2068, 3, :o2, 3099862800, 59435173, 24 tz.transition 2068, 10, :o1, 3118611600, 59440381, 24 tz.transition 2069, 3, :o2, 3131917200, 59444077, 24 tz.transition 2069, 10, :o1, 3150061200, 59449117, 24 tz.transition 2070, 3, :o2, 3163366800, 59452813, 24 tz.transition 2070, 10, :o1, 3181510800, 59457853, 24 end end end end end end tzinfo-2.0.6/test/tzinfo-data1/tzinfo/data/definitions/Europe/Paris.rb000066400000000000000000000356661436527530500257410ustar00rootroot00000000000000# encoding: UTF-8 # This file contains data derived from the IANA Time Zone Database # (https://www.iana.org/time-zones). module TZInfo module Data module Definitions module Europe module Paris include TimezoneDefinition timezone 'Europe/Paris' do |tz| tz.offset :o0, 561, 0, :LMT tz.offset :o1, 561, 0, :PMT tz.offset :o2, 0, 0, :WET tz.offset :o3, 0, 3600, :WEST tz.offset :o4, 3600, 3600, :CEST tz.offset :o5, 3600, 0, :CET tz.offset :o6, 0, 7200, :WEMT tz.transition 1891, 3, :o1, -2486592561, 69460055813, 28800 tz.transition 1911, 3, :o2, -1855958961, 69670267013, 28800 tz.transition 1916, 6, :o3, -1689814800, 58104707, 24 tz.transition 1916, 10, :o2, -1680397200, 58107323, 24 tz.transition 1917, 3, :o3, -1665363600, 58111499, 24 tz.transition 1917, 10, :o2, -1648342800, 58116227, 24 tz.transition 1918, 3, :o3, -1635123600, 58119899, 24 tz.transition 1918, 10, :o2, -1616893200, 58124963, 24 tz.transition 1919, 3, :o3, -1604278800, 58128467, 24 tz.transition 1919, 10, :o2, -1585443600, 58133699, 24 tz.transition 1920, 2, :o3, -1574038800, 58136867, 24 tz.transition 1920, 10, :o2, -1552266000, 58142915, 24 tz.transition 1921, 3, :o3, -1539997200, 58146323, 24 tz.transition 1921, 10, :o2, -1520557200, 58151723, 24 tz.transition 1922, 3, :o3, -1507510800, 58155347, 24 tz.transition 1922, 10, :o2, -1490576400, 58160051, 24 tz.transition 1923, 5, :o3, -1470618000, 58165595, 24 tz.transition 1923, 10, :o2, -1459126800, 58168787, 24 tz.transition 1924, 3, :o3, -1444006800, 58172987, 24 tz.transition 1924, 10, :o2, -1427677200, 58177523, 24 tz.transition 1925, 4, :o3, -1411952400, 58181891, 24 tz.transition 1925, 10, :o2, -1396227600, 58186259, 24 tz.transition 1926, 4, :o3, -1379293200, 58190963, 24 tz.transition 1926, 10, :o2, -1364778000, 58194995, 24 tz.transition 1927, 4, :o3, -1348448400, 58199531, 24 tz.transition 1927, 10, :o2, -1333328400, 58203731, 24 tz.transition 1928, 4, :o3, -1316394000, 58208435, 24 tz.transition 1928, 10, :o2, -1301274000, 58212635, 24 tz.transition 1929, 4, :o3, -1284339600, 58217339, 24 tz.transition 1929, 10, :o2, -1269824400, 58221371, 24 tz.transition 1930, 4, :o3, -1253494800, 58225907, 24 tz.transition 1930, 10, :o2, -1238374800, 58230107, 24 tz.transition 1931, 4, :o3, -1221440400, 58234811, 24 tz.transition 1931, 10, :o2, -1206925200, 58238843, 24 tz.transition 1932, 4, :o3, -1191200400, 58243211, 24 tz.transition 1932, 10, :o2, -1175475600, 58247579, 24 tz.transition 1933, 3, :o3, -1160355600, 58251779, 24 tz.transition 1933, 10, :o2, -1143421200, 58256483, 24 tz.transition 1934, 4, :o3, -1127696400, 58260851, 24 tz.transition 1934, 10, :o2, -1111971600, 58265219, 24 tz.transition 1935, 3, :o3, -1096851600, 58269419, 24 tz.transition 1935, 10, :o2, -1080522000, 58273955, 24 tz.transition 1936, 4, :o3, -1063587600, 58278659, 24 tz.transition 1936, 10, :o2, -1049072400, 58282691, 24 tz.transition 1937, 4, :o3, -1033347600, 58287059, 24 tz.transition 1937, 10, :o2, -1017622800, 58291427, 24 tz.transition 1938, 3, :o3, -1002502800, 58295627, 24 tz.transition 1938, 10, :o2, -986173200, 58300163, 24 tz.transition 1939, 4, :o3, -969238800, 58304867, 24 tz.transition 1939, 11, :o2, -950490000, 58310075, 24 tz.transition 1940, 2, :o3, -942012000, 29156215, 12 tz.transition 1940, 6, :o4, -932436000, 29157545, 12 tz.transition 1942, 11, :o5, -857257200, 58335973, 24 tz.transition 1943, 3, :o4, -844556400, 58339501, 24 tz.transition 1943, 10, :o5, -828226800, 58344037, 24 tz.transition 1944, 4, :o4, -812502000, 58348405, 24 tz.transition 1944, 8, :o6, -800071200, 29175929, 12 tz.transition 1944, 10, :o3, -796266000, 58352915, 24 tz.transition 1945, 4, :o6, -781052400, 58357141, 24 tz.transition 1945, 9, :o5, -766623600, 58361149, 24 tz.transition 1976, 3, :o4, 196819200 tz.transition 1976, 9, :o5, 212540400 tz.transition 1977, 4, :o4, 228877200 tz.transition 1977, 9, :o5, 243997200 tz.transition 1978, 4, :o4, 260326800 tz.transition 1978, 10, :o5, 276051600 tz.transition 1979, 4, :o4, 291776400 tz.transition 1979, 9, :o5, 307501200 tz.transition 1980, 4, :o4, 323830800 tz.transition 1980, 9, :o5, 338950800 tz.transition 1981, 3, :o4, 354675600 tz.transition 1981, 9, :o5, 370400400 tz.transition 1982, 3, :o4, 386125200 tz.transition 1982, 9, :o5, 401850000 tz.transition 1983, 3, :o4, 417574800 tz.transition 1983, 9, :o5, 433299600 tz.transition 1984, 3, :o4, 449024400 tz.transition 1984, 9, :o5, 465354000 tz.transition 1985, 3, :o4, 481078800 tz.transition 1985, 9, :o5, 496803600 tz.transition 1986, 3, :o4, 512528400 tz.transition 1986, 9, :o5, 528253200 tz.transition 1987, 3, :o4, 543978000 tz.transition 1987, 9, :o5, 559702800 tz.transition 1988, 3, :o4, 575427600 tz.transition 1988, 9, :o5, 591152400 tz.transition 1989, 3, :o4, 606877200 tz.transition 1989, 9, :o5, 622602000 tz.transition 1990, 3, :o4, 638326800 tz.transition 1990, 9, :o5, 654656400 tz.transition 1991, 3, :o4, 670381200 tz.transition 1991, 9, :o5, 686106000 tz.transition 1992, 3, :o4, 701830800 tz.transition 1992, 9, :o5, 717555600 tz.transition 1993, 3, :o4, 733280400 tz.transition 1993, 9, :o5, 749005200 tz.transition 1994, 3, :o4, 764730000 tz.transition 1994, 9, :o5, 780454800 tz.transition 1995, 3, :o4, 796179600 tz.transition 1995, 9, :o5, 811904400 tz.transition 1996, 3, :o4, 828234000 tz.transition 1996, 10, :o5, 846378000 tz.transition 1997, 3, :o4, 859683600 tz.transition 1997, 10, :o5, 877827600 tz.transition 1998, 3, :o4, 891133200 tz.transition 1998, 10, :o5, 909277200 tz.transition 1999, 3, :o4, 922582800 tz.transition 1999, 10, :o5, 941331600 tz.transition 2000, 3, :o4, 954032400 tz.transition 2000, 10, :o5, 972781200 tz.transition 2001, 3, :o4, 985482000 tz.transition 2001, 10, :o5, 1004230800 tz.transition 2002, 3, :o4, 1017536400 tz.transition 2002, 10, :o5, 1035680400 tz.transition 2003, 3, :o4, 1048986000 tz.transition 2003, 10, :o5, 1067130000 tz.transition 2004, 3, :o4, 1080435600 tz.transition 2004, 10, :o5, 1099184400 tz.transition 2005, 3, :o4, 1111885200 tz.transition 2005, 10, :o5, 1130634000 tz.transition 2006, 3, :o4, 1143334800 tz.transition 2006, 10, :o5, 1162083600 tz.transition 2007, 3, :o4, 1174784400 tz.transition 2007, 10, :o5, 1193533200 tz.transition 2008, 3, :o4, 1206838800 tz.transition 2008, 10, :o5, 1224982800 tz.transition 2009, 3, :o4, 1238288400 tz.transition 2009, 10, :o5, 1256432400 tz.transition 2010, 3, :o4, 1269738000 tz.transition 2010, 10, :o5, 1288486800 tz.transition 2011, 3, :o4, 1301187600 tz.transition 2011, 10, :o5, 1319936400 tz.transition 2012, 3, :o4, 1332637200 tz.transition 2012, 10, :o5, 1351386000 tz.transition 2013, 3, :o4, 1364691600 tz.transition 2013, 10, :o5, 1382835600 tz.transition 2014, 3, :o4, 1396141200 tz.transition 2014, 10, :o5, 1414285200 tz.transition 2015, 3, :o4, 1427590800 tz.transition 2015, 10, :o5, 1445734800 tz.transition 2016, 3, :o4, 1459040400 tz.transition 2016, 10, :o5, 1477789200 tz.transition 2017, 3, :o4, 1490490000 tz.transition 2017, 10, :o5, 1509238800 tz.transition 2018, 3, :o4, 1521939600 tz.transition 2018, 10, :o5, 1540688400 tz.transition 2019, 3, :o4, 1553994000 tz.transition 2019, 10, :o5, 1572138000 tz.transition 2020, 3, :o4, 1585443600 tz.transition 2020, 10, :o5, 1603587600 tz.transition 2021, 3, :o4, 1616893200 tz.transition 2021, 10, :o5, 1635642000 tz.transition 2022, 3, :o4, 1648342800 tz.transition 2022, 10, :o5, 1667091600 tz.transition 2023, 3, :o4, 1679792400 tz.transition 2023, 10, :o5, 1698541200 tz.transition 2024, 3, :o4, 1711846800 tz.transition 2024, 10, :o5, 1729990800 tz.transition 2025, 3, :o4, 1743296400 tz.transition 2025, 10, :o5, 1761440400 tz.transition 2026, 3, :o4, 1774746000 tz.transition 2026, 10, :o5, 1792890000 tz.transition 2027, 3, :o4, 1806195600 tz.transition 2027, 10, :o5, 1824944400 tz.transition 2028, 3, :o4, 1837645200 tz.transition 2028, 10, :o5, 1856394000 tz.transition 2029, 3, :o4, 1869094800 tz.transition 2029, 10, :o5, 1887843600 tz.transition 2030, 3, :o4, 1901149200 tz.transition 2030, 10, :o5, 1919293200 tz.transition 2031, 3, :o4, 1932598800 tz.transition 2031, 10, :o5, 1950742800 tz.transition 2032, 3, :o4, 1964048400 tz.transition 2032, 10, :o5, 1982797200 tz.transition 2033, 3, :o4, 1995498000 tz.transition 2033, 10, :o5, 2014246800 tz.transition 2034, 3, :o4, 2026947600 tz.transition 2034, 10, :o5, 2045696400 tz.transition 2035, 3, :o4, 2058397200 tz.transition 2035, 10, :o5, 2077146000 tz.transition 2036, 3, :o4, 2090451600 tz.transition 2036, 10, :o5, 2108595600 tz.transition 2037, 3, :o4, 2121901200 tz.transition 2037, 10, :o5, 2140045200 tz.transition 2038, 3, :o4, 2153350800, 59172253, 24 tz.transition 2038, 10, :o5, 2172099600, 59177461, 24 tz.transition 2039, 3, :o4, 2184800400, 59180989, 24 tz.transition 2039, 10, :o5, 2203549200, 59186197, 24 tz.transition 2040, 3, :o4, 2216250000, 59189725, 24 tz.transition 2040, 10, :o5, 2234998800, 59194933, 24 tz.transition 2041, 3, :o4, 2248304400, 59198629, 24 tz.transition 2041, 10, :o5, 2266448400, 59203669, 24 tz.transition 2042, 3, :o4, 2279754000, 59207365, 24 tz.transition 2042, 10, :o5, 2297898000, 59212405, 24 tz.transition 2043, 3, :o4, 2311203600, 59216101, 24 tz.transition 2043, 10, :o5, 2329347600, 59221141, 24 tz.transition 2044, 3, :o4, 2342653200, 59224837, 24 tz.transition 2044, 10, :o5, 2361402000, 59230045, 24 tz.transition 2045, 3, :o4, 2374102800, 59233573, 24 tz.transition 2045, 10, :o5, 2392851600, 59238781, 24 tz.transition 2046, 3, :o4, 2405552400, 59242309, 24 tz.transition 2046, 10, :o5, 2424301200, 59247517, 24 tz.transition 2047, 3, :o4, 2437606800, 59251213, 24 tz.transition 2047, 10, :o5, 2455750800, 59256253, 24 tz.transition 2048, 3, :o4, 2469056400, 59259949, 24 tz.transition 2048, 10, :o5, 2487200400, 59264989, 24 tz.transition 2049, 3, :o4, 2500506000, 59268685, 24 tz.transition 2049, 10, :o5, 2519254800, 59273893, 24 tz.transition 2050, 3, :o4, 2531955600, 59277421, 24 tz.transition 2050, 10, :o5, 2550704400, 59282629, 24 tz.transition 2051, 3, :o4, 2563405200, 59286157, 24 tz.transition 2051, 10, :o5, 2582154000, 59291365, 24 tz.transition 2052, 3, :o4, 2595459600, 59295061, 24 tz.transition 2052, 10, :o5, 2613603600, 59300101, 24 tz.transition 2053, 3, :o4, 2626909200, 59303797, 24 tz.transition 2053, 10, :o5, 2645053200, 59308837, 24 tz.transition 2054, 3, :o4, 2658358800, 59312533, 24 tz.transition 2054, 10, :o5, 2676502800, 59317573, 24 tz.transition 2055, 3, :o4, 2689808400, 59321269, 24 tz.transition 2055, 10, :o5, 2708557200, 59326477, 24 tz.transition 2056, 3, :o4, 2721258000, 59330005, 24 tz.transition 2056, 10, :o5, 2740006800, 59335213, 24 tz.transition 2057, 3, :o4, 2752707600, 59338741, 24 tz.transition 2057, 10, :o5, 2771456400, 59343949, 24 tz.transition 2058, 3, :o4, 2784762000, 59347645, 24 tz.transition 2058, 10, :o5, 2802906000, 59352685, 24 tz.transition 2059, 3, :o4, 2816211600, 59356381, 24 tz.transition 2059, 10, :o5, 2834355600, 59361421, 24 tz.transition 2060, 3, :o4, 2847661200, 59365117, 24 tz.transition 2060, 10, :o5, 2866410000, 59370325, 24 tz.transition 2061, 3, :o4, 2879110800, 59373853, 24 tz.transition 2061, 10, :o5, 2897859600, 59379061, 24 tz.transition 2062, 3, :o4, 2910560400, 59382589, 24 tz.transition 2062, 10, :o5, 2929309200, 59387797, 24 tz.transition 2063, 3, :o4, 2942010000, 59391325, 24 tz.transition 2063, 10, :o5, 2960758800, 59396533, 24 tz.transition 2064, 3, :o4, 2974064400, 59400229, 24 tz.transition 2064, 10, :o5, 2992208400, 59405269, 24 tz.transition 2065, 3, :o4, 3005514000, 59408965, 24 tz.transition 2065, 10, :o5, 3023658000, 59414005, 24 tz.transition 2066, 3, :o4, 3036963600, 59417701, 24 tz.transition 2066, 10, :o5, 3055712400, 59422909, 24 tz.transition 2067, 3, :o4, 3068413200, 59426437, 24 tz.transition 2067, 10, :o5, 3087162000, 59431645, 24 tz.transition 2068, 3, :o4, 3099862800, 59435173, 24 tz.transition 2068, 10, :o5, 3118611600, 59440381, 24 tz.transition 2069, 3, :o4, 3131917200, 59444077, 24 tz.transition 2069, 10, :o5, 3150061200, 59449117, 24 tz.transition 2070, 3, :o4, 3163366800, 59452813, 24 tz.transition 2070, 10, :o5, 3181510800, 59457853, 24 end end end end end end tzinfo-2.0.6/test/tzinfo-data1/tzinfo/data/definitions/Europe/Prague.rb000066400000000000000000000305461436527530500260760ustar00rootroot00000000000000# encoding: UTF-8 # This file contains data derived from the IANA Time Zone Database # (https://www.iana.org/time-zones). module TZInfo module Data module Definitions module Europe module Prague include TimezoneDefinition timezone 'Europe/Prague' do |tz| tz.offset :o0, 3464, 0, :LMT tz.offset :o1, 3464, 0, :PMT tz.offset :o2, 3600, 0, :CET tz.offset :o3, 3600, 3600, :CEST tz.offset :o4, 3600, -3600, :GMT tz.transition 1849, 12, :o1, -3786829064, 25884991367, 10800 tz.transition 1891, 9, :o2, -2469401864, 26049669767, 10800 tz.transition 1916, 4, :o3, -1693706400, 29051813, 12 tz.transition 1916, 9, :o2, -1680483600, 58107299, 24 tz.transition 1917, 4, :o3, -1663455600, 58112029, 24 tz.transition 1917, 9, :o2, -1650150000, 58115725, 24 tz.transition 1918, 4, :o3, -1632006000, 58120765, 24 tz.transition 1918, 9, :o2, -1618700400, 58124461, 24 tz.transition 1940, 4, :o3, -938905200, 58313293, 24 tz.transition 1942, 11, :o2, -857257200, 58335973, 24 tz.transition 1943, 3, :o3, -844556400, 58339501, 24 tz.transition 1943, 10, :o2, -828226800, 58344037, 24 tz.transition 1944, 4, :o3, -812502000, 58348405, 24 tz.transition 1944, 10, :o2, -796777200, 58352773, 24 tz.transition 1945, 4, :o3, -781052400, 58357141, 24 tz.transition 1945, 10, :o2, -765327600, 58361509, 24 tz.transition 1946, 5, :o3, -746578800, 58366717, 24 tz.transition 1946, 10, :o2, -733359600, 58370389, 24 tz.transition 1946, 12, :o4, -728517600, 29185867, 12 tz.transition 1947, 2, :o2, -721260000, 29186875, 12 tz.transition 1947, 4, :o3, -716425200, 58375093, 24 tz.transition 1947, 10, :o2, -701910000, 58379125, 24 tz.transition 1948, 4, :o3, -684975600, 58383829, 24 tz.transition 1948, 10, :o2, -670460400, 58387861, 24 tz.transition 1949, 4, :o3, -654217200, 58392373, 24 tz.transition 1949, 10, :o2, -639010800, 58396597, 24 tz.transition 1979, 4, :o3, 291776400 tz.transition 1979, 9, :o2, 307501200 tz.transition 1980, 4, :o3, 323830800 tz.transition 1980, 9, :o2, 338950800 tz.transition 1981, 3, :o3, 354675600 tz.transition 1981, 9, :o2, 370400400 tz.transition 1982, 3, :o3, 386125200 tz.transition 1982, 9, :o2, 401850000 tz.transition 1983, 3, :o3, 417574800 tz.transition 1983, 9, :o2, 433299600 tz.transition 1984, 3, :o3, 449024400 tz.transition 1984, 9, :o2, 465354000 tz.transition 1985, 3, :o3, 481078800 tz.transition 1985, 9, :o2, 496803600 tz.transition 1986, 3, :o3, 512528400 tz.transition 1986, 9, :o2, 528253200 tz.transition 1987, 3, :o3, 543978000 tz.transition 1987, 9, :o2, 559702800 tz.transition 1988, 3, :o3, 575427600 tz.transition 1988, 9, :o2, 591152400 tz.transition 1989, 3, :o3, 606877200 tz.transition 1989, 9, :o2, 622602000 tz.transition 1990, 3, :o3, 638326800 tz.transition 1990, 9, :o2, 654656400 tz.transition 1991, 3, :o3, 670381200 tz.transition 1991, 9, :o2, 686106000 tz.transition 1992, 3, :o3, 701830800 tz.transition 1992, 9, :o2, 717555600 tz.transition 1993, 3, :o3, 733280400 tz.transition 1993, 9, :o2, 749005200 tz.transition 1994, 3, :o3, 764730000 tz.transition 1994, 9, :o2, 780454800 tz.transition 1995, 3, :o3, 796179600 tz.transition 1995, 9, :o2, 811904400 tz.transition 1996, 3, :o3, 828234000 tz.transition 1996, 10, :o2, 846378000 tz.transition 1997, 3, :o3, 859683600 tz.transition 1997, 10, :o2, 877827600 tz.transition 1998, 3, :o3, 891133200 tz.transition 1998, 10, :o2, 909277200 tz.transition 1999, 3, :o3, 922582800 tz.transition 1999, 10, :o2, 941331600 tz.transition 2000, 3, :o3, 954032400 tz.transition 2000, 10, :o2, 972781200 tz.transition 2001, 3, :o3, 985482000 tz.transition 2001, 10, :o2, 1004230800 tz.transition 2002, 3, :o3, 1017536400 tz.transition 2002, 10, :o2, 1035680400 tz.transition 2003, 3, :o3, 1048986000 tz.transition 2003, 10, :o2, 1067130000 tz.transition 2004, 3, :o3, 1080435600 tz.transition 2004, 10, :o2, 1099184400 tz.transition 2005, 3, :o3, 1111885200 tz.transition 2005, 10, :o2, 1130634000 tz.transition 2006, 3, :o3, 1143334800 tz.transition 2006, 10, :o2, 1162083600 tz.transition 2007, 3, :o3, 1174784400 tz.transition 2007, 10, :o2, 1193533200 tz.transition 2008, 3, :o3, 1206838800 tz.transition 2008, 10, :o2, 1224982800 tz.transition 2009, 3, :o3, 1238288400 tz.transition 2009, 10, :o2, 1256432400 tz.transition 2010, 3, :o3, 1269738000 tz.transition 2010, 10, :o2, 1288486800 tz.transition 2011, 3, :o3, 1301187600 tz.transition 2011, 10, :o2, 1319936400 tz.transition 2012, 3, :o3, 1332637200 tz.transition 2012, 10, :o2, 1351386000 tz.transition 2013, 3, :o3, 1364691600 tz.transition 2013, 10, :o2, 1382835600 tz.transition 2014, 3, :o3, 1396141200 tz.transition 2014, 10, :o2, 1414285200 tz.transition 2015, 3, :o3, 1427590800 tz.transition 2015, 10, :o2, 1445734800 tz.transition 2016, 3, :o3, 1459040400 tz.transition 2016, 10, :o2, 1477789200 tz.transition 2017, 3, :o3, 1490490000 tz.transition 2017, 10, :o2, 1509238800 tz.transition 2018, 3, :o3, 1521939600 tz.transition 2018, 10, :o2, 1540688400 tz.transition 2019, 3, :o3, 1553994000 tz.transition 2019, 10, :o2, 1572138000 tz.transition 2020, 3, :o3, 1585443600 tz.transition 2020, 10, :o2, 1603587600 tz.transition 2021, 3, :o3, 1616893200 tz.transition 2021, 10, :o2, 1635642000 tz.transition 2022, 3, :o3, 1648342800 tz.transition 2022, 10, :o2, 1667091600 tz.transition 2023, 3, :o3, 1679792400 tz.transition 2023, 10, :o2, 1698541200 tz.transition 2024, 3, :o3, 1711846800 tz.transition 2024, 10, :o2, 1729990800 tz.transition 2025, 3, :o3, 1743296400 tz.transition 2025, 10, :o2, 1761440400 tz.transition 2026, 3, :o3, 1774746000 tz.transition 2026, 10, :o2, 1792890000 tz.transition 2027, 3, :o3, 1806195600 tz.transition 2027, 10, :o2, 1824944400 tz.transition 2028, 3, :o3, 1837645200 tz.transition 2028, 10, :o2, 1856394000 tz.transition 2029, 3, :o3, 1869094800 tz.transition 2029, 10, :o2, 1887843600 tz.transition 2030, 3, :o3, 1901149200 tz.transition 2030, 10, :o2, 1919293200 tz.transition 2031, 3, :o3, 1932598800 tz.transition 2031, 10, :o2, 1950742800 tz.transition 2032, 3, :o3, 1964048400 tz.transition 2032, 10, :o2, 1982797200 tz.transition 2033, 3, :o3, 1995498000 tz.transition 2033, 10, :o2, 2014246800 tz.transition 2034, 3, :o3, 2026947600 tz.transition 2034, 10, :o2, 2045696400 tz.transition 2035, 3, :o3, 2058397200 tz.transition 2035, 10, :o2, 2077146000 tz.transition 2036, 3, :o3, 2090451600 tz.transition 2036, 10, :o2, 2108595600 tz.transition 2037, 3, :o3, 2121901200 tz.transition 2037, 10, :o2, 2140045200 tz.transition 2038, 3, :o3, 2153350800, 59172253, 24 tz.transition 2038, 10, :o2, 2172099600, 59177461, 24 tz.transition 2039, 3, :o3, 2184800400, 59180989, 24 tz.transition 2039, 10, :o2, 2203549200, 59186197, 24 tz.transition 2040, 3, :o3, 2216250000, 59189725, 24 tz.transition 2040, 10, :o2, 2234998800, 59194933, 24 tz.transition 2041, 3, :o3, 2248304400, 59198629, 24 tz.transition 2041, 10, :o2, 2266448400, 59203669, 24 tz.transition 2042, 3, :o3, 2279754000, 59207365, 24 tz.transition 2042, 10, :o2, 2297898000, 59212405, 24 tz.transition 2043, 3, :o3, 2311203600, 59216101, 24 tz.transition 2043, 10, :o2, 2329347600, 59221141, 24 tz.transition 2044, 3, :o3, 2342653200, 59224837, 24 tz.transition 2044, 10, :o2, 2361402000, 59230045, 24 tz.transition 2045, 3, :o3, 2374102800, 59233573, 24 tz.transition 2045, 10, :o2, 2392851600, 59238781, 24 tz.transition 2046, 3, :o3, 2405552400, 59242309, 24 tz.transition 2046, 10, :o2, 2424301200, 59247517, 24 tz.transition 2047, 3, :o3, 2437606800, 59251213, 24 tz.transition 2047, 10, :o2, 2455750800, 59256253, 24 tz.transition 2048, 3, :o3, 2469056400, 59259949, 24 tz.transition 2048, 10, :o2, 2487200400, 59264989, 24 tz.transition 2049, 3, :o3, 2500506000, 59268685, 24 tz.transition 2049, 10, :o2, 2519254800, 59273893, 24 tz.transition 2050, 3, :o3, 2531955600, 59277421, 24 tz.transition 2050, 10, :o2, 2550704400, 59282629, 24 tz.transition 2051, 3, :o3, 2563405200, 59286157, 24 tz.transition 2051, 10, :o2, 2582154000, 59291365, 24 tz.transition 2052, 3, :o3, 2595459600, 59295061, 24 tz.transition 2052, 10, :o2, 2613603600, 59300101, 24 tz.transition 2053, 3, :o3, 2626909200, 59303797, 24 tz.transition 2053, 10, :o2, 2645053200, 59308837, 24 tz.transition 2054, 3, :o3, 2658358800, 59312533, 24 tz.transition 2054, 10, :o2, 2676502800, 59317573, 24 tz.transition 2055, 3, :o3, 2689808400, 59321269, 24 tz.transition 2055, 10, :o2, 2708557200, 59326477, 24 tz.transition 2056, 3, :o3, 2721258000, 59330005, 24 tz.transition 2056, 10, :o2, 2740006800, 59335213, 24 tz.transition 2057, 3, :o3, 2752707600, 59338741, 24 tz.transition 2057, 10, :o2, 2771456400, 59343949, 24 tz.transition 2058, 3, :o3, 2784762000, 59347645, 24 tz.transition 2058, 10, :o2, 2802906000, 59352685, 24 tz.transition 2059, 3, :o3, 2816211600, 59356381, 24 tz.transition 2059, 10, :o2, 2834355600, 59361421, 24 tz.transition 2060, 3, :o3, 2847661200, 59365117, 24 tz.transition 2060, 10, :o2, 2866410000, 59370325, 24 tz.transition 2061, 3, :o3, 2879110800, 59373853, 24 tz.transition 2061, 10, :o2, 2897859600, 59379061, 24 tz.transition 2062, 3, :o3, 2910560400, 59382589, 24 tz.transition 2062, 10, :o2, 2929309200, 59387797, 24 tz.transition 2063, 3, :o3, 2942010000, 59391325, 24 tz.transition 2063, 10, :o2, 2960758800, 59396533, 24 tz.transition 2064, 3, :o3, 2974064400, 59400229, 24 tz.transition 2064, 10, :o2, 2992208400, 59405269, 24 tz.transition 2065, 3, :o3, 3005514000, 59408965, 24 tz.transition 2065, 10, :o2, 3023658000, 59414005, 24 tz.transition 2066, 3, :o3, 3036963600, 59417701, 24 tz.transition 2066, 10, :o2, 3055712400, 59422909, 24 tz.transition 2067, 3, :o3, 3068413200, 59426437, 24 tz.transition 2067, 10, :o2, 3087162000, 59431645, 24 tz.transition 2068, 3, :o3, 3099862800, 59435173, 24 tz.transition 2068, 10, :o2, 3118611600, 59440381, 24 tz.transition 2069, 3, :o3, 3131917200, 59444077, 24 tz.transition 2069, 10, :o2, 3150061200, 59449117, 24 tz.transition 2070, 3, :o3, 3163366800, 59452813, 24 tz.transition 2070, 10, :o2, 3181510800, 59457853, 24 end end end end end end tzinfo-2.0.6/test/tzinfo-data1/tzinfo/data/definitions/Invalid/000077500000000000000000000000001436527530500244455ustar00rootroot00000000000000tzinfo-2.0.6/test/tzinfo-data1/tzinfo/data/definitions/Invalid/Incorrect_Module.rb000066400000000000000000000006721436527530500302340ustar00rootroot00000000000000# encoding: UTF-8 # This file was created manually. It purposefully contains module names that # don't match the zone identifier to test load errors. module TZInfo module Data module Definitions module InvalidX module Incorrect_ModuleX include TimezoneDefinition timezone 'Invalid/Incorrect_Module' do |tz| tz.offset :o0, 0, 0, :UTC end end end end end end tzinfo-2.0.6/test/tzinfo-data1/tzinfo/data/definitions/UTC.rb000066400000000000000000000004611436527530500240400ustar00rootroot00000000000000# encoding: UTF-8 # This file contains data derived from the IANA Time Zone Database # (https://www.iana.org/time-zones). module TZInfo module Data module Definitions module UTC include TimezoneDefinition linked_timezone 'UTC', 'Etc/UTC' end end end end tzinfo-2.0.6/test/tzinfo-data1/tzinfo/data/indexes/000077500000000000000000000000001436527530500222035ustar00rootroot00000000000000tzinfo-2.0.6/test/tzinfo-data1/tzinfo/data/indexes/countries.rb000066400000000000000000001272101436527530500245460ustar00rootroot00000000000000# encoding: UTF-8 # This file contains data derived from the IANA Time Zone Database # (https://www.iana.org/time-zones). module TZInfo module Data module Indexes module Countries include CountryIndexDefinition country 'AD', 'Andorra' do |c| c.timezone 'Europe/Andorra', 85, 2, 91, 60 end country 'AE', 'United Arab Emirates' do |c| c.timezone 'Asia/Dubai', 253, 10, 553, 10 end country 'AF', 'Afghanistan' do |c| c.timezone 'Asia/Kabul', 2071, 60, 346, 5 end country 'AG', 'Antigua & Barbuda' do |c| c.timezone 'America/Port_of_Spain', 213, 20, -3691, 60 end country 'AI', 'Anguilla' do |c| c.timezone 'America/Port_of_Spain', 213, 20, -3691, 60 end country 'AL', 'Albania' do |c| c.timezone 'Europe/Tirane', 124, 3, 119, 6 end country 'AM', 'Armenia' do |c| c.timezone 'Asia/Yerevan', 2411, 60, 89, 2 end country 'AO', 'Angola' do |c| c.timezone 'Africa/Lagos', 129, 20, 17, 5, 'West Africa Time' end country 'AQ', 'Antarctica' do |c| c.timezone 'Antarctica/Casey', -3977, 60, 6631, 60, 'Casey' c.timezone 'Antarctica/Davis', -823, 12, 2339, 30, 'Davis' c.timezone 'Antarctica/DumontDUrville', -200, 3, 8401, 60, 'Dumont-d\'Urville' c.timezone 'Antarctica/Mawson', -338, 5, 3773, 60, 'Mawson' c.timezone 'Antarctica/Palmer', -324, 5, -641, 10, 'Palmer' c.timezone 'Antarctica/Rothera', -2027, 30, -1022, 15, 'Rothera' c.timezone 'Antarctica/Syowa', -124211, 1800, 3959, 100, 'Syowa' c.timezone 'Antarctica/Troll', -259241, 3600, 507, 200, 'Troll' c.timezone 'Antarctica/Vostok', -392, 5, 1069, 10, 'Vostok' c.timezone 'Pacific/Auckland', -553, 15, 5243, 30, 'New Zealand time' end country 'AR', 'Argentina' do |c| c.timezone 'America/Argentina/Buenos_Aires', -173, 5, -1169, 20, 'Buenos Aires (BA, CF)' c.timezone 'America/Argentina/Cordoba', -157, 5, -3851, 60, 'Argentina (most areas: CB, CC, CN, ER, FM, MN, SE, SF)' c.timezone 'America/Argentina/Salta', -1487, 60, -785, 12, 'Salta (SA, LP, NQ, RN)' c.timezone 'America/Argentina/Jujuy', -1451, 60, -653, 10, 'Jujuy (JY)' c.timezone 'America/Argentina/Tucuman', -1609, 60, -3913, 60, 'Tucumán (TM)' c.timezone 'America/Argentina/Catamarca', -427, 15, -3947, 60, 'Catamarca (CT); Chubut (CH)' c.timezone 'America/Argentina/La_Rioja', -883, 30, -1337, 20, 'La Rioja (LR)' c.timezone 'America/Argentina/San_Juan', -473, 15, -4111, 60, 'San Juan (SJ)' c.timezone 'America/Argentina/Mendoza', -1973, 60, -4129, 60, 'Mendoza (MZ)' c.timezone 'America/Argentina/San_Luis', -1999, 60, -1327, 20, 'San Luis (SL)' c.timezone 'America/Argentina/Rio_Gallegos', -1549, 30, -4153, 60, 'Santa Cruz (SC)' c.timezone 'America/Argentina/Ushuaia', -274, 5, -683, 10, 'Tierra del Fuego (TF)' end country 'AS', 'Samoa (American)' do |c| c.timezone 'Pacific/Pago_Pago', -214, 15, -1707, 10, 'Samoa, Midway' end country 'AT', 'Austria' do |c| c.timezone 'Europe/Vienna', 2893, 60, 49, 3 end country 'AU', 'Australia' do |c| c.timezone 'Australia/Lord_Howe', -631, 20, 1909, 12, 'Lord Howe Island' c.timezone 'Antarctica/Macquarie', -109, 2, 3179, 20, 'Macquarie Island' c.timezone 'Australia/Hobart', -2573, 60, 8839, 60, 'Tasmania (most areas)' c.timezone 'Australia/Currie', -599, 15, 2158, 15, 'Tasmania (King Island)' c.timezone 'Australia/Melbourne', -2269, 60, 4349, 30, 'Victoria' c.timezone 'Australia/Sydney', -508, 15, 9073, 60, 'New South Wales (most areas)' c.timezone 'Australia/Broken_Hill', -639, 20, 2829, 20, 'New South Wales (Yancowinna)' c.timezone 'Australia/Brisbane', -412, 15, 4591, 30, 'Queensland (most areas)' c.timezone 'Australia/Lindeman', -304, 15, 149, 1, 'Queensland (Whitsunday Islands)' c.timezone 'Australia/Adelaide', -419, 12, 1663, 12, 'South Australia' c.timezone 'Australia/Darwin', -187, 15, 785, 6, 'Northern Territory' c.timezone 'Australia/Perth', -639, 20, 2317, 20, 'Western Australia (most areas)' c.timezone 'Australia/Eucla', -1903, 60, 1933, 15, 'Western Australia (Eucla)' end country 'AW', 'Aruba' do |c| c.timezone 'America/Curacao', 731, 60, -69, 1 end country 'AX', 'Åland Islands' do |c| c.timezone 'Europe/Helsinki', 361, 6, 749, 30 end country 'AZ', 'Azerbaijan' do |c| c.timezone 'Asia/Baku', 2423, 60, 997, 20 end country 'BA', 'Bosnia & Herzegovina' do |c| c.timezone 'Europe/Belgrade', 269, 6, 41, 2 end country 'BB', 'Barbados' do |c| c.timezone 'America/Barbados', 131, 10, -3577, 60 end country 'BD', 'Bangladesh' do |c| c.timezone 'Asia/Dhaka', 1423, 60, 1085, 12 end country 'BE', 'Belgium' do |c| c.timezone 'Europe/Brussels', 305, 6, 13, 3 end country 'BF', 'Burkina Faso' do |c| c.timezone 'Africa/Abidjan', 319, 60, -121, 30 end country 'BG', 'Bulgaria' do |c| c.timezone 'Europe/Sofia', 2561, 60, 1399, 60 end country 'BH', 'Bahrain' do |c| c.timezone 'Asia/Qatar', 1517, 60, 773, 15 end country 'BI', 'Burundi' do |c| c.timezone 'Africa/Maputo', -779, 30, 391, 12, 'Central Africa Time' end country 'BJ', 'Benin' do |c| c.timezone 'Africa/Lagos', 129, 20, 17, 5, 'West Africa Time' end country 'BL', 'St Barthelemy' do |c| c.timezone 'America/Port_of_Spain', 213, 20, -3691, 60 end country 'BM', 'Bermuda' do |c| c.timezone 'Atlantic/Bermuda', 1937, 60, -1943, 30 end country 'BN', 'Brunei' do |c| c.timezone 'Asia/Brunei', 74, 15, 1379, 12 end country 'BO', 'Bolivia' do |c| c.timezone 'America/La_Paz', -33, 2, -1363, 20 end country 'BQ', 'Caribbean NL' do |c| c.timezone 'America/Curacao', 731, 60, -69, 1 end country 'BR', 'Brazil' do |c| c.timezone 'America/Noronha', -77, 20, -389, 12, 'Atlantic islands' c.timezone 'America/Belem', -29, 20, -2909, 60, 'Pará (east); Amapá' c.timezone 'America/Fortaleza', -223, 60, -77, 2, 'Brazil (northeast: MA, PI, CE, RN, PB)' c.timezone 'America/Recife', -161, 20, -349, 10, 'Pernambuco' c.timezone 'America/Araguaina', -36, 5, -241, 5, 'Tocantins' c.timezone 'America/Maceio', -29, 3, -2143, 60, 'Alagoas, Sergipe' c.timezone 'America/Bahia', -779, 60, -2311, 60, 'Bahia' c.timezone 'America/Sao_Paulo', -353, 15, -2797, 60, 'Brazil (southeast: GO, DF, MG, ES, RJ, SP, PR, SC, RS)' c.timezone 'America/Campo_Grande', -409, 20, -3277, 60, 'Mato Grosso do Sul' c.timezone 'America/Cuiaba', -187, 12, -673, 12, 'Mato Grosso' c.timezone 'America/Santarem', -73, 30, -823, 15, 'Pará (west)' c.timezone 'America/Porto_Velho', -263, 30, -639, 10, 'Rondônia' c.timezone 'America/Boa_Vista', 169, 60, -182, 3, 'Roraima' c.timezone 'America/Manaus', -47, 15, -3601, 60, 'Amazonas (east)' c.timezone 'America/Eirunepe', -20, 3, -1048, 15, 'Amazonas (west)' c.timezone 'America/Rio_Branco', -299, 30, -339, 5, 'Acre' end country 'BS', 'Bahamas' do |c| c.timezone 'America/Nassau', 301, 12, -1547, 20 end country 'BT', 'Bhutan' do |c| c.timezone 'Asia/Thimphu', 412, 15, 1793, 20 end country 'BV', 'Bouvet Island' country 'BW', 'Botswana' do |c| c.timezone 'Africa/Maputo', -779, 30, 391, 12, 'Central Africa Time' end country 'BY', 'Belarus' do |c| c.timezone 'Europe/Minsk', 539, 10, 827, 30 end country 'BZ', 'Belize' do |c| c.timezone 'America/Belize', 35, 2, -441, 5 end country 'CA', 'Canada' do |c| c.timezone 'America/St_Johns', 1427, 30, -3163, 60, 'Newfoundland; Labrador (southeast)' c.timezone 'America/Halifax', 893, 20, -318, 5, 'Atlantic - NS (most areas); PE' c.timezone 'America/Glace_Bay', 231, 5, -1199, 20, 'Atlantic - NS (Cape Breton)' c.timezone 'America/Moncton', 461, 10, -3887, 60, 'Atlantic - New Brunswick' c.timezone 'America/Goose_Bay', 160, 3, -725, 12, 'Atlantic - Labrador (most areas)' c.timezone 'America/Blanc-Sablon', 617, 12, -3427, 60, 'AST - QC (Lower North Shore)' c.timezone 'America/Toronto', 873, 20, -4763, 60, 'Eastern - ON, QC (most areas)' c.timezone 'America/Nipigon', 2941, 60, -1324, 15, 'Eastern - ON, QC (no DST 1967-73)' c.timezone 'America/Thunder_Bay', 2903, 60, -357, 4, 'Eastern - ON (Thunder Bay)' c.timezone 'America/Iqaluit', 956, 15, -1027, 15, 'Eastern - NU (most east areas)' c.timezone 'America/Pangnirtung', 992, 15, -986, 15, 'Eastern - NU (Pangnirtung)' c.timezone 'America/Atikokan', 175531, 3600, -54973, 600, 'EST - ON (Atikokan); NU (Coral H)' c.timezone 'America/Winnipeg', 2993, 60, -1943, 20, 'Central - ON (west); Manitoba' c.timezone 'America/Rainy_River', 2923, 60, -2837, 30, 'Central - ON (Rainy R, Ft Frances)' c.timezone 'America/Resolute', 33613, 450, -22759, 240, 'Central - NU (Resolute)' c.timezone 'America/Rankin_Inlet', 3769, 60, -331499, 3600, 'Central - NU (central)' c.timezone 'America/Regina', 252, 5, -2093, 20, 'CST - SK (most areas)' c.timezone 'America/Swift_Current', 3017, 60, -647, 6, 'CST - SK (midwest)' c.timezone 'America/Edmonton', 1071, 20, -1702, 15, 'Mountain - AB; BC (E); SK (W)' c.timezone 'America/Cambridge_Bay', 24881, 360, -37819, 360, 'Mountain - NU (west)' c.timezone 'America/Yellowknife', 1249, 20, -2287, 20, 'Mountain - NT (central)' c.timezone 'America/Inuvik', 246059, 3600, -8023, 60, 'Mountain - NT (west)' c.timezone 'America/Creston', 491, 10, -6991, 60, 'MST - BC (Creston)' c.timezone 'America/Dawson_Creek', 1793, 30, -3607, 30, 'MST - BC (Dawson Cr, Ft St John)' c.timezone 'America/Fort_Nelson', 294, 5, -1227, 10, 'MST - BC (Ft Nelson)' c.timezone 'America/Vancouver', 739, 15, -7387, 60, 'Pacific - BC (most areas)' c.timezone 'America/Whitehorse', 3643, 60, -2701, 20, 'Pacific - Yukon (east)' c.timezone 'America/Dawson', 961, 15, -1673, 12, 'Pacific - Yukon (west)' end country 'CC', 'Cocos (Keeling) Islands' do |c| c.timezone 'Indian/Cocos', -73, 6, 1163, 12 end country 'CD', 'Congo (Dem. Rep.)' do |c| c.timezone 'Africa/Maputo', -779, 30, 391, 12, 'Central Africa Time' c.timezone 'Africa/Lagos', 129, 20, 17, 5, 'West Africa Time' end country 'CF', 'Central African Rep.' do |c| c.timezone 'Africa/Lagos', 129, 20, 17, 5, 'West Africa Time' end country 'CG', 'Congo (Rep.)' do |c| c.timezone 'Africa/Lagos', 129, 20, 17, 5, 'West Africa Time' end country 'CH', 'Switzerland' do |c| c.timezone 'Europe/Zurich', 2843, 60, 128, 15, 'Swiss time' end country 'CI', 'Côte d\'Ivoire' do |c| c.timezone 'Africa/Abidjan', 319, 60, -121, 30 end country 'CK', 'Cook Islands' do |c| c.timezone 'Pacific/Rarotonga', -637, 30, -4793, 30 end country 'CL', 'Chile' do |c| c.timezone 'America/Santiago', -669, 20, -212, 3, 'Chile (most areas)' c.timezone 'America/Punta_Arenas', -1063, 20, -851, 12, 'Region of Magallanes' c.timezone 'Pacific/Easter', -543, 20, -3283, 30, 'Easter Island' end country 'CM', 'Cameroon' do |c| c.timezone 'Africa/Lagos', 129, 20, 17, 5, 'West Africa Time' end country 'CN', 'China' do |c| c.timezone 'Asia/Shanghai', 937, 30, 1822, 15, 'Beijing Time' c.timezone 'Asia/Urumqi', 219, 5, 1051, 12, 'Xinjiang Time' end country 'CO', 'Colombia' do |c| c.timezone 'America/Bogota', 23, 5, -889, 12 end country 'CR', 'Costa Rica' do |c| c.timezone 'America/Costa_Rica', 149, 15, -1009, 12 end country 'CU', 'Cuba' do |c| c.timezone 'America/Havana', 347, 15, -2471, 30 end country 'CV', 'Cape Verde' do |c| c.timezone 'Atlantic/Cape_Verde', 179, 12, -1411, 60 end country 'CW', 'Curaçao' do |c| c.timezone 'America/Curacao', 731, 60, -69, 1 end country 'CX', 'Christmas Island' do |c| c.timezone 'Indian/Christmas', -125, 12, 6343, 60 end country 'CY', 'Cyprus' do |c| c.timezone 'Asia/Nicosia', 211, 6, 1001, 30, 'Cyprus (most areas)' c.timezone 'Asia/Famagusta', 2107, 60, 679, 20, 'Northern Cyprus' end country 'CZ', 'Czech Republic' do |c| c.timezone 'Europe/Prague', 601, 12, 433, 30 end country 'DE', 'Germany' do |c| c.timezone 'Europe/Berlin', 105, 2, 401, 30, 'Germany (most areas)' c.timezone 'Europe/Zurich', 2843, 60, 128, 15, 'Swiss time' end country 'DJ', 'Djibouti' do |c| c.timezone 'Africa/Nairobi', -77, 60, 2209, 60 end country 'DK', 'Denmark' do |c| c.timezone 'Europe/Copenhagen', 167, 3, 151, 12 end country 'DM', 'Dominica' do |c| c.timezone 'America/Port_of_Spain', 213, 20, -3691, 60 end country 'DO', 'Dominican Republic' do |c| c.timezone 'America/Santo_Domingo', 277, 15, -699, 10 end country 'DZ', 'Algeria' do |c| c.timezone 'Africa/Algiers', 2207, 60, 61, 20 end country 'EC', 'Ecuador' do |c| c.timezone 'America/Guayaquil', -13, 6, -479, 6, 'Ecuador (mainland)' c.timezone 'Pacific/Galapagos', -9, 10, -448, 5, 'Galápagos Islands' end country 'EE', 'Estonia' do |c| c.timezone 'Europe/Tallinn', 713, 12, 99, 4 end country 'EG', 'Egypt' do |c| c.timezone 'Africa/Cairo', 601, 20, 125, 4 end country 'EH', 'Western Sahara' do |c| c.timezone 'Africa/El_Aaiun', 543, 20, -66, 5 end country 'ER', 'Eritrea' do |c| c.timezone 'Africa/Nairobi', -77, 60, 2209, 60 end country 'ES', 'Spain' do |c| c.timezone 'Europe/Madrid', 202, 5, -221, 60, 'Spain (mainland)' c.timezone 'Africa/Ceuta', 2153, 60, -319, 60, 'Ceuta, Melilla' c.timezone 'Atlantic/Canary', 281, 10, -77, 5, 'Canary Islands' end country 'ET', 'Ethiopia' do |c| c.timezone 'Africa/Nairobi', -77, 60, 2209, 60 end country 'FI', 'Finland' do |c| c.timezone 'Europe/Helsinki', 361, 6, 749, 30 end country 'FJ', 'Fiji' do |c| c.timezone 'Pacific/Fiji', -272, 15, 2141, 12 end country 'FK', 'Falkland Islands' do |c| c.timezone 'Atlantic/Stanley', -517, 10, -1157, 20 end country 'FM', 'Micronesia' do |c| c.timezone 'Pacific/Chuuk', 89, 12, 9107, 60, 'Chuuk/Truk, Yap' c.timezone 'Pacific/Pohnpei', 209, 30, 9493, 60, 'Pohnpei/Ponape' c.timezone 'Pacific/Kosrae', 319, 60, 9779, 60, 'Kosrae' end country 'FO', 'Faroe Islands' do |c| c.timezone 'Atlantic/Faroe', 3721, 60, -203, 30 end country 'FR', 'France' do |c| c.timezone 'Europe/Paris', 733, 15, 7, 3 end country 'GA', 'Gabon' do |c| c.timezone 'Africa/Lagos', 129, 20, 17, 5, 'West Africa Time' end country 'GB', 'Britain (UK)' do |c| c.timezone 'Europe/London', 6181, 120, -451, 3600 end country 'GD', 'Grenada' do |c| c.timezone 'America/Port_of_Spain', 213, 20, -3691, 60 end country 'GE', 'Georgia' do |c| c.timezone 'Asia/Tbilisi', 2503, 60, 2689, 60 end country 'GF', 'French Guiana' do |c| c.timezone 'America/Cayenne', 74, 15, -157, 3 end country 'GG', 'Guernsey' do |c| c.timezone 'Europe/London', 6181, 120, -451, 3600 end country 'GH', 'Ghana' do |c| c.timezone 'Africa/Accra', 111, 20, -13, 60 end country 'GI', 'Gibraltar' do |c| c.timezone 'Europe/Gibraltar', 542, 15, -107, 20 end country 'GL', 'Greenland' do |c| c.timezone 'America/Nuuk', 3851, 60, -776, 15, 'Greenland (most areas)' c.timezone 'America/Danmarkshavn', 2303, 30, -56, 3, 'National Park (east coast)' c.timezone 'America/Scoresbysund', 4229, 60, -659, 30, 'Scoresbysund/Ittoqqortoormiit' c.timezone 'America/Thule', 2297, 30, -4127, 60, 'Thule/Pituffik' end country 'GM', 'Gambia' do |c| c.timezone 'Africa/Abidjan', 319, 60, -121, 30 end country 'GN', 'Guinea' do |c| c.timezone 'Africa/Abidjan', 319, 60, -121, 30 end country 'GP', 'Guadeloupe' do |c| c.timezone 'America/Port_of_Spain', 213, 20, -3691, 60 end country 'GQ', 'Equatorial Guinea' do |c| c.timezone 'Africa/Lagos', 129, 20, 17, 5, 'West Africa Time' end country 'GR', 'Greece' do |c| c.timezone 'Europe/Athens', 1139, 30, 1423, 60 end country 'GS', 'South Georgia & the South Sandwich Islands' do |c| c.timezone 'Atlantic/South_Georgia', -814, 15, -548, 15 end country 'GT', 'Guatemala' do |c| c.timezone 'America/Guatemala', 439, 30, -5431, 60 end country 'GU', 'Guam' do |c| c.timezone 'Pacific/Guam', 202, 15, 579, 4 end country 'GW', 'Guinea-Bissau' do |c| c.timezone 'Africa/Bissau', 237, 20, -187, 12 end country 'GY', 'Guyana' do |c| c.timezone 'America/Guyana', 34, 5, -349, 6 end country 'HK', 'Hong Kong' do |c| c.timezone 'Asia/Hong_Kong', 1337, 60, 2283, 20 end country 'HM', 'Heard Island & McDonald Islands' country 'HN', 'Honduras' do |c| c.timezone 'America/Tegucigalpa', 141, 10, -5233, 60 end country 'HR', 'Croatia' do |c| c.timezone 'Europe/Belgrade', 269, 6, 41, 2 end country 'HT', 'Haiti' do |c| c.timezone 'America/Port-au-Prince', 278, 15, -217, 3 end country 'HU', 'Hungary' do |c| c.timezone 'Europe/Budapest', 95, 2, 229, 12 end country 'ID', 'Indonesia' do |c| c.timezone 'Asia/Jakarta', -37, 6, 534, 5, 'Java, Sumatra' c.timezone 'Asia/Pontianak', -1, 30, 328, 3, 'Borneo (west, central)' c.timezone 'Asia/Makassar', -307, 60, 597, 5, 'Borneo (east, south); Sulawesi/Celebes, Bali, Nusa Tengarra; Timor (west)' c.timezone 'Asia/Jayapura', -38, 15, 1407, 10, 'New Guinea (West Papua / Irian Jaya); Malukus/Moluccas' end country 'IE', 'Ireland' do |c| c.timezone 'Europe/Dublin', 160, 3, -25, 4 end country 'IL', 'Israel' do |c| c.timezone 'Asia/Jerusalem', 11441, 360, 63403, 1800 end country 'IM', 'Isle of Man' do |c| c.timezone 'Europe/London', 6181, 120, -451, 3600 end country 'IN', 'India' do |c| c.timezone 'Asia/Kolkata', 338, 15, 2651, 30 end country 'IO', 'British Indian Ocean Territory' do |c| c.timezone 'Indian/Chagos', -22, 3, 869, 12 end country 'IQ', 'Iraq' do |c| c.timezone 'Asia/Baghdad', 667, 20, 533, 12 end country 'IR', 'Iran' do |c| c.timezone 'Asia/Tehran', 107, 3, 1543, 30 end country 'IS', 'Iceland' do |c| c.timezone 'Atlantic/Reykjavik', 1283, 20, -437, 20 end country 'IT', 'Italy' do |c| c.timezone 'Europe/Rome', 419, 10, 749, 60 end country 'JE', 'Jersey' do |c| c.timezone 'Europe/London', 6181, 120, -451, 3600 end country 'JM', 'Jamaica' do |c| c.timezone 'America/Jamaica', 12937, 720, -11519, 150 end country 'JO', 'Jordan' do |c| c.timezone 'Asia/Amman', 639, 20, 539, 15 end country 'JP', 'Japan' do |c| c.timezone 'Asia/Tokyo', 32089, 900, 503081, 3600 end country 'KE', 'Kenya' do |c| c.timezone 'Africa/Nairobi', -77, 60, 2209, 60 end country 'KG', 'Kyrgyzstan' do |c| c.timezone 'Asia/Bishkek', 429, 10, 373, 5 end country 'KH', 'Cambodia' do |c| c.timezone 'Asia/Bangkok', 55, 4, 6031, 60, 'Indochina (most areas)' end country 'KI', 'Kiribati' do |c| c.timezone 'Pacific/Tarawa', 17, 12, 173, 1, 'Gilbert Islands' c.timezone 'Pacific/Enderbury', -47, 15, -2053, 12, 'Phoenix Islands' c.timezone 'Pacific/Kiritimati', 28, 15, -472, 3, 'Line Islands' end country 'KM', 'Comoros' do |c| c.timezone 'Africa/Nairobi', -77, 60, 2209, 60 end country 'KN', 'St Kitts & Nevis' do |c| c.timezone 'America/Port_of_Spain', 213, 20, -3691, 60 end country 'KP', 'Korea (North)' do |c| c.timezone 'Asia/Pyongyang', 2341, 60, 503, 4 end country 'KR', 'Korea (South)' do |c| c.timezone 'Asia/Seoul', 751, 20, 3809, 30 end country 'KW', 'Kuwait' do |c| c.timezone 'Asia/Riyadh', 739, 30, 2803, 60 end country 'KY', 'Cayman Islands' do |c| c.timezone 'America/Panama', 269, 30, -1193, 15 end country 'KZ', 'Kazakhstan' do |c| c.timezone 'Asia/Almaty', 173, 4, 1539, 20, 'Kazakhstan (most areas)' c.timezone 'Asia/Qyzylorda', 224, 5, 982, 15, 'Qyzylorda/Kyzylorda/Kzyl-Orda' c.timezone 'Asia/Qostanay', 266, 5, 3817, 60, 'Qostanay/Kostanay/Kustanay' c.timezone 'Asia/Aqtobe', 3017, 60, 343, 6, 'Aqtöbe/Aktobe' c.timezone 'Asia/Aqtau', 2671, 60, 754, 15, 'Mangghystaū/Mankistau' c.timezone 'Asia/Atyrau', 2827, 60, 779, 15, 'Atyraū/Atirau/Gur\'yev' c.timezone 'Asia/Oral', 3073, 60, 1027, 20, 'West Kazakhstan' end country 'LA', 'Laos' do |c| c.timezone 'Asia/Bangkok', 55, 4, 6031, 60, 'Indochina (most areas)' end country 'LB', 'Lebanon' do |c| c.timezone 'Asia/Beirut', 2033, 60, 71, 2 end country 'LC', 'St Lucia' do |c| c.timezone 'America/Port_of_Spain', 213, 20, -3691, 60 end country 'LI', 'Liechtenstein' do |c| c.timezone 'Europe/Zurich', 2843, 60, 128, 15, 'Swiss time' end country 'LK', 'Sri Lanka' do |c| c.timezone 'Asia/Colombo', 104, 15, 1597, 20 end country 'LR', 'Liberia' do |c| c.timezone 'Africa/Monrovia', 63, 10, -647, 60 end country 'LS', 'Lesotho' do |c| c.timezone 'Africa/Johannesburg', -105, 4, 28, 1 end country 'LT', 'Lithuania' do |c| c.timezone 'Europe/Vilnius', 3281, 60, 1519, 60 end country 'LU', 'Luxembourg' do |c| c.timezone 'Europe/Luxembourg', 248, 5, 123, 20 end country 'LV', 'Latvia' do |c| c.timezone 'Europe/Riga', 1139, 20, 241, 10 end country 'LY', 'Libya' do |c| c.timezone 'Africa/Tripoli', 329, 10, 791, 60 end country 'MA', 'Morocco' do |c| c.timezone 'Africa/Casablanca', 673, 20, -91, 12 end country 'MC', 'Monaco' do |c| c.timezone 'Europe/Monaco', 437, 10, 443, 60 end country 'MD', 'Moldova' do |c| c.timezone 'Europe/Chisinau', 47, 1, 173, 6 end country 'ME', 'Montenegro' do |c| c.timezone 'Europe/Belgrade', 269, 6, 41, 2 end country 'MF', 'St Martin (French)' do |c| c.timezone 'America/Port_of_Spain', 213, 20, -3691, 60 end country 'MG', 'Madagascar' do |c| c.timezone 'Africa/Nairobi', -77, 60, 2209, 60 end country 'MH', 'Marshall Islands' do |c| c.timezone 'Pacific/Majuro', 143, 20, 856, 5, 'Marshall Islands (most areas)' c.timezone 'Pacific/Kwajalein', 109, 12, 502, 3, 'Kwajalein' end country 'MK', 'North Macedonia' do |c| c.timezone 'Europe/Belgrade', 269, 6, 41, 2 end country 'ML', 'Mali' do |c| c.timezone 'Africa/Abidjan', 319, 60, -121, 30 end country 'MM', 'Myanmar (Burma)' do |c| c.timezone 'Asia/Yangon', 1007, 60, 577, 6 end country 'MN', 'Mongolia' do |c| c.timezone 'Asia/Ulaanbaatar', 575, 12, 6413, 60, 'Mongolia (most areas)' c.timezone 'Asia/Hovd', 2881, 60, 1833, 20, 'Bayan-Ölgii, Govi-Altai, Hovd, Uvs, Zavkhan' c.timezone 'Asia/Choibalsan', 721, 15, 229, 2, 'Dornod, Sükhbaatar' end country 'MO', 'Macau' do |c| c.timezone 'Asia/Macau', 7991, 360, 2725, 24 end country 'MP', 'Northern Mariana Islands' do |c| c.timezone 'Pacific/Guam', 202, 15, 579, 4 end country 'MQ', 'Martinique' do |c| c.timezone 'America/Martinique', 73, 5, -733, 12 end country 'MR', 'Mauritania' do |c| c.timezone 'Africa/Abidjan', 319, 60, -121, 30 end country 'MS', 'Montserrat' do |c| c.timezone 'America/Port_of_Spain', 213, 20, -3691, 60 end country 'MT', 'Malta' do |c| c.timezone 'Europe/Malta', 359, 10, 871, 60 end country 'MU', 'Mauritius' do |c| c.timezone 'Indian/Mauritius', -121, 6, 115, 2 end country 'MV', 'Maldives' do |c| c.timezone 'Indian/Maldives', 25, 6, 147, 2 end country 'MW', 'Malawi' do |c| c.timezone 'Africa/Maputo', -779, 30, 391, 12, 'Central Africa Time' end country 'MX', 'Mexico' do |c| c.timezone 'America/Mexico_City', 97, 5, -1983, 20, 'Central Time' c.timezone 'America/Cancun', 253, 12, -2603, 30, 'Eastern Standard Time - Quintana Roo' c.timezone 'America/Merida', 629, 30, -5377, 60, 'Central Time - Campeche, Yucatán' c.timezone 'America/Monterrey', 77, 3, -6019, 60, 'Central Time - Durango; Coahuila, Nuevo León, Tamaulipas (most areas)' c.timezone 'America/Matamoros', 155, 6, -195, 2, 'Central Time US - Coahuila, Nuevo León, Tamaulipas (US border)' c.timezone 'America/Mazatlan', 1393, 60, -1277, 12, 'Mountain Time - Baja California Sur, Nayarit, Sinaloa' c.timezone 'America/Chihuahua', 859, 30, -1273, 12, 'Mountain Time - Chihuahua (most areas)' c.timezone 'America/Ojinaga', 887, 30, -1253, 12, 'Mountain Time US - Chihuahua (US border)' c.timezone 'America/Hermosillo', 436, 15, -3329, 30, 'Mountain Standard Time - Sonora' c.timezone 'America/Tijuana', 488, 15, -7021, 60, 'Pacific Time US - Baja California' c.timezone 'America/Bahia_Banderas', 104, 5, -421, 4, 'Central Time - Bahía de Banderas' end country 'MY', 'Malaysia' do |c| c.timezone 'Asia/Kuala_Lumpur', 19, 6, 1017, 10, 'Malaysia (peninsula)' c.timezone 'Asia/Kuching', 31, 20, 331, 3, 'Sabah, Sarawak' end country 'MZ', 'Mozambique' do |c| c.timezone 'Africa/Maputo', -779, 30, 391, 12, 'Central Africa Time' end country 'NA', 'Namibia' do |c| c.timezone 'Africa/Windhoek', -677, 30, 171, 10 end country 'NC', 'New Caledonia' do |c| c.timezone 'Pacific/Noumea', -334, 15, 3329, 20 end country 'NE', 'Niger' do |c| c.timezone 'Africa/Lagos', 129, 20, 17, 5, 'West Africa Time' end country 'NF', 'Norfolk Island' do |c| c.timezone 'Pacific/Norfolk', -581, 20, 5039, 30 end country 'NG', 'Nigeria' do |c| c.timezone 'Africa/Lagos', 129, 20, 17, 5, 'West Africa Time' end country 'NI', 'Nicaragua' do |c| c.timezone 'America/Managua', 243, 20, -5177, 60 end country 'NL', 'Netherlands' do |c| c.timezone 'Europe/Amsterdam', 1571, 30, 49, 10 end country 'NO', 'Norway' do |c| c.timezone 'Europe/Oslo', 719, 12, 43, 4 end country 'NP', 'Nepal' do |c| c.timezone 'Asia/Kathmandu', 1663, 60, 5119, 60 end country 'NR', 'Nauru' do |c| c.timezone 'Pacific/Nauru', -31, 60, 2003, 12 end country 'NU', 'Niue' do |c| c.timezone 'Pacific/Niue', -1141, 60, -2039, 12 end country 'NZ', 'New Zealand' do |c| c.timezone 'Pacific/Auckland', -553, 15, 5243, 30, 'New Zealand time' c.timezone 'Pacific/Chatham', -879, 20, -3531, 20, 'Chatham Islands' end country 'OM', 'Oman' do |c| c.timezone 'Asia/Dubai', 253, 10, 553, 10 end country 'PA', 'Panama' do |c| c.timezone 'America/Panama', 269, 30, -1193, 15 end country 'PE', 'Peru' do |c| c.timezone 'America/Lima', -241, 20, -1541, 20 end country 'PF', 'French Polynesia' do |c| c.timezone 'Pacific/Tahiti', -263, 15, -4487, 30, 'Society Islands' c.timezone 'Pacific/Marquesas', -9, 1, -279, 2, 'Marquesas Islands' c.timezone 'Pacific/Gambier', -347, 15, -2699, 20, 'Gambier Islands' end country 'PG', 'Papua New Guinea' do |c| c.timezone 'Pacific/Port_Moresby', -19, 2, 883, 6, 'Papua New Guinea (most areas)' c.timezone 'Pacific/Bougainville', -373, 60, 4667, 30, 'Bougainville' end country 'PH', 'Philippines' do |c| c.timezone 'Asia/Manila', 175, 12, 121, 1 end country 'PK', 'Pakistan' do |c| c.timezone 'Asia/Karachi', 373, 15, 1341, 20 end country 'PL', 'Poland' do |c| c.timezone 'Europe/Warsaw', 209, 4, 21, 1 end country 'PM', 'St Pierre & Miquelon' do |c| c.timezone 'America/Miquelon', 941, 20, -169, 3 end country 'PN', 'Pitcairn' do |c| c.timezone 'Pacific/Pitcairn', -376, 15, -1561, 12 end country 'PR', 'Puerto Rico' do |c| c.timezone 'America/Puerto_Rico', 11081, 600, -118991, 1800 end country 'PS', 'Palestine' do |c| c.timezone 'Asia/Gaza', 63, 2, 517, 15, 'Gaza Strip' c.timezone 'Asia/Hebron', 473, 15, 7019, 200, 'West Bank' end country 'PT', 'Portugal' do |c| c.timezone 'Europe/Lisbon', 2323, 60, -137, 15, 'Portugal (mainland)' c.timezone 'Atlantic/Madeira', 979, 30, -169, 10, 'Madeira Islands' c.timezone 'Atlantic/Azores', 566, 15, -77, 3, 'Azores' end country 'PW', 'Palau' do |c| c.timezone 'Pacific/Palau', 22, 3, 8069, 60 end country 'PY', 'Paraguay' do |c| c.timezone 'America/Asuncion', -379, 15, -173, 3 end country 'QA', 'Qatar' do |c| c.timezone 'Asia/Qatar', 1517, 60, 773, 15 end country 'RE', 'Réunion' do |c| c.timezone 'Indian/Reunion', -313, 15, 832, 15, 'Réunion, Crozet, Scattered Islands' end country 'RO', 'Romania' do |c| c.timezone 'Europe/Bucharest', 1333, 30, 261, 10 end country 'RS', 'Serbia' do |c| c.timezone 'Europe/Belgrade', 269, 6, 41, 2 end country 'RU', 'Russia' do |c| c.timezone 'Europe/Kaliningrad', 3283, 60, 41, 2, 'MSK-01 - Kaliningrad' c.timezone 'Europe/Moscow', 66907, 1200, 8464, 225, 'MSK+00 - Moscow area' c.timezone 'Europe/Simferopol', 899, 20, 341, 10, 'Crimea' c.timezone 'Europe/Kirov', 293, 5, 993, 20, 'MSK+00 - Kirov' c.timezone 'Europe/Astrakhan', 927, 20, 961, 20, 'MSK+01 - Astrakhan' c.timezone 'Europe/Volgograd', 731, 15, 533, 12, 'MSK+01 - Volgograd' c.timezone 'Europe/Saratov', 1547, 30, 1381, 30, 'MSK+01 - Saratov' c.timezone 'Europe/Ulyanovsk', 163, 3, 242, 5, 'MSK+01 - Ulyanovsk' c.timezone 'Europe/Samara', 266, 5, 1003, 20, 'MSK+01 - Samara, Udmurtia' c.timezone 'Asia/Yekaterinburg', 1137, 20, 303, 5, 'MSK+02 - Urals' c.timezone 'Asia/Omsk', 55, 1, 367, 5, 'MSK+03 - Omsk' c.timezone 'Asia/Novosibirsk', 1651, 30, 995, 12, 'MSK+04 - Novosibirsk' c.timezone 'Asia/Barnaul', 1601, 30, 335, 4, 'MSK+04 - Altai' c.timezone 'Asia/Tomsk', 113, 2, 2549, 30, 'MSK+04 - Tomsk' c.timezone 'Asia/Novokuznetsk', 215, 4, 5227, 60, 'MSK+04 - Kemerovo' c.timezone 'Asia/Krasnoyarsk', 3361, 60, 557, 6, 'MSK+04 - Krasnoyarsk area' c.timezone 'Asia/Irkutsk', 784, 15, 313, 3, 'MSK+05 - Irkutsk, Buryatia' c.timezone 'Asia/Chita', 1041, 20, 1702, 15, 'MSK+06 - Zabaykalsky' c.timezone 'Asia/Yakutsk', 62, 1, 389, 3, 'MSK+06 - Lena River' c.timezone 'Asia/Khandyga', 225563, 3600, 243997, 1800, 'MSK+06 - Tomponsky, Ust-Maysky' c.timezone 'Asia/Vladivostok', 259, 6, 1979, 15, 'MSK+07 - Amur River' c.timezone 'Asia/Ust-Nera', 232417, 3600, 10742, 75, 'MSK+07 - Oymyakonsky' c.timezone 'Asia/Magadan', 1787, 30, 754, 5, 'MSK+08 - Magadan' c.timezone 'Asia/Sakhalin', 1409, 30, 1427, 10, 'MSK+08 - Sakhalin Island' c.timezone 'Asia/Srednekolymsk', 1012, 15, 9223, 60, 'MSK+08 - Sakha (E); North Kuril Is' c.timezone 'Asia/Kamchatka', 3181, 60, 3173, 20, 'MSK+09 - Kamchatka' c.timezone 'Asia/Anadyr', 259, 4, 10649, 60, 'MSK+09 - Bering Sea' end country 'RW', 'Rwanda' do |c| c.timezone 'Africa/Maputo', -779, 30, 391, 12, 'Central Africa Time' end country 'SA', 'Saudi Arabia' do |c| c.timezone 'Asia/Riyadh', 739, 30, 2803, 60 end country 'SB', 'Solomon Islands' do |c| c.timezone 'Pacific/Guadalcanal', -143, 15, 801, 5 end country 'SC', 'Seychelles' do |c| c.timezone 'Indian/Mahe', -14, 3, 832, 15 end country 'SD', 'Sudan' do |c| c.timezone 'Africa/Khartoum', 78, 5, 488, 15 end country 'SE', 'Sweden' do |c| c.timezone 'Europe/Stockholm', 178, 3, 361, 20 end country 'SG', 'Singapore' do |c| c.timezone 'Asia/Singapore', 77, 60, 2077, 20 end country 'SH', 'St Helena' do |c| c.timezone 'Africa/Abidjan', 319, 60, -121, 30 end country 'SI', 'Slovenia' do |c| c.timezone 'Europe/Belgrade', 269, 6, 41, 2 end country 'SJ', 'Svalbard & Jan Mayen' do |c| c.timezone 'Europe/Oslo', 719, 12, 43, 4 end country 'SK', 'Slovakia' do |c| c.timezone 'Europe/Prague', 601, 12, 433, 30 end country 'SL', 'Sierra Leone' do |c| c.timezone 'Africa/Abidjan', 319, 60, -121, 30 end country 'SM', 'San Marino' do |c| c.timezone 'Europe/Rome', 419, 10, 749, 60 end country 'SN', 'Senegal' do |c| c.timezone 'Africa/Abidjan', 319, 60, -121, 30 end country 'SO', 'Somalia' do |c| c.timezone 'Africa/Nairobi', -77, 60, 2209, 60 end country 'SR', 'Suriname' do |c| c.timezone 'America/Paramaribo', 35, 6, -331, 6 end country 'SS', 'South Sudan' do |c| c.timezone 'Africa/Juba', 97, 20, 1897, 60 end country 'ST', 'Sao Tome & Principe' do |c| c.timezone 'Africa/Sao_Tome', 1, 3, 101, 15 end country 'SV', 'El Salvador' do |c| c.timezone 'America/El_Salvador', 137, 10, -446, 5 end country 'SX', 'St Maarten (Dutch)' do |c| c.timezone 'America/Curacao', 731, 60, -69, 1 end country 'SY', 'Syria' do |c| c.timezone 'Asia/Damascus', 67, 2, 363, 10 end country 'SZ', 'Eswatini (Swaziland)' do |c| c.timezone 'Africa/Johannesburg', -105, 4, 28, 1 end country 'TC', 'Turks & Caicos Is' do |c| c.timezone 'America/Grand_Turk', 322, 15, -1067, 15 end country 'TD', 'Chad' do |c| c.timezone 'Africa/Ndjamena', 727, 60, 301, 20 end country 'TF', 'French Southern & Antarctic Lands' do |c| c.timezone 'Indian/Kerguelen', -17767, 360, 28087, 400, 'Kerguelen, St Paul Island, Amsterdam Island' c.timezone 'Indian/Reunion', -313, 15, 832, 15, 'Réunion, Crozet, Scattered Islands' end country 'TG', 'Togo' do |c| c.timezone 'Africa/Abidjan', 319, 60, -121, 30 end country 'TH', 'Thailand' do |c| c.timezone 'Asia/Bangkok', 55, 4, 6031, 60, 'Indochina (most areas)' end country 'TJ', 'Tajikistan' do |c| c.timezone 'Asia/Dushanbe', 463, 12, 344, 5 end country 'TK', 'Tokelau' do |c| c.timezone 'Pacific/Fakaofo', -281, 30, -5137, 30 end country 'TL', 'East Timor' do |c| c.timezone 'Asia/Dili', -171, 20, 1507, 12 end country 'TM', 'Turkmenistan' do |c| c.timezone 'Asia/Ashgabat', 759, 20, 3503, 60 end country 'TN', 'Tunisia' do |c| c.timezone 'Africa/Tunis', 184, 5, 611, 60 end country 'TO', 'Tonga' do |c| c.timezone 'Pacific/Tongatapu', -127, 6, -1051, 6 end country 'TR', 'Turkey' do |c| c.timezone 'Europe/Istanbul', 2461, 60, 869, 30 end country 'TT', 'Trinidad & Tobago' do |c| c.timezone 'America/Port_of_Spain', 213, 20, -3691, 60 end country 'TV', 'Tuvalu' do |c| c.timezone 'Pacific/Funafuti', -511, 60, 10753, 60 end country 'TW', 'Taiwan' do |c| c.timezone 'Asia/Taipei', 501, 20, 243, 2 end country 'TZ', 'Tanzania' do |c| c.timezone 'Africa/Nairobi', -77, 60, 2209, 60 end country 'UA', 'Ukraine' do |c| c.timezone 'Europe/Kiev', 1513, 30, 1831, 60, 'Ukraine (most areas)' c.timezone 'Europe/Uzhgorod', 2917, 60, 223, 10, 'Transcarpathia' c.timezone 'Europe/Zaporozhye', 287, 6, 211, 6, 'Zaporozhye and east Lugansk' c.timezone 'Europe/Simferopol', 899, 20, 341, 10, 'Crimea' end country 'UG', 'Uganda' do |c| c.timezone 'Africa/Nairobi', -77, 60, 2209, 60 end country 'UM', 'US minor outlying islands' do |c| c.timezone 'Pacific/Wake', 1157, 60, 9997, 60, 'Wake Island' c.timezone 'Pacific/Pago_Pago', -214, 15, -1707, 10, 'Samoa, Midway' c.timezone 'Pacific/Honolulu', 15341, 720, -18943, 120, 'Hawaii' end country 'US', 'United States' do |c| c.timezone 'America/New_York', 48857, 1200, -266423, 3600, 'Eastern (most areas)' c.timezone 'America/Detroit', 152393, 3600, -19931, 240, 'Eastern - MI (most areas)' c.timezone 'America/Kentucky/Louisville', 9181, 240, -154367, 1800, 'Eastern - KY (Louisville area)' c.timezone 'America/Kentucky/Monticello', 132587, 3600, -101819, 1200, 'Eastern - KY (Wayne)' c.timezone 'America/Indiana/Indianapolis', 23861, 600, -310169, 3600, 'Eastern - IN (most areas)' c.timezone 'America/Indiana/Vincennes', 69619, 1800, -315103, 3600, 'Eastern - IN (Da, Du, K, Mn)' c.timezone 'America/Indiana/Winamac', 29557, 720, -311771, 3600, 'Eastern - IN (Pulaski)' c.timezone 'America/Indiana/Marengo', 17269, 450, -310841, 3600, 'Eastern - IN (Crawford)' c.timezone 'America/Indiana/Petersburg', 138571, 3600, -314203, 3600, 'Eastern - IN (Pike)' c.timezone 'America/Indiana/Vevay', 34873, 900, -153121, 1800, 'Eastern - IN (Switzerland)' c.timezone 'America/Chicago', 837, 20, -1753, 20, 'Central (most areas)' c.timezone 'America/Indiana/Tell_City', 136631, 3600, -312341, 3600, 'Central - IN (Perry)' c.timezone 'America/Indiana/Knox', 9911, 240, -693, 8, 'Central - IN (Starke)' c.timezone 'America/Menominee', 40597, 900, -105137, 1200, 'Central - MI (Wisconsin border)' c.timezone 'America/North_Dakota/Center', 169619, 3600, -121559, 1200, 'Central - ND (Oliver)' c.timezone 'America/North_Dakota/New_Salem', 9369, 200, -121693, 1200, 'Central - ND (Morton rural)' c.timezone 'America/North_Dakota/Beulah', 56717, 1200, -916, 9, 'Central - ND (Mercer)' c.timezone 'America/Denver', 47687, 1200, -125981, 1200, 'Mountain (most areas)' c.timezone 'America/Boise', 157009, 3600, -46481, 400, 'Mountain - ID (south); OR (east)' c.timezone 'America/Phoenix', 20069, 600, -16811, 150, 'MST - Arizona (except Navajo)' c.timezone 'America/Los_Angeles', 30647, 900, -212837, 1800, 'Pacific' c.timezone 'America/Anchorage', 44077, 720, -539641, 3600, 'Alaska (most areas)' c.timezone 'America/Juneau', 209887, 3600, -483911, 3600, 'Alaska - Juneau area' c.timezone 'America/Sitka', 41167, 720, -487087, 3600, 'Alaska - Sitka area' c.timezone 'America/Metlakatla', 198457, 3600, -18947, 144, 'Alaska - Annette Island' c.timezone 'America/Yakutat', 214369, 3600, -251509, 1800, 'Alaska - Yakutat' c.timezone 'America/Nome', 58051, 900, -595463, 3600, 'Alaska (west)' c.timezone 'America/Adak', 1297, 25, -635969, 3600, 'Aleutian Islands' c.timezone 'Pacific/Honolulu', 15341, 720, -18943, 120, 'Hawaii' end country 'UY', 'Uruguay' do |c| c.timezone 'America/Montevideo', -41891, 1200, -4497, 80 end country 'UZ', 'Uzbekistan' do |c| c.timezone 'Asia/Samarkand', 119, 3, 334, 5, 'Uzbekistan (west)' c.timezone 'Asia/Tashkent', 124, 3, 693, 10, 'Uzbekistan (east)' end country 'VA', 'Vatican City' do |c| c.timezone 'Europe/Rome', 419, 10, 749, 60 end country 'VC', 'St Vincent' do |c| c.timezone 'America/Port_of_Spain', 213, 20, -3691, 60 end country 'VE', 'Venezuela' do |c| c.timezone 'America/Caracas', 21, 2, -1004, 15 end country 'VG', 'Virgin Islands (UK)' do |c| c.timezone 'America/Port_of_Spain', 213, 20, -3691, 60 end country 'VI', 'Virgin Islands (US)' do |c| c.timezone 'America/Port_of_Spain', 213, 20, -3691, 60 end country 'VN', 'Vietnam' do |c| c.timezone 'Asia/Ho_Chi_Minh', 43, 4, 320, 3, 'Vietnam (south)' c.timezone 'Asia/Bangkok', 55, 4, 6031, 60, 'Indochina (most areas)' end country 'VU', 'Vanuatu' do |c| c.timezone 'Pacific/Efate', -53, 3, 2021, 12 end country 'WF', 'Wallis & Futuna' do |c| c.timezone 'Pacific/Wallis', -133, 10, -1057, 6 end country 'WS', 'Samoa (western)' do |c| c.timezone 'Pacific/Apia', -83, 6, -2576, 15 end country 'YE', 'Yemen' do |c| c.timezone 'Asia/Riyadh', 739, 30, 2803, 60 end country 'YT', 'Mayotte' do |c| c.timezone 'Africa/Nairobi', -77, 60, 2209, 60 end country 'ZA', 'South Africa' do |c| c.timezone 'Africa/Johannesburg', -105, 4, 28, 1 end country 'ZM', 'Zambia' do |c| c.timezone 'Africa/Maputo', -779, 30, 391, 12, 'Central Africa Time' end country 'ZW', 'Zimbabwe' do |c| c.timezone 'Africa/Maputo', -779, 30, 391, 12, 'Central Africa Time' end end end end end tzinfo-2.0.6/test/tzinfo-data1/tzinfo/data/indexes/timezones.rb000066400000000000000000000530121436527530500245460ustar00rootroot00000000000000# encoding: UTF-8 # This file contains data derived from the IANA Time Zone Database # (https://www.iana.org/time-zones). module TZInfo module Data module Indexes module Timezones include TimezoneIndexDefinition timezone 'Africa/Abidjan' timezone 'Africa/Accra' linked_timezone 'Africa/Addis_Ababa' timezone 'Africa/Algiers' linked_timezone 'Africa/Asmara' linked_timezone 'Africa/Asmera' linked_timezone 'Africa/Bamako' linked_timezone 'Africa/Bangui' linked_timezone 'Africa/Banjul' timezone 'Africa/Bissau' linked_timezone 'Africa/Blantyre' linked_timezone 'Africa/Brazzaville' linked_timezone 'Africa/Bujumbura' timezone 'Africa/Cairo' timezone 'Africa/Casablanca' timezone 'Africa/Ceuta' linked_timezone 'Africa/Conakry' linked_timezone 'Africa/Dakar' linked_timezone 'Africa/Dar_es_Salaam' linked_timezone 'Africa/Djibouti' linked_timezone 'Africa/Douala' timezone 'Africa/El_Aaiun' linked_timezone 'Africa/Freetown' linked_timezone 'Africa/Gaborone' linked_timezone 'Africa/Harare' timezone 'Africa/Johannesburg' timezone 'Africa/Juba' linked_timezone 'Africa/Kampala' timezone 'Africa/Khartoum' linked_timezone 'Africa/Kigali' linked_timezone 'Africa/Kinshasa' timezone 'Africa/Lagos' linked_timezone 'Africa/Libreville' linked_timezone 'Africa/Lome' linked_timezone 'Africa/Luanda' linked_timezone 'Africa/Lubumbashi' linked_timezone 'Africa/Lusaka' linked_timezone 'Africa/Malabo' timezone 'Africa/Maputo' linked_timezone 'Africa/Maseru' linked_timezone 'Africa/Mbabane' linked_timezone 'Africa/Mogadishu' timezone 'Africa/Monrovia' timezone 'Africa/Nairobi' timezone 'Africa/Ndjamena' linked_timezone 'Africa/Niamey' linked_timezone 'Africa/Nouakchott' linked_timezone 'Africa/Ouagadougou' linked_timezone 'Africa/Porto-Novo' timezone 'Africa/Sao_Tome' linked_timezone 'Africa/Timbuktu' timezone 'Africa/Tripoli' timezone 'Africa/Tunis' timezone 'Africa/Windhoek' timezone 'America/Adak' timezone 'America/Anchorage' linked_timezone 'America/Anguilla' linked_timezone 'America/Antigua' timezone 'America/Araguaina' timezone 'America/Argentina/Buenos_Aires' timezone 'America/Argentina/Catamarca' linked_timezone 'America/Argentina/ComodRivadavia' timezone 'America/Argentina/Cordoba' timezone 'America/Argentina/Jujuy' timezone 'America/Argentina/La_Rioja' timezone 'America/Argentina/Mendoza' timezone 'America/Argentina/Rio_Gallegos' timezone 'America/Argentina/Salta' timezone 'America/Argentina/San_Juan' timezone 'America/Argentina/San_Luis' timezone 'America/Argentina/Tucuman' timezone 'America/Argentina/Ushuaia' linked_timezone 'America/Aruba' timezone 'America/Asuncion' timezone 'America/Atikokan' linked_timezone 'America/Atka' timezone 'America/Bahia' timezone 'America/Bahia_Banderas' timezone 'America/Barbados' timezone 'America/Belem' timezone 'America/Belize' timezone 'America/Blanc-Sablon' timezone 'America/Boa_Vista' timezone 'America/Bogota' timezone 'America/Boise' linked_timezone 'America/Buenos_Aires' timezone 'America/Cambridge_Bay' timezone 'America/Campo_Grande' timezone 'America/Cancun' timezone 'America/Caracas' linked_timezone 'America/Catamarca' timezone 'America/Cayenne' linked_timezone 'America/Cayman' timezone 'America/Chicago' timezone 'America/Chihuahua' linked_timezone 'America/Coral_Harbour' linked_timezone 'America/Cordoba' timezone 'America/Costa_Rica' timezone 'America/Creston' timezone 'America/Cuiaba' timezone 'America/Curacao' timezone 'America/Danmarkshavn' timezone 'America/Dawson' timezone 'America/Dawson_Creek' timezone 'America/Denver' timezone 'America/Detroit' linked_timezone 'America/Dominica' timezone 'America/Edmonton' timezone 'America/Eirunepe' timezone 'America/El_Salvador' linked_timezone 'America/Ensenada' timezone 'America/Fort_Nelson' linked_timezone 'America/Fort_Wayne' timezone 'America/Fortaleza' timezone 'America/Glace_Bay' linked_timezone 'America/Godthab' timezone 'America/Goose_Bay' timezone 'America/Grand_Turk' linked_timezone 'America/Grenada' linked_timezone 'America/Guadeloupe' timezone 'America/Guatemala' timezone 'America/Guayaquil' timezone 'America/Guyana' timezone 'America/Halifax' timezone 'America/Havana' timezone 'America/Hermosillo' timezone 'America/Indiana/Indianapolis' timezone 'America/Indiana/Knox' timezone 'America/Indiana/Marengo' timezone 'America/Indiana/Petersburg' timezone 'America/Indiana/Tell_City' timezone 'America/Indiana/Vevay' timezone 'America/Indiana/Vincennes' timezone 'America/Indiana/Winamac' linked_timezone 'America/Indianapolis' timezone 'America/Inuvik' timezone 'America/Iqaluit' timezone 'America/Jamaica' linked_timezone 'America/Jujuy' timezone 'America/Juneau' timezone 'America/Kentucky/Louisville' timezone 'America/Kentucky/Monticello' linked_timezone 'America/Knox_IN' linked_timezone 'America/Kralendijk' timezone 'America/La_Paz' timezone 'America/Lima' timezone 'America/Los_Angeles' linked_timezone 'America/Louisville' linked_timezone 'America/Lower_Princes' timezone 'America/Maceio' timezone 'America/Managua' timezone 'America/Manaus' linked_timezone 'America/Marigot' timezone 'America/Martinique' timezone 'America/Matamoros' timezone 'America/Mazatlan' linked_timezone 'America/Mendoza' timezone 'America/Menominee' timezone 'America/Merida' timezone 'America/Metlakatla' timezone 'America/Mexico_City' timezone 'America/Miquelon' timezone 'America/Moncton' timezone 'America/Monterrey' timezone 'America/Montevideo' linked_timezone 'America/Montreal' linked_timezone 'America/Montserrat' timezone 'America/Nassau' timezone 'America/New_York' timezone 'America/Nipigon' timezone 'America/Nome' timezone 'America/Noronha' timezone 'America/North_Dakota/Beulah' timezone 'America/North_Dakota/Center' timezone 'America/North_Dakota/New_Salem' timezone 'America/Nuuk' timezone 'America/Ojinaga' timezone 'America/Panama' timezone 'America/Pangnirtung' timezone 'America/Paramaribo' timezone 'America/Phoenix' timezone 'America/Port-au-Prince' timezone 'America/Port_of_Spain' linked_timezone 'America/Porto_Acre' timezone 'America/Porto_Velho' timezone 'America/Puerto_Rico' timezone 'America/Punta_Arenas' timezone 'America/Rainy_River' timezone 'America/Rankin_Inlet' timezone 'America/Recife' timezone 'America/Regina' timezone 'America/Resolute' timezone 'America/Rio_Branco' linked_timezone 'America/Rosario' linked_timezone 'America/Santa_Isabel' timezone 'America/Santarem' timezone 'America/Santiago' timezone 'America/Santo_Domingo' timezone 'America/Sao_Paulo' timezone 'America/Scoresbysund' linked_timezone 'America/Shiprock' timezone 'America/Sitka' linked_timezone 'America/St_Barthelemy' timezone 'America/St_Johns' linked_timezone 'America/St_Kitts' linked_timezone 'America/St_Lucia' linked_timezone 'America/St_Thomas' linked_timezone 'America/St_Vincent' timezone 'America/Swift_Current' timezone 'America/Tegucigalpa' timezone 'America/Thule' timezone 'America/Thunder_Bay' timezone 'America/Tijuana' timezone 'America/Toronto' linked_timezone 'America/Tortola' timezone 'America/Vancouver' linked_timezone 'America/Virgin' timezone 'America/Whitehorse' timezone 'America/Winnipeg' timezone 'America/Yakutat' timezone 'America/Yellowknife' timezone 'Antarctica/Casey' timezone 'Antarctica/Davis' timezone 'Antarctica/DumontDUrville' timezone 'Antarctica/Macquarie' timezone 'Antarctica/Mawson' linked_timezone 'Antarctica/McMurdo' timezone 'Antarctica/Palmer' timezone 'Antarctica/Rothera' linked_timezone 'Antarctica/South_Pole' timezone 'Antarctica/Syowa' timezone 'Antarctica/Troll' timezone 'Antarctica/Vostok' linked_timezone 'Arctic/Longyearbyen' linked_timezone 'Asia/Aden' timezone 'Asia/Almaty' timezone 'Asia/Amman' timezone 'Asia/Anadyr' timezone 'Asia/Aqtau' timezone 'Asia/Aqtobe' timezone 'Asia/Ashgabat' linked_timezone 'Asia/Ashkhabad' timezone 'Asia/Atyrau' timezone 'Asia/Baghdad' linked_timezone 'Asia/Bahrain' timezone 'Asia/Baku' timezone 'Asia/Bangkok' timezone 'Asia/Barnaul' timezone 'Asia/Beirut' timezone 'Asia/Bishkek' timezone 'Asia/Brunei' linked_timezone 'Asia/Calcutta' timezone 'Asia/Chita' timezone 'Asia/Choibalsan' linked_timezone 'Asia/Chongqing' linked_timezone 'Asia/Chungking' timezone 'Asia/Colombo' linked_timezone 'Asia/Dacca' timezone 'Asia/Damascus' timezone 'Asia/Dhaka' timezone 'Asia/Dili' timezone 'Asia/Dubai' timezone 'Asia/Dushanbe' timezone 'Asia/Famagusta' timezone 'Asia/Gaza' linked_timezone 'Asia/Harbin' timezone 'Asia/Hebron' timezone 'Asia/Ho_Chi_Minh' timezone 'Asia/Hong_Kong' timezone 'Asia/Hovd' timezone 'Asia/Irkutsk' linked_timezone 'Asia/Istanbul' timezone 'Asia/Jakarta' timezone 'Asia/Jayapura' timezone 'Asia/Jerusalem' timezone 'Asia/Kabul' timezone 'Asia/Kamchatka' timezone 'Asia/Karachi' linked_timezone 'Asia/Kashgar' timezone 'Asia/Kathmandu' linked_timezone 'Asia/Katmandu' timezone 'Asia/Khandyga' timezone 'Asia/Kolkata' timezone 'Asia/Krasnoyarsk' timezone 'Asia/Kuala_Lumpur' timezone 'Asia/Kuching' linked_timezone 'Asia/Kuwait' linked_timezone 'Asia/Macao' timezone 'Asia/Macau' timezone 'Asia/Magadan' timezone 'Asia/Makassar' timezone 'Asia/Manila' linked_timezone 'Asia/Muscat' timezone 'Asia/Nicosia' timezone 'Asia/Novokuznetsk' timezone 'Asia/Novosibirsk' timezone 'Asia/Omsk' timezone 'Asia/Oral' linked_timezone 'Asia/Phnom_Penh' timezone 'Asia/Pontianak' timezone 'Asia/Pyongyang' timezone 'Asia/Qatar' timezone 'Asia/Qostanay' timezone 'Asia/Qyzylorda' linked_timezone 'Asia/Rangoon' timezone 'Asia/Riyadh' linked_timezone 'Asia/Saigon' timezone 'Asia/Sakhalin' timezone 'Asia/Samarkand' timezone 'Asia/Seoul' timezone 'Asia/Shanghai' timezone 'Asia/Singapore' timezone 'Asia/Srednekolymsk' timezone 'Asia/Taipei' timezone 'Asia/Tashkent' timezone 'Asia/Tbilisi' timezone 'Asia/Tehran' linked_timezone 'Asia/Tel_Aviv' linked_timezone 'Asia/Thimbu' timezone 'Asia/Thimphu' timezone 'Asia/Tokyo' timezone 'Asia/Tomsk' linked_timezone 'Asia/Ujung_Pandang' timezone 'Asia/Ulaanbaatar' linked_timezone 'Asia/Ulan_Bator' timezone 'Asia/Urumqi' timezone 'Asia/Ust-Nera' linked_timezone 'Asia/Vientiane' timezone 'Asia/Vladivostok' timezone 'Asia/Yakutsk' timezone 'Asia/Yangon' timezone 'Asia/Yekaterinburg' timezone 'Asia/Yerevan' timezone 'Atlantic/Azores' timezone 'Atlantic/Bermuda' timezone 'Atlantic/Canary' timezone 'Atlantic/Cape_Verde' linked_timezone 'Atlantic/Faeroe' timezone 'Atlantic/Faroe' linked_timezone 'Atlantic/Jan_Mayen' timezone 'Atlantic/Madeira' timezone 'Atlantic/Reykjavik' timezone 'Atlantic/South_Georgia' linked_timezone 'Atlantic/St_Helena' timezone 'Atlantic/Stanley' linked_timezone 'Australia/ACT' timezone 'Australia/Adelaide' timezone 'Australia/Brisbane' timezone 'Australia/Broken_Hill' linked_timezone 'Australia/Canberra' timezone 'Australia/Currie' timezone 'Australia/Darwin' timezone 'Australia/Eucla' timezone 'Australia/Hobart' linked_timezone 'Australia/LHI' timezone 'Australia/Lindeman' timezone 'Australia/Lord_Howe' timezone 'Australia/Melbourne' linked_timezone 'Australia/NSW' linked_timezone 'Australia/North' timezone 'Australia/Perth' linked_timezone 'Australia/Queensland' linked_timezone 'Australia/South' timezone 'Australia/Sydney' linked_timezone 'Australia/Tasmania' linked_timezone 'Australia/Victoria' linked_timezone 'Australia/West' linked_timezone 'Australia/Yancowinna' linked_timezone 'Brazil/Acre' linked_timezone 'Brazil/DeNoronha' linked_timezone 'Brazil/East' linked_timezone 'Brazil/West' timezone 'CET' timezone 'CST6CDT' linked_timezone 'Canada/Atlantic' linked_timezone 'Canada/Central' linked_timezone 'Canada/Eastern' linked_timezone 'Canada/Mountain' linked_timezone 'Canada/Newfoundland' linked_timezone 'Canada/Pacific' linked_timezone 'Canada/Saskatchewan' linked_timezone 'Canada/Yukon' linked_timezone 'Chile/Continental' linked_timezone 'Chile/EasterIsland' linked_timezone 'Cuba' timezone 'EET' timezone 'EST' timezone 'EST5EDT' linked_timezone 'Egypt' linked_timezone 'Eire' timezone 'Etc/GMT' linked_timezone 'Etc/GMT+0' timezone 'Etc/GMT+1' timezone 'Etc/GMT+10' timezone 'Etc/GMT+11' timezone 'Etc/GMT+12' timezone 'Etc/GMT+2' timezone 'Etc/GMT+3' timezone 'Etc/GMT+4' timezone 'Etc/GMT+5' timezone 'Etc/GMT+6' timezone 'Etc/GMT+7' timezone 'Etc/GMT+8' timezone 'Etc/GMT+9' linked_timezone 'Etc/GMT-0' timezone 'Etc/GMT-1' timezone 'Etc/GMT-10' timezone 'Etc/GMT-11' timezone 'Etc/GMT-12' timezone 'Etc/GMT-13' timezone 'Etc/GMT-14' timezone 'Etc/GMT-2' timezone 'Etc/GMT-3' timezone 'Etc/GMT-4' timezone 'Etc/GMT-5' timezone 'Etc/GMT-6' timezone 'Etc/GMT-7' timezone 'Etc/GMT-8' timezone 'Etc/GMT-9' linked_timezone 'Etc/GMT0' linked_timezone 'Etc/Greenwich' linked_timezone 'Etc/UCT' timezone 'Etc/UTC' linked_timezone 'Etc/Universal' linked_timezone 'Etc/Zulu' timezone 'Europe/Amsterdam' timezone 'Europe/Andorra' timezone 'Europe/Astrakhan' timezone 'Europe/Athens' linked_timezone 'Europe/Belfast' timezone 'Europe/Belgrade' timezone 'Europe/Berlin' linked_timezone 'Europe/Bratislava' timezone 'Europe/Brussels' timezone 'Europe/Bucharest' timezone 'Europe/Budapest' linked_timezone 'Europe/Busingen' timezone 'Europe/Chisinau' timezone 'Europe/Copenhagen' timezone 'Europe/Dublin' timezone 'Europe/Gibraltar' linked_timezone 'Europe/Guernsey' timezone 'Europe/Helsinki' linked_timezone 'Europe/Isle_of_Man' timezone 'Europe/Istanbul' linked_timezone 'Europe/Jersey' timezone 'Europe/Kaliningrad' timezone 'Europe/Kiev' timezone 'Europe/Kirov' timezone 'Europe/Lisbon' linked_timezone 'Europe/Ljubljana' timezone 'Europe/London' timezone 'Europe/Luxembourg' timezone 'Europe/Madrid' timezone 'Europe/Malta' linked_timezone 'Europe/Mariehamn' timezone 'Europe/Minsk' timezone 'Europe/Monaco' timezone 'Europe/Moscow' linked_timezone 'Europe/Nicosia' timezone 'Europe/Oslo' timezone 'Europe/Paris' linked_timezone 'Europe/Podgorica' timezone 'Europe/Prague' timezone 'Europe/Riga' timezone 'Europe/Rome' timezone 'Europe/Samara' linked_timezone 'Europe/San_Marino' linked_timezone 'Europe/Sarajevo' timezone 'Europe/Saratov' timezone 'Europe/Simferopol' linked_timezone 'Europe/Skopje' timezone 'Europe/Sofia' timezone 'Europe/Stockholm' timezone 'Europe/Tallinn' timezone 'Europe/Tirane' linked_timezone 'Europe/Tiraspol' timezone 'Europe/Ulyanovsk' timezone 'Europe/Uzhgorod' linked_timezone 'Europe/Vaduz' linked_timezone 'Europe/Vatican' timezone 'Europe/Vienna' timezone 'Europe/Vilnius' timezone 'Europe/Volgograd' timezone 'Europe/Warsaw' linked_timezone 'Europe/Zagreb' timezone 'Europe/Zaporozhye' timezone 'Europe/Zurich' timezone 'Factory' linked_timezone 'GB' linked_timezone 'GB-Eire' linked_timezone 'GMT' linked_timezone 'GMT+0' linked_timezone 'GMT-0' linked_timezone 'GMT0' linked_timezone 'Greenwich' timezone 'HST' linked_timezone 'Hongkong' linked_timezone 'Iceland' linked_timezone 'Indian/Antananarivo' timezone 'Indian/Chagos' timezone 'Indian/Christmas' timezone 'Indian/Cocos' linked_timezone 'Indian/Comoro' timezone 'Indian/Kerguelen' timezone 'Indian/Mahe' timezone 'Indian/Maldives' timezone 'Indian/Mauritius' linked_timezone 'Indian/Mayotte' timezone 'Indian/Reunion' linked_timezone 'Iran' linked_timezone 'Israel' linked_timezone 'Jamaica' linked_timezone 'Japan' linked_timezone 'Kwajalein' linked_timezone 'Libya' timezone 'MET' timezone 'MST' timezone 'MST7MDT' linked_timezone 'Mexico/BajaNorte' linked_timezone 'Mexico/BajaSur' linked_timezone 'Mexico/General' linked_timezone 'NZ' linked_timezone 'NZ-CHAT' linked_timezone 'Navajo' linked_timezone 'PRC' timezone 'PST8PDT' timezone 'Pacific/Apia' timezone 'Pacific/Auckland' timezone 'Pacific/Bougainville' timezone 'Pacific/Chatham' timezone 'Pacific/Chuuk' timezone 'Pacific/Easter' timezone 'Pacific/Efate' timezone 'Pacific/Enderbury' timezone 'Pacific/Fakaofo' timezone 'Pacific/Fiji' timezone 'Pacific/Funafuti' timezone 'Pacific/Galapagos' timezone 'Pacific/Gambier' timezone 'Pacific/Guadalcanal' timezone 'Pacific/Guam' timezone 'Pacific/Honolulu' linked_timezone 'Pacific/Johnston' timezone 'Pacific/Kiritimati' timezone 'Pacific/Kosrae' timezone 'Pacific/Kwajalein' timezone 'Pacific/Majuro' timezone 'Pacific/Marquesas' linked_timezone 'Pacific/Midway' timezone 'Pacific/Nauru' timezone 'Pacific/Niue' timezone 'Pacific/Norfolk' timezone 'Pacific/Noumea' timezone 'Pacific/Pago_Pago' timezone 'Pacific/Palau' timezone 'Pacific/Pitcairn' timezone 'Pacific/Pohnpei' linked_timezone 'Pacific/Ponape' timezone 'Pacific/Port_Moresby' timezone 'Pacific/Rarotonga' linked_timezone 'Pacific/Saipan' linked_timezone 'Pacific/Samoa' timezone 'Pacific/Tahiti' timezone 'Pacific/Tarawa' timezone 'Pacific/Tongatapu' linked_timezone 'Pacific/Truk' timezone 'Pacific/Wake' timezone 'Pacific/Wallis' linked_timezone 'Pacific/Yap' linked_timezone 'Poland' linked_timezone 'Portugal' linked_timezone 'ROC' linked_timezone 'ROK' linked_timezone 'Singapore' linked_timezone 'Turkey' linked_timezone 'UCT' linked_timezone 'US/Alaska' linked_timezone 'US/Aleutian' linked_timezone 'US/Arizona' linked_timezone 'US/Central' linked_timezone 'US/East-Indiana' linked_timezone 'US/Eastern' linked_timezone 'US/Hawaii' linked_timezone 'US/Indiana-Starke' linked_timezone 'US/Michigan' linked_timezone 'US/Mountain' linked_timezone 'US/Pacific' linked_timezone 'US/Samoa' linked_timezone 'UTC' linked_timezone 'Universal' linked_timezone 'W-SU' timezone 'WET' linked_timezone 'Zulu' end end end end tzinfo-2.0.6/test/tzinfo-data1/tzinfo/data/version.rb000066400000000000000000000010121436527530500225500ustar00rootroot00000000000000module TZInfo module Data # TZInfo::Data version number. VERSION = '1.2020.4.test' # TZInfo::Data version information. module Version # The format of the Ruby modules. The only format currently supported by # TZInfo is version 1. FORMAT = 1 # TZInfo::Data version number. STRING = VERSION # The version of the {IANA Time Zone Database}[https://www.iana.org/time-zones] # used to generate this version of TZInfo::Data. TZDATA = '2020d' end end end tzinfo-2.0.6/test/tzinfo-data2/000077500000000000000000000000001436527530500163235ustar00rootroot00000000000000tzinfo-2.0.6/test/tzinfo-data2/tzinfo/000077500000000000000000000000001436527530500176345ustar00rootroot00000000000000tzinfo-2.0.6/test/tzinfo-data2/tzinfo/data.rb000066400000000000000000000007141436527530500210740ustar00rootroot00000000000000# encoding: UTF-8 # Top level module for TZInfo. module TZInfo # Top level module for TZInfo::Data. module Data location = File.dirname(File.dirname(__FILE__)) if location.respond_to?(:untaint) && RUBY_VERSION =~ /\A(\d+)\.(\d+)(?:\.|\z)/ && ($1 == '2' && $2.to_i < 7 || $1.to_i <= 1) location.untaint end # The directory containing the TZInfo::Data files. LOCATION = location.freeze end end require_relative 'data/version' tzinfo-2.0.6/test/tzinfo-data2/tzinfo/data/000077500000000000000000000000001436527530500205455ustar00rootroot00000000000000tzinfo-2.0.6/test/tzinfo-data2/tzinfo/data/definitions/000077500000000000000000000000001436527530500230605ustar00rootroot00000000000000tzinfo-2.0.6/test/tzinfo-data2/tzinfo/data/definitions/America/000077500000000000000000000000001436527530500244215ustar00rootroot00000000000000tzinfo-2.0.6/test/tzinfo-data2/tzinfo/data/definitions/America/Argentina/000077500000000000000000000000001436527530500263315ustar00rootroot00000000000000tzinfo-2.0.6/test/tzinfo-data2/tzinfo/data/definitions/America/Argentina/Buenos_Aires.rb000066400000000000000000000065421436527530500312430ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true # This file contains data derived from the IANA Time Zone Database # (https://www.iana.org/time-zones). module TZInfo module Data module Definitions module America module Argentina module Buenos_Aires include Format2::TimezoneDefinition timezone 'America/Argentina/Buenos_Aires' do |tz| tz.offset :o0, -14028, 0, 'LMT' tz.offset :o1, -15408, 0, 'CMT' tz.offset :o2, -14400, 0, '-04' tz.offset :o3, -14400, 3600, '-03' tz.offset :o4, -10800, 0, '-03' tz.offset :o5, -10800, 3600, '-02' tz.transition :o1, -2372097972 tz.transition :o2, -1567453392 tz.transition :o3, -1233432000 tz.transition :o2, -1222981200 tz.transition :o3, -1205956800 tz.transition :o2, -1194037200 tz.transition :o3, -1172865600 tz.transition :o2, -1162501200 tz.transition :o3, -1141329600 tz.transition :o2, -1130965200 tz.transition :o3, -1109793600 tz.transition :o2, -1099429200 tz.transition :o3, -1078257600 tz.transition :o2, -1067806800 tz.transition :o3, -1046635200 tz.transition :o2, -1036270800 tz.transition :o3, -1015099200 tz.transition :o2, -1004734800 tz.transition :o3, -983563200 tz.transition :o2, -973198800 tz.transition :o3, -952027200 tz.transition :o2, -941576400 tz.transition :o3, -931032000 tz.transition :o2, -900882000 tz.transition :o3, -890337600 tz.transition :o2, -833749200 tz.transition :o3, -827265600 tz.transition :o2, -752274000 tz.transition :o3, -733780800 tz.transition :o2, -197326800 tz.transition :o3, -190843200 tz.transition :o2, -184194000 tz.transition :o3, -164491200 tz.transition :o2, -152658000 tz.transition :o3, -132955200 tz.transition :o2, -121122000 tz.transition :o3, -101419200 tz.transition :o2, -86821200 tz.transition :o3, -71092800 tz.transition :o2, -54766800 tz.transition :o3, -39038400 tz.transition :o2, -23317200 tz.transition :o4, -7588800 tz.transition :o5, 128142000 tz.transition :o4, 136605600 tz.transition :o5, 596948400 tz.transition :o4, 605066400 tz.transition :o5, 624423600 tz.transition :o4, 636516000 tz.transition :o5, 656478000 tz.transition :o4, 667965600 tz.transition :o5, 687927600 tz.transition :o4, 699415200 tz.transition :o5, 719377200 tz.transition :o4, 731469600 tz.transition :o3, 938919600 tz.transition :o4, 952052400 tz.transition :o5, 1198983600 tz.transition :o4, 1205632800 tz.transition :o5, 1224385200 tz.transition :o4, 1237082400 end end end end end end end tzinfo-2.0.6/test/tzinfo-data2/tzinfo/data/definitions/America/New_York.rb000066400000000000000000000317341436527530500265130ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true # This file contains data derived from the IANA Time Zone Database # (https://www.iana.org/time-zones). module TZInfo module Data module Definitions module America module New_York include Format2::TimezoneDefinition timezone 'America/New_York' do |tz| tz.offset :o0, -17762, 0, 'LMT' tz.offset :o1, -18000, 0, 'EST' tz.offset :o2, -18000, 3600, 'EDT' tz.offset :o3, -18000, 3600, 'EWT' tz.offset :o4, -18000, 3600, 'EPT' tz.transition :o1, -2717650800 tz.transition :o2, -1633280400 tz.transition :o1, -1615140000 tz.transition :o2, -1601830800 tz.transition :o1, -1583690400 tz.transition :o2, -1570381200 tz.transition :o1, -1551636000 tz.transition :o2, -1536512400 tz.transition :o1, -1523210400 tz.transition :o2, -1504458000 tz.transition :o1, -1491760800 tz.transition :o2, -1473008400 tz.transition :o1, -1459706400 tz.transition :o2, -1441558800 tz.transition :o1, -1428256800 tz.transition :o2, -1410109200 tz.transition :o1, -1396807200 tz.transition :o2, -1378659600 tz.transition :o1, -1365357600 tz.transition :o2, -1347210000 tz.transition :o1, -1333908000 tz.transition :o2, -1315155600 tz.transition :o1, -1301853600 tz.transition :o2, -1283706000 tz.transition :o1, -1270404000 tz.transition :o2, -1252256400 tz.transition :o1, -1238954400 tz.transition :o2, -1220806800 tz.transition :o1, -1207504800 tz.transition :o2, -1189357200 tz.transition :o1, -1176055200 tz.transition :o2, -1157302800 tz.transition :o1, -1144605600 tz.transition :o2, -1125853200 tz.transition :o1, -1112551200 tz.transition :o2, -1094403600 tz.transition :o1, -1081101600 tz.transition :o2, -1062954000 tz.transition :o1, -1049652000 tz.transition :o2, -1031504400 tz.transition :o1, -1018202400 tz.transition :o2, -1000054800 tz.transition :o1, -986752800 tz.transition :o2, -968000400 tz.transition :o1, -955303200 tz.transition :o2, -936550800 tz.transition :o1, -923248800 tz.transition :o2, -905101200 tz.transition :o1, -891799200 tz.transition :o3, -880218000 tz.transition :o4, -769395600 tz.transition :o1, -765396000 tz.transition :o2, -747248400 tz.transition :o1, -733946400 tz.transition :o2, -715798800 tz.transition :o1, -702496800 tz.transition :o2, -684349200 tz.transition :o1, -671047200 tz.transition :o2, -652899600 tz.transition :o1, -639597600 tz.transition :o2, -620845200 tz.transition :o1, -608148000 tz.transition :o2, -589395600 tz.transition :o1, -576093600 tz.transition :o2, -557946000 tz.transition :o1, -544644000 tz.transition :o2, -526496400 tz.transition :o1, -513194400 tz.transition :o2, -495046800 tz.transition :o1, -481744800 tz.transition :o2, -463597200 tz.transition :o1, -447271200 tz.transition :o2, -431542800 tz.transition :o1, -415821600 tz.transition :o2, -400093200 tz.transition :o1, -384372000 tz.transition :o2, -368643600 tz.transition :o1, -352922400 tz.transition :o2, -337194000 tz.transition :o1, -321472800 tz.transition :o2, -305744400 tz.transition :o1, -289418400 tz.transition :o2, -273690000 tz.transition :o1, -257968800 tz.transition :o2, -242240400 tz.transition :o1, -226519200 tz.transition :o2, -210790800 tz.transition :o1, -195069600 tz.transition :o2, -179341200 tz.transition :o1, -163620000 tz.transition :o2, -147891600 tz.transition :o1, -131565600 tz.transition :o2, -116442000 tz.transition :o1, -100116000 tz.transition :o2, -84387600 tz.transition :o1, -68666400 tz.transition :o2, -52938000 tz.transition :o1, -37216800 tz.transition :o2, -21488400 tz.transition :o1, -5767200 tz.transition :o2, 9961200 tz.transition :o1, 25682400 tz.transition :o2, 41410800 tz.transition :o1, 57736800 tz.transition :o2, 73465200 tz.transition :o1, 89186400 tz.transition :o2, 104914800 tz.transition :o1, 120636000 tz.transition :o2, 126687600 tz.transition :o1, 152085600 tz.transition :o2, 162370800 tz.transition :o1, 183535200 tz.transition :o2, 199263600 tz.transition :o1, 215589600 tz.transition :o2, 230713200 tz.transition :o1, 247039200 tz.transition :o2, 262767600 tz.transition :o1, 278488800 tz.transition :o2, 294217200 tz.transition :o1, 309938400 tz.transition :o2, 325666800 tz.transition :o1, 341388000 tz.transition :o2, 357116400 tz.transition :o1, 372837600 tz.transition :o2, 388566000 tz.transition :o1, 404892000 tz.transition :o2, 420015600 tz.transition :o1, 436341600 tz.transition :o2, 452070000 tz.transition :o1, 467791200 tz.transition :o2, 483519600 tz.transition :o1, 499240800 tz.transition :o2, 514969200 tz.transition :o1, 530690400 tz.transition :o2, 544604400 tz.transition :o1, 562140000 tz.transition :o2, 576054000 tz.transition :o1, 594194400 tz.transition :o2, 607503600 tz.transition :o1, 625644000 tz.transition :o2, 638953200 tz.transition :o1, 657093600 tz.transition :o2, 671007600 tz.transition :o1, 688543200 tz.transition :o2, 702457200 tz.transition :o1, 719992800 tz.transition :o2, 733906800 tz.transition :o1, 752047200 tz.transition :o2, 765356400 tz.transition :o1, 783496800 tz.transition :o2, 796806000 tz.transition :o1, 814946400 tz.transition :o2, 828860400 tz.transition :o1, 846396000 tz.transition :o2, 860310000 tz.transition :o1, 877845600 tz.transition :o2, 891759600 tz.transition :o1, 909295200 tz.transition :o2, 923209200 tz.transition :o1, 941349600 tz.transition :o2, 954658800 tz.transition :o1, 972799200 tz.transition :o2, 986108400 tz.transition :o1, 1004248800 tz.transition :o2, 1018162800 tz.transition :o1, 1035698400 tz.transition :o2, 1049612400 tz.transition :o1, 1067148000 tz.transition :o2, 1081062000 tz.transition :o1, 1099202400 tz.transition :o2, 1112511600 tz.transition :o1, 1130652000 tz.transition :o2, 1143961200 tz.transition :o1, 1162101600 tz.transition :o2, 1173596400 tz.transition :o1, 1194156000 tz.transition :o2, 1205046000 tz.transition :o1, 1225605600 tz.transition :o2, 1236495600 tz.transition :o1, 1257055200 tz.transition :o2, 1268550000 tz.transition :o1, 1289109600 tz.transition :o2, 1299999600 tz.transition :o1, 1320559200 tz.transition :o2, 1331449200 tz.transition :o1, 1352008800 tz.transition :o2, 1362898800 tz.transition :o1, 1383458400 tz.transition :o2, 1394348400 tz.transition :o1, 1414908000 tz.transition :o2, 1425798000 tz.transition :o1, 1446357600 tz.transition :o2, 1457852400 tz.transition :o1, 1478412000 tz.transition :o2, 1489302000 tz.transition :o1, 1509861600 tz.transition :o2, 1520751600 tz.transition :o1, 1541311200 tz.transition :o2, 1552201200 tz.transition :o1, 1572760800 tz.transition :o2, 1583650800 tz.transition :o1, 1604210400 tz.transition :o2, 1615705200 tz.transition :o1, 1636264800 tz.transition :o2, 1647154800 tz.transition :o1, 1667714400 tz.transition :o2, 1678604400 tz.transition :o1, 1699164000 tz.transition :o2, 1710054000 tz.transition :o1, 1730613600 tz.transition :o2, 1741503600 tz.transition :o1, 1762063200 tz.transition :o2, 1772953200 tz.transition :o1, 1793512800 tz.transition :o2, 1805007600 tz.transition :o1, 1825567200 tz.transition :o2, 1836457200 tz.transition :o1, 1857016800 tz.transition :o2, 1867906800 tz.transition :o1, 1888466400 tz.transition :o2, 1899356400 tz.transition :o1, 1919916000 tz.transition :o2, 1930806000 tz.transition :o1, 1951365600 tz.transition :o2, 1962860400 tz.transition :o1, 1983420000 tz.transition :o2, 1994310000 tz.transition :o1, 2014869600 tz.transition :o2, 2025759600 tz.transition :o1, 2046319200 tz.transition :o2, 2057209200 tz.transition :o1, 2077768800 tz.transition :o2, 2088658800 tz.transition :o1, 2109218400 tz.transition :o2, 2120108400 tz.transition :o1, 2140668000 tz.transition :o2, 2152162800 tz.transition :o1, 2172722400 tz.transition :o2, 2183612400 tz.transition :o1, 2204172000 tz.transition :o2, 2215062000 tz.transition :o1, 2235621600 tz.transition :o2, 2246511600 tz.transition :o1, 2267071200 tz.transition :o2, 2277961200 tz.transition :o1, 2298520800 tz.transition :o2, 2309410800 tz.transition :o1, 2329970400 tz.transition :o2, 2341465200 tz.transition :o1, 2362024800 tz.transition :o2, 2372914800 tz.transition :o1, 2393474400 tz.transition :o2, 2404364400 tz.transition :o1, 2424924000 tz.transition :o2, 2435814000 tz.transition :o1, 2456373600 tz.transition :o2, 2467263600 tz.transition :o1, 2487823200 tz.transition :o2, 2499318000 tz.transition :o1, 2519877600 tz.transition :o2, 2530767600 tz.transition :o1, 2551327200 tz.transition :o2, 2562217200 tz.transition :o1, 2582776800 tz.transition :o2, 2593666800 tz.transition :o1, 2614226400 tz.transition :o2, 2625116400 tz.transition :o1, 2645676000 tz.transition :o2, 2656566000 tz.transition :o1, 2677125600 tz.transition :o2, 2688620400 tz.transition :o1, 2709180000 tz.transition :o2, 2720070000 tz.transition :o1, 2740629600 tz.transition :o2, 2751519600 tz.transition :o1, 2772079200 tz.transition :o2, 2782969200 tz.transition :o1, 2803528800 tz.transition :o2, 2814418800 tz.transition :o1, 2834978400 tz.transition :o2, 2846473200 tz.transition :o1, 2867032800 tz.transition :o2, 2877922800 tz.transition :o1, 2898482400 tz.transition :o2, 2909372400 tz.transition :o1, 2929932000 tz.transition :o2, 2940822000 tz.transition :o1, 2961381600 tz.transition :o2, 2972271600 tz.transition :o1, 2992831200 tz.transition :o2, 3003721200 tz.transition :o1, 3024280800 tz.transition :o2, 3035775600 tz.transition :o1, 3056335200 tz.transition :o2, 3067225200 tz.transition :o1, 3087784800 tz.transition :o2, 3098674800 tz.transition :o1, 3119234400 tz.transition :o2, 3130124400 tz.transition :o1, 3150684000 tz.transition :o2, 3161574000 tz.transition :o1, 3182133600 end end end end end end tzinfo-2.0.6/test/tzinfo-data2/tzinfo/data/definitions/Australia/000077500000000000000000000000001436527530500250055ustar00rootroot00000000000000tzinfo-2.0.6/test/tzinfo-data2/tzinfo/data/definitions/Australia/Melbourne.rb000066400000000000000000000217241436527530500272700ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true # This file contains data derived from the IANA Time Zone Database # (https://www.iana.org/time-zones). module TZInfo module Data module Definitions module Australia module Melbourne include Format2::TimezoneDefinition timezone 'Australia/Melbourne' do |tz| tz.offset :o0, 34792, 0, 'LMT' tz.offset :o1, 36000, 0, 'AEST' tz.offset :o2, 36000, 3600, 'AEDT' tz.transition :o1, -2364111592 tz.transition :o2, -1672567140 tz.transition :o1, -1665392400 tz.transition :o2, -883641600 tz.transition :o1, -876128400 tz.transition :o2, -860400000 tz.transition :o1, -844678800 tz.transition :o2, -828345600 tz.transition :o1, -813229200 tz.transition :o2, 57686400 tz.transition :o1, 67968000 tz.transition :o2, 89136000 tz.transition :o1, 100022400 tz.transition :o2, 120585600 tz.transition :o1, 131472000 tz.transition :o2, 152035200 tz.transition :o1, 162921600 tz.transition :o2, 183484800 tz.transition :o1, 194976000 tz.transition :o2, 215539200 tz.transition :o1, 226425600 tz.transition :o2, 246988800 tz.transition :o1, 257875200 tz.transition :o2, 278438400 tz.transition :o1, 289324800 tz.transition :o2, 309888000 tz.transition :o1, 320774400 tz.transition :o2, 341337600 tz.transition :o1, 352224000 tz.transition :o2, 372787200 tz.transition :o1, 384278400 tz.transition :o2, 404841600 tz.transition :o1, 415728000 tz.transition :o2, 436291200 tz.transition :o1, 447177600 tz.transition :o2, 467740800 tz.transition :o1, 478627200 tz.transition :o2, 499190400 tz.transition :o1, 511286400 tz.transition :o2, 530035200 tz.transition :o1, 542736000 tz.transition :o2, 561484800 tz.transition :o1, 574790400 tz.transition :o2, 594144000 tz.transition :o1, 606240000 tz.transition :o2, 625593600 tz.transition :o1, 637689600 tz.transition :o2, 657043200 tz.transition :o1, 667929600 tz.transition :o2, 688492800 tz.transition :o1, 699379200 tz.transition :o2, 719942400 tz.transition :o1, 731433600 tz.transition :o2, 751996800 tz.transition :o1, 762883200 tz.transition :o2, 783446400 tz.transition :o1, 796147200 tz.transition :o2, 814896000 tz.transition :o1, 828201600 tz.transition :o2, 846345600 tz.transition :o1, 859651200 tz.transition :o2, 877795200 tz.transition :o1, 891100800 tz.transition :o2, 909244800 tz.transition :o1, 922550400 tz.transition :o2, 941299200 tz.transition :o1, 954000000 tz.transition :o2, 967305600 tz.transition :o1, 985449600 tz.transition :o2, 1004198400 tz.transition :o1, 1017504000 tz.transition :o2, 1035648000 tz.transition :o1, 1048953600 tz.transition :o2, 1067097600 tz.transition :o1, 1080403200 tz.transition :o2, 1099152000 tz.transition :o1, 1111852800 tz.transition :o2, 1130601600 tz.transition :o1, 1143907200 tz.transition :o2, 1162051200 tz.transition :o1, 1174752000 tz.transition :o2, 1193500800 tz.transition :o1, 1207411200 tz.transition :o2, 1223136000 tz.transition :o1, 1238860800 tz.transition :o2, 1254585600 tz.transition :o1, 1270310400 tz.transition :o2, 1286035200 tz.transition :o1, 1301760000 tz.transition :o2, 1317484800 tz.transition :o1, 1333209600 tz.transition :o2, 1349539200 tz.transition :o1, 1365264000 tz.transition :o2, 1380988800 tz.transition :o1, 1396713600 tz.transition :o2, 1412438400 tz.transition :o1, 1428163200 tz.transition :o2, 1443888000 tz.transition :o1, 1459612800 tz.transition :o2, 1475337600 tz.transition :o1, 1491062400 tz.transition :o2, 1506787200 tz.transition :o1, 1522512000 tz.transition :o2, 1538841600 tz.transition :o1, 1554566400 tz.transition :o2, 1570291200 tz.transition :o1, 1586016000 tz.transition :o2, 1601740800 tz.transition :o1, 1617465600 tz.transition :o2, 1633190400 tz.transition :o1, 1648915200 tz.transition :o2, 1664640000 tz.transition :o1, 1680364800 tz.transition :o2, 1696089600 tz.transition :o1, 1712419200 tz.transition :o2, 1728144000 tz.transition :o1, 1743868800 tz.transition :o2, 1759593600 tz.transition :o1, 1775318400 tz.transition :o2, 1791043200 tz.transition :o1, 1806768000 tz.transition :o2, 1822492800 tz.transition :o1, 1838217600 tz.transition :o2, 1853942400 tz.transition :o1, 1869667200 tz.transition :o2, 1885996800 tz.transition :o1, 1901721600 tz.transition :o2, 1917446400 tz.transition :o1, 1933171200 tz.transition :o2, 1948896000 tz.transition :o1, 1964620800 tz.transition :o2, 1980345600 tz.transition :o1, 1996070400 tz.transition :o2, 2011795200 tz.transition :o1, 2027520000 tz.transition :o2, 2043244800 tz.transition :o1, 2058969600 tz.transition :o2, 2075299200 tz.transition :o1, 2091024000 tz.transition :o2, 2106748800 tz.transition :o1, 2122473600 tz.transition :o2, 2138198400 tz.transition :o1, 2153923200 tz.transition :o2, 2169648000 tz.transition :o1, 2185372800 tz.transition :o2, 2201097600 tz.transition :o1, 2216822400 tz.transition :o2, 2233152000 tz.transition :o1, 2248876800 tz.transition :o2, 2264601600 tz.transition :o1, 2280326400 tz.transition :o2, 2296051200 tz.transition :o1, 2311776000 tz.transition :o2, 2327500800 tz.transition :o1, 2343225600 tz.transition :o2, 2358950400 tz.transition :o1, 2374675200 tz.transition :o2, 2390400000 tz.transition :o1, 2406124800 tz.transition :o2, 2422454400 tz.transition :o1, 2438179200 tz.transition :o2, 2453904000 tz.transition :o1, 2469628800 tz.transition :o2, 2485353600 tz.transition :o1, 2501078400 tz.transition :o2, 2516803200 tz.transition :o1, 2532528000 tz.transition :o2, 2548252800 tz.transition :o1, 2563977600 tz.transition :o2, 2579702400 tz.transition :o1, 2596032000 tz.transition :o2, 2611756800 tz.transition :o1, 2627481600 tz.transition :o2, 2643206400 tz.transition :o1, 2658931200 tz.transition :o2, 2674656000 tz.transition :o1, 2690380800 tz.transition :o2, 2706105600 tz.transition :o1, 2721830400 tz.transition :o2, 2737555200 tz.transition :o1, 2753280000 tz.transition :o2, 2769609600 tz.transition :o1, 2785334400 tz.transition :o2, 2801059200 tz.transition :o1, 2816784000 tz.transition :o2, 2832508800 tz.transition :o1, 2848233600 tz.transition :o2, 2863958400 tz.transition :o1, 2879683200 tz.transition :o2, 2895408000 tz.transition :o1, 2911132800 tz.transition :o2, 2926857600 tz.transition :o1, 2942582400 tz.transition :o2, 2958912000 tz.transition :o1, 2974636800 tz.transition :o2, 2990361600 tz.transition :o1, 3006086400 tz.transition :o2, 3021811200 tz.transition :o1, 3037536000 tz.transition :o2, 3053260800 tz.transition :o1, 3068985600 tz.transition :o2, 3084710400 tz.transition :o1, 3100435200 tz.transition :o2, 3116764800 tz.transition :o1, 3132489600 tz.transition :o2, 3148214400 tz.transition :o1, 3163939200 end end end end end end tzinfo-2.0.6/test/tzinfo-data2/tzinfo/data/definitions/EST.rb000066400000000000000000000005751436527530500240470ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true # This file contains data derived from the IANA Time Zone Database # (https://www.iana.org/time-zones). module TZInfo module Data module Definitions module EST include Format2::TimezoneDefinition timezone 'EST' do |tz| tz.offset :o0, -18000, 0, 'EST' end end end end end tzinfo-2.0.6/test/tzinfo-data2/tzinfo/data/definitions/Etc/000077500000000000000000000000001436527530500235735ustar00rootroot00000000000000tzinfo-2.0.6/test/tzinfo-data2/tzinfo/data/definitions/Etc/GMT__m__1.rb000066400000000000000000000006561436527530500256100ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true # This file contains data derived from the IANA Time Zone Database # (https://www.iana.org/time-zones). module TZInfo module Data module Definitions module Etc module GMT__m__1 include Format2::TimezoneDefinition timezone 'Etc/GMT-1' do |tz| tz.offset :o0, 3600, 0, '+01' end end end end end end tzinfo-2.0.6/test/tzinfo-data2/tzinfo/data/definitions/Etc/GMT__p__1.rb000066400000000000000000000006571436527530500256140ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true # This file contains data derived from the IANA Time Zone Database # (https://www.iana.org/time-zones). module TZInfo module Data module Definitions module Etc module GMT__p__1 include Format2::TimezoneDefinition timezone 'Etc/GMT+1' do |tz| tz.offset :o0, -3600, 0, '-01' end end end end end end tzinfo-2.0.6/test/tzinfo-data2/tzinfo/data/definitions/Etc/UTC.rb000066400000000000000000000006431436527530500245560ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true # This file contains data derived from the IANA Time Zone Database # (https://www.iana.org/time-zones). module TZInfo module Data module Definitions module Etc module UTC include Format2::TimezoneDefinition timezone 'Etc/UTC' do |tz| tz.offset :o0, 0, 0, 'UTC' end end end end end end tzinfo-2.0.6/test/tzinfo-data2/tzinfo/data/definitions/Europe/000077500000000000000000000000001436527530500243175ustar00rootroot00000000000000tzinfo-2.0.6/test/tzinfo-data2/tzinfo/data/definitions/Europe/Amsterdam.rb000066400000000000000000000254331436527530500265700ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true # This file contains data derived from the IANA Time Zone Database # (https://www.iana.org/time-zones). module TZInfo module Data module Definitions module Europe module Amsterdam include Format2::TimezoneDefinition timezone 'Europe/Amsterdam' do |tz| tz.offset :o0, 1172, 0, 'LMT' tz.offset :o1, 1172, 0, 'AMT' tz.offset :o2, 1172, 3600, 'NST' tz.offset :o3, 1200, 3600, '+0120' tz.offset :o4, 1200, 0, '+0020' tz.offset :o5, 3600, 3600, 'CEST' tz.offset :o6, 3600, 0, 'CET' tz.transition :o1, -4260212372 tz.transition :o2, -1693700372 tz.transition :o1, -1680484772 tz.transition :o2, -1663453172 tz.transition :o1, -1650147572 tz.transition :o2, -1633213172 tz.transition :o1, -1617488372 tz.transition :o2, -1601158772 tz.transition :o1, -1586038772 tz.transition :o2, -1569709172 tz.transition :o1, -1554589172 tz.transition :o2, -1538259572 tz.transition :o1, -1523139572 tz.transition :o2, -1507501172 tz.transition :o1, -1490566772 tz.transition :o2, -1470176372 tz.transition :o1, -1459117172 tz.transition :o2, -1443997172 tz.transition :o1, -1427667572 tz.transition :o2, -1406672372 tz.transition :o1, -1396217972 tz.transition :o2, -1376950772 tz.transition :o1, -1364768372 tz.transition :o2, -1345414772 tz.transition :o1, -1333318772 tz.transition :o2, -1313792372 tz.transition :o1, -1301264372 tz.transition :o2, -1282256372 tz.transition :o1, -1269814772 tz.transition :o2, -1250720372 tz.transition :o1, -1238365172 tz.transition :o2, -1219184372 tz.transition :o1, -1206915572 tz.transition :o2, -1186957172 tz.transition :o1, -1175465972 tz.transition :o2, -1156025972 tz.transition :o1, -1143411572 tz.transition :o2, -1124489972 tz.transition :o1, -1111961972 tz.transition :o2, -1092953972 tz.transition :o1, -1080512372 tz.transition :o2, -1061331572 tz.transition :o1, -1049062772 tz.transition :o2, -1029190772 tz.transition :o3, -1025745572 tz.transition :o4, -1017613200 tz.transition :o3, -998259600 tz.transition :o4, -986163600 tz.transition :o3, -966723600 tz.transition :o4, -954109200 tz.transition :o5, -935022000 tz.transition :o6, -857257200 tz.transition :o5, -844556400 tz.transition :o6, -828226800 tz.transition :o5, -812502000 tz.transition :o6, -796777200 tz.transition :o5, -781052400 tz.transition :o6, -766623600 tz.transition :o5, 228877200 tz.transition :o6, 243997200 tz.transition :o5, 260326800 tz.transition :o6, 276051600 tz.transition :o5, 291776400 tz.transition :o6, 307501200 tz.transition :o5, 323830800 tz.transition :o6, 338950800 tz.transition :o5, 354675600 tz.transition :o6, 370400400 tz.transition :o5, 386125200 tz.transition :o6, 401850000 tz.transition :o5, 417574800 tz.transition :o6, 433299600 tz.transition :o5, 449024400 tz.transition :o6, 465354000 tz.transition :o5, 481078800 tz.transition :o6, 496803600 tz.transition :o5, 512528400 tz.transition :o6, 528253200 tz.transition :o5, 543978000 tz.transition :o6, 559702800 tz.transition :o5, 575427600 tz.transition :o6, 591152400 tz.transition :o5, 606877200 tz.transition :o6, 622602000 tz.transition :o5, 638326800 tz.transition :o6, 654656400 tz.transition :o5, 670381200 tz.transition :o6, 686106000 tz.transition :o5, 701830800 tz.transition :o6, 717555600 tz.transition :o5, 733280400 tz.transition :o6, 749005200 tz.transition :o5, 764730000 tz.transition :o6, 780454800 tz.transition :o5, 796179600 tz.transition :o6, 811904400 tz.transition :o5, 828234000 tz.transition :o6, 846378000 tz.transition :o5, 859683600 tz.transition :o6, 877827600 tz.transition :o5, 891133200 tz.transition :o6, 909277200 tz.transition :o5, 922582800 tz.transition :o6, 941331600 tz.transition :o5, 954032400 tz.transition :o6, 972781200 tz.transition :o5, 985482000 tz.transition :o6, 1004230800 tz.transition :o5, 1017536400 tz.transition :o6, 1035680400 tz.transition :o5, 1048986000 tz.transition :o6, 1067130000 tz.transition :o5, 1080435600 tz.transition :o6, 1099184400 tz.transition :o5, 1111885200 tz.transition :o6, 1130634000 tz.transition :o5, 1143334800 tz.transition :o6, 1162083600 tz.transition :o5, 1174784400 tz.transition :o6, 1193533200 tz.transition :o5, 1206838800 tz.transition :o6, 1224982800 tz.transition :o5, 1238288400 tz.transition :o6, 1256432400 tz.transition :o5, 1269738000 tz.transition :o6, 1288486800 tz.transition :o5, 1301187600 tz.transition :o6, 1319936400 tz.transition :o5, 1332637200 tz.transition :o6, 1351386000 tz.transition :o5, 1364691600 tz.transition :o6, 1382835600 tz.transition :o5, 1396141200 tz.transition :o6, 1414285200 tz.transition :o5, 1427590800 tz.transition :o6, 1445734800 tz.transition :o5, 1459040400 tz.transition :o6, 1477789200 tz.transition :o5, 1490490000 tz.transition :o6, 1509238800 tz.transition :o5, 1521939600 tz.transition :o6, 1540688400 tz.transition :o5, 1553994000 tz.transition :o6, 1572138000 tz.transition :o5, 1585443600 tz.transition :o6, 1603587600 tz.transition :o5, 1616893200 tz.transition :o6, 1635642000 tz.transition :o5, 1648342800 tz.transition :o6, 1667091600 tz.transition :o5, 1679792400 tz.transition :o6, 1698541200 tz.transition :o5, 1711846800 tz.transition :o6, 1729990800 tz.transition :o5, 1743296400 tz.transition :o6, 1761440400 tz.transition :o5, 1774746000 tz.transition :o6, 1792890000 tz.transition :o5, 1806195600 tz.transition :o6, 1824944400 tz.transition :o5, 1837645200 tz.transition :o6, 1856394000 tz.transition :o5, 1869094800 tz.transition :o6, 1887843600 tz.transition :o5, 1901149200 tz.transition :o6, 1919293200 tz.transition :o5, 1932598800 tz.transition :o6, 1950742800 tz.transition :o5, 1964048400 tz.transition :o6, 1982797200 tz.transition :o5, 1995498000 tz.transition :o6, 2014246800 tz.transition :o5, 2026947600 tz.transition :o6, 2045696400 tz.transition :o5, 2058397200 tz.transition :o6, 2077146000 tz.transition :o5, 2090451600 tz.transition :o6, 2108595600 tz.transition :o5, 2121901200 tz.transition :o6, 2140045200 tz.transition :o5, 2153350800 tz.transition :o6, 2172099600 tz.transition :o5, 2184800400 tz.transition :o6, 2203549200 tz.transition :o5, 2216250000 tz.transition :o6, 2234998800 tz.transition :o5, 2248304400 tz.transition :o6, 2266448400 tz.transition :o5, 2279754000 tz.transition :o6, 2297898000 tz.transition :o5, 2311203600 tz.transition :o6, 2329347600 tz.transition :o5, 2342653200 tz.transition :o6, 2361402000 tz.transition :o5, 2374102800 tz.transition :o6, 2392851600 tz.transition :o5, 2405552400 tz.transition :o6, 2424301200 tz.transition :o5, 2437606800 tz.transition :o6, 2455750800 tz.transition :o5, 2469056400 tz.transition :o6, 2487200400 tz.transition :o5, 2500506000 tz.transition :o6, 2519254800 tz.transition :o5, 2531955600 tz.transition :o6, 2550704400 tz.transition :o5, 2563405200 tz.transition :o6, 2582154000 tz.transition :o5, 2595459600 tz.transition :o6, 2613603600 tz.transition :o5, 2626909200 tz.transition :o6, 2645053200 tz.transition :o5, 2658358800 tz.transition :o6, 2676502800 tz.transition :o5, 2689808400 tz.transition :o6, 2708557200 tz.transition :o5, 2721258000 tz.transition :o6, 2740006800 tz.transition :o5, 2752707600 tz.transition :o6, 2771456400 tz.transition :o5, 2784762000 tz.transition :o6, 2802906000 tz.transition :o5, 2816211600 tz.transition :o6, 2834355600 tz.transition :o5, 2847661200 tz.transition :o6, 2866410000 tz.transition :o5, 2879110800 tz.transition :o6, 2897859600 tz.transition :o5, 2910560400 tz.transition :o6, 2929309200 tz.transition :o5, 2942010000 tz.transition :o6, 2960758800 tz.transition :o5, 2974064400 tz.transition :o6, 2992208400 tz.transition :o5, 3005514000 tz.transition :o6, 3023658000 tz.transition :o5, 3036963600 tz.transition :o6, 3055712400 tz.transition :o5, 3068413200 tz.transition :o6, 3087162000 tz.transition :o5, 3099862800 tz.transition :o6, 3118611600 tz.transition :o5, 3131917200 tz.transition :o6, 3150061200 tz.transition :o5, 3163366800 tz.transition :o6, 3181510800 end end end end end end tzinfo-2.0.6/test/tzinfo-data2/tzinfo/data/definitions/Europe/Andorra.rb000066400000000000000000000172361436527530500262430ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true # This file contains data derived from the IANA Time Zone Database # (https://www.iana.org/time-zones). module TZInfo module Data module Definitions module Europe module Andorra include Format2::TimezoneDefinition timezone 'Europe/Andorra' do |tz| tz.offset :o0, 364, 0, 'LMT' tz.offset :o1, 0, 0, 'WET' tz.offset :o2, 3600, 0, 'CET' tz.offset :o3, 3600, 3600, 'CEST' tz.transition :o1, -2177453164 tz.transition :o2, -733881600 tz.transition :o3, 481078800 tz.transition :o2, 496803600 tz.transition :o3, 512528400 tz.transition :o2, 528253200 tz.transition :o3, 543978000 tz.transition :o2, 559702800 tz.transition :o3, 575427600 tz.transition :o2, 591152400 tz.transition :o3, 606877200 tz.transition :o2, 622602000 tz.transition :o3, 638326800 tz.transition :o2, 654656400 tz.transition :o3, 670381200 tz.transition :o2, 686106000 tz.transition :o3, 701830800 tz.transition :o2, 717555600 tz.transition :o3, 733280400 tz.transition :o2, 749005200 tz.transition :o3, 764730000 tz.transition :o2, 780454800 tz.transition :o3, 796179600 tz.transition :o2, 811904400 tz.transition :o3, 828234000 tz.transition :o2, 846378000 tz.transition :o3, 859683600 tz.transition :o2, 877827600 tz.transition :o3, 891133200 tz.transition :o2, 909277200 tz.transition :o3, 922582800 tz.transition :o2, 941331600 tz.transition :o3, 954032400 tz.transition :o2, 972781200 tz.transition :o3, 985482000 tz.transition :o2, 1004230800 tz.transition :o3, 1017536400 tz.transition :o2, 1035680400 tz.transition :o3, 1048986000 tz.transition :o2, 1067130000 tz.transition :o3, 1080435600 tz.transition :o2, 1099184400 tz.transition :o3, 1111885200 tz.transition :o2, 1130634000 tz.transition :o3, 1143334800 tz.transition :o2, 1162083600 tz.transition :o3, 1174784400 tz.transition :o2, 1193533200 tz.transition :o3, 1206838800 tz.transition :o2, 1224982800 tz.transition :o3, 1238288400 tz.transition :o2, 1256432400 tz.transition :o3, 1269738000 tz.transition :o2, 1288486800 tz.transition :o3, 1301187600 tz.transition :o2, 1319936400 tz.transition :o3, 1332637200 tz.transition :o2, 1351386000 tz.transition :o3, 1364691600 tz.transition :o2, 1382835600 tz.transition :o3, 1396141200 tz.transition :o2, 1414285200 tz.transition :o3, 1427590800 tz.transition :o2, 1445734800 tz.transition :o3, 1459040400 tz.transition :o2, 1477789200 tz.transition :o3, 1490490000 tz.transition :o2, 1509238800 tz.transition :o3, 1521939600 tz.transition :o2, 1540688400 tz.transition :o3, 1553994000 tz.transition :o2, 1572138000 tz.transition :o3, 1585443600 tz.transition :o2, 1603587600 tz.transition :o3, 1616893200 tz.transition :o2, 1635642000 tz.transition :o3, 1648342800 tz.transition :o2, 1667091600 tz.transition :o3, 1679792400 tz.transition :o2, 1698541200 tz.transition :o3, 1711846800 tz.transition :o2, 1729990800 tz.transition :o3, 1743296400 tz.transition :o2, 1761440400 tz.transition :o3, 1774746000 tz.transition :o2, 1792890000 tz.transition :o3, 1806195600 tz.transition :o2, 1824944400 tz.transition :o3, 1837645200 tz.transition :o2, 1856394000 tz.transition :o3, 1869094800 tz.transition :o2, 1887843600 tz.transition :o3, 1901149200 tz.transition :o2, 1919293200 tz.transition :o3, 1932598800 tz.transition :o2, 1950742800 tz.transition :o3, 1964048400 tz.transition :o2, 1982797200 tz.transition :o3, 1995498000 tz.transition :o2, 2014246800 tz.transition :o3, 2026947600 tz.transition :o2, 2045696400 tz.transition :o3, 2058397200 tz.transition :o2, 2077146000 tz.transition :o3, 2090451600 tz.transition :o2, 2108595600 tz.transition :o3, 2121901200 tz.transition :o2, 2140045200 tz.transition :o3, 2153350800 tz.transition :o2, 2172099600 tz.transition :o3, 2184800400 tz.transition :o2, 2203549200 tz.transition :o3, 2216250000 tz.transition :o2, 2234998800 tz.transition :o3, 2248304400 tz.transition :o2, 2266448400 tz.transition :o3, 2279754000 tz.transition :o2, 2297898000 tz.transition :o3, 2311203600 tz.transition :o2, 2329347600 tz.transition :o3, 2342653200 tz.transition :o2, 2361402000 tz.transition :o3, 2374102800 tz.transition :o2, 2392851600 tz.transition :o3, 2405552400 tz.transition :o2, 2424301200 tz.transition :o3, 2437606800 tz.transition :o2, 2455750800 tz.transition :o3, 2469056400 tz.transition :o2, 2487200400 tz.transition :o3, 2500506000 tz.transition :o2, 2519254800 tz.transition :o3, 2531955600 tz.transition :o2, 2550704400 tz.transition :o3, 2563405200 tz.transition :o2, 2582154000 tz.transition :o3, 2595459600 tz.transition :o2, 2613603600 tz.transition :o3, 2626909200 tz.transition :o2, 2645053200 tz.transition :o3, 2658358800 tz.transition :o2, 2676502800 tz.transition :o3, 2689808400 tz.transition :o2, 2708557200 tz.transition :o3, 2721258000 tz.transition :o2, 2740006800 tz.transition :o3, 2752707600 tz.transition :o2, 2771456400 tz.transition :o3, 2784762000 tz.transition :o2, 2802906000 tz.transition :o3, 2816211600 tz.transition :o2, 2834355600 tz.transition :o3, 2847661200 tz.transition :o2, 2866410000 tz.transition :o3, 2879110800 tz.transition :o2, 2897859600 tz.transition :o3, 2910560400 tz.transition :o2, 2929309200 tz.transition :o3, 2942010000 tz.transition :o2, 2960758800 tz.transition :o3, 2974064400 tz.transition :o2, 2992208400 tz.transition :o3, 3005514000 tz.transition :o2, 3023658000 tz.transition :o3, 3036963600 tz.transition :o2, 3055712400 tz.transition :o3, 3068413200 tz.transition :o2, 3087162000 tz.transition :o3, 3099862800 tz.transition :o2, 3118611600 tz.transition :o3, 3131917200 tz.transition :o2, 3150061200 tz.transition :o3, 3163366800 tz.transition :o2, 3181510800 end end end end end end tzinfo-2.0.6/test/tzinfo-data2/tzinfo/data/definitions/Europe/London.rb000066400000000000000000000323121436527530500260760ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true # This file contains data derived from the IANA Time Zone Database # (https://www.iana.org/time-zones). module TZInfo module Data module Definitions module Europe module London include Format2::TimezoneDefinition timezone 'Europe/London' do |tz| tz.offset :o0, -75, 0, 'LMT' tz.offset :o1, 0, 0, 'GMT' tz.offset :o2, 0, 3600, 'BST' tz.offset :o3, 0, 7200, 'BDST' tz.offset :o4, 3600, 0, 'BST' tz.transition :o1, -3852662325 tz.transition :o2, -1691964000 tz.transition :o1, -1680472800 tz.transition :o2, -1664143200 tz.transition :o1, -1650146400 tz.transition :o2, -1633903200 tz.transition :o1, -1617487200 tz.transition :o2, -1601848800 tz.transition :o1, -1586037600 tz.transition :o2, -1570399200 tz.transition :o1, -1552168800 tz.transition :o2, -1538344800 tz.transition :o1, -1522533600 tz.transition :o2, -1507500000 tz.transition :o1, -1490565600 tz.transition :o2, -1473631200 tz.transition :o1, -1460930400 tz.transition :o2, -1442786400 tz.transition :o1, -1428876000 tz.transition :o2, -1410732000 tz.transition :o1, -1396216800 tz.transition :o2, -1379282400 tz.transition :o1, -1364767200 tz.transition :o2, -1348437600 tz.transition :o1, -1333317600 tz.transition :o2, -1315778400 tz.transition :o1, -1301263200 tz.transition :o2, -1284328800 tz.transition :o1, -1269813600 tz.transition :o2, -1253484000 tz.transition :o1, -1238364000 tz.transition :o2, -1221429600 tz.transition :o1, -1206914400 tz.transition :o2, -1189980000 tz.transition :o1, -1175464800 tz.transition :o2, -1159135200 tz.transition :o1, -1143410400 tz.transition :o2, -1126476000 tz.transition :o1, -1111960800 tz.transition :o2, -1095631200 tz.transition :o1, -1080511200 tz.transition :o2, -1063576800 tz.transition :o1, -1049061600 tz.transition :o2, -1032127200 tz.transition :o1, -1017612000 tz.transition :o2, -1001282400 tz.transition :o1, -986162400 tz.transition :o2, -969228000 tz.transition :o1, -950479200 tz.transition :o2, -942012000 tz.transition :o3, -904518000 tz.transition :o2, -896050800 tz.transition :o3, -875487600 tz.transition :o2, -864601200 tz.transition :o3, -844038000 tz.transition :o2, -832546800 tz.transition :o3, -812588400 tz.transition :o2, -798073200 tz.transition :o3, -781052400 tz.transition :o2, -772066800 tz.transition :o1, -764805600 tz.transition :o2, -748476000 tz.transition :o1, -733356000 tz.transition :o2, -719445600 tz.transition :o3, -717030000 tz.transition :o2, -706748400 tz.transition :o1, -699487200 tz.transition :o2, -687996000 tz.transition :o1, -668037600 tz.transition :o2, -654732000 tz.transition :o1, -636588000 tz.transition :o2, -622072800 tz.transition :o1, -605743200 tz.transition :o2, -590623200 tz.transition :o1, -574293600 tz.transition :o2, -558568800 tz.transition :o1, -542239200 tz.transition :o2, -527119200 tz.transition :o1, -512604000 tz.transition :o2, -496274400 tz.transition :o1, -481154400 tz.transition :o2, -464220000 tz.transition :o1, -449704800 tz.transition :o2, -432165600 tz.transition :o1, -417650400 tz.transition :o2, -401320800 tz.transition :o1, -386200800 tz.transition :o2, -369266400 tz.transition :o1, -354751200 tz.transition :o2, -337816800 tz.transition :o1, -323301600 tz.transition :o2, -306972000 tz.transition :o1, -291852000 tz.transition :o2, -276732000 tz.transition :o1, -257983200 tz.transition :o2, -245282400 tz.transition :o1, -226533600 tz.transition :o2, -213228000 tz.transition :o1, -195084000 tz.transition :o2, -182383200 tz.transition :o1, -163634400 tz.transition :o2, -150933600 tz.transition :o1, -132184800 tz.transition :o2, -119484000 tz.transition :o1, -100735200 tz.transition :o2, -88034400 tz.transition :o1, -68680800 tz.transition :o2, -59004000 tz.transition :o4, -37242000 tz.transition :o1, 57722400 tz.transition :o2, 69818400 tz.transition :o1, 89172000 tz.transition :o2, 101268000 tz.transition :o1, 120621600 tz.transition :o2, 132717600 tz.transition :o1, 152071200 tz.transition :o2, 164167200 tz.transition :o1, 183520800 tz.transition :o2, 196221600 tz.transition :o1, 214970400 tz.transition :o2, 227671200 tz.transition :o1, 246420000 tz.transition :o2, 259120800 tz.transition :o1, 278474400 tz.transition :o2, 290570400 tz.transition :o1, 309924000 tz.transition :o2, 322020000 tz.transition :o1, 341373600 tz.transition :o2, 354675600 tz.transition :o1, 372819600 tz.transition :o2, 386125200 tz.transition :o1, 404269200 tz.transition :o2, 417574800 tz.transition :o1, 435718800 tz.transition :o2, 449024400 tz.transition :o1, 467773200 tz.transition :o2, 481078800 tz.transition :o1, 499222800 tz.transition :o2, 512528400 tz.transition :o1, 530672400 tz.transition :o2, 543978000 tz.transition :o1, 562122000 tz.transition :o2, 575427600 tz.transition :o1, 593571600 tz.transition :o2, 606877200 tz.transition :o1, 625626000 tz.transition :o2, 638326800 tz.transition :o1, 657075600 tz.transition :o2, 670381200 tz.transition :o1, 688525200 tz.transition :o2, 701830800 tz.transition :o1, 719974800 tz.transition :o2, 733280400 tz.transition :o1, 751424400 tz.transition :o2, 764730000 tz.transition :o1, 782874000 tz.transition :o2, 796179600 tz.transition :o1, 814323600 tz.transition :o2, 828234000 tz.transition :o1, 846378000 tz.transition :o2, 859683600 tz.transition :o1, 877827600 tz.transition :o2, 891133200 tz.transition :o1, 909277200 tz.transition :o2, 922582800 tz.transition :o1, 941331600 tz.transition :o2, 954032400 tz.transition :o1, 972781200 tz.transition :o2, 985482000 tz.transition :o1, 1004230800 tz.transition :o2, 1017536400 tz.transition :o1, 1035680400 tz.transition :o2, 1048986000 tz.transition :o1, 1067130000 tz.transition :o2, 1080435600 tz.transition :o1, 1099184400 tz.transition :o2, 1111885200 tz.transition :o1, 1130634000 tz.transition :o2, 1143334800 tz.transition :o1, 1162083600 tz.transition :o2, 1174784400 tz.transition :o1, 1193533200 tz.transition :o2, 1206838800 tz.transition :o1, 1224982800 tz.transition :o2, 1238288400 tz.transition :o1, 1256432400 tz.transition :o2, 1269738000 tz.transition :o1, 1288486800 tz.transition :o2, 1301187600 tz.transition :o1, 1319936400 tz.transition :o2, 1332637200 tz.transition :o1, 1351386000 tz.transition :o2, 1364691600 tz.transition :o1, 1382835600 tz.transition :o2, 1396141200 tz.transition :o1, 1414285200 tz.transition :o2, 1427590800 tz.transition :o1, 1445734800 tz.transition :o2, 1459040400 tz.transition :o1, 1477789200 tz.transition :o2, 1490490000 tz.transition :o1, 1509238800 tz.transition :o2, 1521939600 tz.transition :o1, 1540688400 tz.transition :o2, 1553994000 tz.transition :o1, 1572138000 tz.transition :o2, 1585443600 tz.transition :o1, 1603587600 tz.transition :o2, 1616893200 tz.transition :o1, 1635642000 tz.transition :o2, 1648342800 tz.transition :o1, 1667091600 tz.transition :o2, 1679792400 tz.transition :o1, 1698541200 tz.transition :o2, 1711846800 tz.transition :o1, 1729990800 tz.transition :o2, 1743296400 tz.transition :o1, 1761440400 tz.transition :o2, 1774746000 tz.transition :o1, 1792890000 tz.transition :o2, 1806195600 tz.transition :o1, 1824944400 tz.transition :o2, 1837645200 tz.transition :o1, 1856394000 tz.transition :o2, 1869094800 tz.transition :o1, 1887843600 tz.transition :o2, 1901149200 tz.transition :o1, 1919293200 tz.transition :o2, 1932598800 tz.transition :o1, 1950742800 tz.transition :o2, 1964048400 tz.transition :o1, 1982797200 tz.transition :o2, 1995498000 tz.transition :o1, 2014246800 tz.transition :o2, 2026947600 tz.transition :o1, 2045696400 tz.transition :o2, 2058397200 tz.transition :o1, 2077146000 tz.transition :o2, 2090451600 tz.transition :o1, 2108595600 tz.transition :o2, 2121901200 tz.transition :o1, 2140045200 tz.transition :o2, 2153350800 tz.transition :o1, 2172099600 tz.transition :o2, 2184800400 tz.transition :o1, 2203549200 tz.transition :o2, 2216250000 tz.transition :o1, 2234998800 tz.transition :o2, 2248304400 tz.transition :o1, 2266448400 tz.transition :o2, 2279754000 tz.transition :o1, 2297898000 tz.transition :o2, 2311203600 tz.transition :o1, 2329347600 tz.transition :o2, 2342653200 tz.transition :o1, 2361402000 tz.transition :o2, 2374102800 tz.transition :o1, 2392851600 tz.transition :o2, 2405552400 tz.transition :o1, 2424301200 tz.transition :o2, 2437606800 tz.transition :o1, 2455750800 tz.transition :o2, 2469056400 tz.transition :o1, 2487200400 tz.transition :o2, 2500506000 tz.transition :o1, 2519254800 tz.transition :o2, 2531955600 tz.transition :o1, 2550704400 tz.transition :o2, 2563405200 tz.transition :o1, 2582154000 tz.transition :o2, 2595459600 tz.transition :o1, 2613603600 tz.transition :o2, 2626909200 tz.transition :o1, 2645053200 tz.transition :o2, 2658358800 tz.transition :o1, 2676502800 tz.transition :o2, 2689808400 tz.transition :o1, 2708557200 tz.transition :o2, 2721258000 tz.transition :o1, 2740006800 tz.transition :o2, 2752707600 tz.transition :o1, 2771456400 tz.transition :o2, 2784762000 tz.transition :o1, 2802906000 tz.transition :o2, 2816211600 tz.transition :o1, 2834355600 tz.transition :o2, 2847661200 tz.transition :o1, 2866410000 tz.transition :o2, 2879110800 tz.transition :o1, 2897859600 tz.transition :o2, 2910560400 tz.transition :o1, 2929309200 tz.transition :o2, 2942010000 tz.transition :o1, 2960758800 tz.transition :o2, 2974064400 tz.transition :o1, 2992208400 tz.transition :o2, 3005514000 tz.transition :o1, 3023658000 tz.transition :o2, 3036963600 tz.transition :o1, 3055712400 tz.transition :o2, 3068413200 tz.transition :o1, 3087162000 tz.transition :o2, 3099862800 tz.transition :o1, 3118611600 tz.transition :o2, 3131917200 tz.transition :o1, 3150061200 tz.transition :o2, 3163366800 tz.transition :o1, 3181510800 end end end end end end tzinfo-2.0.6/test/tzinfo-data2/tzinfo/data/definitions/Europe/Paris.rb000066400000000000000000000256551436527530500257370ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true # This file contains data derived from the IANA Time Zone Database # (https://www.iana.org/time-zones). module TZInfo module Data module Definitions module Europe module Paris include Format2::TimezoneDefinition timezone 'Europe/Paris' do |tz| tz.offset :o0, 561, 0, 'LMT' tz.offset :o1, 561, 0, 'PMT' tz.offset :o2, 0, 0, 'WET' tz.offset :o3, 0, 3600, 'WEST' tz.offset :o4, 3600, 3600, 'CEST' tz.offset :o5, 3600, 0, 'CET' tz.offset :o6, 0, 7200, 'WEMT' tz.transition :o1, -2486592561 tz.transition :o2, -1855958961 tz.transition :o3, -1689814800 tz.transition :o2, -1680397200 tz.transition :o3, -1665363600 tz.transition :o2, -1648342800 tz.transition :o3, -1635123600 tz.transition :o2, -1616893200 tz.transition :o3, -1604278800 tz.transition :o2, -1585443600 tz.transition :o3, -1574038800 tz.transition :o2, -1552266000 tz.transition :o3, -1539997200 tz.transition :o2, -1520557200 tz.transition :o3, -1507510800 tz.transition :o2, -1490576400 tz.transition :o3, -1470618000 tz.transition :o2, -1459126800 tz.transition :o3, -1444006800 tz.transition :o2, -1427677200 tz.transition :o3, -1411952400 tz.transition :o2, -1396227600 tz.transition :o3, -1379293200 tz.transition :o2, -1364778000 tz.transition :o3, -1348448400 tz.transition :o2, -1333328400 tz.transition :o3, -1316394000 tz.transition :o2, -1301274000 tz.transition :o3, -1284339600 tz.transition :o2, -1269824400 tz.transition :o3, -1253494800 tz.transition :o2, -1238374800 tz.transition :o3, -1221440400 tz.transition :o2, -1206925200 tz.transition :o3, -1191200400 tz.transition :o2, -1175475600 tz.transition :o3, -1160355600 tz.transition :o2, -1143421200 tz.transition :o3, -1127696400 tz.transition :o2, -1111971600 tz.transition :o3, -1096851600 tz.transition :o2, -1080522000 tz.transition :o3, -1063587600 tz.transition :o2, -1049072400 tz.transition :o3, -1033347600 tz.transition :o2, -1017622800 tz.transition :o3, -1002502800 tz.transition :o2, -986173200 tz.transition :o3, -969238800 tz.transition :o2, -950490000 tz.transition :o3, -942012000 tz.transition :o4, -932436000 tz.transition :o5, -857257200 tz.transition :o4, -844556400 tz.transition :o5, -828226800 tz.transition :o4, -812502000 tz.transition :o6, -800071200 tz.transition :o3, -796266000 tz.transition :o6, -781052400 tz.transition :o5, -766623600 tz.transition :o4, 196819200 tz.transition :o5, 212540400 tz.transition :o4, 228877200 tz.transition :o5, 243997200 tz.transition :o4, 260326800 tz.transition :o5, 276051600 tz.transition :o4, 291776400 tz.transition :o5, 307501200 tz.transition :o4, 323830800 tz.transition :o5, 338950800 tz.transition :o4, 354675600 tz.transition :o5, 370400400 tz.transition :o4, 386125200 tz.transition :o5, 401850000 tz.transition :o4, 417574800 tz.transition :o5, 433299600 tz.transition :o4, 449024400 tz.transition :o5, 465354000 tz.transition :o4, 481078800 tz.transition :o5, 496803600 tz.transition :o4, 512528400 tz.transition :o5, 528253200 tz.transition :o4, 543978000 tz.transition :o5, 559702800 tz.transition :o4, 575427600 tz.transition :o5, 591152400 tz.transition :o4, 606877200 tz.transition :o5, 622602000 tz.transition :o4, 638326800 tz.transition :o5, 654656400 tz.transition :o4, 670381200 tz.transition :o5, 686106000 tz.transition :o4, 701830800 tz.transition :o5, 717555600 tz.transition :o4, 733280400 tz.transition :o5, 749005200 tz.transition :o4, 764730000 tz.transition :o5, 780454800 tz.transition :o4, 796179600 tz.transition :o5, 811904400 tz.transition :o4, 828234000 tz.transition :o5, 846378000 tz.transition :o4, 859683600 tz.transition :o5, 877827600 tz.transition :o4, 891133200 tz.transition :o5, 909277200 tz.transition :o4, 922582800 tz.transition :o5, 941331600 tz.transition :o4, 954032400 tz.transition :o5, 972781200 tz.transition :o4, 985482000 tz.transition :o5, 1004230800 tz.transition :o4, 1017536400 tz.transition :o5, 1035680400 tz.transition :o4, 1048986000 tz.transition :o5, 1067130000 tz.transition :o4, 1080435600 tz.transition :o5, 1099184400 tz.transition :o4, 1111885200 tz.transition :o5, 1130634000 tz.transition :o4, 1143334800 tz.transition :o5, 1162083600 tz.transition :o4, 1174784400 tz.transition :o5, 1193533200 tz.transition :o4, 1206838800 tz.transition :o5, 1224982800 tz.transition :o4, 1238288400 tz.transition :o5, 1256432400 tz.transition :o4, 1269738000 tz.transition :o5, 1288486800 tz.transition :o4, 1301187600 tz.transition :o5, 1319936400 tz.transition :o4, 1332637200 tz.transition :o5, 1351386000 tz.transition :o4, 1364691600 tz.transition :o5, 1382835600 tz.transition :o4, 1396141200 tz.transition :o5, 1414285200 tz.transition :o4, 1427590800 tz.transition :o5, 1445734800 tz.transition :o4, 1459040400 tz.transition :o5, 1477789200 tz.transition :o4, 1490490000 tz.transition :o5, 1509238800 tz.transition :o4, 1521939600 tz.transition :o5, 1540688400 tz.transition :o4, 1553994000 tz.transition :o5, 1572138000 tz.transition :o4, 1585443600 tz.transition :o5, 1603587600 tz.transition :o4, 1616893200 tz.transition :o5, 1635642000 tz.transition :o4, 1648342800 tz.transition :o5, 1667091600 tz.transition :o4, 1679792400 tz.transition :o5, 1698541200 tz.transition :o4, 1711846800 tz.transition :o5, 1729990800 tz.transition :o4, 1743296400 tz.transition :o5, 1761440400 tz.transition :o4, 1774746000 tz.transition :o5, 1792890000 tz.transition :o4, 1806195600 tz.transition :o5, 1824944400 tz.transition :o4, 1837645200 tz.transition :o5, 1856394000 tz.transition :o4, 1869094800 tz.transition :o5, 1887843600 tz.transition :o4, 1901149200 tz.transition :o5, 1919293200 tz.transition :o4, 1932598800 tz.transition :o5, 1950742800 tz.transition :o4, 1964048400 tz.transition :o5, 1982797200 tz.transition :o4, 1995498000 tz.transition :o5, 2014246800 tz.transition :o4, 2026947600 tz.transition :o5, 2045696400 tz.transition :o4, 2058397200 tz.transition :o5, 2077146000 tz.transition :o4, 2090451600 tz.transition :o5, 2108595600 tz.transition :o4, 2121901200 tz.transition :o5, 2140045200 tz.transition :o4, 2153350800 tz.transition :o5, 2172099600 tz.transition :o4, 2184800400 tz.transition :o5, 2203549200 tz.transition :o4, 2216250000 tz.transition :o5, 2234998800 tz.transition :o4, 2248304400 tz.transition :o5, 2266448400 tz.transition :o4, 2279754000 tz.transition :o5, 2297898000 tz.transition :o4, 2311203600 tz.transition :o5, 2329347600 tz.transition :o4, 2342653200 tz.transition :o5, 2361402000 tz.transition :o4, 2374102800 tz.transition :o5, 2392851600 tz.transition :o4, 2405552400 tz.transition :o5, 2424301200 tz.transition :o4, 2437606800 tz.transition :o5, 2455750800 tz.transition :o4, 2469056400 tz.transition :o5, 2487200400 tz.transition :o4, 2500506000 tz.transition :o5, 2519254800 tz.transition :o4, 2531955600 tz.transition :o5, 2550704400 tz.transition :o4, 2563405200 tz.transition :o5, 2582154000 tz.transition :o4, 2595459600 tz.transition :o5, 2613603600 tz.transition :o4, 2626909200 tz.transition :o5, 2645053200 tz.transition :o4, 2658358800 tz.transition :o5, 2676502800 tz.transition :o4, 2689808400 tz.transition :o5, 2708557200 tz.transition :o4, 2721258000 tz.transition :o5, 2740006800 tz.transition :o4, 2752707600 tz.transition :o5, 2771456400 tz.transition :o4, 2784762000 tz.transition :o5, 2802906000 tz.transition :o4, 2816211600 tz.transition :o5, 2834355600 tz.transition :o4, 2847661200 tz.transition :o5, 2866410000 tz.transition :o4, 2879110800 tz.transition :o5, 2897859600 tz.transition :o4, 2910560400 tz.transition :o5, 2929309200 tz.transition :o4, 2942010000 tz.transition :o5, 2960758800 tz.transition :o4, 2974064400 tz.transition :o5, 2992208400 tz.transition :o4, 3005514000 tz.transition :o5, 3023658000 tz.transition :o4, 3036963600 tz.transition :o5, 3055712400 tz.transition :o4, 3068413200 tz.transition :o5, 3087162000 tz.transition :o4, 3099862800 tz.transition :o5, 3118611600 tz.transition :o4, 3131917200 tz.transition :o5, 3150061200 tz.transition :o4, 3163366800 tz.transition :o5, 3181510800 end end end end end end tzinfo-2.0.6/test/tzinfo-data2/tzinfo/data/definitions/Europe/Prague.rb000066400000000000000000000222611436527530500260720ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true # This file contains data derived from the IANA Time Zone Database # (https://www.iana.org/time-zones). module TZInfo module Data module Definitions module Europe module Prague include Format2::TimezoneDefinition timezone 'Europe/Prague' do |tz| tz.offset :o0, 3464, 0, 'LMT' tz.offset :o1, 3464, 0, 'PMT' tz.offset :o2, 3600, 0, 'CET' tz.offset :o3, 3600, 3600, 'CEST' tz.offset :o4, 3600, -3600, 'GMT' tz.transition :o1, -3786829064 tz.transition :o2, -2469401864 tz.transition :o3, -1693706400 tz.transition :o2, -1680483600 tz.transition :o3, -1663455600 tz.transition :o2, -1650150000 tz.transition :o3, -1632006000 tz.transition :o2, -1618700400 tz.transition :o3, -938905200 tz.transition :o2, -857257200 tz.transition :o3, -844556400 tz.transition :o2, -828226800 tz.transition :o3, -812502000 tz.transition :o2, -796777200 tz.transition :o3, -781052400 tz.transition :o2, -765327600 tz.transition :o3, -746578800 tz.transition :o2, -733359600 tz.transition :o4, -728517600 tz.transition :o2, -721260000 tz.transition :o3, -716425200 tz.transition :o2, -701910000 tz.transition :o3, -684975600 tz.transition :o2, -670460400 tz.transition :o3, -654217200 tz.transition :o2, -639010800 tz.transition :o3, 291776400 tz.transition :o2, 307501200 tz.transition :o3, 323830800 tz.transition :o2, 338950800 tz.transition :o3, 354675600 tz.transition :o2, 370400400 tz.transition :o3, 386125200 tz.transition :o2, 401850000 tz.transition :o3, 417574800 tz.transition :o2, 433299600 tz.transition :o3, 449024400 tz.transition :o2, 465354000 tz.transition :o3, 481078800 tz.transition :o2, 496803600 tz.transition :o3, 512528400 tz.transition :o2, 528253200 tz.transition :o3, 543978000 tz.transition :o2, 559702800 tz.transition :o3, 575427600 tz.transition :o2, 591152400 tz.transition :o3, 606877200 tz.transition :o2, 622602000 tz.transition :o3, 638326800 tz.transition :o2, 654656400 tz.transition :o3, 670381200 tz.transition :o2, 686106000 tz.transition :o3, 701830800 tz.transition :o2, 717555600 tz.transition :o3, 733280400 tz.transition :o2, 749005200 tz.transition :o3, 764730000 tz.transition :o2, 780454800 tz.transition :o3, 796179600 tz.transition :o2, 811904400 tz.transition :o3, 828234000 tz.transition :o2, 846378000 tz.transition :o3, 859683600 tz.transition :o2, 877827600 tz.transition :o3, 891133200 tz.transition :o2, 909277200 tz.transition :o3, 922582800 tz.transition :o2, 941331600 tz.transition :o3, 954032400 tz.transition :o2, 972781200 tz.transition :o3, 985482000 tz.transition :o2, 1004230800 tz.transition :o3, 1017536400 tz.transition :o2, 1035680400 tz.transition :o3, 1048986000 tz.transition :o2, 1067130000 tz.transition :o3, 1080435600 tz.transition :o2, 1099184400 tz.transition :o3, 1111885200 tz.transition :o2, 1130634000 tz.transition :o3, 1143334800 tz.transition :o2, 1162083600 tz.transition :o3, 1174784400 tz.transition :o2, 1193533200 tz.transition :o3, 1206838800 tz.transition :o2, 1224982800 tz.transition :o3, 1238288400 tz.transition :o2, 1256432400 tz.transition :o3, 1269738000 tz.transition :o2, 1288486800 tz.transition :o3, 1301187600 tz.transition :o2, 1319936400 tz.transition :o3, 1332637200 tz.transition :o2, 1351386000 tz.transition :o3, 1364691600 tz.transition :o2, 1382835600 tz.transition :o3, 1396141200 tz.transition :o2, 1414285200 tz.transition :o3, 1427590800 tz.transition :o2, 1445734800 tz.transition :o3, 1459040400 tz.transition :o2, 1477789200 tz.transition :o3, 1490490000 tz.transition :o2, 1509238800 tz.transition :o3, 1521939600 tz.transition :o2, 1540688400 tz.transition :o3, 1553994000 tz.transition :o2, 1572138000 tz.transition :o3, 1585443600 tz.transition :o2, 1603587600 tz.transition :o3, 1616893200 tz.transition :o2, 1635642000 tz.transition :o3, 1648342800 tz.transition :o2, 1667091600 tz.transition :o3, 1679792400 tz.transition :o2, 1698541200 tz.transition :o3, 1711846800 tz.transition :o2, 1729990800 tz.transition :o3, 1743296400 tz.transition :o2, 1761440400 tz.transition :o3, 1774746000 tz.transition :o2, 1792890000 tz.transition :o3, 1806195600 tz.transition :o2, 1824944400 tz.transition :o3, 1837645200 tz.transition :o2, 1856394000 tz.transition :o3, 1869094800 tz.transition :o2, 1887843600 tz.transition :o3, 1901149200 tz.transition :o2, 1919293200 tz.transition :o3, 1932598800 tz.transition :o2, 1950742800 tz.transition :o3, 1964048400 tz.transition :o2, 1982797200 tz.transition :o3, 1995498000 tz.transition :o2, 2014246800 tz.transition :o3, 2026947600 tz.transition :o2, 2045696400 tz.transition :o3, 2058397200 tz.transition :o2, 2077146000 tz.transition :o3, 2090451600 tz.transition :o2, 2108595600 tz.transition :o3, 2121901200 tz.transition :o2, 2140045200 tz.transition :o3, 2153350800 tz.transition :o2, 2172099600 tz.transition :o3, 2184800400 tz.transition :o2, 2203549200 tz.transition :o3, 2216250000 tz.transition :o2, 2234998800 tz.transition :o3, 2248304400 tz.transition :o2, 2266448400 tz.transition :o3, 2279754000 tz.transition :o2, 2297898000 tz.transition :o3, 2311203600 tz.transition :o2, 2329347600 tz.transition :o3, 2342653200 tz.transition :o2, 2361402000 tz.transition :o3, 2374102800 tz.transition :o2, 2392851600 tz.transition :o3, 2405552400 tz.transition :o2, 2424301200 tz.transition :o3, 2437606800 tz.transition :o2, 2455750800 tz.transition :o3, 2469056400 tz.transition :o2, 2487200400 tz.transition :o3, 2500506000 tz.transition :o2, 2519254800 tz.transition :o3, 2531955600 tz.transition :o2, 2550704400 tz.transition :o3, 2563405200 tz.transition :o2, 2582154000 tz.transition :o3, 2595459600 tz.transition :o2, 2613603600 tz.transition :o3, 2626909200 tz.transition :o2, 2645053200 tz.transition :o3, 2658358800 tz.transition :o2, 2676502800 tz.transition :o3, 2689808400 tz.transition :o2, 2708557200 tz.transition :o3, 2721258000 tz.transition :o2, 2740006800 tz.transition :o3, 2752707600 tz.transition :o2, 2771456400 tz.transition :o3, 2784762000 tz.transition :o2, 2802906000 tz.transition :o3, 2816211600 tz.transition :o2, 2834355600 tz.transition :o3, 2847661200 tz.transition :o2, 2866410000 tz.transition :o3, 2879110800 tz.transition :o2, 2897859600 tz.transition :o3, 2910560400 tz.transition :o2, 2929309200 tz.transition :o3, 2942010000 tz.transition :o2, 2960758800 tz.transition :o3, 2974064400 tz.transition :o2, 2992208400 tz.transition :o3, 3005514000 tz.transition :o2, 3023658000 tz.transition :o3, 3036963600 tz.transition :o2, 3055712400 tz.transition :o3, 3068413200 tz.transition :o2, 3087162000 tz.transition :o3, 3099862800 tz.transition :o2, 3118611600 tz.transition :o3, 3131917200 tz.transition :o2, 3150061200 tz.transition :o3, 3163366800 tz.transition :o2, 3181510800 end end end end end end tzinfo-2.0.6/test/tzinfo-data2/tzinfo/data/definitions/Invalid/000077500000000000000000000000001436527530500244465ustar00rootroot00000000000000tzinfo-2.0.6/test/tzinfo-data2/tzinfo/data/definitions/Invalid/Incorrect_Module.rb000066400000000000000000000007421436527530500302330ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true # This file was created manually. It purposefully contains module names that # don't match the zone identifier to test load errors. module TZInfo module Data module Definitions module InvalidX module Incorrect_ModuleX include Format2::TimezoneDefinition timezone 'Invalid/Incorrect_Module' do |tz| tz.offset :o0, 0, 0, 'UTC' end end end end end end tzinfo-2.0.6/test/tzinfo-data2/tzinfo/data/definitions/UTC.rb000066400000000000000000000005201436527530500240350ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true # This file contains data derived from the IANA Time Zone Database # (https://www.iana.org/time-zones). module TZInfo module Data module Definitions module UTC include Format2::TimezoneDefinition linked_timezone 'UTC', 'Etc/UTC' end end end end tzinfo-2.0.6/test/tzinfo-data2/tzinfo/data/indexes/000077500000000000000000000000001436527530500222045ustar00rootroot00000000000000tzinfo-2.0.6/test/tzinfo-data2/tzinfo/data/indexes/countries.rb000066400000000000000000001273121436527530500245520ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true # This file contains data derived from the IANA Time Zone Database # (https://www.iana.org/time-zones). module TZInfo module Data module Indexes module Countries include Format2::CountryIndexDefinition country_index do |i| i.timezone :t1, 'Africa/Abidjan', 319, 60, -121, 30 i.timezone :t2, 'Africa/Johannesburg', -105, 4, 28, 1 i.timezone :t3, 'Africa/Lagos', 129, 20, 17, 5, 'West Africa Time' i.timezone :t4, 'Africa/Maputo', -779, 30, 391, 12, 'Central Africa Time' i.timezone :t5, 'Africa/Nairobi', -77, 60, 2209, 60 i.timezone :t6, 'America/Curacao', 731, 60, -69, 1 i.timezone :t7, 'America/Panama', 269, 30, -1193, 15 i.timezone :t8, 'America/Port_of_Spain', 213, 20, -3691, 60 i.timezone :t9, 'Asia/Bangkok', 55, 4, 6031, 60, 'Indochina (most areas)' i.timezone :t10, 'Asia/Dubai', 253, 10, 553, 10 i.timezone :t11, 'Asia/Qatar', 1517, 60, 773, 15 i.timezone :t12, 'Asia/Riyadh', 739, 30, 2803, 60 i.timezone :t13, 'Europe/Belgrade', 269, 6, 41, 2 i.timezone :t14, 'Europe/Helsinki', 361, 6, 749, 30 i.timezone :t15, 'Europe/London', 6181, 120, -451, 3600 i.timezone :t16, 'Europe/Oslo', 719, 12, 43, 4 i.timezone :t17, 'Europe/Prague', 601, 12, 433, 30 i.timezone :t18, 'Europe/Rome', 419, 10, 749, 60 i.timezone :t19, 'Europe/Zurich', 2843, 60, 128, 15, 'Swiss time' i.timezone :t20, 'Indian/Reunion', -313, 15, 832, 15, 'Réunion, Crozet, Scattered Islands' i.timezone :t21, 'Pacific/Auckland', -553, 15, 5243, 30, 'New Zealand time' i.timezone :t22, 'Pacific/Guam', 202, 15, 579, 4 i.timezone :t23, 'Pacific/Honolulu', 15341, 720, -18943, 120, 'Hawaii' i.timezone :t24, 'Pacific/Pago_Pago', -214, 15, -1707, 10, 'Samoa, Midway' i.country 'AD', 'Andorra' do |c| c.timezone 'Europe/Andorra', 85, 2, 91, 60 end i.country 'AE', 'United Arab Emirates' do |c| c.timezone :t10 end i.country 'AF', 'Afghanistan' do |c| c.timezone 'Asia/Kabul', 2071, 60, 346, 5 end i.country 'AG', 'Antigua & Barbuda' do |c| c.timezone :t8 end i.country 'AI', 'Anguilla' do |c| c.timezone :t8 end i.country 'AL', 'Albania' do |c| c.timezone 'Europe/Tirane', 124, 3, 119, 6 end i.country 'AM', 'Armenia' do |c| c.timezone 'Asia/Yerevan', 2411, 60, 89, 2 end i.country 'AO', 'Angola' do |c| c.timezone :t3 end i.country 'AQ', 'Antarctica' do |c| c.timezone 'Antarctica/Casey', -3977, 60, 6631, 60, 'Casey' c.timezone 'Antarctica/Davis', -823, 12, 2339, 30, 'Davis' c.timezone 'Antarctica/DumontDUrville', -200, 3, 8401, 60, 'Dumont-d\'Urville' c.timezone 'Antarctica/Mawson', -338, 5, 3773, 60, 'Mawson' c.timezone 'Antarctica/Palmer', -324, 5, -641, 10, 'Palmer' c.timezone 'Antarctica/Rothera', -2027, 30, -1022, 15, 'Rothera' c.timezone 'Antarctica/Syowa', -124211, 1800, 3959, 100, 'Syowa' c.timezone 'Antarctica/Troll', -259241, 3600, 507, 200, 'Troll' c.timezone 'Antarctica/Vostok', -392, 5, 1069, 10, 'Vostok' c.timezone :t21 end i.country 'AR', 'Argentina' do |c| c.timezone 'America/Argentina/Buenos_Aires', -173, 5, -1169, 20, 'Buenos Aires (BA, CF)' c.timezone 'America/Argentina/Cordoba', -157, 5, -3851, 60, 'Argentina (most areas: CB, CC, CN, ER, FM, MN, SE, SF)' c.timezone 'America/Argentina/Salta', -1487, 60, -785, 12, 'Salta (SA, LP, NQ, RN)' c.timezone 'America/Argentina/Jujuy', -1451, 60, -653, 10, 'Jujuy (JY)' c.timezone 'America/Argentina/Tucuman', -1609, 60, -3913, 60, 'Tucumán (TM)' c.timezone 'America/Argentina/Catamarca', -427, 15, -3947, 60, 'Catamarca (CT); Chubut (CH)' c.timezone 'America/Argentina/La_Rioja', -883, 30, -1337, 20, 'La Rioja (LR)' c.timezone 'America/Argentina/San_Juan', -473, 15, -4111, 60, 'San Juan (SJ)' c.timezone 'America/Argentina/Mendoza', -1973, 60, -4129, 60, 'Mendoza (MZ)' c.timezone 'America/Argentina/San_Luis', -1999, 60, -1327, 20, 'San Luis (SL)' c.timezone 'America/Argentina/Rio_Gallegos', -1549, 30, -4153, 60, 'Santa Cruz (SC)' c.timezone 'America/Argentina/Ushuaia', -274, 5, -683, 10, 'Tierra del Fuego (TF)' end i.country 'AS', 'Samoa (American)' do |c| c.timezone :t24 end i.country 'AT', 'Austria' do |c| c.timezone 'Europe/Vienna', 2893, 60, 49, 3 end i.country 'AU', 'Australia' do |c| c.timezone 'Australia/Lord_Howe', -631, 20, 1909, 12, 'Lord Howe Island' c.timezone 'Antarctica/Macquarie', -109, 2, 3179, 20, 'Macquarie Island' c.timezone 'Australia/Hobart', -2573, 60, 8839, 60, 'Tasmania (most areas)' c.timezone 'Australia/Currie', -599, 15, 2158, 15, 'Tasmania (King Island)' c.timezone 'Australia/Melbourne', -2269, 60, 4349, 30, 'Victoria' c.timezone 'Australia/Sydney', -508, 15, 9073, 60, 'New South Wales (most areas)' c.timezone 'Australia/Broken_Hill', -639, 20, 2829, 20, 'New South Wales (Yancowinna)' c.timezone 'Australia/Brisbane', -412, 15, 4591, 30, 'Queensland (most areas)' c.timezone 'Australia/Lindeman', -304, 15, 149, 1, 'Queensland (Whitsunday Islands)' c.timezone 'Australia/Adelaide', -419, 12, 1663, 12, 'South Australia' c.timezone 'Australia/Darwin', -187, 15, 785, 6, 'Northern Territory' c.timezone 'Australia/Perth', -639, 20, 2317, 20, 'Western Australia (most areas)' c.timezone 'Australia/Eucla', -1903, 60, 1933, 15, 'Western Australia (Eucla)' end i.country 'AW', 'Aruba' do |c| c.timezone :t6 end i.country 'AX', 'Åland Islands' do |c| c.timezone :t14 end i.country 'AZ', 'Azerbaijan' do |c| c.timezone 'Asia/Baku', 2423, 60, 997, 20 end i.country 'BA', 'Bosnia & Herzegovina' do |c| c.timezone :t13 end i.country 'BB', 'Barbados' do |c| c.timezone 'America/Barbados', 131, 10, -3577, 60 end i.country 'BD', 'Bangladesh' do |c| c.timezone 'Asia/Dhaka', 1423, 60, 1085, 12 end i.country 'BE', 'Belgium' do |c| c.timezone 'Europe/Brussels', 305, 6, 13, 3 end i.country 'BF', 'Burkina Faso' do |c| c.timezone :t1 end i.country 'BG', 'Bulgaria' do |c| c.timezone 'Europe/Sofia', 2561, 60, 1399, 60 end i.country 'BH', 'Bahrain' do |c| c.timezone :t11 end i.country 'BI', 'Burundi' do |c| c.timezone :t4 end i.country 'BJ', 'Benin' do |c| c.timezone :t3 end i.country 'BL', 'St Barthelemy' do |c| c.timezone :t8 end i.country 'BM', 'Bermuda' do |c| c.timezone 'Atlantic/Bermuda', 1937, 60, -1943, 30 end i.country 'BN', 'Brunei' do |c| c.timezone 'Asia/Brunei', 74, 15, 1379, 12 end i.country 'BO', 'Bolivia' do |c| c.timezone 'America/La_Paz', -33, 2, -1363, 20 end i.country 'BQ', 'Caribbean NL' do |c| c.timezone :t6 end i.country 'BR', 'Brazil' do |c| c.timezone 'America/Noronha', -77, 20, -389, 12, 'Atlantic islands' c.timezone 'America/Belem', -29, 20, -2909, 60, 'Pará (east); Amapá' c.timezone 'America/Fortaleza', -223, 60, -77, 2, 'Brazil (northeast: MA, PI, CE, RN, PB)' c.timezone 'America/Recife', -161, 20, -349, 10, 'Pernambuco' c.timezone 'America/Araguaina', -36, 5, -241, 5, 'Tocantins' c.timezone 'America/Maceio', -29, 3, -2143, 60, 'Alagoas, Sergipe' c.timezone 'America/Bahia', -779, 60, -2311, 60, 'Bahia' c.timezone 'America/Sao_Paulo', -353, 15, -2797, 60, 'Brazil (southeast: GO, DF, MG, ES, RJ, SP, PR, SC, RS)' c.timezone 'America/Campo_Grande', -409, 20, -3277, 60, 'Mato Grosso do Sul' c.timezone 'America/Cuiaba', -187, 12, -673, 12, 'Mato Grosso' c.timezone 'America/Santarem', -73, 30, -823, 15, 'Pará (west)' c.timezone 'America/Porto_Velho', -263, 30, -639, 10, 'Rondônia' c.timezone 'America/Boa_Vista', 169, 60, -182, 3, 'Roraima' c.timezone 'America/Manaus', -47, 15, -3601, 60, 'Amazonas (east)' c.timezone 'America/Eirunepe', -20, 3, -1048, 15, 'Amazonas (west)' c.timezone 'America/Rio_Branco', -299, 30, -339, 5, 'Acre' end i.country 'BS', 'Bahamas' do |c| c.timezone 'America/Nassau', 301, 12, -1547, 20 end i.country 'BT', 'Bhutan' do |c| c.timezone 'Asia/Thimphu', 412, 15, 1793, 20 end i.country 'BV', 'Bouvet Island' i.country 'BW', 'Botswana' do |c| c.timezone :t4 end i.country 'BY', 'Belarus' do |c| c.timezone 'Europe/Minsk', 539, 10, 827, 30 end i.country 'BZ', 'Belize' do |c| c.timezone 'America/Belize', 35, 2, -441, 5 end i.country 'CA', 'Canada' do |c| c.timezone 'America/St_Johns', 1427, 30, -3163, 60, 'Newfoundland; Labrador (southeast)' c.timezone 'America/Halifax', 893, 20, -318, 5, 'Atlantic - NS (most areas); PE' c.timezone 'America/Glace_Bay', 231, 5, -1199, 20, 'Atlantic - NS (Cape Breton)' c.timezone 'America/Moncton', 461, 10, -3887, 60, 'Atlantic - New Brunswick' c.timezone 'America/Goose_Bay', 160, 3, -725, 12, 'Atlantic - Labrador (most areas)' c.timezone 'America/Blanc-Sablon', 617, 12, -3427, 60, 'AST - QC (Lower North Shore)' c.timezone 'America/Toronto', 873, 20, -4763, 60, 'Eastern - ON, QC (most areas)' c.timezone 'America/Nipigon', 2941, 60, -1324, 15, 'Eastern - ON, QC (no DST 1967-73)' c.timezone 'America/Thunder_Bay', 2903, 60, -357, 4, 'Eastern - ON (Thunder Bay)' c.timezone 'America/Iqaluit', 956, 15, -1027, 15, 'Eastern - NU (most east areas)' c.timezone 'America/Pangnirtung', 992, 15, -986, 15, 'Eastern - NU (Pangnirtung)' c.timezone 'America/Atikokan', 175531, 3600, -54973, 600, 'EST - ON (Atikokan); NU (Coral H)' c.timezone 'America/Winnipeg', 2993, 60, -1943, 20, 'Central - ON (west); Manitoba' c.timezone 'America/Rainy_River', 2923, 60, -2837, 30, 'Central - ON (Rainy R, Ft Frances)' c.timezone 'America/Resolute', 33613, 450, -22759, 240, 'Central - NU (Resolute)' c.timezone 'America/Rankin_Inlet', 3769, 60, -331499, 3600, 'Central - NU (central)' c.timezone 'America/Regina', 252, 5, -2093, 20, 'CST - SK (most areas)' c.timezone 'America/Swift_Current', 3017, 60, -647, 6, 'CST - SK (midwest)' c.timezone 'America/Edmonton', 1071, 20, -1702, 15, 'Mountain - AB; BC (E); SK (W)' c.timezone 'America/Cambridge_Bay', 24881, 360, -37819, 360, 'Mountain - NU (west)' c.timezone 'America/Yellowknife', 1249, 20, -2287, 20, 'Mountain - NT (central)' c.timezone 'America/Inuvik', 246059, 3600, -8023, 60, 'Mountain - NT (west)' c.timezone 'America/Creston', 491, 10, -6991, 60, 'MST - BC (Creston)' c.timezone 'America/Dawson_Creek', 1793, 30, -3607, 30, 'MST - BC (Dawson Cr, Ft St John)' c.timezone 'America/Fort_Nelson', 294, 5, -1227, 10, 'MST - BC (Ft Nelson)' c.timezone 'America/Vancouver', 739, 15, -7387, 60, 'Pacific - BC (most areas)' c.timezone 'America/Whitehorse', 3643, 60, -2701, 20, 'Pacific - Yukon (east)' c.timezone 'America/Dawson', 961, 15, -1673, 12, 'Pacific - Yukon (west)' end i.country 'CC', 'Cocos (Keeling) Islands' do |c| c.timezone 'Indian/Cocos', -73, 6, 1163, 12 end i.country 'CD', 'Congo (Dem. Rep.)' do |c| c.timezone :t4 c.timezone :t3 end i.country 'CF', 'Central African Rep.' do |c| c.timezone :t3 end i.country 'CG', 'Congo (Rep.)' do |c| c.timezone :t3 end i.country 'CH', 'Switzerland' do |c| c.timezone :t19 end i.country 'CI', 'Côte d\'Ivoire' do |c| c.timezone :t1 end i.country 'CK', 'Cook Islands' do |c| c.timezone 'Pacific/Rarotonga', -637, 30, -4793, 30 end i.country 'CL', 'Chile' do |c| c.timezone 'America/Santiago', -669, 20, -212, 3, 'Chile (most areas)' c.timezone 'America/Punta_Arenas', -1063, 20, -851, 12, 'Region of Magallanes' c.timezone 'Pacific/Easter', -543, 20, -3283, 30, 'Easter Island' end i.country 'CM', 'Cameroon' do |c| c.timezone :t3 end i.country 'CN', 'China' do |c| c.timezone 'Asia/Shanghai', 937, 30, 1822, 15, 'Beijing Time' c.timezone 'Asia/Urumqi', 219, 5, 1051, 12, 'Xinjiang Time' end i.country 'CO', 'Colombia' do |c| c.timezone 'America/Bogota', 23, 5, -889, 12 end i.country 'CR', 'Costa Rica' do |c| c.timezone 'America/Costa_Rica', 149, 15, -1009, 12 end i.country 'CU', 'Cuba' do |c| c.timezone 'America/Havana', 347, 15, -2471, 30 end i.country 'CV', 'Cape Verde' do |c| c.timezone 'Atlantic/Cape_Verde', 179, 12, -1411, 60 end i.country 'CW', 'Curaçao' do |c| c.timezone :t6 end i.country 'CX', 'Christmas Island' do |c| c.timezone 'Indian/Christmas', -125, 12, 6343, 60 end i.country 'CY', 'Cyprus' do |c| c.timezone 'Asia/Nicosia', 211, 6, 1001, 30, 'Cyprus (most areas)' c.timezone 'Asia/Famagusta', 2107, 60, 679, 20, 'Northern Cyprus' end i.country 'CZ', 'Czech Republic' do |c| c.timezone :t17 end i.country 'DE', 'Germany' do |c| c.timezone 'Europe/Berlin', 105, 2, 401, 30, 'Germany (most areas)' c.timezone :t19 end i.country 'DJ', 'Djibouti' do |c| c.timezone :t5 end i.country 'DK', 'Denmark' do |c| c.timezone 'Europe/Copenhagen', 167, 3, 151, 12 end i.country 'DM', 'Dominica' do |c| c.timezone :t8 end i.country 'DO', 'Dominican Republic' do |c| c.timezone 'America/Santo_Domingo', 277, 15, -699, 10 end i.country 'DZ', 'Algeria' do |c| c.timezone 'Africa/Algiers', 2207, 60, 61, 20 end i.country 'EC', 'Ecuador' do |c| c.timezone 'America/Guayaquil', -13, 6, -479, 6, 'Ecuador (mainland)' c.timezone 'Pacific/Galapagos', -9, 10, -448, 5, 'Galápagos Islands' end i.country 'EE', 'Estonia' do |c| c.timezone 'Europe/Tallinn', 713, 12, 99, 4 end i.country 'EG', 'Egypt' do |c| c.timezone 'Africa/Cairo', 601, 20, 125, 4 end i.country 'EH', 'Western Sahara' do |c| c.timezone 'Africa/El_Aaiun', 543, 20, -66, 5 end i.country 'ER', 'Eritrea' do |c| c.timezone :t5 end i.country 'ES', 'Spain' do |c| c.timezone 'Europe/Madrid', 202, 5, -221, 60, 'Spain (mainland)' c.timezone 'Africa/Ceuta', 2153, 60, -319, 60, 'Ceuta, Melilla' c.timezone 'Atlantic/Canary', 281, 10, -77, 5, 'Canary Islands' end i.country 'ET', 'Ethiopia' do |c| c.timezone :t5 end i.country 'FI', 'Finland' do |c| c.timezone :t14 end i.country 'FJ', 'Fiji' do |c| c.timezone 'Pacific/Fiji', -272, 15, 2141, 12 end i.country 'FK', 'Falkland Islands' do |c| c.timezone 'Atlantic/Stanley', -517, 10, -1157, 20 end i.country 'FM', 'Micronesia' do |c| c.timezone 'Pacific/Chuuk', 89, 12, 9107, 60, 'Chuuk/Truk, Yap' c.timezone 'Pacific/Pohnpei', 209, 30, 9493, 60, 'Pohnpei/Ponape' c.timezone 'Pacific/Kosrae', 319, 60, 9779, 60, 'Kosrae' end i.country 'FO', 'Faroe Islands' do |c| c.timezone 'Atlantic/Faroe', 3721, 60, -203, 30 end i.country 'FR', 'France' do |c| c.timezone 'Europe/Paris', 733, 15, 7, 3 end i.country 'GA', 'Gabon' do |c| c.timezone :t3 end i.country 'GB', 'Britain (UK)' do |c| c.timezone :t15 end i.country 'GD', 'Grenada' do |c| c.timezone :t8 end i.country 'GE', 'Georgia' do |c| c.timezone 'Asia/Tbilisi', 2503, 60, 2689, 60 end i.country 'GF', 'French Guiana' do |c| c.timezone 'America/Cayenne', 74, 15, -157, 3 end i.country 'GG', 'Guernsey' do |c| c.timezone :t15 end i.country 'GH', 'Ghana' do |c| c.timezone 'Africa/Accra', 111, 20, -13, 60 end i.country 'GI', 'Gibraltar' do |c| c.timezone 'Europe/Gibraltar', 542, 15, -107, 20 end i.country 'GL', 'Greenland' do |c| c.timezone 'America/Nuuk', 3851, 60, -776, 15, 'Greenland (most areas)' c.timezone 'America/Danmarkshavn', 2303, 30, -56, 3, 'National Park (east coast)' c.timezone 'America/Scoresbysund', 4229, 60, -659, 30, 'Scoresbysund/Ittoqqortoormiit' c.timezone 'America/Thule', 2297, 30, -4127, 60, 'Thule/Pituffik' end i.country 'GM', 'Gambia' do |c| c.timezone :t1 end i.country 'GN', 'Guinea' do |c| c.timezone :t1 end i.country 'GP', 'Guadeloupe' do |c| c.timezone :t8 end i.country 'GQ', 'Equatorial Guinea' do |c| c.timezone :t3 end i.country 'GR', 'Greece' do |c| c.timezone 'Europe/Athens', 1139, 30, 1423, 60 end i.country 'GS', 'South Georgia & the South Sandwich Islands' do |c| c.timezone 'Atlantic/South_Georgia', -814, 15, -548, 15 end i.country 'GT', 'Guatemala' do |c| c.timezone 'America/Guatemala', 439, 30, -5431, 60 end i.country 'GU', 'Guam' do |c| c.timezone :t22 end i.country 'GW', 'Guinea-Bissau' do |c| c.timezone 'Africa/Bissau', 237, 20, -187, 12 end i.country 'GY', 'Guyana' do |c| c.timezone 'America/Guyana', 34, 5, -349, 6 end i.country 'HK', 'Hong Kong' do |c| c.timezone 'Asia/Hong_Kong', 1337, 60, 2283, 20 end i.country 'HM', 'Heard Island & McDonald Islands' i.country 'HN', 'Honduras' do |c| c.timezone 'America/Tegucigalpa', 141, 10, -5233, 60 end i.country 'HR', 'Croatia' do |c| c.timezone :t13 end i.country 'HT', 'Haiti' do |c| c.timezone 'America/Port-au-Prince', 278, 15, -217, 3 end i.country 'HU', 'Hungary' do |c| c.timezone 'Europe/Budapest', 95, 2, 229, 12 end i.country 'ID', 'Indonesia' do |c| c.timezone 'Asia/Jakarta', -37, 6, 534, 5, 'Java, Sumatra' c.timezone 'Asia/Pontianak', -1, 30, 328, 3, 'Borneo (west, central)' c.timezone 'Asia/Makassar', -307, 60, 597, 5, 'Borneo (east, south); Sulawesi/Celebes, Bali, Nusa Tengarra; Timor (west)' c.timezone 'Asia/Jayapura', -38, 15, 1407, 10, 'New Guinea (West Papua / Irian Jaya); Malukus/Moluccas' end i.country 'IE', 'Ireland' do |c| c.timezone 'Europe/Dublin', 160, 3, -25, 4 end i.country 'IL', 'Israel' do |c| c.timezone 'Asia/Jerusalem', 11441, 360, 63403, 1800 end i.country 'IM', 'Isle of Man' do |c| c.timezone :t15 end i.country 'IN', 'India' do |c| c.timezone 'Asia/Kolkata', 338, 15, 2651, 30 end i.country 'IO', 'British Indian Ocean Territory' do |c| c.timezone 'Indian/Chagos', -22, 3, 869, 12 end i.country 'IQ', 'Iraq' do |c| c.timezone 'Asia/Baghdad', 667, 20, 533, 12 end i.country 'IR', 'Iran' do |c| c.timezone 'Asia/Tehran', 107, 3, 1543, 30 end i.country 'IS', 'Iceland' do |c| c.timezone 'Atlantic/Reykjavik', 1283, 20, -437, 20 end i.country 'IT', 'Italy' do |c| c.timezone :t18 end i.country 'JE', 'Jersey' do |c| c.timezone :t15 end i.country 'JM', 'Jamaica' do |c| c.timezone 'America/Jamaica', 12937, 720, -11519, 150 end i.country 'JO', 'Jordan' do |c| c.timezone 'Asia/Amman', 639, 20, 539, 15 end i.country 'JP', 'Japan' do |c| c.timezone 'Asia/Tokyo', 32089, 900, 503081, 3600 end i.country 'KE', 'Kenya' do |c| c.timezone :t5 end i.country 'KG', 'Kyrgyzstan' do |c| c.timezone 'Asia/Bishkek', 429, 10, 373, 5 end i.country 'KH', 'Cambodia' do |c| c.timezone :t9 end i.country 'KI', 'Kiribati' do |c| c.timezone 'Pacific/Tarawa', 17, 12, 173, 1, 'Gilbert Islands' c.timezone 'Pacific/Enderbury', -47, 15, -2053, 12, 'Phoenix Islands' c.timezone 'Pacific/Kiritimati', 28, 15, -472, 3, 'Line Islands' end i.country 'KM', 'Comoros' do |c| c.timezone :t5 end i.country 'KN', 'St Kitts & Nevis' do |c| c.timezone :t8 end i.country 'KP', 'Korea (North)' do |c| c.timezone 'Asia/Pyongyang', 2341, 60, 503, 4 end i.country 'KR', 'Korea (South)' do |c| c.timezone 'Asia/Seoul', 751, 20, 3809, 30 end i.country 'KW', 'Kuwait' do |c| c.timezone :t12 end i.country 'KY', 'Cayman Islands' do |c| c.timezone :t7 end i.country 'KZ', 'Kazakhstan' do |c| c.timezone 'Asia/Almaty', 173, 4, 1539, 20, 'Kazakhstan (most areas)' c.timezone 'Asia/Qyzylorda', 224, 5, 982, 15, 'Qyzylorda/Kyzylorda/Kzyl-Orda' c.timezone 'Asia/Qostanay', 266, 5, 3817, 60, 'Qostanay/Kostanay/Kustanay' c.timezone 'Asia/Aqtobe', 3017, 60, 343, 6, 'Aqtöbe/Aktobe' c.timezone 'Asia/Aqtau', 2671, 60, 754, 15, 'Mangghystaū/Mankistau' c.timezone 'Asia/Atyrau', 2827, 60, 779, 15, 'Atyraū/Atirau/Gur\'yev' c.timezone 'Asia/Oral', 3073, 60, 1027, 20, 'West Kazakhstan' end i.country 'LA', 'Laos' do |c| c.timezone :t9 end i.country 'LB', 'Lebanon' do |c| c.timezone 'Asia/Beirut', 2033, 60, 71, 2 end i.country 'LC', 'St Lucia' do |c| c.timezone :t8 end i.country 'LI', 'Liechtenstein' do |c| c.timezone :t19 end i.country 'LK', 'Sri Lanka' do |c| c.timezone 'Asia/Colombo', 104, 15, 1597, 20 end i.country 'LR', 'Liberia' do |c| c.timezone 'Africa/Monrovia', 63, 10, -647, 60 end i.country 'LS', 'Lesotho' do |c| c.timezone :t2 end i.country 'LT', 'Lithuania' do |c| c.timezone 'Europe/Vilnius', 3281, 60, 1519, 60 end i.country 'LU', 'Luxembourg' do |c| c.timezone 'Europe/Luxembourg', 248, 5, 123, 20 end i.country 'LV', 'Latvia' do |c| c.timezone 'Europe/Riga', 1139, 20, 241, 10 end i.country 'LY', 'Libya' do |c| c.timezone 'Africa/Tripoli', 329, 10, 791, 60 end i.country 'MA', 'Morocco' do |c| c.timezone 'Africa/Casablanca', 673, 20, -91, 12 end i.country 'MC', 'Monaco' do |c| c.timezone 'Europe/Monaco', 437, 10, 443, 60 end i.country 'MD', 'Moldova' do |c| c.timezone 'Europe/Chisinau', 47, 1, 173, 6 end i.country 'ME', 'Montenegro' do |c| c.timezone :t13 end i.country 'MF', 'St Martin (French)' do |c| c.timezone :t8 end i.country 'MG', 'Madagascar' do |c| c.timezone :t5 end i.country 'MH', 'Marshall Islands' do |c| c.timezone 'Pacific/Majuro', 143, 20, 856, 5, 'Marshall Islands (most areas)' c.timezone 'Pacific/Kwajalein', 109, 12, 502, 3, 'Kwajalein' end i.country 'MK', 'North Macedonia' do |c| c.timezone :t13 end i.country 'ML', 'Mali' do |c| c.timezone :t1 end i.country 'MM', 'Myanmar (Burma)' do |c| c.timezone 'Asia/Yangon', 1007, 60, 577, 6 end i.country 'MN', 'Mongolia' do |c| c.timezone 'Asia/Ulaanbaatar', 575, 12, 6413, 60, 'Mongolia (most areas)' c.timezone 'Asia/Hovd', 2881, 60, 1833, 20, 'Bayan-Ölgii, Govi-Altai, Hovd, Uvs, Zavkhan' c.timezone 'Asia/Choibalsan', 721, 15, 229, 2, 'Dornod, Sükhbaatar' end i.country 'MO', 'Macau' do |c| c.timezone 'Asia/Macau', 7991, 360, 2725, 24 end i.country 'MP', 'Northern Mariana Islands' do |c| c.timezone :t22 end i.country 'MQ', 'Martinique' do |c| c.timezone 'America/Martinique', 73, 5, -733, 12 end i.country 'MR', 'Mauritania' do |c| c.timezone :t1 end i.country 'MS', 'Montserrat' do |c| c.timezone :t8 end i.country 'MT', 'Malta' do |c| c.timezone 'Europe/Malta', 359, 10, 871, 60 end i.country 'MU', 'Mauritius' do |c| c.timezone 'Indian/Mauritius', -121, 6, 115, 2 end i.country 'MV', 'Maldives' do |c| c.timezone 'Indian/Maldives', 25, 6, 147, 2 end i.country 'MW', 'Malawi' do |c| c.timezone :t4 end i.country 'MX', 'Mexico' do |c| c.timezone 'America/Mexico_City', 97, 5, -1983, 20, 'Central Time' c.timezone 'America/Cancun', 253, 12, -2603, 30, 'Eastern Standard Time - Quintana Roo' c.timezone 'America/Merida', 629, 30, -5377, 60, 'Central Time - Campeche, Yucatán' c.timezone 'America/Monterrey', 77, 3, -6019, 60, 'Central Time - Durango; Coahuila, Nuevo León, Tamaulipas (most areas)' c.timezone 'America/Matamoros', 155, 6, -195, 2, 'Central Time US - Coahuila, Nuevo León, Tamaulipas (US border)' c.timezone 'America/Mazatlan', 1393, 60, -1277, 12, 'Mountain Time - Baja California Sur, Nayarit, Sinaloa' c.timezone 'America/Chihuahua', 859, 30, -1273, 12, 'Mountain Time - Chihuahua (most areas)' c.timezone 'America/Ojinaga', 887, 30, -1253, 12, 'Mountain Time US - Chihuahua (US border)' c.timezone 'America/Hermosillo', 436, 15, -3329, 30, 'Mountain Standard Time - Sonora' c.timezone 'America/Tijuana', 488, 15, -7021, 60, 'Pacific Time US - Baja California' c.timezone 'America/Bahia_Banderas', 104, 5, -421, 4, 'Central Time - Bahía de Banderas' end i.country 'MY', 'Malaysia' do |c| c.timezone 'Asia/Kuala_Lumpur', 19, 6, 1017, 10, 'Malaysia (peninsula)' c.timezone 'Asia/Kuching', 31, 20, 331, 3, 'Sabah, Sarawak' end i.country 'MZ', 'Mozambique' do |c| c.timezone :t4 end i.country 'NA', 'Namibia' do |c| c.timezone 'Africa/Windhoek', -677, 30, 171, 10 end i.country 'NC', 'New Caledonia' do |c| c.timezone 'Pacific/Noumea', -334, 15, 3329, 20 end i.country 'NE', 'Niger' do |c| c.timezone :t3 end i.country 'NF', 'Norfolk Island' do |c| c.timezone 'Pacific/Norfolk', -581, 20, 5039, 30 end i.country 'NG', 'Nigeria' do |c| c.timezone :t3 end i.country 'NI', 'Nicaragua' do |c| c.timezone 'America/Managua', 243, 20, -5177, 60 end i.country 'NL', 'Netherlands' do |c| c.timezone 'Europe/Amsterdam', 1571, 30, 49, 10 end i.country 'NO', 'Norway' do |c| c.timezone :t16 end i.country 'NP', 'Nepal' do |c| c.timezone 'Asia/Kathmandu', 1663, 60, 5119, 60 end i.country 'NR', 'Nauru' do |c| c.timezone 'Pacific/Nauru', -31, 60, 2003, 12 end i.country 'NU', 'Niue' do |c| c.timezone 'Pacific/Niue', -1141, 60, -2039, 12 end i.country 'NZ', 'New Zealand' do |c| c.timezone :t21 c.timezone 'Pacific/Chatham', -879, 20, -3531, 20, 'Chatham Islands' end i.country 'OM', 'Oman' do |c| c.timezone :t10 end i.country 'PA', 'Panama' do |c| c.timezone :t7 end i.country 'PE', 'Peru' do |c| c.timezone 'America/Lima', -241, 20, -1541, 20 end i.country 'PF', 'French Polynesia' do |c| c.timezone 'Pacific/Tahiti', -263, 15, -4487, 30, 'Society Islands' c.timezone 'Pacific/Marquesas', -9, 1, -279, 2, 'Marquesas Islands' c.timezone 'Pacific/Gambier', -347, 15, -2699, 20, 'Gambier Islands' end i.country 'PG', 'Papua New Guinea' do |c| c.timezone 'Pacific/Port_Moresby', -19, 2, 883, 6, 'Papua New Guinea (most areas)' c.timezone 'Pacific/Bougainville', -373, 60, 4667, 30, 'Bougainville' end i.country 'PH', 'Philippines' do |c| c.timezone 'Asia/Manila', 175, 12, 121, 1 end i.country 'PK', 'Pakistan' do |c| c.timezone 'Asia/Karachi', 373, 15, 1341, 20 end i.country 'PL', 'Poland' do |c| c.timezone 'Europe/Warsaw', 209, 4, 21, 1 end i.country 'PM', 'St Pierre & Miquelon' do |c| c.timezone 'America/Miquelon', 941, 20, -169, 3 end i.country 'PN', 'Pitcairn' do |c| c.timezone 'Pacific/Pitcairn', -376, 15, -1561, 12 end i.country 'PR', 'Puerto Rico' do |c| c.timezone 'America/Puerto_Rico', 11081, 600, -118991, 1800 end i.country 'PS', 'Palestine' do |c| c.timezone 'Asia/Gaza', 63, 2, 517, 15, 'Gaza Strip' c.timezone 'Asia/Hebron', 473, 15, 7019, 200, 'West Bank' end i.country 'PT', 'Portugal' do |c| c.timezone 'Europe/Lisbon', 2323, 60, -137, 15, 'Portugal (mainland)' c.timezone 'Atlantic/Madeira', 979, 30, -169, 10, 'Madeira Islands' c.timezone 'Atlantic/Azores', 566, 15, -77, 3, 'Azores' end i.country 'PW', 'Palau' do |c| c.timezone 'Pacific/Palau', 22, 3, 8069, 60 end i.country 'PY', 'Paraguay' do |c| c.timezone 'America/Asuncion', -379, 15, -173, 3 end i.country 'QA', 'Qatar' do |c| c.timezone :t11 end i.country 'RE', 'Réunion' do |c| c.timezone :t20 end i.country 'RO', 'Romania' do |c| c.timezone 'Europe/Bucharest', 1333, 30, 261, 10 end i.country 'RS', 'Serbia' do |c| c.timezone :t13 end i.country 'RU', 'Russia' do |c| c.timezone 'Europe/Kaliningrad', 3283, 60, 41, 2, 'MSK-01 - Kaliningrad' c.timezone 'Europe/Moscow', 66907, 1200, 8464, 225, 'MSK+00 - Moscow area' c.timezone 'Europe/Simferopol', 899, 20, 341, 10, 'Crimea' c.timezone 'Europe/Kirov', 293, 5, 993, 20, 'MSK+00 - Kirov' c.timezone 'Europe/Astrakhan', 927, 20, 961, 20, 'MSK+01 - Astrakhan' c.timezone 'Europe/Volgograd', 731, 15, 533, 12, 'MSK+01 - Volgograd' c.timezone 'Europe/Saratov', 1547, 30, 1381, 30, 'MSK+01 - Saratov' c.timezone 'Europe/Ulyanovsk', 163, 3, 242, 5, 'MSK+01 - Ulyanovsk' c.timezone 'Europe/Samara', 266, 5, 1003, 20, 'MSK+01 - Samara, Udmurtia' c.timezone 'Asia/Yekaterinburg', 1137, 20, 303, 5, 'MSK+02 - Urals' c.timezone 'Asia/Omsk', 55, 1, 367, 5, 'MSK+03 - Omsk' c.timezone 'Asia/Novosibirsk', 1651, 30, 995, 12, 'MSK+04 - Novosibirsk' c.timezone 'Asia/Barnaul', 1601, 30, 335, 4, 'MSK+04 - Altai' c.timezone 'Asia/Tomsk', 113, 2, 2549, 30, 'MSK+04 - Tomsk' c.timezone 'Asia/Novokuznetsk', 215, 4, 5227, 60, 'MSK+04 - Kemerovo' c.timezone 'Asia/Krasnoyarsk', 3361, 60, 557, 6, 'MSK+04 - Krasnoyarsk area' c.timezone 'Asia/Irkutsk', 784, 15, 313, 3, 'MSK+05 - Irkutsk, Buryatia' c.timezone 'Asia/Chita', 1041, 20, 1702, 15, 'MSK+06 - Zabaykalsky' c.timezone 'Asia/Yakutsk', 62, 1, 389, 3, 'MSK+06 - Lena River' c.timezone 'Asia/Khandyga', 225563, 3600, 243997, 1800, 'MSK+06 - Tomponsky, Ust-Maysky' c.timezone 'Asia/Vladivostok', 259, 6, 1979, 15, 'MSK+07 - Amur River' c.timezone 'Asia/Ust-Nera', 232417, 3600, 10742, 75, 'MSK+07 - Oymyakonsky' c.timezone 'Asia/Magadan', 1787, 30, 754, 5, 'MSK+08 - Magadan' c.timezone 'Asia/Sakhalin', 1409, 30, 1427, 10, 'MSK+08 - Sakhalin Island' c.timezone 'Asia/Srednekolymsk', 1012, 15, 9223, 60, 'MSK+08 - Sakha (E); North Kuril Is' c.timezone 'Asia/Kamchatka', 3181, 60, 3173, 20, 'MSK+09 - Kamchatka' c.timezone 'Asia/Anadyr', 259, 4, 10649, 60, 'MSK+09 - Bering Sea' end i.country 'RW', 'Rwanda' do |c| c.timezone :t4 end i.country 'SA', 'Saudi Arabia' do |c| c.timezone :t12 end i.country 'SB', 'Solomon Islands' do |c| c.timezone 'Pacific/Guadalcanal', -143, 15, 801, 5 end i.country 'SC', 'Seychelles' do |c| c.timezone 'Indian/Mahe', -14, 3, 832, 15 end i.country 'SD', 'Sudan' do |c| c.timezone :t3 end i.country 'SE', 'Sweden' do |c| c.timezone 'Europe/Stockholm', 178, 3, 361, 20 end i.country 'SG', 'Singapore' do |c| c.timezone 'Asia/Singapore', 77, 60, 2077, 20 end i.country 'SH', 'St Helena' do |c| c.timezone :t1 end i.country 'SI', 'Slovenia' do |c| c.timezone :t13 end i.country 'SJ', 'Svalbard & Jan Mayen' do |c| c.timezone :t16 end i.country 'SK', 'Slovakia' do |c| c.timezone :t17 end i.country 'SL', 'Sierra Leone' do |c| c.timezone :t1 end i.country 'SM', 'San Marino' do |c| c.timezone :t18 end i.country 'SN', 'Senegal' do |c| c.timezone :t1 end i.country 'SO', 'Somalia' do |c| c.timezone :t5 end i.country 'SR', 'Suriname' do |c| c.timezone 'America/Paramaribo', 35, 6, -331, 6 end i.country 'SS', 'South Sudan' do |c| c.timezone 'Africa/Juba', 97, 20, 1897, 60 end i.country 'ST', 'Sao Tome & Principe' do |c| c.timezone 'Africa/Sao_Tome', 1, 3, 101, 15 end i.country 'SV', 'El Salvador' do |c| c.timezone 'America/El_Salvador', 137, 10, -446, 5 end i.country 'SX', 'St Maarten (Dutch)' do |c| c.timezone :t6 end i.country 'SY', 'Syria' do |c| c.timezone 'Asia/Damascus', 67, 2, 363, 10 end i.country 'SZ', 'Eswatini (Swaziland)' do |c| c.timezone :t2 end i.country 'TC', 'Turks & Caicos Is' do |c| c.timezone 'America/Grand_Turk', 322, 15, -1067, 15 end i.country 'TD', 'Chad' do |c| c.timezone 'Africa/Ndjamena', 727, 60, 301, 20 end i.country 'TF', 'French Southern & Antarctic Lands' do |c| c.timezone 'Indian/Kerguelen', -17767, 360, 28087, 400, 'Kerguelen, St Paul Island, Amsterdam Island' c.timezone :t20 end i.country 'TG', 'Togo' do |c| c.timezone :t1 end i.country 'TH', 'Thailand' do |c| c.timezone :t9 end i.country 'TJ', 'Tajikistan' do |c| c.timezone 'Asia/Dushanbe', 463, 12, 344, 5 end i.country 'TK', 'Tokelau' do |c| c.timezone 'Pacific/Fakaofo', -281, 30, -5137, 30 end i.country 'TL', 'East Timor' do |c| c.timezone 'Asia/Dili', -171, 20, 1507, 12 end i.country 'TM', 'Turkmenistan' do |c| c.timezone 'Asia/Ashgabat', 759, 20, 3503, 60 end i.country 'TN', 'Tunisia' do |c| c.timezone 'Africa/Tunis', 184, 5, 611, 60 end i.country 'TO', 'Tonga' do |c| c.timezone 'Pacific/Tongatapu', -127, 6, -1051, 6 end i.country 'TR', 'Turkey' do |c| c.timezone 'Europe/Istanbul', 2461, 60, 869, 30 end i.country 'TT', 'Trinidad & Tobago' do |c| c.timezone :t8 end i.country 'TV', 'Tuvalu' do |c| c.timezone 'Pacific/Funafuti', -511, 60, 10753, 60 end i.country 'TW', 'Taiwan' do |c| c.timezone 'Asia/Taipei', 501, 20, 243, 2 end i.country 'TZ', 'Tanzania' do |c| c.timezone :t5 end i.country 'UA', 'Ukraine' do |c| c.timezone 'Europe/Kiev', 1513, 30, 1831, 60, 'Ukraine (most areas)' c.timezone 'Europe/Uzhgorod', 2917, 60, 223, 10, 'Transcarpathia' c.timezone 'Europe/Zaporozhye', 287, 6, 211, 6, 'Zaporozhye and east Lugansk' c.timezone 'Europe/Simferopol', 899, 20, 341, 10, 'Crimea' end i.country 'UG', 'Uganda' do |c| c.timezone :t5 end i.country 'UM', 'US minor outlying islands' do |c| c.timezone 'Pacific/Wake', 1157, 60, 9997, 60, 'Wake Island' c.timezone :t24 c.timezone :t23 end i.country 'US', 'United States' do |c| c.timezone 'America/New_York', 48857, 1200, -266423, 3600, 'Eastern (most areas)' c.timezone 'America/Detroit', 152393, 3600, -19931, 240, 'Eastern - MI (most areas)' c.timezone 'America/Kentucky/Louisville', 9181, 240, -154367, 1800, 'Eastern - KY (Louisville area)' c.timezone 'America/Kentucky/Monticello', 132587, 3600, -101819, 1200, 'Eastern - KY (Wayne)' c.timezone 'America/Indiana/Indianapolis', 23861, 600, -310169, 3600, 'Eastern - IN (most areas)' c.timezone 'America/Indiana/Vincennes', 69619, 1800, -315103, 3600, 'Eastern - IN (Da, Du, K, Mn)' c.timezone 'America/Indiana/Winamac', 29557, 720, -311771, 3600, 'Eastern - IN (Pulaski)' c.timezone 'America/Indiana/Marengo', 17269, 450, -310841, 3600, 'Eastern - IN (Crawford)' c.timezone 'America/Indiana/Petersburg', 138571, 3600, -314203, 3600, 'Eastern - IN (Pike)' c.timezone 'America/Indiana/Vevay', 34873, 900, -153121, 1800, 'Eastern - IN (Switzerland)' c.timezone 'America/Chicago', 837, 20, -1753, 20, 'Central (most areas)' c.timezone 'America/Indiana/Tell_City', 136631, 3600, -312341, 3600, 'Central - IN (Perry)' c.timezone 'America/Indiana/Knox', 9911, 240, -693, 8, 'Central - IN (Starke)' c.timezone 'America/Menominee', 40597, 900, -105137, 1200, 'Central - MI (Wisconsin border)' c.timezone 'America/North_Dakota/Center', 169619, 3600, -121559, 1200, 'Central - ND (Oliver)' c.timezone 'America/North_Dakota/New_Salem', 9369, 200, -121693, 1200, 'Central - ND (Morton rural)' c.timezone 'America/North_Dakota/Beulah', 56717, 1200, -916, 9, 'Central - ND (Mercer)' c.timezone 'America/Denver', 47687, 1200, -125981, 1200, 'Mountain (most areas)' c.timezone 'America/Boise', 157009, 3600, -46481, 400, 'Mountain - ID (south); OR (east)' c.timezone 'America/Phoenix', 20069, 600, -16811, 150, 'MST - Arizona (except Navajo)' c.timezone 'America/Los_Angeles', 30647, 900, -212837, 1800, 'Pacific' c.timezone 'America/Anchorage', 44077, 720, -539641, 3600, 'Alaska (most areas)' c.timezone 'America/Juneau', 209887, 3600, -483911, 3600, 'Alaska - Juneau area' c.timezone 'America/Sitka', 41167, 720, -487087, 3600, 'Alaska - Sitka area' c.timezone 'America/Metlakatla', 198457, 3600, -18947, 144, 'Alaska - Annette Island' c.timezone 'America/Yakutat', 214369, 3600, -251509, 1800, 'Alaska - Yakutat' c.timezone 'America/Nome', 58051, 900, -595463, 3600, 'Alaska (west)' c.timezone 'America/Adak', 1297, 25, -635969, 3600, 'Aleutian Islands' c.timezone :t23 end i.country 'UY', 'Uruguay' do |c| c.timezone 'America/Montevideo', -41891, 1200, -4497, 80 end i.country 'UZ', 'Uzbekistan' do |c| c.timezone 'Asia/Samarkand', 119, 3, 334, 5, 'Uzbekistan (west)' c.timezone 'Asia/Tashkent', 124, 3, 693, 10, 'Uzbekistan (east)' end i.country 'VA', 'Vatican City' do |c| c.timezone :t18 end i.country 'VC', 'St Vincent' do |c| c.timezone :t8 end i.country 'VE', 'Venezuela' do |c| c.timezone 'America/Caracas', 21, 2, -1004, 15 end i.country 'VG', 'Virgin Islands (UK)' do |c| c.timezone :t8 end i.country 'VI', 'Virgin Islands (US)' do |c| c.timezone :t8 end i.country 'VN', 'Vietnam' do |c| c.timezone 'Asia/Ho_Chi_Minh', 43, 4, 320, 3, 'Vietnam (south)' c.timezone :t9 end i.country 'VU', 'Vanuatu' do |c| c.timezone 'Pacific/Efate', -53, 3, 2021, 12 end i.country 'WF', 'Wallis & Futuna' do |c| c.timezone 'Pacific/Wallis', -133, 10, -1057, 6 end i.country 'WS', 'Samoa (western)' do |c| c.timezone 'Pacific/Apia', -83, 6, -2576, 15 end i.country 'YE', 'Yemen' do |c| c.timezone :t12 end i.country 'YT', 'Mayotte' do |c| c.timezone :t5 end i.country 'ZA', 'South Africa' do |c| c.timezone :t2 end i.country 'ZM', 'Zambia' do |c| c.timezone :t4 end i.country 'ZW', 'Zimbabwe' do |c| c.timezone :t4 end end end end end end tzinfo-2.0.6/test/tzinfo-data2/tzinfo/data/indexes/timezones.rb000066400000000000000000000634671436527530500245660ustar00rootroot00000000000000# encoding: UTF-8 # frozen_string_literal: true # This file contains data derived from the IANA Time Zone Database # (https://www.iana.org/time-zones). module TZInfo module Data module Indexes module Timezones include Format2::TimezoneIndexDefinition timezone_index do |i| i.data_timezone 'Africa/Abidjan' i.data_timezone 'Africa/Accra' i.linked_timezone 'Africa/Addis_Ababa' i.data_timezone 'Africa/Algiers' i.linked_timezone 'Africa/Asmara' i.linked_timezone 'Africa/Asmera' i.linked_timezone 'Africa/Bamako' i.linked_timezone 'Africa/Bangui' i.linked_timezone 'Africa/Banjul' i.data_timezone 'Africa/Bissau' i.linked_timezone 'Africa/Blantyre' i.linked_timezone 'Africa/Brazzaville' i.linked_timezone 'Africa/Bujumbura' i.data_timezone 'Africa/Cairo' i.data_timezone 'Africa/Casablanca' i.data_timezone 'Africa/Ceuta' i.linked_timezone 'Africa/Conakry' i.linked_timezone 'Africa/Dakar' i.linked_timezone 'Africa/Dar_es_Salaam' i.linked_timezone 'Africa/Djibouti' i.linked_timezone 'Africa/Douala' i.data_timezone 'Africa/El_Aaiun' i.linked_timezone 'Africa/Freetown' i.linked_timezone 'Africa/Gaborone' i.linked_timezone 'Africa/Harare' i.data_timezone 'Africa/Johannesburg' i.data_timezone 'Africa/Juba' i.linked_timezone 'Africa/Kampala' i.data_timezone 'Africa/Khartoum' i.linked_timezone 'Africa/Kigali' i.linked_timezone 'Africa/Kinshasa' i.data_timezone 'Africa/Lagos' i.linked_timezone 'Africa/Libreville' i.linked_timezone 'Africa/Lome' i.linked_timezone 'Africa/Luanda' i.linked_timezone 'Africa/Lubumbashi' i.linked_timezone 'Africa/Lusaka' i.linked_timezone 'Africa/Malabo' i.data_timezone 'Africa/Maputo' i.linked_timezone 'Africa/Maseru' i.linked_timezone 'Africa/Mbabane' i.linked_timezone 'Africa/Mogadishu' i.data_timezone 'Africa/Monrovia' i.data_timezone 'Africa/Nairobi' i.data_timezone 'Africa/Ndjamena' i.linked_timezone 'Africa/Niamey' i.linked_timezone 'Africa/Nouakchott' i.linked_timezone 'Africa/Ouagadougou' i.linked_timezone 'Africa/Porto-Novo' i.data_timezone 'Africa/Sao_Tome' i.linked_timezone 'Africa/Timbuktu' i.data_timezone 'Africa/Tripoli' i.data_timezone 'Africa/Tunis' i.data_timezone 'Africa/Windhoek' i.data_timezone 'America/Adak' i.data_timezone 'America/Anchorage' i.linked_timezone 'America/Anguilla' i.linked_timezone 'America/Antigua' i.data_timezone 'America/Araguaina' i.data_timezone 'America/Argentina/Buenos_Aires' i.data_timezone 'America/Argentina/Catamarca' i.linked_timezone 'America/Argentina/ComodRivadavia' i.data_timezone 'America/Argentina/Cordoba' i.data_timezone 'America/Argentina/Jujuy' i.data_timezone 'America/Argentina/La_Rioja' i.data_timezone 'America/Argentina/Mendoza' i.data_timezone 'America/Argentina/Rio_Gallegos' i.data_timezone 'America/Argentina/Salta' i.data_timezone 'America/Argentina/San_Juan' i.data_timezone 'America/Argentina/San_Luis' i.data_timezone 'America/Argentina/Tucuman' i.data_timezone 'America/Argentina/Ushuaia' i.linked_timezone 'America/Aruba' i.data_timezone 'America/Asuncion' i.data_timezone 'America/Atikokan' i.linked_timezone 'America/Atka' i.data_timezone 'America/Bahia' i.data_timezone 'America/Bahia_Banderas' i.data_timezone 'America/Barbados' i.data_timezone 'America/Belem' i.data_timezone 'America/Belize' i.data_timezone 'America/Blanc-Sablon' i.data_timezone 'America/Boa_Vista' i.data_timezone 'America/Bogota' i.data_timezone 'America/Boise' i.linked_timezone 'America/Buenos_Aires' i.data_timezone 'America/Cambridge_Bay' i.data_timezone 'America/Campo_Grande' i.data_timezone 'America/Cancun' i.data_timezone 'America/Caracas' i.linked_timezone 'America/Catamarca' i.data_timezone 'America/Cayenne' i.linked_timezone 'America/Cayman' i.data_timezone 'America/Chicago' i.data_timezone 'America/Chihuahua' i.linked_timezone 'America/Coral_Harbour' i.linked_timezone 'America/Cordoba' i.data_timezone 'America/Costa_Rica' i.data_timezone 'America/Creston' i.data_timezone 'America/Cuiaba' i.data_timezone 'America/Curacao' i.data_timezone 'America/Danmarkshavn' i.data_timezone 'America/Dawson' i.data_timezone 'America/Dawson_Creek' i.data_timezone 'America/Denver' i.data_timezone 'America/Detroit' i.linked_timezone 'America/Dominica' i.data_timezone 'America/Edmonton' i.data_timezone 'America/Eirunepe' i.data_timezone 'America/El_Salvador' i.linked_timezone 'America/Ensenada' i.data_timezone 'America/Fort_Nelson' i.linked_timezone 'America/Fort_Wayne' i.data_timezone 'America/Fortaleza' i.data_timezone 'America/Glace_Bay' i.linked_timezone 'America/Godthab' i.data_timezone 'America/Goose_Bay' i.data_timezone 'America/Grand_Turk' i.linked_timezone 'America/Grenada' i.linked_timezone 'America/Guadeloupe' i.data_timezone 'America/Guatemala' i.data_timezone 'America/Guayaquil' i.data_timezone 'America/Guyana' i.data_timezone 'America/Halifax' i.data_timezone 'America/Havana' i.data_timezone 'America/Hermosillo' i.data_timezone 'America/Indiana/Indianapolis' i.data_timezone 'America/Indiana/Knox' i.data_timezone 'America/Indiana/Marengo' i.data_timezone 'America/Indiana/Petersburg' i.data_timezone 'America/Indiana/Tell_City' i.data_timezone 'America/Indiana/Vevay' i.data_timezone 'America/Indiana/Vincennes' i.data_timezone 'America/Indiana/Winamac' i.linked_timezone 'America/Indianapolis' i.data_timezone 'America/Inuvik' i.data_timezone 'America/Iqaluit' i.data_timezone 'America/Jamaica' i.linked_timezone 'America/Jujuy' i.data_timezone 'America/Juneau' i.data_timezone 'America/Kentucky/Louisville' i.data_timezone 'America/Kentucky/Monticello' i.linked_timezone 'America/Knox_IN' i.linked_timezone 'America/Kralendijk' i.data_timezone 'America/La_Paz' i.data_timezone 'America/Lima' i.data_timezone 'America/Los_Angeles' i.linked_timezone 'America/Louisville' i.linked_timezone 'America/Lower_Princes' i.data_timezone 'America/Maceio' i.data_timezone 'America/Managua' i.data_timezone 'America/Manaus' i.linked_timezone 'America/Marigot' i.data_timezone 'America/Martinique' i.data_timezone 'America/Matamoros' i.data_timezone 'America/Mazatlan' i.linked_timezone 'America/Mendoza' i.data_timezone 'America/Menominee' i.data_timezone 'America/Merida' i.data_timezone 'America/Metlakatla' i.data_timezone 'America/Mexico_City' i.data_timezone 'America/Miquelon' i.data_timezone 'America/Moncton' i.data_timezone 'America/Monterrey' i.data_timezone 'America/Montevideo' i.linked_timezone 'America/Montreal' i.linked_timezone 'America/Montserrat' i.data_timezone 'America/Nassau' i.data_timezone 'America/New_York' i.data_timezone 'America/Nipigon' i.data_timezone 'America/Nome' i.data_timezone 'America/Noronha' i.data_timezone 'America/North_Dakota/Beulah' i.data_timezone 'America/North_Dakota/Center' i.data_timezone 'America/North_Dakota/New_Salem' i.data_timezone 'America/Nuuk' i.data_timezone 'America/Ojinaga' i.data_timezone 'America/Panama' i.data_timezone 'America/Pangnirtung' i.data_timezone 'America/Paramaribo' i.data_timezone 'America/Phoenix' i.data_timezone 'America/Port-au-Prince' i.data_timezone 'America/Port_of_Spain' i.linked_timezone 'America/Porto_Acre' i.data_timezone 'America/Porto_Velho' i.data_timezone 'America/Puerto_Rico' i.data_timezone 'America/Punta_Arenas' i.data_timezone 'America/Rainy_River' i.data_timezone 'America/Rankin_Inlet' i.data_timezone 'America/Recife' i.data_timezone 'America/Regina' i.data_timezone 'America/Resolute' i.data_timezone 'America/Rio_Branco' i.linked_timezone 'America/Rosario' i.linked_timezone 'America/Santa_Isabel' i.data_timezone 'America/Santarem' i.data_timezone 'America/Santiago' i.data_timezone 'America/Santo_Domingo' i.data_timezone 'America/Sao_Paulo' i.data_timezone 'America/Scoresbysund' i.linked_timezone 'America/Shiprock' i.data_timezone 'America/Sitka' i.linked_timezone 'America/St_Barthelemy' i.data_timezone 'America/St_Johns' i.linked_timezone 'America/St_Kitts' i.linked_timezone 'America/St_Lucia' i.linked_timezone 'America/St_Thomas' i.linked_timezone 'America/St_Vincent' i.data_timezone 'America/Swift_Current' i.data_timezone 'America/Tegucigalpa' i.data_timezone 'America/Thule' i.data_timezone 'America/Thunder_Bay' i.data_timezone 'America/Tijuana' i.data_timezone 'America/Toronto' i.linked_timezone 'America/Tortola' i.data_timezone 'America/Vancouver' i.linked_timezone 'America/Virgin' i.data_timezone 'America/Whitehorse' i.data_timezone 'America/Winnipeg' i.data_timezone 'America/Yakutat' i.data_timezone 'America/Yellowknife' i.data_timezone 'Antarctica/Casey' i.data_timezone 'Antarctica/Davis' i.data_timezone 'Antarctica/DumontDUrville' i.data_timezone 'Antarctica/Macquarie' i.data_timezone 'Antarctica/Mawson' i.linked_timezone 'Antarctica/McMurdo' i.data_timezone 'Antarctica/Palmer' i.data_timezone 'Antarctica/Rothera' i.linked_timezone 'Antarctica/South_Pole' i.data_timezone 'Antarctica/Syowa' i.data_timezone 'Antarctica/Troll' i.data_timezone 'Antarctica/Vostok' i.linked_timezone 'Arctic/Longyearbyen' i.linked_timezone 'Asia/Aden' i.data_timezone 'Asia/Almaty' i.data_timezone 'Asia/Amman' i.data_timezone 'Asia/Anadyr' i.data_timezone 'Asia/Aqtau' i.data_timezone 'Asia/Aqtobe' i.data_timezone 'Asia/Ashgabat' i.linked_timezone 'Asia/Ashkhabad' i.data_timezone 'Asia/Atyrau' i.data_timezone 'Asia/Baghdad' i.linked_timezone 'Asia/Bahrain' i.data_timezone 'Asia/Baku' i.data_timezone 'Asia/Bangkok' i.data_timezone 'Asia/Barnaul' i.data_timezone 'Asia/Beirut' i.data_timezone 'Asia/Bishkek' i.data_timezone 'Asia/Brunei' i.linked_timezone 'Asia/Calcutta' i.data_timezone 'Asia/Chita' i.data_timezone 'Asia/Choibalsan' i.linked_timezone 'Asia/Chongqing' i.linked_timezone 'Asia/Chungking' i.data_timezone 'Asia/Colombo' i.linked_timezone 'Asia/Dacca' i.data_timezone 'Asia/Damascus' i.data_timezone 'Asia/Dhaka' i.data_timezone 'Asia/Dili' i.data_timezone 'Asia/Dubai' i.data_timezone 'Asia/Dushanbe' i.data_timezone 'Asia/Famagusta' i.data_timezone 'Asia/Gaza' i.linked_timezone 'Asia/Harbin' i.data_timezone 'Asia/Hebron' i.data_timezone 'Asia/Ho_Chi_Minh' i.data_timezone 'Asia/Hong_Kong' i.data_timezone 'Asia/Hovd' i.data_timezone 'Asia/Irkutsk' i.linked_timezone 'Asia/Istanbul' i.data_timezone 'Asia/Jakarta' i.data_timezone 'Asia/Jayapura' i.data_timezone 'Asia/Jerusalem' i.data_timezone 'Asia/Kabul' i.data_timezone 'Asia/Kamchatka' i.data_timezone 'Asia/Karachi' i.linked_timezone 'Asia/Kashgar' i.data_timezone 'Asia/Kathmandu' i.linked_timezone 'Asia/Katmandu' i.data_timezone 'Asia/Khandyga' i.data_timezone 'Asia/Kolkata' i.data_timezone 'Asia/Krasnoyarsk' i.data_timezone 'Asia/Kuala_Lumpur' i.data_timezone 'Asia/Kuching' i.linked_timezone 'Asia/Kuwait' i.linked_timezone 'Asia/Macao' i.data_timezone 'Asia/Macau' i.data_timezone 'Asia/Magadan' i.data_timezone 'Asia/Makassar' i.data_timezone 'Asia/Manila' i.linked_timezone 'Asia/Muscat' i.data_timezone 'Asia/Nicosia' i.data_timezone 'Asia/Novokuznetsk' i.data_timezone 'Asia/Novosibirsk' i.data_timezone 'Asia/Omsk' i.data_timezone 'Asia/Oral' i.linked_timezone 'Asia/Phnom_Penh' i.data_timezone 'Asia/Pontianak' i.data_timezone 'Asia/Pyongyang' i.data_timezone 'Asia/Qatar' i.data_timezone 'Asia/Qostanay' i.data_timezone 'Asia/Qyzylorda' i.linked_timezone 'Asia/Rangoon' i.data_timezone 'Asia/Riyadh' i.linked_timezone 'Asia/Saigon' i.data_timezone 'Asia/Sakhalin' i.data_timezone 'Asia/Samarkand' i.data_timezone 'Asia/Seoul' i.data_timezone 'Asia/Shanghai' i.data_timezone 'Asia/Singapore' i.data_timezone 'Asia/Srednekolymsk' i.data_timezone 'Asia/Taipei' i.data_timezone 'Asia/Tashkent' i.data_timezone 'Asia/Tbilisi' i.data_timezone 'Asia/Tehran' i.linked_timezone 'Asia/Tel_Aviv' i.linked_timezone 'Asia/Thimbu' i.data_timezone 'Asia/Thimphu' i.data_timezone 'Asia/Tokyo' i.data_timezone 'Asia/Tomsk' i.linked_timezone 'Asia/Ujung_Pandang' i.data_timezone 'Asia/Ulaanbaatar' i.linked_timezone 'Asia/Ulan_Bator' i.data_timezone 'Asia/Urumqi' i.data_timezone 'Asia/Ust-Nera' i.linked_timezone 'Asia/Vientiane' i.data_timezone 'Asia/Vladivostok' i.data_timezone 'Asia/Yakutsk' i.data_timezone 'Asia/Yangon' i.data_timezone 'Asia/Yekaterinburg' i.data_timezone 'Asia/Yerevan' i.data_timezone 'Atlantic/Azores' i.data_timezone 'Atlantic/Bermuda' i.data_timezone 'Atlantic/Canary' i.data_timezone 'Atlantic/Cape_Verde' i.linked_timezone 'Atlantic/Faeroe' i.data_timezone 'Atlantic/Faroe' i.linked_timezone 'Atlantic/Jan_Mayen' i.data_timezone 'Atlantic/Madeira' i.data_timezone 'Atlantic/Reykjavik' i.data_timezone 'Atlantic/South_Georgia' i.linked_timezone 'Atlantic/St_Helena' i.data_timezone 'Atlantic/Stanley' i.linked_timezone 'Australia/ACT' i.data_timezone 'Australia/Adelaide' i.data_timezone 'Australia/Brisbane' i.data_timezone 'Australia/Broken_Hill' i.linked_timezone 'Australia/Canberra' i.data_timezone 'Australia/Currie' i.data_timezone 'Australia/Darwin' i.data_timezone 'Australia/Eucla' i.data_timezone 'Australia/Hobart' i.linked_timezone 'Australia/LHI' i.data_timezone 'Australia/Lindeman' i.data_timezone 'Australia/Lord_Howe' i.data_timezone 'Australia/Melbourne' i.linked_timezone 'Australia/NSW' i.linked_timezone 'Australia/North' i.data_timezone 'Australia/Perth' i.linked_timezone 'Australia/Queensland' i.linked_timezone 'Australia/South' i.data_timezone 'Australia/Sydney' i.linked_timezone 'Australia/Tasmania' i.linked_timezone 'Australia/Victoria' i.linked_timezone 'Australia/West' i.linked_timezone 'Australia/Yancowinna' i.linked_timezone 'Brazil/Acre' i.linked_timezone 'Brazil/DeNoronha' i.linked_timezone 'Brazil/East' i.linked_timezone 'Brazil/West' i.data_timezone 'CET' i.data_timezone 'CST6CDT' i.linked_timezone 'Canada/Atlantic' i.linked_timezone 'Canada/Central' i.linked_timezone 'Canada/Eastern' i.linked_timezone 'Canada/Mountain' i.linked_timezone 'Canada/Newfoundland' i.linked_timezone 'Canada/Pacific' i.linked_timezone 'Canada/Saskatchewan' i.linked_timezone 'Canada/Yukon' i.linked_timezone 'Chile/Continental' i.linked_timezone 'Chile/EasterIsland' i.linked_timezone 'Cuba' i.data_timezone 'EET' i.data_timezone 'EST' i.data_timezone 'EST5EDT' i.linked_timezone 'Egypt' i.linked_timezone 'Eire' i.data_timezone 'Etc/GMT' i.linked_timezone 'Etc/GMT+0' i.data_timezone 'Etc/GMT+1' i.data_timezone 'Etc/GMT+10' i.data_timezone 'Etc/GMT+11' i.data_timezone 'Etc/GMT+12' i.data_timezone 'Etc/GMT+2' i.data_timezone 'Etc/GMT+3' i.data_timezone 'Etc/GMT+4' i.data_timezone 'Etc/GMT+5' i.data_timezone 'Etc/GMT+6' i.data_timezone 'Etc/GMT+7' i.data_timezone 'Etc/GMT+8' i.data_timezone 'Etc/GMT+9' i.linked_timezone 'Etc/GMT-0' i.data_timezone 'Etc/GMT-1' i.data_timezone 'Etc/GMT-10' i.data_timezone 'Etc/GMT-11' i.data_timezone 'Etc/GMT-12' i.data_timezone 'Etc/GMT-13' i.data_timezone 'Etc/GMT-14' i.data_timezone 'Etc/GMT-2' i.data_timezone 'Etc/GMT-3' i.data_timezone 'Etc/GMT-4' i.data_timezone 'Etc/GMT-5' i.data_timezone 'Etc/GMT-6' i.data_timezone 'Etc/GMT-7' i.data_timezone 'Etc/GMT-8' i.data_timezone 'Etc/GMT-9' i.linked_timezone 'Etc/GMT0' i.linked_timezone 'Etc/Greenwich' i.linked_timezone 'Etc/UCT' i.data_timezone 'Etc/UTC' i.linked_timezone 'Etc/Universal' i.linked_timezone 'Etc/Zulu' i.data_timezone 'Europe/Amsterdam' i.data_timezone 'Europe/Andorra' i.data_timezone 'Europe/Astrakhan' i.data_timezone 'Europe/Athens' i.linked_timezone 'Europe/Belfast' i.data_timezone 'Europe/Belgrade' i.data_timezone 'Europe/Berlin' i.linked_timezone 'Europe/Bratislava' i.data_timezone 'Europe/Brussels' i.data_timezone 'Europe/Bucharest' i.data_timezone 'Europe/Budapest' i.linked_timezone 'Europe/Busingen' i.data_timezone 'Europe/Chisinau' i.data_timezone 'Europe/Copenhagen' i.data_timezone 'Europe/Dublin' i.data_timezone 'Europe/Gibraltar' i.linked_timezone 'Europe/Guernsey' i.data_timezone 'Europe/Helsinki' i.linked_timezone 'Europe/Isle_of_Man' i.data_timezone 'Europe/Istanbul' i.linked_timezone 'Europe/Jersey' i.data_timezone 'Europe/Kaliningrad' i.data_timezone 'Europe/Kiev' i.data_timezone 'Europe/Kirov' i.data_timezone 'Europe/Lisbon' i.linked_timezone 'Europe/Ljubljana' i.data_timezone 'Europe/London' i.data_timezone 'Europe/Luxembourg' i.data_timezone 'Europe/Madrid' i.data_timezone 'Europe/Malta' i.linked_timezone 'Europe/Mariehamn' i.data_timezone 'Europe/Minsk' i.data_timezone 'Europe/Monaco' i.data_timezone 'Europe/Moscow' i.linked_timezone 'Europe/Nicosia' i.data_timezone 'Europe/Oslo' i.data_timezone 'Europe/Paris' i.linked_timezone 'Europe/Podgorica' i.data_timezone 'Europe/Prague' i.data_timezone 'Europe/Riga' i.data_timezone 'Europe/Rome' i.data_timezone 'Europe/Samara' i.linked_timezone 'Europe/San_Marino' i.linked_timezone 'Europe/Sarajevo' i.data_timezone 'Europe/Saratov' i.data_timezone 'Europe/Simferopol' i.linked_timezone 'Europe/Skopje' i.data_timezone 'Europe/Sofia' i.data_timezone 'Europe/Stockholm' i.data_timezone 'Europe/Tallinn' i.data_timezone 'Europe/Tirane' i.linked_timezone 'Europe/Tiraspol' i.data_timezone 'Europe/Ulyanovsk' i.data_timezone 'Europe/Uzhgorod' i.linked_timezone 'Europe/Vaduz' i.linked_timezone 'Europe/Vatican' i.data_timezone 'Europe/Vienna' i.data_timezone 'Europe/Vilnius' i.data_timezone 'Europe/Volgograd' i.data_timezone 'Europe/Warsaw' i.linked_timezone 'Europe/Zagreb' i.data_timezone 'Europe/Zaporozhye' i.data_timezone 'Europe/Zurich' i.data_timezone 'Factory' i.linked_timezone 'GB' i.linked_timezone 'GB-Eire' i.linked_timezone 'GMT' i.linked_timezone 'GMT+0' i.linked_timezone 'GMT-0' i.linked_timezone 'GMT0' i.linked_timezone 'Greenwich' i.data_timezone 'HST' i.linked_timezone 'Hongkong' i.linked_timezone 'Iceland' i.linked_timezone 'Indian/Antananarivo' i.data_timezone 'Indian/Chagos' i.data_timezone 'Indian/Christmas' i.data_timezone 'Indian/Cocos' i.linked_timezone 'Indian/Comoro' i.data_timezone 'Indian/Kerguelen' i.data_timezone 'Indian/Mahe' i.data_timezone 'Indian/Maldives' i.data_timezone 'Indian/Mauritius' i.linked_timezone 'Indian/Mayotte' i.data_timezone 'Indian/Reunion' i.linked_timezone 'Iran' i.linked_timezone 'Israel' i.linked_timezone 'Jamaica' i.linked_timezone 'Japan' i.linked_timezone 'Kwajalein' i.linked_timezone 'Libya' i.data_timezone 'MET' i.data_timezone 'MST' i.data_timezone 'MST7MDT' i.linked_timezone 'Mexico/BajaNorte' i.linked_timezone 'Mexico/BajaSur' i.linked_timezone 'Mexico/General' i.linked_timezone 'NZ' i.linked_timezone 'NZ-CHAT' i.linked_timezone 'Navajo' i.linked_timezone 'PRC' i.data_timezone 'PST8PDT' i.data_timezone 'Pacific/Apia' i.data_timezone 'Pacific/Auckland' i.data_timezone 'Pacific/Bougainville' i.data_timezone 'Pacific/Chatham' i.data_timezone 'Pacific/Chuuk' i.data_timezone 'Pacific/Easter' i.data_timezone 'Pacific/Efate' i.data_timezone 'Pacific/Enderbury' i.data_timezone 'Pacific/Fakaofo' i.data_timezone 'Pacific/Fiji' i.data_timezone 'Pacific/Funafuti' i.data_timezone 'Pacific/Galapagos' i.data_timezone 'Pacific/Gambier' i.data_timezone 'Pacific/Guadalcanal' i.data_timezone 'Pacific/Guam' i.data_timezone 'Pacific/Honolulu' i.linked_timezone 'Pacific/Johnston' i.data_timezone 'Pacific/Kiritimati' i.data_timezone 'Pacific/Kosrae' i.data_timezone 'Pacific/Kwajalein' i.data_timezone 'Pacific/Majuro' i.data_timezone 'Pacific/Marquesas' i.linked_timezone 'Pacific/Midway' i.data_timezone 'Pacific/Nauru' i.data_timezone 'Pacific/Niue' i.data_timezone 'Pacific/Norfolk' i.data_timezone 'Pacific/Noumea' i.data_timezone 'Pacific/Pago_Pago' i.data_timezone 'Pacific/Palau' i.data_timezone 'Pacific/Pitcairn' i.data_timezone 'Pacific/Pohnpei' i.linked_timezone 'Pacific/Ponape' i.data_timezone 'Pacific/Port_Moresby' i.data_timezone 'Pacific/Rarotonga' i.linked_timezone 'Pacific/Saipan' i.linked_timezone 'Pacific/Samoa' i.data_timezone 'Pacific/Tahiti' i.data_timezone 'Pacific/Tarawa' i.data_timezone 'Pacific/Tongatapu' i.linked_timezone 'Pacific/Truk' i.data_timezone 'Pacific/Wake' i.data_timezone 'Pacific/Wallis' i.linked_timezone 'Pacific/Yap' i.linked_timezone 'Poland' i.linked_timezone 'Portugal' i.linked_timezone 'ROC' i.linked_timezone 'ROK' i.linked_timezone 'Singapore' i.linked_timezone 'Turkey' i.linked_timezone 'UCT' i.linked_timezone 'US/Alaska' i.linked_timezone 'US/Aleutian' i.linked_timezone 'US/Arizona' i.linked_timezone 'US/Central' i.linked_timezone 'US/East-Indiana' i.linked_timezone 'US/Eastern' i.linked_timezone 'US/Hawaii' i.linked_timezone 'US/Indiana-Starke' i.linked_timezone 'US/Michigan' i.linked_timezone 'US/Mountain' i.linked_timezone 'US/Pacific' i.linked_timezone 'US/Samoa' i.linked_timezone 'UTC' i.linked_timezone 'Universal' i.linked_timezone 'W-SU' i.data_timezone 'WET' i.linked_timezone 'Zulu' end end end end end tzinfo-2.0.6/test/tzinfo-data2/tzinfo/data/version.rb000066400000000000000000000010011436527530500225470ustar00rootroot00000000000000# encoding: UTF-8 module TZInfo module Data # TZInfo::Data version number. VERSION = '2.2020.4.test' # TZInfo::Data version information. module Version # The format of the Ruby modules. TZInfo v2.0.0 supports formats 1 and 2. FORMAT = 2 # TZInfo::Data version number. STRING = VERSION # The version of the {IANA Time Zone Database}[https://www.iana.org/time-zones] # used to generate this version of TZInfo::Data. TZDATA = '2020d' end end end tzinfo-2.0.6/test/zoneinfo/000077500000000000000000000000001436527530500156505ustar00rootroot00000000000000tzinfo-2.0.6/test/zoneinfo/.gitignore000066400000000000000000000000161436527530500176350ustar00rootroot00000000000000UTC localtime tzinfo-2.0.6/test/zoneinfo/America/000077500000000000000000000000001436527530500172115ustar00rootroot00000000000000tzinfo-2.0.6/test/zoneinfo/America/Argentina/000077500000000000000000000000001436527530500211215ustar00rootroot00000000000000tzinfo-2.0.6/test/zoneinfo/America/Argentina/Buenos_Aires000066400000000000000000000013041436527530500234200ustar00rootroot00000000000000TZif2TZif2=rL0{R@ɰ@p0}@0x @Z@;0~`@*0A70ȁ@MM0ΰ)5Cd=0l02@柰C0w@65S0R@504@J$o#$%7%v'!0'X)0):*0+W 7ư8*Gw G HIa 4  LMTCMT-04-03-02 <-03>3 tzinfo-2.0.6/test/zoneinfo/America/New_York000066400000000000000000000033201436527530500206670ustar00rootroot00000000000000TZif2TZif2^p`p`epjp5`S`3އpiRK4~-QpgJ`|3pG,`\p'`;p`p`ƴ`Ĺo„}Ovd_/XM|p:-^pW` @p9`ˈp#p`u@U 5peމpݩ`޾kp߉d`MpiF`~/pI(`^pW.G-7'ֶƵ`p`p`op_y`Oxp?[`/Zp(wp?b@opA`BOpCda`D/vpEDC`E LMTEDTESTEWTEPT EST5EDT,M3.2.0,M11.1.0 tzinfo-2.0.6/test/zoneinfo/Australia/000077500000000000000000000000001436527530500175755ustar00rootroot00000000000000tzinfo-2.0.6/test/zoneinfo/Australia/Melbourne000066400000000000000000000016101436527530500214460ustar00rootroot00000000000000TZif2TZif2SsN TWp̷Vͧ9pΠsχpp9 P8/ ߀  ~^>xXf8H矀!dǁFc(E y Y~!w"B#i$"}%I&_')') )*s+ʀ,ҏ-x.q/t>0S1]Z2r53=<4R5616889:Ā;<=>?@eABECcD.EC~FKG#`G LMTAEDTAEST AEST-10AEDT,M10.1.0,M4.1.0/3 tzinfo-2.0.6/test/zoneinfo/EST000066400000000000000000000001571436527530500162310ustar00rootroot00000000000000TZif2TZif2EST EST5 tzinfo-2.0.6/test/zoneinfo/Etc/000077500000000000000000000000001436527530500163635ustar00rootroot00000000000000tzinfo-2.0.6/test/zoneinfo/Etc/UTC000066400000000000000000000001571436527530500167440ustar00rootroot00000000000000TZif2TZif2UTC UTC0 tzinfo-2.0.6/test/zoneinfo/Europe/000077500000000000000000000000001436527530500171075ustar00rootroot00000000000000tzinfo-2.0.6/test/zoneinfo/Europe/Amsterdam000066400000000000000000000020571436527530500207530ustar00rootroot00000000000000TZif2TZif2a!Ql .\ٸ %  Av p#V P6 %['^Z 煌' gf IΙ+pH R P* s0 T  @x q Ό،]x§ˌ]\Xtpp8Vp`!rDPKͩ΢Cϒ4Ђ%rN@ cEt6d'TMD3#ܐ͐㯐ӠÑ| lr!\c"LT#0 tzinfo-2.0.6/test/zoneinfo/iso3166.tab000066400000000000000000000105571436527530500174620ustar00rootroot00000000000000# ISO 3166 alpha-2 country codes # # This file is in the public domain, so clarified as of # 2009-05-17 by Arthur David Olson. # # From Paul Eggert (2015-05-02): # This file contains a table of two-letter country codes. Columns are # separated by a single tab. Lines beginning with '#' are comments. # All text uses UTF-8 encoding. The columns of the table are as follows: # # 1. ISO 3166-1 alpha-2 country code, current as of # ISO 3166-1 N976 (2018-11-06). See: Updates on ISO 3166-1 # https://isotc.iso.org/livelink/livelink/Open/16944257 # 2. The usual English name for the coded region, # chosen so that alphabetic sorting of subsets produces helpful lists. # This is not the same as the English name in the ISO 3166 tables. # # The table is sorted by country code. # # This table is intended as an aid for users, to help them select time # zone data appropriate for their practical needs. It is not intended # to take or endorse any position on legal or territorial claims. # #country- #code name of country, territory, area, or subdivision AD Andorra AE United Arab Emirates AF Afghanistan AG Antigua & Barbuda AI Anguilla AL Albania AM Armenia AO Angola AQ Antarctica AR Argentina AS Samoa (American) AT Austria AU Australia AW Aruba AX Åland Islands AZ Azerbaijan BA Bosnia & Herzegovina BB Barbados BD Bangladesh BE Belgium BF Burkina Faso BG Bulgaria BH Bahrain BI Burundi BJ Benin BL St Barthelemy BM Bermuda BN Brunei BO Bolivia BQ Caribbean NL BR Brazil BS Bahamas BT Bhutan BV Bouvet Island BW Botswana BY Belarus BZ Belize CA Canada CC Cocos (Keeling) Islands CD Congo (Dem. Rep.) CF Central African Rep. CG Congo (Rep.) CH Switzerland CI Côte d'Ivoire CK Cook Islands CL Chile CM Cameroon CN China CO Colombia CR Costa Rica CU Cuba CV Cape Verde CW Curaçao CX Christmas Island CY Cyprus CZ Czech Republic DE Germany DJ Djibouti DK Denmark DM Dominica DO Dominican Republic DZ Algeria EC Ecuador EE Estonia EG Egypt EH Western Sahara ER Eritrea ES Spain ET Ethiopia FI Finland FJ Fiji FK Falkland Islands FM Micronesia FO Faroe Islands FR France GA Gabon GB Britain (UK) GD Grenada GE Georgia GF French Guiana GG Guernsey GH Ghana GI Gibraltar GL Greenland GM Gambia GN Guinea GP Guadeloupe GQ Equatorial Guinea GR Greece GS South Georgia & the South Sandwich Islands GT Guatemala GU Guam GW Guinea-Bissau GY Guyana HK Hong Kong HM Heard Island & McDonald Islands HN Honduras HR Croatia HT Haiti HU Hungary ID Indonesia IE Ireland IL Israel IM Isle of Man IN India IO British Indian Ocean Territory IQ Iraq IR Iran IS Iceland IT Italy JE Jersey JM Jamaica JO Jordan JP Japan KE Kenya KG Kyrgyzstan KH Cambodia KI Kiribati KM Comoros KN St Kitts & Nevis KP Korea (North) KR Korea (South) KW Kuwait KY Cayman Islands KZ Kazakhstan LA Laos LB Lebanon LC St Lucia LI Liechtenstein LK Sri Lanka LR Liberia LS Lesotho LT Lithuania LU Luxembourg LV Latvia LY Libya MA Morocco MC Monaco MD Moldova ME Montenegro MF St Martin (French) MG Madagascar MH Marshall Islands MK North Macedonia ML Mali MM Myanmar (Burma) MN Mongolia MO Macau MP Northern Mariana Islands MQ Martinique MR Mauritania MS Montserrat MT Malta MU Mauritius MV Maldives MW Malawi MX Mexico MY Malaysia MZ Mozambique NA Namibia NC New Caledonia NE Niger NF Norfolk Island NG Nigeria NI Nicaragua NL Netherlands NO Norway NP Nepal NR Nauru NU Niue NZ New Zealand OM Oman PA Panama PE Peru PF French Polynesia PG Papua New Guinea PH Philippines PK Pakistan PL Poland PM St Pierre & Miquelon PN Pitcairn PR Puerto Rico PS Palestine PT Portugal PW Palau PY Paraguay QA Qatar RE Réunion RO Romania RS Serbia RU Russia RW Rwanda SA Saudi Arabia SB Solomon Islands SC Seychelles SD Sudan SE Sweden SG Singapore SH St Helena SI Slovenia SJ Svalbard & Jan Mayen SK Slovakia SL Sierra Leone SM San Marino SN Senegal SO Somalia SR Suriname SS South Sudan ST Sao Tome & Principe SV El Salvador SX St Maarten (Dutch) SY Syria SZ Eswatini (Swaziland) TC Turks & Caicos Is TD Chad TF French Southern & Antarctic Lands TG Togo TH Thailand TJ Tajikistan TK Tokelau TL East Timor TM Turkmenistan TN Tunisia TO Tonga TR Turkey TT Trinidad & Tobago TV Tuvalu TW Taiwan TZ Tanzania UA Ukraine UG Uganda UM US minor outlying islands US United States UY Uruguay UZ Uzbekistan VA Vatican City VC St Vincent VE Venezuela VG Virgin Islands (UK) VI Virgin Islands (US) VN Vietnam VU Vanuatu WF Wallis & Futuna WS Samoa (western) YE Yemen YT Mayotte ZA South Africa ZM Zambia ZW Zimbabwe tzinfo-2.0.6/test/zoneinfo/leapseconds000066400000000000000000000061021436527530500200720ustar00rootroot00000000000000# Allowance for leap seconds added to each time zone file. # This file is in the public domain. # This file is generated automatically from the data in the public-domain # NIST format leap-seconds.list file, which can be copied from # # or . # For more about leap-seconds.list, please see # The NTP Timescale and Leap Seconds # . # The rules for leap seconds are specified in Annex 1 (Time scales) of: # Standard-frequency and time-signal emissions. # International Telecommunication Union - Radiocommunication Sector # (ITU-R) Recommendation TF.460-6 (02/2002) # . # The International Earth Rotation and Reference Systems Service (IERS) # periodically uses leap seconds to keep UTC to within 0.9 s of UT1 # (a proxy for Earth's angle in space as measured by astronomers) # and publishes leap second data in a copyrighted file # . # See: Levine J. Coordinated Universal Time and the leap second. # URSI Radio Sci Bull. 2016;89(4):30-6. doi:10.23919/URSIRSB.2016.7909995 # . # There were no leap seconds before 1972, as no official mechanism # accounted for the discrepancy between atomic time (TAI) and the earth's # rotation. The first ("1 Jan 1972") data line in leap-seconds.list # does not denote a leap second; it denotes the start of the current definition # of UTC. # All leap-seconds are Stationary (S) at the given UTC time. # The correction (+ or -) is made at the given time, so in the unlikely # event of a negative leap second, a line would look like this: # Leap YEAR MON DAY 23:59:59 - S # Typical lines look like this: # Leap YEAR MON DAY 23:59:60 + S Leap 1972 Jun 30 23:59:60 + S Leap 1972 Dec 31 23:59:60 + S Leap 1973 Dec 31 23:59:60 + S Leap 1974 Dec 31 23:59:60 + S Leap 1975 Dec 31 23:59:60 + S Leap 1976 Dec 31 23:59:60 + S Leap 1977 Dec 31 23:59:60 + S Leap 1978 Dec 31 23:59:60 + S Leap 1979 Dec 31 23:59:60 + S Leap 1981 Jun 30 23:59:60 + S Leap 1982 Jun 30 23:59:60 + S Leap 1983 Jun 30 23:59:60 + S Leap 1985 Jun 30 23:59:60 + S Leap 1987 Dec 31 23:59:60 + S Leap 1989 Dec 31 23:59:60 + S Leap 1990 Dec 31 23:59:60 + S Leap 1992 Jun 30 23:59:60 + S Leap 1993 Jun 30 23:59:60 + S Leap 1994 Jun 30 23:59:60 + S Leap 1995 Dec 31 23:59:60 + S Leap 1997 Jun 30 23:59:60 + S Leap 1998 Dec 31 23:59:60 + S Leap 2005 Dec 31 23:59:60 + S Leap 2008 Dec 31 23:59:60 + S Leap 2012 Jun 30 23:59:60 + S Leap 2015 Jun 30 23:59:60 + S Leap 2016 Dec 31 23:59:60 + S # UTC timestamp when this leap second list expires. # Any additional leap seconds will come after this. # This Expires line is commented out for now, # so that pre-2020a zic implementations do not reject this file. #Expires 2021 Jun 28 00:00:00 # POSIX timestamps for the data in this file: #updated 1467936000 (2016-07-08 00:00:00 UTC) #expires 1624838400 (2021-06-28 00:00:00 UTC) # Updated through IERS Bulletin C60 # File expires on: 28 June 2021 tzinfo-2.0.6/test/zoneinfo/posix/000077500000000000000000000000001436527530500170125ustar00rootroot00000000000000tzinfo-2.0.6/test/zoneinfo/posix/Europe/000077500000000000000000000000001436527530500202515ustar00rootroot00000000000000tzinfo-2.0.6/test/zoneinfo/posix/Europe/London000066400000000000000000000030771436527530500214340ustar00rootroot00000000000000TZif2TZif2] & 0à ve {ȠN? %` ' *, Ӡ l N y0 РpLrP.IZ 02vXԠ W  x z Xy Q8[ : X֠ &ʗYw;ͱ`Xϐn^r2i c)I !BN . p  ޴߮ ̠rHkt R*T2 = ) T q S  g} aI_ Jf _A ! ?#  Ѡ {ǻpp )X P  : 0  l N  0  qޠ.Qy1X#8Ɛ͐㯐Ñk lr!M"LT#a/$,6%JK& '*-'4) )*+,Ӑ-ڐ./t01]  LMTBSTGMTBDST GMT0BST,M3.5.0/1,M10.5.0 tzinfo-2.0.6/test/zoneinfo/posixrules000066400000000000000000000033201436527530500200060ustar00rootroot00000000000000TZif2TZif2^p`p`epjp5`S`3އpiRK4~-QpgJ`|3pG,`\p'`;p`p`ƴ`Ĺo„}Ovd_/XM|p:-^pW` @p9`ˈp#p`u@U 5peމpݩ`޾kp߉d`MpiF`~/pI(`^pW.G-7'ֶƵ`p`p`op_y`Oxp?[`/Zp(wp?b@opA`BOpCda`D/vpEDC`E LMTEDTESTEWTEPT EST5EDT,M3.2.0,M11.1.0 tzinfo-2.0.6/test/zoneinfo/right/000077500000000000000000000000001436527530500167655ustar00rootroot00000000000000tzinfo-2.0.6/test/zoneinfo/right/Europe/000077500000000000000000000000001436527530500202245ustar00rootroot00000000000000tzinfo-2.0.6/test/zoneinfo/right/Europe/London000066400000000000000000000044661436527530500214120ustar00rootroot00000000000000TZif2TZif2] & 0à ve {ȠN? %` ' *, Ӡ l N y0 РpLrP.IZ 02vXԠ W  x z Xy Q8[ : X֠ &ʗYw;ͱ`Xϐn^r2i c)I !BN . p  ޴߮ ̠rHkt R*T2 = ) T q S  g} aI_ Jf _A ! ?#  Ѡ {ǻpp )X P! :"0"# l# $ N$  0% &qާ.Qy1X#8ƚ͚㯛Ñk lr!M"LT#a/$,6%JK& '*-'4) )*+,Ӣ-ڢ./t01]$2r$3=$4R%5%62x%6&88a&9v:C&;X<_=:>A?@f#A9&BFCd&D%EC'FɧG#'G'I'I(J(K(L̿M(NOnn(PQWRleS7lTLGUNV,)V0XF*XY(+Z[ +\+]+^+_+`_+`  LMTBSTGMTBDSTX gS H +  ?rΦ ʉ  b1 % ! %'*P,2).\0$3H6CI\OU-XhF tzinfo-2.0.6/test/zoneinfo/zone.tab000066400000000000000000000457051436527530500173260ustar00rootroot00000000000000# tzdb timezone descriptions (deprecated version) # # This file is in the public domain, so clarified as of # 2009-05-17 by Arthur David Olson. # # From Paul Eggert (2018-06-27): # This file is intended as a backward-compatibility aid for older programs. # New programs should use zone1970.tab. This file is like zone1970.tab (see # zone1970.tab's comments), but with the following additional restrictions: # # 1. This file contains only ASCII characters. # 2. The first data column contains exactly one country code. # # Because of (2), each row stands for an area that is the intersection # of a region identified by a country code and of a timezone where civil # clocks have agreed since 1970; this is a narrower definition than # that of zone1970.tab. # # This table is intended as an aid for users, to help them select timezones # appropriate for their practical needs. It is not intended to take or # endorse any position on legal or territorial claims. # #country- #code coordinates TZ comments AD +4230+00131 Europe/Andorra AE +2518+05518 Asia/Dubai AF +3431+06912 Asia/Kabul AG +1703-06148 America/Antigua AI +1812-06304 America/Anguilla AL +4120+01950 Europe/Tirane AM +4011+04430 Asia/Yerevan AO -0848+01314 Africa/Luanda AQ -7750+16636 Antarctica/McMurdo New Zealand time - McMurdo, South Pole AQ -6617+11031 Antarctica/Casey Casey AQ -6835+07758 Antarctica/Davis Davis AQ -6640+14001 Antarctica/DumontDUrville Dumont-d'Urville AQ -6736+06253 Antarctica/Mawson Mawson AQ -6448-06406 Antarctica/Palmer Palmer AQ -6734-06808 Antarctica/Rothera Rothera AQ -690022+0393524 Antarctica/Syowa Syowa AQ -720041+0023206 Antarctica/Troll Troll AQ -7824+10654 Antarctica/Vostok Vostok AR -3436-05827 America/Argentina/Buenos_Aires Buenos Aires (BA, CF) AR -3124-06411 America/Argentina/Cordoba Argentina (most areas: CB, CC, CN, ER, FM, MN, SE, SF) AR -2447-06525 America/Argentina/Salta Salta (SA, LP, NQ, RN) AR -2411-06518 America/Argentina/Jujuy Jujuy (JY) AR -2649-06513 America/Argentina/Tucuman Tucuman (TM) AR -2828-06547 America/Argentina/Catamarca Catamarca (CT); Chubut (CH) AR -2926-06651 America/Argentina/La_Rioja La Rioja (LR) AR -3132-06831 America/Argentina/San_Juan San Juan (SJ) AR -3253-06849 America/Argentina/Mendoza Mendoza (MZ) AR -3319-06621 America/Argentina/San_Luis San Luis (SL) AR -5138-06913 America/Argentina/Rio_Gallegos Santa Cruz (SC) AR -5448-06818 America/Argentina/Ushuaia Tierra del Fuego (TF) AS -1416-17042 Pacific/Pago_Pago AT +4813+01620 Europe/Vienna AU -3133+15905 Australia/Lord_Howe Lord Howe Island AU -5430+15857 Antarctica/Macquarie Macquarie Island AU -4253+14719 Australia/Hobart Tasmania (most areas) AU -3956+14352 Australia/Currie Tasmania (King Island) AU -3749+14458 Australia/Melbourne Victoria AU -3352+15113 Australia/Sydney New South Wales (most areas) AU -3157+14127 Australia/Broken_Hill New South Wales (Yancowinna) AU -2728+15302 Australia/Brisbane Queensland (most areas) AU -2016+14900 Australia/Lindeman Queensland (Whitsunday Islands) AU -3455+13835 Australia/Adelaide South Australia AU -1228+13050 Australia/Darwin Northern Territory AU -3157+11551 Australia/Perth Western Australia (most areas) AU -3143+12852 Australia/Eucla Western Australia (Eucla) AW +1230-06958 America/Aruba AX +6006+01957 Europe/Mariehamn AZ +4023+04951 Asia/Baku BA +4352+01825 Europe/Sarajevo BB +1306-05937 America/Barbados BD +2343+09025 Asia/Dhaka BE +5050+00420 Europe/Brussels BF +1222-00131 Africa/Ouagadougou BG +4241+02319 Europe/Sofia BH +2623+05035 Asia/Bahrain BI -0323+02922 Africa/Bujumbura BJ +0629+00237 Africa/Porto-Novo BL +1753-06251 America/St_Barthelemy BM +3217-06446 Atlantic/Bermuda BN +0456+11455 Asia/Brunei BO -1630-06809 America/La_Paz BQ +120903-0681636 America/Kralendijk BR -0351-03225 America/Noronha Atlantic islands BR -0127-04829 America/Belem Para (east); Amapa BR -0343-03830 America/Fortaleza Brazil (northeast: MA, PI, CE, RN, PB) BR -0803-03454 America/Recife Pernambuco BR -0712-04812 America/Araguaina Tocantins BR -0940-03543 America/Maceio Alagoas, Sergipe BR -1259-03831 America/Bahia Bahia BR -2332-04637 America/Sao_Paulo Brazil (southeast: GO, DF, MG, ES, RJ, SP, PR, SC, RS) BR -2027-05437 America/Campo_Grande Mato Grosso do Sul BR -1535-05605 America/Cuiaba Mato Grosso BR -0226-05452 America/Santarem Para (west) BR -0846-06354 America/Porto_Velho Rondonia BR +0249-06040 America/Boa_Vista Roraima BR -0308-06001 America/Manaus Amazonas (east) BR -0640-06952 America/Eirunepe Amazonas (west) BR -0958-06748 America/Rio_Branco Acre BS +2505-07721 America/Nassau BT +2728+08939 Asia/Thimphu BW -2439+02555 Africa/Gaborone BY +5354+02734 Europe/Minsk BZ +1730-08812 America/Belize CA +4734-05243 America/St_Johns Newfoundland; Labrador (southeast) CA +4439-06336 America/Halifax Atlantic - NS (most areas); PE CA +4612-05957 America/Glace_Bay Atlantic - NS (Cape Breton) CA +4606-06447 America/Moncton Atlantic - New Brunswick CA +5320-06025 America/Goose_Bay Atlantic - Labrador (most areas) CA +5125-05707 America/Blanc-Sablon AST - QC (Lower North Shore) CA +4339-07923 America/Toronto Eastern - ON, QC (most areas) CA +4901-08816 America/Nipigon Eastern - ON, QC (no DST 1967-73) CA +4823-08915 America/Thunder_Bay Eastern - ON (Thunder Bay) CA +6344-06828 America/Iqaluit Eastern - NU (most east areas) CA +6608-06544 America/Pangnirtung Eastern - NU (Pangnirtung) CA +484531-0913718 America/Atikokan EST - ON (Atikokan); NU (Coral H) CA +4953-09709 America/Winnipeg Central - ON (west); Manitoba CA +4843-09434 America/Rainy_River Central - ON (Rainy R, Ft Frances) CA +744144-0944945 America/Resolute Central - NU (Resolute) CA +624900-0920459 America/Rankin_Inlet Central - NU (central) CA +5024-10439 America/Regina CST - SK (most areas) CA +5017-10750 America/Swift_Current CST - SK (midwest) CA +5333-11328 America/Edmonton Mountain - AB; BC (E); SK (W) CA +690650-1050310 America/Cambridge_Bay Mountain - NU (west) CA +6227-11421 America/Yellowknife Mountain - NT (central) CA +682059-1334300 America/Inuvik Mountain - NT (west) CA +4906-11631 America/Creston MST - BC (Creston) CA +5946-12014 America/Dawson_Creek MST - BC (Dawson Cr, Ft St John) CA +5848-12242 America/Fort_Nelson MST - BC (Ft Nelson) CA +4916-12307 America/Vancouver Pacific - BC (most areas) CA +6043-13503 America/Whitehorse Pacific - Yukon (east) CA +6404-13925 America/Dawson Pacific - Yukon (west) CC -1210+09655 Indian/Cocos CD -0418+01518 Africa/Kinshasa Dem. Rep. of Congo (west) CD -1140+02728 Africa/Lubumbashi Dem. Rep. of Congo (east) CF +0422+01835 Africa/Bangui CG -0416+01517 Africa/Brazzaville CH +4723+00832 Europe/Zurich CI +0519-00402 Africa/Abidjan CK -2114-15946 Pacific/Rarotonga CL -3327-07040 America/Santiago Chile (most areas) CL -5309-07055 America/Punta_Arenas Region of Magallanes CL -2709-10926 Pacific/Easter Easter Island CM +0403+00942 Africa/Douala CN +3114+12128 Asia/Shanghai Beijing Time CN +4348+08735 Asia/Urumqi Xinjiang Time CO +0436-07405 America/Bogota CR +0956-08405 America/Costa_Rica CU +2308-08222 America/Havana CV +1455-02331 Atlantic/Cape_Verde CW +1211-06900 America/Curacao CX -1025+10543 Indian/Christmas CY +3510+03322 Asia/Nicosia Cyprus (most areas) CY +3507+03357 Asia/Famagusta Northern Cyprus CZ +5005+01426 Europe/Prague DE +5230+01322 Europe/Berlin Germany (most areas) DE +4742+00841 Europe/Busingen Busingen DJ +1136+04309 Africa/Djibouti DK +5540+01235 Europe/Copenhagen DM +1518-06124 America/Dominica DO +1828-06954 America/Santo_Domingo DZ +3647+00303 Africa/Algiers EC -0210-07950 America/Guayaquil Ecuador (mainland) EC -0054-08936 Pacific/Galapagos Galapagos Islands EE +5925+02445 Europe/Tallinn EG +3003+03115 Africa/Cairo EH +2709-01312 Africa/El_Aaiun ER +1520+03853 Africa/Asmara ES +4024-00341 Europe/Madrid Spain (mainland) ES +3553-00519 Africa/Ceuta Ceuta, Melilla ES +2806-01524 Atlantic/Canary Canary Islands ET +0902+03842 Africa/Addis_Ababa FI +6010+02458 Europe/Helsinki FJ -1808+17825 Pacific/Fiji FK -5142-05751 Atlantic/Stanley FM +0725+15147 Pacific/Chuuk Chuuk/Truk, Yap FM +0658+15813 Pacific/Pohnpei Pohnpei/Ponape FM +0519+16259 Pacific/Kosrae Kosrae FO +6201-00646 Atlantic/Faroe FR +4852+00220 Europe/Paris GA +0023+00927 Africa/Libreville GB +513030-0000731 Europe/London GD +1203-06145 America/Grenada GE +4143+04449 Asia/Tbilisi GF +0456-05220 America/Cayenne GG +492717-0023210 Europe/Guernsey GH +0533-00013 Africa/Accra GI +3608-00521 Europe/Gibraltar GL +6411-05144 America/Nuuk Greenland (most areas) GL +7646-01840 America/Danmarkshavn National Park (east coast) GL +7029-02158 America/Scoresbysund Scoresbysund/Ittoqqortoormiit GL +7634-06847 America/Thule Thule/Pituffik GM +1328-01639 Africa/Banjul GN +0931-01343 Africa/Conakry GP +1614-06132 America/Guadeloupe GQ +0345+00847 Africa/Malabo GR +3758+02343 Europe/Athens GS -5416-03632 Atlantic/South_Georgia GT +1438-09031 America/Guatemala GU +1328+14445 Pacific/Guam GW +1151-01535 Africa/Bissau GY +0648-05810 America/Guyana HK +2217+11409 Asia/Hong_Kong HN +1406-08713 America/Tegucigalpa HR +4548+01558 Europe/Zagreb HT +1832-07220 America/Port-au-Prince HU +4730+01905 Europe/Budapest ID -0610+10648 Asia/Jakarta Java, Sumatra ID -0002+10920 Asia/Pontianak Borneo (west, central) ID -0507+11924 Asia/Makassar Borneo (east, south); Sulawesi/Celebes, Bali, Nusa Tengarra; Timor (west) ID -0232+14042 Asia/Jayapura New Guinea (West Papua / Irian Jaya); Malukus/Moluccas IE +5320-00615 Europe/Dublin IL +314650+0351326 Asia/Jerusalem IM +5409-00428 Europe/Isle_of_Man IN +2232+08822 Asia/Kolkata IO -0720+07225 Indian/Chagos IQ +3321+04425 Asia/Baghdad IR +3540+05126 Asia/Tehran IS +6409-02151 Atlantic/Reykjavik IT +4154+01229 Europe/Rome JE +491101-0020624 Europe/Jersey JM +175805-0764736 America/Jamaica JO +3157+03556 Asia/Amman JP +353916+1394441 Asia/Tokyo KE -0117+03649 Africa/Nairobi KG +4254+07436 Asia/Bishkek KH +1133+10455 Asia/Phnom_Penh KI +0125+17300 Pacific/Tarawa Gilbert Islands KI -0308-17105 Pacific/Enderbury Phoenix Islands KI +0152-15720 Pacific/Kiritimati Line Islands KM -1141+04316 Indian/Comoro KN +1718-06243 America/St_Kitts KP +3901+12545 Asia/Pyongyang KR +3733+12658 Asia/Seoul KW +2920+04759 Asia/Kuwait KY +1918-08123 America/Cayman KZ +4315+07657 Asia/Almaty Kazakhstan (most areas) KZ +4448+06528 Asia/Qyzylorda Qyzylorda/Kyzylorda/Kzyl-Orda KZ +5312+06337 Asia/Qostanay Qostanay/Kostanay/Kustanay KZ +5017+05710 Asia/Aqtobe Aqtobe/Aktobe KZ +4431+05016 Asia/Aqtau Mangghystau/Mankistau KZ +4707+05156 Asia/Atyrau Atyrau/Atirau/Gur'yev KZ +5113+05121 Asia/Oral West Kazakhstan LA +1758+10236 Asia/Vientiane LB +3353+03530 Asia/Beirut LC +1401-06100 America/St_Lucia LI +4709+00931 Europe/Vaduz LK +0656+07951 Asia/Colombo LR +0618-01047 Africa/Monrovia LS -2928+02730 Africa/Maseru LT +5441+02519 Europe/Vilnius LU +4936+00609 Europe/Luxembourg LV +5657+02406 Europe/Riga LY +3254+01311 Africa/Tripoli MA +3339-00735 Africa/Casablanca MC +4342+00723 Europe/Monaco MD +4700+02850 Europe/Chisinau ME +4226+01916 Europe/Podgorica MF +1804-06305 America/Marigot MG -1855+04731 Indian/Antananarivo MH +0709+17112 Pacific/Majuro Marshall Islands (most areas) MH +0905+16720 Pacific/Kwajalein Kwajalein MK +4159+02126 Europe/Skopje ML +1239-00800 Africa/Bamako MM +1647+09610 Asia/Yangon MN +4755+10653 Asia/Ulaanbaatar Mongolia (most areas) MN +4801+09139 Asia/Hovd Bayan-Olgiy, Govi-Altai, Hovd, Uvs, Zavkhan MN +4804+11430 Asia/Choibalsan Dornod, Sukhbaatar MO +221150+1133230 Asia/Macau MP +1512+14545 Pacific/Saipan MQ +1436-06105 America/Martinique MR +1806-01557 Africa/Nouakchott MS +1643-06213 America/Montserrat MT +3554+01431 Europe/Malta MU -2010+05730 Indian/Mauritius MV +0410+07330 Indian/Maldives MW -1547+03500 Africa/Blantyre MX +1924-09909 America/Mexico_City Central Time MX +2105-08646 America/Cancun Eastern Standard Time - Quintana Roo MX +2058-08937 America/Merida Central Time - Campeche, Yucatan MX +2540-10019 America/Monterrey Central Time - Durango; Coahuila, Nuevo Leon, Tamaulipas (most areas) MX +2550-09730 America/Matamoros Central Time US - Coahuila, Nuevo Leon, Tamaulipas (US border) MX +2313-10625 America/Mazatlan Mountain Time - Baja California Sur, Nayarit, Sinaloa MX +2838-10605 America/Chihuahua Mountain Time - Chihuahua (most areas) MX +2934-10425 America/Ojinaga Mountain Time US - Chihuahua (US border) MX +2904-11058 America/Hermosillo Mountain Standard Time - Sonora MX +3232-11701 America/Tijuana Pacific Time US - Baja California MX +2048-10515 America/Bahia_Banderas Central Time - Bahia de Banderas MY +0310+10142 Asia/Kuala_Lumpur Malaysia (peninsula) MY +0133+11020 Asia/Kuching Sabah, Sarawak MZ -2558+03235 Africa/Maputo NA -2234+01706 Africa/Windhoek NC -2216+16627 Pacific/Noumea NE +1331+00207 Africa/Niamey NF -2903+16758 Pacific/Norfolk NG +0627+00324 Africa/Lagos NI +1209-08617 America/Managua NL +5222+00454 Europe/Amsterdam NO +5955+01045 Europe/Oslo NP +2743+08519 Asia/Kathmandu NR -0031+16655 Pacific/Nauru NU -1901-16955 Pacific/Niue NZ -3652+17446 Pacific/Auckland New Zealand (most areas) NZ -4357-17633 Pacific/Chatham Chatham Islands OM +2336+05835 Asia/Muscat PA +0858-07932 America/Panama PE -1203-07703 America/Lima PF -1732-14934 Pacific/Tahiti Society Islands PF -0900-13930 Pacific/Marquesas Marquesas Islands PF -2308-13457 Pacific/Gambier Gambier Islands PG -0930+14710 Pacific/Port_Moresby Papua New Guinea (most areas) PG -0613+15534 Pacific/Bougainville Bougainville PH +1435+12100 Asia/Manila PK +2452+06703 Asia/Karachi PL +5215+02100 Europe/Warsaw PM +4703-05620 America/Miquelon PN -2504-13005 Pacific/Pitcairn PR +182806-0660622 America/Puerto_Rico PS +3130+03428 Asia/Gaza Gaza Strip PS +313200+0350542 Asia/Hebron West Bank PT +3843-00908 Europe/Lisbon Portugal (mainland) PT +3238-01654 Atlantic/Madeira Madeira Islands PT +3744-02540 Atlantic/Azores Azores PW +0720+13429 Pacific/Palau PY -2516-05740 America/Asuncion QA +2517+05132 Asia/Qatar RE -2052+05528 Indian/Reunion RO +4426+02606 Europe/Bucharest RS +4450+02030 Europe/Belgrade RU +5443+02030 Europe/Kaliningrad MSK-01 - Kaliningrad RU +554521+0373704 Europe/Moscow MSK+00 - Moscow area # The obsolescent zone.tab format cannot represent Europe/Simferopol well. # Put it in RU section and list as UA. See "territorial claims" above. # Programs should use zone1970.tab instead; see above. UA +4457+03406 Europe/Simferopol Crimea RU +5836+04939 Europe/Kirov MSK+00 - Kirov RU +4621+04803 Europe/Astrakhan MSK+01 - Astrakhan RU +4844+04425 Europe/Volgograd MSK+01 - Volgograd RU +5134+04602 Europe/Saratov MSK+01 - Saratov RU +5420+04824 Europe/Ulyanovsk MSK+01 - Ulyanovsk RU +5312+05009 Europe/Samara MSK+01 - Samara, Udmurtia RU +5651+06036 Asia/Yekaterinburg MSK+02 - Urals RU +5500+07324 Asia/Omsk MSK+03 - Omsk RU +5502+08255 Asia/Novosibirsk MSK+04 - Novosibirsk RU +5322+08345 Asia/Barnaul MSK+04 - Altai RU +5630+08458 Asia/Tomsk MSK+04 - Tomsk RU +5345+08707 Asia/Novokuznetsk MSK+04 - Kemerovo RU +5601+09250 Asia/Krasnoyarsk MSK+04 - Krasnoyarsk area RU +5216+10420 Asia/Irkutsk MSK+05 - Irkutsk, Buryatia RU +5203+11328 Asia/Chita MSK+06 - Zabaykalsky RU +6200+12940 Asia/Yakutsk MSK+06 - Lena River RU +623923+1353314 Asia/Khandyga MSK+06 - Tomponsky, Ust-Maysky RU +4310+13156 Asia/Vladivostok MSK+07 - Amur River RU +643337+1431336 Asia/Ust-Nera MSK+07 - Oymyakonsky RU +5934+15048 Asia/Magadan MSK+08 - Magadan RU +4658+14242 Asia/Sakhalin MSK+08 - Sakhalin Island RU +6728+15343 Asia/Srednekolymsk MSK+08 - Sakha (E); North Kuril Is RU +5301+15839 Asia/Kamchatka MSK+09 - Kamchatka RU +6445+17729 Asia/Anadyr MSK+09 - Bering Sea RW -0157+03004 Africa/Kigali SA +2438+04643 Asia/Riyadh SB -0932+16012 Pacific/Guadalcanal SC -0440+05528 Indian/Mahe SD +1536+03232 Africa/Khartoum SE +5920+01803 Europe/Stockholm SG +0117+10351 Asia/Singapore SH -1555-00542 Atlantic/St_Helena SI +4603+01431 Europe/Ljubljana SJ +7800+01600 Arctic/Longyearbyen SK +4809+01707 Europe/Bratislava SL +0830-01315 Africa/Freetown SM +4355+01228 Europe/San_Marino SN +1440-01726 Africa/Dakar SO +0204+04522 Africa/Mogadishu SR +0550-05510 America/Paramaribo SS +0451+03137 Africa/Juba ST +0020+00644 Africa/Sao_Tome SV +1342-08912 America/El_Salvador SX +180305-0630250 America/Lower_Princes SY +3330+03618 Asia/Damascus SZ -2618+03106 Africa/Mbabane TC +2128-07108 America/Grand_Turk TD +1207+01503 Africa/Ndjamena TF -492110+0701303 Indian/Kerguelen TG +0608+00113 Africa/Lome TH +1345+10031 Asia/Bangkok TJ +3835+06848 Asia/Dushanbe TK -0922-17114 Pacific/Fakaofo TL -0833+12535 Asia/Dili TM +3757+05823 Asia/Ashgabat TN +3648+01011 Africa/Tunis TO -2110-17510 Pacific/Tongatapu TR +4101+02858 Europe/Istanbul TT +1039-06131 America/Port_of_Spain TV -0831+17913 Pacific/Funafuti TW +2503+12130 Asia/Taipei TZ -0648+03917 Africa/Dar_es_Salaam UA +5026+03031 Europe/Kiev Ukraine (most areas) UA +4837+02218 Europe/Uzhgorod Transcarpathia UA +4750+03510 Europe/Zaporozhye Zaporozhye and east Lugansk UG +0019+03225 Africa/Kampala UM +2813-17722 Pacific/Midway Midway Islands UM +1917+16637 Pacific/Wake Wake Island US +404251-0740023 America/New_York Eastern (most areas) US +421953-0830245 America/Detroit Eastern - MI (most areas) US +381515-0854534 America/Kentucky/Louisville Eastern - KY (Louisville area) US +364947-0845057 America/Kentucky/Monticello Eastern - KY (Wayne) US +394606-0860929 America/Indiana/Indianapolis Eastern - IN (most areas) US +384038-0873143 America/Indiana/Vincennes Eastern - IN (Da, Du, K, Mn) US +410305-0863611 America/Indiana/Winamac Eastern - IN (Pulaski) US +382232-0862041 America/Indiana/Marengo Eastern - IN (Crawford) US +382931-0871643 America/Indiana/Petersburg Eastern - IN (Pike) US +384452-0850402 America/Indiana/Vevay Eastern - IN (Switzerland) US +415100-0873900 America/Chicago Central (most areas) US +375711-0864541 America/Indiana/Tell_City Central - IN (Perry) US +411745-0863730 America/Indiana/Knox Central - IN (Starke) US +450628-0873651 America/Menominee Central - MI (Wisconsin border) US +470659-1011757 America/North_Dakota/Center Central - ND (Oliver) US +465042-1012439 America/North_Dakota/New_Salem Central - ND (Morton rural) US +471551-1014640 America/North_Dakota/Beulah Central - ND (Mercer) US +394421-1045903 America/Denver Mountain (most areas) US +433649-1161209 America/Boise Mountain - ID (south); OR (east) US +332654-1120424 America/Phoenix MST - Arizona (except Navajo) US +340308-1181434 America/Los_Angeles Pacific US +611305-1495401 America/Anchorage Alaska (most areas) US +581807-1342511 America/Juneau Alaska - Juneau area US +571035-1351807 America/Sitka Alaska - Sitka area US +550737-1313435 America/Metlakatla Alaska - Annette Island US +593249-1394338 America/Yakutat Alaska - Yakutat US +643004-1652423 America/Nome Alaska (west) US +515248-1763929 America/Adak Aleutian Islands US +211825-1575130 Pacific/Honolulu Hawaii UY -345433-0561245 America/Montevideo UZ +3940+06648 Asia/Samarkand Uzbekistan (west) UZ +4120+06918 Asia/Tashkent Uzbekistan (east) VA +415408+0122711 Europe/Vatican VC +1309-06114 America/St_Vincent VE +1030-06656 America/Caracas VG +1827-06437 America/Tortola VI +1821-06456 America/St_Thomas VN +1045+10640 Asia/Ho_Chi_Minh VU -1740+16825 Pacific/Efate WF -1318-17610 Pacific/Wallis WS -1350-17144 Pacific/Apia YE +1245+04512 Asia/Aden YT -1247+04514 Indian/Mayotte ZA -2615+02800 Africa/Johannesburg ZM -1525+02817 Africa/Lusaka ZW -1750+03103 Africa/Harare tzinfo-2.0.6/test/zoneinfo/zone1970.tab000066400000000000000000000427671436527530500176540ustar00rootroot00000000000000# tzdb timezone descriptions # # This file is in the public domain. # # From Paul Eggert (2018-06-27): # This file contains a table where each row stands for a timezone where # civil timestamps have agreed since 1970. Columns are separated by # a single tab. Lines beginning with '#' are comments. All text uses # UTF-8 encoding. The columns of the table are as follows: # # 1. The countries that overlap the timezone, as a comma-separated list # of ISO 3166 2-character country codes. See the file 'iso3166.tab'. # 2. Latitude and longitude of the timezone's principal location # in ISO 6709 sign-degrees-minutes-seconds format, # either ±DDMM±DDDMM or ±DDMMSS±DDDMMSS, # first latitude (+ is north), then longitude (+ is east). # 3. Timezone name used in value of TZ environment variable. # Please see the theory.html file for how these names are chosen. # If multiple timezones overlap a country, each has a row in the # table, with each column 1 containing the country code. # 4. Comments; present if and only if a country has multiple timezones. # # If a timezone covers multiple countries, the most-populous city is used, # and that country is listed first in column 1; any other countries # are listed alphabetically by country code. The table is sorted # first by country code, then (if possible) by an order within the # country that (1) makes some geographical sense, and (2) puts the # most populous timezones first, where that does not contradict (1). # # This table is intended as an aid for users, to help them select timezones # appropriate for their practical needs. It is not intended to take or # endorse any position on legal or territorial claims. # #country- #codes coordinates TZ comments AD +4230+00131 Europe/Andorra AE,OM +2518+05518 Asia/Dubai AF +3431+06912 Asia/Kabul AL +4120+01950 Europe/Tirane AM +4011+04430 Asia/Yerevan AQ -6617+11031 Antarctica/Casey Casey AQ -6835+07758 Antarctica/Davis Davis AQ -6640+14001 Antarctica/DumontDUrville Dumont-d'Urville AQ -6736+06253 Antarctica/Mawson Mawson AQ -6448-06406 Antarctica/Palmer Palmer AQ -6734-06808 Antarctica/Rothera Rothera AQ -690022+0393524 Antarctica/Syowa Syowa AQ -720041+0023206 Antarctica/Troll Troll AQ -7824+10654 Antarctica/Vostok Vostok AR -3436-05827 America/Argentina/Buenos_Aires Buenos Aires (BA, CF) AR -3124-06411 America/Argentina/Cordoba Argentina (most areas: CB, CC, CN, ER, FM, MN, SE, SF) AR -2447-06525 America/Argentina/Salta Salta (SA, LP, NQ, RN) AR -2411-06518 America/Argentina/Jujuy Jujuy (JY) AR -2649-06513 America/Argentina/Tucuman Tucumán (TM) AR -2828-06547 America/Argentina/Catamarca Catamarca (CT); Chubut (CH) AR -2926-06651 America/Argentina/La_Rioja La Rioja (LR) AR -3132-06831 America/Argentina/San_Juan San Juan (SJ) AR -3253-06849 America/Argentina/Mendoza Mendoza (MZ) AR -3319-06621 America/Argentina/San_Luis San Luis (SL) AR -5138-06913 America/Argentina/Rio_Gallegos Santa Cruz (SC) AR -5448-06818 America/Argentina/Ushuaia Tierra del Fuego (TF) AS,UM -1416-17042 Pacific/Pago_Pago Samoa, Midway AT +4813+01620 Europe/Vienna AU -3133+15905 Australia/Lord_Howe Lord Howe Island AU -5430+15857 Antarctica/Macquarie Macquarie Island AU -4253+14719 Australia/Hobart Tasmania (most areas) AU -3956+14352 Australia/Currie Tasmania (King Island) AU -3749+14458 Australia/Melbourne Victoria AU -3352+15113 Australia/Sydney New South Wales (most areas) AU -3157+14127 Australia/Broken_Hill New South Wales (Yancowinna) AU -2728+15302 Australia/Brisbane Queensland (most areas) AU -2016+14900 Australia/Lindeman Queensland (Whitsunday Islands) AU -3455+13835 Australia/Adelaide South Australia AU -1228+13050 Australia/Darwin Northern Territory AU -3157+11551 Australia/Perth Western Australia (most areas) AU -3143+12852 Australia/Eucla Western Australia (Eucla) AZ +4023+04951 Asia/Baku BB +1306-05937 America/Barbados BD +2343+09025 Asia/Dhaka BE +5050+00420 Europe/Brussels BG +4241+02319 Europe/Sofia BM +3217-06446 Atlantic/Bermuda BN +0456+11455 Asia/Brunei BO -1630-06809 America/La_Paz BR -0351-03225 America/Noronha Atlantic islands BR -0127-04829 America/Belem Pará (east); Amapá BR -0343-03830 America/Fortaleza Brazil (northeast: MA, PI, CE, RN, PB) BR -0803-03454 America/Recife Pernambuco BR -0712-04812 America/Araguaina Tocantins BR -0940-03543 America/Maceio Alagoas, Sergipe BR -1259-03831 America/Bahia Bahia BR -2332-04637 America/Sao_Paulo Brazil (southeast: GO, DF, MG, ES, RJ, SP, PR, SC, RS) BR -2027-05437 America/Campo_Grande Mato Grosso do Sul BR -1535-05605 America/Cuiaba Mato Grosso BR -0226-05452 America/Santarem Pará (west) BR -0846-06354 America/Porto_Velho Rondônia BR +0249-06040 America/Boa_Vista Roraima BR -0308-06001 America/Manaus Amazonas (east) BR -0640-06952 America/Eirunepe Amazonas (west) BR -0958-06748 America/Rio_Branco Acre BS +2505-07721 America/Nassau BT +2728+08939 Asia/Thimphu BY +5354+02734 Europe/Minsk BZ +1730-08812 America/Belize CA +4734-05243 America/St_Johns Newfoundland; Labrador (southeast) CA +4439-06336 America/Halifax Atlantic - NS (most areas); PE CA +4612-05957 America/Glace_Bay Atlantic - NS (Cape Breton) CA +4606-06447 America/Moncton Atlantic - New Brunswick CA +5320-06025 America/Goose_Bay Atlantic - Labrador (most areas) CA +5125-05707 America/Blanc-Sablon AST - QC (Lower North Shore) CA +4339-07923 America/Toronto Eastern - ON, QC (most areas) CA +4901-08816 America/Nipigon Eastern - ON, QC (no DST 1967-73) CA +4823-08915 America/Thunder_Bay Eastern - ON (Thunder Bay) CA +6344-06828 America/Iqaluit Eastern - NU (most east areas) CA +6608-06544 America/Pangnirtung Eastern - NU (Pangnirtung) CA +484531-0913718 America/Atikokan EST - ON (Atikokan); NU (Coral H) CA +4953-09709 America/Winnipeg Central - ON (west); Manitoba CA +4843-09434 America/Rainy_River Central - ON (Rainy R, Ft Frances) CA +744144-0944945 America/Resolute Central - NU (Resolute) CA +624900-0920459 America/Rankin_Inlet Central - NU (central) CA +5024-10439 America/Regina CST - SK (most areas) CA +5017-10750 America/Swift_Current CST - SK (midwest) CA +5333-11328 America/Edmonton Mountain - AB; BC (E); SK (W) CA +690650-1050310 America/Cambridge_Bay Mountain - NU (west) CA +6227-11421 America/Yellowknife Mountain - NT (central) CA +682059-1334300 America/Inuvik Mountain - NT (west) CA +4906-11631 America/Creston MST - BC (Creston) CA +5946-12014 America/Dawson_Creek MST - BC (Dawson Cr, Ft St John) CA +5848-12242 America/Fort_Nelson MST - BC (Ft Nelson) CA +4916-12307 America/Vancouver Pacific - BC (most areas) CA +6043-13503 America/Whitehorse Pacific - Yukon (east) CA +6404-13925 America/Dawson Pacific - Yukon (west) CC -1210+09655 Indian/Cocos CH,DE,LI +4723+00832 Europe/Zurich Swiss time CI,BF,GM,GN,ML,MR,SH,SL,SN,TG +0519-00402 Africa/Abidjan CK -2114-15946 Pacific/Rarotonga CL -3327-07040 America/Santiago Chile (most areas) CL -5309-07055 America/Punta_Arenas Region of Magallanes CL -2709-10926 Pacific/Easter Easter Island CN +3114+12128 Asia/Shanghai Beijing Time CN +4348+08735 Asia/Urumqi Xinjiang Time CO +0436-07405 America/Bogota CR +0956-08405 America/Costa_Rica CU +2308-08222 America/Havana CV +1455-02331 Atlantic/Cape_Verde CW,AW,BQ,SX +1211-06900 America/Curacao CX -1025+10543 Indian/Christmas CY +3510+03322 Asia/Nicosia Cyprus (most areas) CY +3507+03357 Asia/Famagusta Northern Cyprus CZ,SK +5005+01426 Europe/Prague DE +5230+01322 Europe/Berlin Germany (most areas) DK +5540+01235 Europe/Copenhagen DO +1828-06954 America/Santo_Domingo DZ +3647+00303 Africa/Algiers EC -0210-07950 America/Guayaquil Ecuador (mainland) EC -0054-08936 Pacific/Galapagos Galápagos Islands EE +5925+02445 Europe/Tallinn EG +3003+03115 Africa/Cairo EH +2709-01312 Africa/El_Aaiun ES +4024-00341 Europe/Madrid Spain (mainland) ES +3553-00519 Africa/Ceuta Ceuta, Melilla ES +2806-01524 Atlantic/Canary Canary Islands FI,AX +6010+02458 Europe/Helsinki FJ -1808+17825 Pacific/Fiji FK -5142-05751 Atlantic/Stanley FM +0725+15147 Pacific/Chuuk Chuuk/Truk, Yap FM +0658+15813 Pacific/Pohnpei Pohnpei/Ponape FM +0519+16259 Pacific/Kosrae Kosrae FO +6201-00646 Atlantic/Faroe FR +4852+00220 Europe/Paris GB,GG,IM,JE +513030-0000731 Europe/London GE +4143+04449 Asia/Tbilisi GF +0456-05220 America/Cayenne GH +0533-00013 Africa/Accra GI +3608-00521 Europe/Gibraltar GL +6411-05144 America/Nuuk Greenland (most areas) GL +7646-01840 America/Danmarkshavn National Park (east coast) GL +7029-02158 America/Scoresbysund Scoresbysund/Ittoqqortoormiit GL +7634-06847 America/Thule Thule/Pituffik GR +3758+02343 Europe/Athens GS -5416-03632 Atlantic/South_Georgia GT +1438-09031 America/Guatemala GU,MP +1328+14445 Pacific/Guam GW +1151-01535 Africa/Bissau GY +0648-05810 America/Guyana HK +2217+11409 Asia/Hong_Kong HN +1406-08713 America/Tegucigalpa HT +1832-07220 America/Port-au-Prince HU +4730+01905 Europe/Budapest ID -0610+10648 Asia/Jakarta Java, Sumatra ID -0002+10920 Asia/Pontianak Borneo (west, central) ID -0507+11924 Asia/Makassar Borneo (east, south); Sulawesi/Celebes, Bali, Nusa Tengarra; Timor (west) ID -0232+14042 Asia/Jayapura New Guinea (West Papua / Irian Jaya); Malukus/Moluccas IE +5320-00615 Europe/Dublin IL +314650+0351326 Asia/Jerusalem IN +2232+08822 Asia/Kolkata IO -0720+07225 Indian/Chagos IQ +3321+04425 Asia/Baghdad IR +3540+05126 Asia/Tehran IS +6409-02151 Atlantic/Reykjavik IT,SM,VA +4154+01229 Europe/Rome JM +175805-0764736 America/Jamaica JO +3157+03556 Asia/Amman JP +353916+1394441 Asia/Tokyo KE,DJ,ER,ET,KM,MG,SO,TZ,UG,YT -0117+03649 Africa/Nairobi KG +4254+07436 Asia/Bishkek KI +0125+17300 Pacific/Tarawa Gilbert Islands KI -0308-17105 Pacific/Enderbury Phoenix Islands KI +0152-15720 Pacific/Kiritimati Line Islands KP +3901+12545 Asia/Pyongyang KR +3733+12658 Asia/Seoul KZ +4315+07657 Asia/Almaty Kazakhstan (most areas) KZ +4448+06528 Asia/Qyzylorda Qyzylorda/Kyzylorda/Kzyl-Orda KZ +5312+06337 Asia/Qostanay Qostanay/Kostanay/Kustanay KZ +5017+05710 Asia/Aqtobe Aqtöbe/Aktobe KZ +4431+05016 Asia/Aqtau Mangghystaū/Mankistau KZ +4707+05156 Asia/Atyrau Atyraū/Atirau/Gur'yev KZ +5113+05121 Asia/Oral West Kazakhstan LB +3353+03530 Asia/Beirut LK +0656+07951 Asia/Colombo LR +0618-01047 Africa/Monrovia LT +5441+02519 Europe/Vilnius LU +4936+00609 Europe/Luxembourg LV +5657+02406 Europe/Riga LY +3254+01311 Africa/Tripoli MA +3339-00735 Africa/Casablanca MC +4342+00723 Europe/Monaco MD +4700+02850 Europe/Chisinau MH +0709+17112 Pacific/Majuro Marshall Islands (most areas) MH +0905+16720 Pacific/Kwajalein Kwajalein MM +1647+09610 Asia/Yangon MN +4755+10653 Asia/Ulaanbaatar Mongolia (most areas) MN +4801+09139 Asia/Hovd Bayan-Ölgii, Govi-Altai, Hovd, Uvs, Zavkhan MN +4804+11430 Asia/Choibalsan Dornod, Sükhbaatar MO +221150+1133230 Asia/Macau MQ +1436-06105 America/Martinique MT +3554+01431 Europe/Malta MU -2010+05730 Indian/Mauritius MV +0410+07330 Indian/Maldives MX +1924-09909 America/Mexico_City Central Time MX +2105-08646 America/Cancun Eastern Standard Time - Quintana Roo MX +2058-08937 America/Merida Central Time - Campeche, Yucatán MX +2540-10019 America/Monterrey Central Time - Durango; Coahuila, Nuevo León, Tamaulipas (most areas) MX +2550-09730 America/Matamoros Central Time US - Coahuila, Nuevo León, Tamaulipas (US border) MX +2313-10625 America/Mazatlan Mountain Time - Baja California Sur, Nayarit, Sinaloa MX +2838-10605 America/Chihuahua Mountain Time - Chihuahua (most areas) MX +2934-10425 America/Ojinaga Mountain Time US - Chihuahua (US border) MX +2904-11058 America/Hermosillo Mountain Standard Time - Sonora MX +3232-11701 America/Tijuana Pacific Time US - Baja California MX +2048-10515 America/Bahia_Banderas Central Time - Bahía de Banderas MY +0310+10142 Asia/Kuala_Lumpur Malaysia (peninsula) MY +0133+11020 Asia/Kuching Sabah, Sarawak MZ,BI,BW,CD,MW,RW,ZM,ZW -2558+03235 Africa/Maputo Central Africa Time NA -2234+01706 Africa/Windhoek NC -2216+16627 Pacific/Noumea NF -2903+16758 Pacific/Norfolk NG,AO,BJ,CD,CF,CG,CM,GA,GQ,NE +0627+00324 Africa/Lagos West Africa Time NI +1209-08617 America/Managua NL +5222+00454 Europe/Amsterdam NO,SJ +5955+01045 Europe/Oslo NP +2743+08519 Asia/Kathmandu NR -0031+16655 Pacific/Nauru NU -1901-16955 Pacific/Niue NZ,AQ -3652+17446 Pacific/Auckland New Zealand time NZ -4357-17633 Pacific/Chatham Chatham Islands PA,KY +0858-07932 America/Panama PE -1203-07703 America/Lima PF -1732-14934 Pacific/Tahiti Society Islands PF -0900-13930 Pacific/Marquesas Marquesas Islands PF -2308-13457 Pacific/Gambier Gambier Islands PG -0930+14710 Pacific/Port_Moresby Papua New Guinea (most areas) PG -0613+15534 Pacific/Bougainville Bougainville PH +1435+12100 Asia/Manila PK +2452+06703 Asia/Karachi PL +5215+02100 Europe/Warsaw PM +4703-05620 America/Miquelon PN -2504-13005 Pacific/Pitcairn PR +182806-0660622 America/Puerto_Rico PS +3130+03428 Asia/Gaza Gaza Strip PS +313200+0350542 Asia/Hebron West Bank PT +3843-00908 Europe/Lisbon Portugal (mainland) PT +3238-01654 Atlantic/Madeira Madeira Islands PT +3744-02540 Atlantic/Azores Azores PW +0720+13429 Pacific/Palau PY -2516-05740 America/Asuncion QA,BH +2517+05132 Asia/Qatar RE,TF -2052+05528 Indian/Reunion Réunion, Crozet, Scattered Islands RO +4426+02606 Europe/Bucharest RS,BA,HR,ME,MK,SI +4450+02030 Europe/Belgrade RU +5443+02030 Europe/Kaliningrad MSK-01 - Kaliningrad RU +554521+0373704 Europe/Moscow MSK+00 - Moscow area # Mention RU and UA alphabetically. See "territorial claims" above. RU,UA +4457+03406 Europe/Simferopol Crimea RU +5836+04939 Europe/Kirov MSK+00 - Kirov RU +4621+04803 Europe/Astrakhan MSK+01 - Astrakhan RU +4844+04425 Europe/Volgograd MSK+01 - Volgograd RU +5134+04602 Europe/Saratov MSK+01 - Saratov RU +5420+04824 Europe/Ulyanovsk MSK+01 - Ulyanovsk RU +5312+05009 Europe/Samara MSK+01 - Samara, Udmurtia RU +5651+06036 Asia/Yekaterinburg MSK+02 - Urals RU +5500+07324 Asia/Omsk MSK+03 - Omsk RU +5502+08255 Asia/Novosibirsk MSK+04 - Novosibirsk RU +5322+08345 Asia/Barnaul MSK+04 - Altai RU +5630+08458 Asia/Tomsk MSK+04 - Tomsk RU +5345+08707 Asia/Novokuznetsk MSK+04 - Kemerovo RU +5601+09250 Asia/Krasnoyarsk MSK+04 - Krasnoyarsk area RU +5216+10420 Asia/Irkutsk MSK+05 - Irkutsk, Buryatia RU +5203+11328 Asia/Chita MSK+06 - Zabaykalsky RU +6200+12940 Asia/Yakutsk MSK+06 - Lena River RU +623923+1353314 Asia/Khandyga MSK+06 - Tomponsky, Ust-Maysky RU +4310+13156 Asia/Vladivostok MSK+07 - Amur River RU +643337+1431336 Asia/Ust-Nera MSK+07 - Oymyakonsky RU +5934+15048 Asia/Magadan MSK+08 - Magadan RU +4658+14242 Asia/Sakhalin MSK+08 - Sakhalin Island RU +6728+15343 Asia/Srednekolymsk MSK+08 - Sakha (E); North Kuril Is RU +5301+15839 Asia/Kamchatka MSK+09 - Kamchatka RU +6445+17729 Asia/Anadyr MSK+09 - Bering Sea SA,KW,YE +2438+04643 Asia/Riyadh SB -0932+16012 Pacific/Guadalcanal SC -0440+05528 Indian/Mahe SD +1536+03232 Africa/Khartoum SE +5920+01803 Europe/Stockholm SG +0117+10351 Asia/Singapore SR +0550-05510 America/Paramaribo SS +0451+03137 Africa/Juba ST +0020+00644 Africa/Sao_Tome SV +1342-08912 America/El_Salvador SY +3330+03618 Asia/Damascus TC +2128-07108 America/Grand_Turk TD +1207+01503 Africa/Ndjamena TF -492110+0701303 Indian/Kerguelen Kerguelen, St Paul Island, Amsterdam Island TH,KH,LA,VN +1345+10031 Asia/Bangkok Indochina (most areas) TJ +3835+06848 Asia/Dushanbe TK -0922-17114 Pacific/Fakaofo TL -0833+12535 Asia/Dili TM +3757+05823 Asia/Ashgabat TN +3648+01011 Africa/Tunis TO -2110-17510 Pacific/Tongatapu TR +4101+02858 Europe/Istanbul TT,AG,AI,BL,DM,GD,GP,KN,LC,MF,MS,VC,VG,VI +1039-06131 America/Port_of_Spain TV -0831+17913 Pacific/Funafuti TW +2503+12130 Asia/Taipei UA +5026+03031 Europe/Kiev Ukraine (most areas) UA +4837+02218 Europe/Uzhgorod Transcarpathia UA +4750+03510 Europe/Zaporozhye Zaporozhye and east Lugansk UM +1917+16637 Pacific/Wake Wake Island US +404251-0740023 America/New_York Eastern (most areas) US +421953-0830245 America/Detroit Eastern - MI (most areas) US +381515-0854534 America/Kentucky/Louisville Eastern - KY (Louisville area) US +364947-0845057 America/Kentucky/Monticello Eastern - KY (Wayne) US +394606-0860929 America/Indiana/Indianapolis Eastern - IN (most areas) US +384038-0873143 America/Indiana/Vincennes Eastern - IN (Da, Du, K, Mn) US +410305-0863611 America/Indiana/Winamac Eastern - IN (Pulaski) US +382232-0862041 America/Indiana/Marengo Eastern - IN (Crawford) US +382931-0871643 America/Indiana/Petersburg Eastern - IN (Pike) US +384452-0850402 America/Indiana/Vevay Eastern - IN (Switzerland) US +415100-0873900 America/Chicago Central (most areas) US +375711-0864541 America/Indiana/Tell_City Central - IN (Perry) US +411745-0863730 America/Indiana/Knox Central - IN (Starke) US +450628-0873651 America/Menominee Central - MI (Wisconsin border) US +470659-1011757 America/North_Dakota/Center Central - ND (Oliver) US +465042-1012439 America/North_Dakota/New_Salem Central - ND (Morton rural) US +471551-1014640 America/North_Dakota/Beulah Central - ND (Mercer) US +394421-1045903 America/Denver Mountain (most areas) US +433649-1161209 America/Boise Mountain - ID (south); OR (east) US +332654-1120424 America/Phoenix MST - Arizona (except Navajo) US +340308-1181434 America/Los_Angeles Pacific US +611305-1495401 America/Anchorage Alaska (most areas) US +581807-1342511 America/Juneau Alaska - Juneau area US +571035-1351807 America/Sitka Alaska - Sitka area US +550737-1313435 America/Metlakatla Alaska - Annette Island US +593249-1394338 America/Yakutat Alaska - Yakutat US +643004-1652423 America/Nome Alaska (west) US +515248-1763929 America/Adak Aleutian Islands US,UM +211825-1575130 Pacific/Honolulu Hawaii UY -345433-0561245 America/Montevideo UZ +3940+06648 Asia/Samarkand Uzbekistan (west) UZ +4120+06918 Asia/Tashkent Uzbekistan (east) VE +1030-06656 America/Caracas VN +1045+10640 Asia/Ho_Chi_Minh Vietnam (south) VU -1740+16825 Pacific/Efate WF -1318-17610 Pacific/Wallis WS -1350-17144 Pacific/Apia ZA,LS,SZ -2615+02800 Africa/Johannesburg tzinfo-2.0.6/tzinfo.gemspec000066400000000000000000000023211436527530500157160ustar00rootroot00000000000000require File.join(File.expand_path(File.dirname(__FILE__)), 'lib', 'tzinfo', 'version') Gem::Specification.new do |s| s.name = 'tzinfo' s.version = TZInfo::VERSION s.summary = 'Time Zone Library' s.description = 'TZInfo provides access to time zone data and allows times to be converted using time zone rules.' s.author = 'Philip Ross' s.email = 'phil.ross@gmail.com' s.homepage = 'https://tzinfo.github.io' s.license = 'MIT' if s.respond_to? :metadata= s.metadata = { 'bug_tracker_uri' => 'https://github.com/tzinfo/tzinfo/issues', 'changelog_uri' => 'https://github.com/tzinfo/tzinfo/blob/master/CHANGES.md', 'documentation_uri' => "https://rubydoc.info/gems/#{s.name}/#{s.version}", 'homepage_uri' => s.homepage, 'source_code_uri' => "https://github.com/tzinfo/tzinfo/tree/v#{s.version}" } end s.files = %w(CHANGES.md LICENSE README.md .yardopts) + Dir['lib/**/*.rb'] s.platform = Gem::Platform::RUBY s.require_path = 'lib' s.rdoc_options << '--title' << 'TZInfo' << '--main' << 'README.md' s.extra_rdoc_files = ['README.md', 'CHANGES.md', 'LICENSE'] s.required_ruby_version = '>= 1.9.3' s.add_dependency 'concurrent-ruby', '~> 1.0' end