brintos

brintos / llvm-project-archived public Read only

0
0
Text · 60.3 KiB · 1924af4 Raw
1414 lines · cpp
1//===----------------------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9// TODO TZDB review the test based on review comments in10// https://github.com/llvm/llvm-project/pull/8561911 12// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23, c++2613// UNSUPPORTED: no-filesystem, no-localization, no-tzdb14 15// XFAIL: libcpp-has-no-experimental-tzdb16// XFAIL: availability-tzdb-missing17 18// <chrono>19 20// class time_zone;21 22// template <class _Duration>23//   sys_info get_info(const sys_time<_Duration>& time) const;24 25// This test uses the system provided database. This makes the test portable,26// but may cause failures when the database information changes. Historic data27// may change if new facts are uncovered, future data may change when regions28// change their time zone or daylight saving time. Most tests will not look in29// the future to attempt to avoid issues. All tests list the data on which they30// are based, this makes debugging easier upon failure; including to see whether31// the provided data has not been changed32//33//34// The data in the tests can be validated by using the zdump tool. For35// example36//   zdump -v Asia/Hong_Kong37// show all transitions in the Hong Kong time zone. Or38//   zdump -c1970,1980 -v Asia/Hong_Kong39// shows all transitions in Hong Kong between 1970 and 1980.40 41#include <algorithm>42#include <cassert>43#include <chrono>44#include <format>45 46#include "test_macros.h"47#include "assert_macros.h"48#include "concat_macros.h"49 50/***** ***** HELPERS ***** *****/51 52[[nodiscard]] static std::chrono::sys_seconds to_sys_seconds(53    std::chrono::year year,54    std::chrono::month month,55    std::chrono::day day,56    std::chrono::hours h   = std::chrono::hours(0),57    std::chrono::minutes m = std::chrono::minutes{0},58    std::chrono::seconds s = std::chrono::seconds{0}) {59  std::chrono::year_month_day result{year, month, day};60 61  return std::chrono::time_point_cast<std::chrono::seconds>(static_cast<std::chrono::sys_days>(result)) + h + m + s;62}63 64static void assert_equal(const std::chrono::sys_info& lhs, const std::chrono::sys_info& rhs) {65  TEST_REQUIRE(lhs.begin == rhs.begin,66               TEST_WRITE_CONCATENATED("\nBegin:\nExpected output ", lhs.begin, "\nActual output   ", rhs.begin, '\n'));67  TEST_REQUIRE(lhs.end == rhs.end,68               TEST_WRITE_CONCATENATED("\nEnd:\nExpected output ", lhs.end, "\nActual output   ", rhs.end, '\n'));69  TEST_REQUIRE(70      lhs.offset == rhs.offset,71      TEST_WRITE_CONCATENATED("\nOffset:\nExpected output ", lhs.offset, "\nActual output   ", rhs.offset, '\n'));72  TEST_REQUIRE(lhs.save == rhs.save,73               TEST_WRITE_CONCATENATED("\nSave:\nExpected output ", lhs.save, "\nActual output   ", rhs.save, '\n'));74  TEST_REQUIRE(75      lhs.abbrev == rhs.abbrev,76      TEST_WRITE_CONCATENATED("\nAbbrev:\nExpected output ", lhs.abbrev, "\nActual output   ", rhs.abbrev, '\n'));77}78 79static void assert_equal(std::string_view expected, const std::chrono::sys_info& value) {80  // Note the output of operator<< is implementation defined, use this81  // format to keep the test portable.82  std::string result = std::format(83      "[{}, {}) {:%T} {:%Q%q} {}",84      value.begin,85      value.end,86      std::chrono::hh_mm_ss{value.offset},87      value.save,88      value.abbrev);89 90  TEST_REQUIRE(expected == result,91               TEST_WRITE_CONCATENATED("\nExpected output ", expected, "\nActual output   ", result, '\n'));92}93 94static void95assert_range(std::string_view expected, const std::chrono::sys_info& begin, const std::chrono::sys_info& end) {96  assert_equal(expected, begin);97  assert_equal(expected, end);98}99 100static void assert_cycle(101    std::string_view expected_1,102    const std::chrono::sys_info& begin_1,103    const std::chrono::sys_info& end_1,104    std::string_view expected_2,105    const std::chrono::sys_info& begin_2,106    const std::chrono::sys_info& end_2107 108) {109  assert_range(expected_1, begin_1, end_1);110  assert_range(expected_2, begin_2, end_2);111}112 113/***** ***** TESTS ***** *****/114 115static void test_gmt() {116  // Simple zone always valid, no rule entries, lookup using a link.117  // L Etc/GMT GMT118  // Z Etc/GMT 0 - GMT119 120  const std::chrono::time_zone* tz = std::chrono::locate_zone("GMT");121 122  assert_equal(123      std::chrono::sys_info(124          std::chrono::sys_seconds::min(),125          std::chrono::sys_seconds::max(),126          std::chrono::seconds(0),127          std::chrono::minutes(0),128          "GMT"),129      tz->get_info(std::chrono::sys_seconds::min()));130  assert_equal(131      std::chrono::sys_info(132          std::chrono::sys_seconds::min(),133          std::chrono::sys_seconds::max(),134          std::chrono::seconds(0),135          std::chrono::minutes(0),136          "GMT"),137      tz->get_info(std::chrono::sys_seconds(std::chrono::seconds{0})));138 139  assert_equal(140      std::chrono::sys_info(141          std::chrono::sys_seconds::min(),142          std::chrono::sys_seconds::max(),143          std::chrono::seconds(0),144          std::chrono::minutes(0),145          "GMT"),146      tz->get_info(std::chrono::sys_seconds::max() - std::chrono::seconds{1})); // max is not valid147}148 149static void test_durations() {150  // Doesn't test a location, instead tests whether different duration151  // specializations work.152  const std::chrono::time_zone* tz = std::chrono::locate_zone("GMT");153 154  // Using the GMT zone means every call gives the same result.155  std::chrono::sys_info expected(156      std::chrono::sys_seconds::min(),157      std::chrono::sys_seconds::max(),158      std::chrono::seconds(0),159      std::chrono::minutes(0),160      "GMT");161 162  assert_equal(expected, tz->get_info(std::chrono::sys_time<std::chrono::nanoseconds>{}));163  assert_equal(expected, tz->get_info(std::chrono::sys_time<std::chrono::microseconds>{}));164  assert_equal(expected, tz->get_info(std::chrono::sys_time<std::chrono::milliseconds>{}));165  assert_equal(expected, tz->get_info(std::chrono::sys_time<std::chrono::seconds>{}));166  assert_equal(expected, tz->get_info(std::chrono::sys_time<std::chrono::minutes>{}));167  assert_equal(expected, tz->get_info(std::chrono::sys_time<std::chrono::minutes>{}));168  assert_equal(expected, tz->get_info(std::chrono::sys_time<std::chrono::hours>{}));169  assert_equal(expected, tz->get_info(std::chrono::sys_time<std::chrono::days>{}));170  assert_equal(expected, tz->get_info(std::chrono::sys_time<std::chrono::weeks>{}));171  assert_equal(expected, tz->get_info(std::chrono::sys_time<std::chrono::months>{}));172  assert_equal(expected, tz->get_info(std::chrono::sys_time<std::chrono::years>{}));173}174 175static void test_antarctica_syowa() {176  // One change, no rules, no dst changes177  // This change uses an ON field with a day number178  //179  // There don't seem to be rule-less zones that use last day or a180  // constrained day181 182  // Z Antarctica/Syowa 0 - -00 1957 Ja 29183  // 3 - +03184 185  const std::chrono::time_zone* tz = std::chrono::locate_zone("Antarctica/Syowa");186 187  std::chrono::sys_seconds transition =188      to_sys_seconds(std::chrono::year(1957), std::chrono::January, std::chrono::day(29));189 190  assert_equal(191      std::chrono::sys_info(192          std::chrono::sys_seconds::min(), //193          transition,                      //194          std::chrono::seconds(0),         //195          std::chrono::minutes(0),         //196          "-00"),                          //197      tz->get_info(std::chrono::sys_seconds::min()));198 199  assert_equal(200      std::chrono::sys_info(201          std::chrono::sys_seconds::min(), //202          transition,                      //203          std::chrono::seconds(0),         //204          std::chrono::minutes(0),         //205          "-00"),                          //206      tz->get_info(transition - std::chrono::seconds(1)));207 208  assert_equal(209      std::chrono::sys_info(210          transition,                      //211          std::chrono::sys_seconds::max(), //212          std::chrono::hours(3),           //213          std::chrono::minutes(0),         //214          "+03"),                          //215      tz->get_info(transition));216}217 218static void test_asia_hong_kong() {219  // A more typical entry, first some hard-coded entires and then at the220  // end a rules based entry. This rule is valid for its entire period221  //222  // Z Asia/Hong_Kong 7:36:42 - LMT 1904 O 30 0:36:42223  // 8 - HKT 1941 Jun 15 3224  // 8 1 HKST 1941 O 1 4225  // 8 0:30 HKWT 1941 D 25226  // 9 - JST 1945 N 18 2227  // 8 HK HK%sT228  //229  // R HK 1946 o - Ap 21 0 1 S230  // R HK 1946 o - D 1 3:30s 0 -231  // R HK 1947 o - Ap 13 3:30s 1 S232  // R HK 1947 o - N 30 3:30s 0 -233  // R HK 1948 o - May 2 3:30s 1 S234  // R HK 1948 1952 - O Su>=28 3:30s 0 -235  // R HK 1949 1953 - Ap Su>=1 3:30 1 S236  // R HK 1953 1964 - O Su>=31 3:30 0 -237  // R HK 1954 1964 - Mar Su>=18 3:30 1 S238  // R HK 1965 1976 - Ap Su>=16 3:30 1 S239  // R HK 1965 1976 - O Su>=16 3:30 0 -240  // R HK 1973 o - D 30 3:30 1 S241  // R HK 1979 o - May 13 3:30 1 S242  // R HK 1979 o - O 21 3:30 0 -243 244  using namespace std::literals::chrono_literals;245  const std::chrono::time_zone* tz = std::chrono::locate_zone("Asia/Hong_Kong");246 247  assert_equal(248      std::chrono::sys_info(249          std::chrono::sys_seconds::min(),250          to_sys_seconds(1904y, std::chrono::October, 29d, 17h), // 7:36:42 - LMT 1904 O 30 0:36:42251          7h + 36min + 42s,252          0min,253          "LMT"),254      tz->get_info(std::chrono::sys_seconds::min()));255 256  assert_equal(257      std::chrono::sys_info(258          std::chrono::sys_seconds::min(),259          to_sys_seconds(1904y, std::chrono::October, 29d, 17h), // 7:36:42 - LMT 1904 O 30 0:36:42260          7h + 36min + 42s,261          0min,262          "LMT"),263      tz->get_info(to_sys_seconds(1904y, std::chrono::October, 29d, 16h, 59min, 59s)));264 265  assert_range("[1904-10-29 17:00:00, 1941-06-14 19:00:00) 08:00:00 0min HKT", // 8 - HKT 1941 Jun 15 3266               tz->get_info(to_sys_seconds(1904y, std::chrono::October, 29d, 17h)),267               tz->get_info(to_sys_seconds(1941y, std::chrono::June, 14d, 18h, 59min, 59s)));268 269  assert_range("[1941-06-14 19:00:00, 1941-09-30 19:00:00) 09:00:00 60min HKST", // 8 1 HKST 1941 O 1 4270               tz->get_info(to_sys_seconds(1941y, std::chrono::June, 14d, 19h)),271               tz->get_info(to_sys_seconds(1941y, std::chrono::September, 30d, 18h, 59min, 59s)));272 273  assert_range("[1941-09-30 19:00:00, 1941-12-24 15:30:00) 08:30:00 30min HKWT", // 8 0:30 HKWT 1941 D 25274               tz->get_info(to_sys_seconds(1941y, std::chrono::September, 30d, 19h)),275               tz->get_info(to_sys_seconds(1941y, std::chrono::December, 24d, 15h, 29min, 59s)));276 277  assert_range("[1941-12-24 15:30:00, 1945-11-17 17:00:00) 09:00:00 0min JST", // 9 - JST 1945 N 18 2278               tz->get_info(to_sys_seconds(1941y, std::chrono::December, 24d, 15h, 30min)),279               tz->get_info(to_sys_seconds(1945y, std::chrono::November, 17d, 16h, 59min, 59s)));280 281  assert_range("[1945-11-17 17:00:00, 1946-04-20 16:00:00) 08:00:00 0min HKT", // 8 HK%sT282               tz->get_info(to_sys_seconds(1945y, std::chrono::November, 17d, 17h)),283               tz->get_info(to_sys_seconds(1946y, std::chrono::April, 20d, 15h, 59min, 59s)));284 285  assert_cycle( // 8 HK%sT286      "[1946-04-20 16:00:00, 1946-11-30 19:30:00) 09:00:00 60min HKST",287      tz->get_info(to_sys_seconds(1946y, std::chrono::April, 20d, 16h)),                // 1946 o Ap 21 0 1 S288      tz->get_info(to_sys_seconds(1946y, std::chrono::November, 30d, 19h, 29min, 59s)), // 1946 o D 1 3:30s 0 -289      "[1946-11-30 19:30:00, 1947-04-12 19:30:00) 08:00:00 0min HKT",290      tz->get_info(to_sys_seconds(1946y, std::chrono::November, 30d, 19h, 30min)),    // 1946 o D 1 3:30s 0 -291      tz->get_info(to_sys_seconds(1947y, std::chrono::April, 12d, 19h, 29min, 59s))); // 1947 o Ap 13 3:30s 1 S292 293  assert_cycle( // 8 HK%sT294      "[1947-04-12 19:30:00, 1947-11-29 19:30:00) 09:00:00 60min HKST",295      tz->get_info(to_sys_seconds(1947y, std::chrono::April, 12d, 19h, 30min)),         // 1947 o Ap 13 3:30s 1 S296      tz->get_info(to_sys_seconds(1947y, std::chrono::November, 29d, 19h, 29min, 59s)), // 1947 o N 30 3:30s 0 -297      "[1947-11-29 19:30:00, 1948-05-01 19:30:00) 08:00:00 0min HKT",298      tz->get_info(to_sys_seconds(1947y, std::chrono::November, 29d, 19h, 30min)), // 1947 o N 30 3:30s 0 -299      tz->get_info(to_sys_seconds(1948y, std::chrono::May, 1d, 19h, 29min, 59s))); // 1948 o May 2 3:30s 1 S300 301  assert_cycle( // 8 HK%sT302      "[1948-05-01 19:30:00, 1948-10-30 19:30:00) 09:00:00 60min HKST",303      tz->get_info(to_sys_seconds(1948y, std::chrono::May, 1d, 19h, 30min)),           // 1948 o May 2 3:30s 1 S304      tz->get_info(to_sys_seconds(1948y, std::chrono::October, 30d, 19h, 29min, 59s)), // 1948 1952 O Su>=28 3:30s 0 -305      "[1948-10-30 19:30:00, 1949-04-02 19:30:00) 08:00:00 0min HKT",306      tz->get_info(to_sys_seconds(1948y, std::chrono::October, 30d, 19h, 30min)),    // 1948 1952 O Su>=28 3:30s 0 -307      tz->get_info(to_sys_seconds(1949y, std::chrono::April, 2d, 19h, 29min, 59s))); // 1949 1953 Ap Su>=1 3:30 1 S308 309  assert_cycle( // 8 HK%sT310      "[1949-04-02 19:30:00, 1949-10-29 19:30:00) 09:00:00 60min HKST",311      tz->get_info(to_sys_seconds(1949y, std::chrono::April, 2d, 19h, 30min)),         // 1949 1953 Ap Su>=1 3:30 1 S312      tz->get_info(to_sys_seconds(1949y, std::chrono::October, 29d, 19h, 29min, 59s)), // 1948 1952 O Su>=28 3:30s 0313      "[1949-10-29 19:30:00, 1950-04-01 19:30:00) 08:00:00 0min HKT",314      tz->get_info(to_sys_seconds(1949y, std::chrono::October, 29d, 19h, 30min)),    // 1948 1952 O Su>=28 3:30s 0315      tz->get_info(to_sys_seconds(1950y, std::chrono::April, 1d, 19h, 29min, 59s))); // 1949 1953 Ap Su>=1 3:30 1 S316 317  assert_range(318      "[1953-10-31 18:30:00, 1954-03-20 19:30:00) 08:00:00 0min HKT",319      tz->get_info(to_sys_seconds(1953y, std::chrono::October, 31d, 18h, 30min)),     // 1953 1964 - O Su>=31 3:30 0 -320      tz->get_info(to_sys_seconds(1954y, std::chrono::March, 20d, 19h, 29min, 59s))); // 1954 1964 - Mar Su>=18 3:30 1 S321 322  assert_cycle( // 8 HK%sT323      "[1953-04-04 19:30:00, 1953-10-31 18:30:00) 09:00:00 60min HKST",324      tz->get_info(to_sys_seconds(1953y, std::chrono::April, 4d, 19h, 30min)),         // 1949 1953 Ap Su>=1 3:30 1 S325      tz->get_info(to_sys_seconds(1953y, std::chrono::October, 31d, 18h, 29min, 59s)), // 1953 1964 - O Su>=31 3:30 0 -326      "[1953-10-31 18:30:00, 1954-03-20 19:30:00) 08:00:00 0min HKT",327      tz->get_info(to_sys_seconds(1953y, std::chrono::October, 31d, 18h, 30min)),     // 1953 1964 - O Su>=31 3:30 0 -328      tz->get_info(to_sys_seconds(1954y, std::chrono::March, 20d, 19h, 29min, 59s))); // 1954 1964 - Mar Su>=18 3:30 1 S329 330  assert_cycle( // 8 HK%sT331      "[1972-04-15 19:30:00, 1972-10-21 18:30:00) 09:00:00 60min HKST",332      tz->get_info(to_sys_seconds(1972y, std::chrono::April, 19d, 19h, 30min)),        // 1965 1976 - Ap Su>=16 3:30 1 S333      tz->get_info(to_sys_seconds(1972y, std::chrono::October, 21d, 18h, 29min, 59s)), // 1965 1976 - O Su>=16 3:30 0 -334      "[1972-10-21 18:30:00, 1973-04-21 19:30:00) 08:00:00 0min HKT",335      tz->get_info(to_sys_seconds(1972y, std::chrono::October, 21d, 18h, 30min)),     // 1965 1976 - O Su>=16 3:30 0 -336      tz->get_info(to_sys_seconds(1973y, std::chrono::April, 21d, 19h, 29min, 59s))); // 1965 1976 - Ap Su>=16 3:30 1 S337 338  assert_range( // 8 HK%sT339      "[1973-04-21 19:30:00, 1973-10-20 18:30:00) 09:00:00 60min HKST",340      tz->get_info(to_sys_seconds(1973y, std::chrono::April, 21d, 19h, 30min)), // 1965 1976 - Ap Su>=16 3:30 1 S341      tz->get_info(to_sys_seconds(1973y, std::chrono::October, 20d, 18h, 29min, 59s))); // 1965 1976 - O Su>=16 3:30 0 -342 343  assert_range( // 8 HK%sT, test "1973 o - D 30 3:30 1 S"344      "[1973-10-20 18:30:00, 1973-12-29 19:30:00) 08:00:00 0min HKT",345      tz->get_info(to_sys_seconds(1973y, std::chrono::October, 20d, 18h, 30min)),        // 1965 1976 - O Su>=16 3:30346      tz->get_info(to_sys_seconds(1973y, std::chrono::December, 29d, 19h, 29min, 59s))); // 1973 o - D 30 3:30 1 S347 348  assert_range( // 8 HK%sT349      "[1973-12-29 19:30:00, 1974-10-19 18:30:00) 09:00:00 60min HKST",350      tz->get_info(to_sys_seconds(1973y, std::chrono::December, 29d, 19h, 30min)),      // 1973 o - D 30 3:30 1 S351      tz->get_info(to_sys_seconds(1974y, std::chrono::October, 19d, 18h, 29min, 59s))); // 1965 1976 - O Su>=16 3:30352 353  assert_range( // 8 HK%sT, between 1973 and 1979 no rule is active so falls back to default354      "[1976-04-17 19:30:00, 1976-10-16 18:30:00) 09:00:00 60min HKST",355      tz->get_info(to_sys_seconds(1976y, std::chrono::April, 17d, 19h, 30min)), // 1965 1976 - Ap Su>=16 3:30 1 S356      tz->get_info(to_sys_seconds(1976y, std::chrono::October, 16d, 18h, 29min, 59s))); // 1965 1976 - O Su>=16 3:30 0 -357 358  assert_range( // 8 HK%sT, between 1973 and 1979 no rule is active so falls back to default359      "[1976-10-16 18:30:00, 1979-05-12 19:30:00) 08:00:00 0min HKT",360      tz->get_info(to_sys_seconds(1976y, std::chrono::October, 16d, 18h, 30min)),   // 1965 1976 - O Su>=16 3:30 0 -361      tz->get_info(to_sys_seconds(1979y, std::chrono::May, 12d, 19h, 29min, 59s))); // 1979 o - May 13 3:30 1 S362 363  assert_range( // 8 HK%sT364      "[1979-05-12 19:30:00, 1979-10-20 18:30:00) 09:00:00 60min HKST",365      tz->get_info(to_sys_seconds(1979y, std::chrono::May, 12d, 19h, 30min)),           // 1979 o - May 13 3:30 1 S366      tz->get_info(to_sys_seconds(1979y, std::chrono::October, 20d, 18h, 29min, 59s))); // 1979 o - O 21 3:30 0 -367 368  assert_equal(369      std::chrono::sys_info(370          to_sys_seconds(1979y, std::chrono::October, 20d, 18h, 30min),371          std::chrono::sys_seconds::max(),372          8h,373          std::chrono::minutes(0),374          "HKT"),375      tz->get_info(to_sys_seconds(1979y, std::chrono::October, 20d, 18h, 30min)));376 377  assert_equal(378      std::chrono::sys_info(379          to_sys_seconds(1979y, std::chrono::October, 20d, 18h, 30min),380          std::chrono::sys_seconds::max(),381          8h,382          std::chrono::minutes(0),383          "HKT"),384      tz->get_info(std::chrono::sys_seconds::max() - std::chrono::seconds{1})); // max is not valid385}386 387static void test_europe_berlin() {388  // A more typical entry, first some hard-coded entires and then at the389  // end a rules based entry. This rule is valid for its entire period390  //391 392  // Z Europe/Berlin 0:53:28 - LMT 1893 Ap393  // 1 c CE%sT 1945 May 24 2394  // 1 So CE%sT 1946395  // 1 DE CE%sT 1980396  // 1 E CE%sT397  //398  // R c 1916 o - Ap 30 23 1 S399  // R c 1916 o - O 1 1 0 -400  // R c 1917 1918 - Ap M>=15 2s 1 S401  // R c 1917 1918 - S M>=15 2s 0 -402  // R c 1940 o - Ap 1 2s 1 S403  // R c 1942 o - N 2 2s 0 -404  // R c 1943 o - Mar 29 2s 1 S405  // R c 1943 o - O 4 2s 0 -406  // R c 1944 1945 - Ap M>=1 2s 1 S407  // R c 1944 o - O 2 2s 0 -408  // R c 1945 o - S 16 2s 0 -409  // R c 1977 1980 - Ap Su>=1 2s 1 S410  // R c 1977 o - S lastSu 2s 0 -411  // R c 1978 o - O 1 2s 0 -412  // R c 1979 1995 - S lastSu 2s 0 -413  // R c 1981 ma - Mar lastSu 2s 1 S414  // R c 1996 ma - O lastSu 2s 0 -415  //416  // R So 1945 o - May 24 2 2 M417  // R So 1945 o - S 24 3 1 S418  // R So 1945 o - N 18 2s 0 -419  //420  // R DE 1946 o - Ap 14 2s 1 S421  // R DE 1946 o - O 7 2s 0 -422  // R DE 1947 1949 - O Su>=1 2s 0 -423  // R DE 1947 o - Ap 6 3s 1 S424  // R DE 1947 o - May 11 2s 2 M425  // R DE 1947 o - Jun 29 3 1 S426  // R DE 1948 o - Ap 18 2s 1 S427  // R DE 1949 o - Ap 10 2s 1 S428  //429  // R E 1977 1980 - Ap Su>=1 1u 1 S430  // R E 1977 o - S lastSu 1u 0 -431  // R E 1978 o - O 1 1u 0 -432  // R E 1979 1995 - S lastSu 1u 0 -433  // R E 1981 ma - Mar lastSu 1u 1 S434  // R E 1996 ma - O lastSu 1u 0 -435  //436  // Note the European Union decided to stop the seasonal change in437  // 2021. In 2023 seasonal changes are still in effect.438 439  using namespace std::literals::chrono_literals;440  const std::chrono::time_zone* tz = std::chrono::locate_zone("Europe/Berlin");441 442  assert_equal(443      std::chrono::sys_info(444          std::chrono::sys_seconds::min(),445          to_sys_seconds(1893y, std::chrono::March, 31d, 23h, 6min, 32s), // 0:53:28 - LMT 1893 Ap446          53min + 28s,447          0min,448          "LMT"),449      tz->get_info(std::chrono::sys_seconds::min()));450 451  assert_equal(452      std::chrono::sys_info(453          std::chrono::sys_seconds::min(),454          to_sys_seconds(1893y, std::chrono::March, 31d, 23h, 6min, 32s), // 0:53:28 - LMT 1893 Ap455          53min + 28s,456          0min,457          "LMT"),458      tz->get_info(to_sys_seconds(1893y, std::chrono::March, 31d, 23h, 6min, 31s)));459 460  assert_range(461      // 1 CE%sT before 1916 o - Ap 30 23 1 S462      "[1893-03-31 23:06:32, 1916-04-30 22:00:00) 01:00:00 0min CET",463      tz->get_info(to_sys_seconds(1893y, std::chrono::March, 31d, 23h, 6min, 32s)),464      tz->get_info(to_sys_seconds(1916y, std::chrono::April, 30d, 21h, 59min, 59s)));465 466  assert_cycle(467      // 1 CE%sT468      "[1916-04-30 22:00:00, 1916-09-30 23:00:00) 02:00:00 60min CEST",469      tz->get_info(to_sys_seconds(1916y, std::chrono::April, 30d, 22h)),                 // 1916 o - Ap 30 23 1 S470      tz->get_info(to_sys_seconds(1916y, std::chrono::September, 30d, 22h, 59min, 59s)), // o - O 1 1 0 -471      "[1916-09-30 23:00:00, 1917-04-16 01:00:00) 01:00:00 0min CET",472      tz->get_info(to_sys_seconds(1916y, std::chrono::September, 30d, 23h)),         // o - O 1 1 0 -473      tz->get_info(to_sys_seconds(1917y, std::chrono::April, 16d, 0h, 59min, 59s))); // 1917 1918 - Ap M>=15 2s 1 S474 475  assert_cycle(476      // 1 CE%sT477      "[1917-04-16 01:00:00, 1917-09-17 01:00:00) 02:00:00 60min CEST",478      tz->get_info(to_sys_seconds(1917y, std::chrono::April, 16d, 1h)),                 // 1917 1918 Ap M>=15 2s 1 S479      tz->get_info(to_sys_seconds(1917y, std::chrono::September, 17d, 0h, 59min, 59s)), // 1917 1918 S M>=15 2s 0 -480      "[1917-09-17 01:00:00, 1918-04-15 01:00:00) 01:00:00 0min CET",481      tz->get_info(to_sys_seconds(1917y, std::chrono::September, 17d, 1h)),          // 1917 1918 S M>=15 2s 0 -482      tz->get_info(to_sys_seconds(1918y, std::chrono::April, 15d, 0h, 59min, 59s))); // 1917 1918 Ap M>=15 2s 1 S483 484  assert_cycle(485      // 1 CE%sT (The cycle is more than 1 year)486      "[1918-04-15 01:00:00, 1918-09-16 01:00:00) 02:00:00 60min CEST",487      tz->get_info(to_sys_seconds(1918y, std::chrono::April, 15d, 1h)),                 // 1917 1918 Ap M>=15 2s 1 S488      tz->get_info(to_sys_seconds(1918y, std::chrono::September, 16d, 0h, 59min, 59s)), // 1917 1918 S M>=15 2s 0 -489      "[1918-09-16 01:00:00, 1940-04-01 01:00:00) 01:00:00 0min CET",490      tz->get_info(to_sys_seconds(1918y, std::chrono::September, 16d, 1h)),         // 1917 1918 S M>=15 2s 0 -491      tz->get_info(to_sys_seconds(1940y, std::chrono::April, 1d, 0h, 59min, 59s))); // 1940 o Ap 1 2s 1 S492 493  assert_cycle(494      // 1 CE%sT (The cycle is more than 1 year)495      "[1940-04-01 01:00:00, 1942-11-02 01:00:00) 02:00:00 60min CEST",496      tz->get_info(to_sys_seconds(1940y, std::chrono::April, 1d, 1h)),                // 1940 o Ap 1 2s 1 S497      tz->get_info(to_sys_seconds(1942y, std::chrono::November, 2d, 0h, 59min, 59s)), // 1942 o N 2 2s 0 -498      "[1942-11-02 01:00:00, 1943-03-29 01:00:00) 01:00:00 0min CET",499      tz->get_info(to_sys_seconds(1942y, std::chrono::November, 2d, 1h)),            // 1942 o N 2 2s 0 -500      tz->get_info(to_sys_seconds(1943y, std::chrono::March, 29d, 0h, 59min, 59s))); // 1943 o Mar 29 2s 1 S501 502  assert_range(503      // Here the zone changes from c (C-Eur) to So (SovietZone).504      // The rule c ends on 1945-09-16, instead it ends at the zone change date/time505      // There is a tricky part in the time506      // "1 c CE%sT" has an offset of 1 at the moment the rule507      // ends there is a save of 60 minutes. This means the508      // local offset to UTC is 2 hours. The rule ends at509      // 1945-05-24 02:00:00 local time, which is510      // 1945-05-24 00:00:00 UTC.511      "[1945-04-02 01:00:00, 1945-05-24 00:00:00) 02:00:00 60min CEST",512      tz->get_info(to_sys_seconds(1945y, std::chrono::April, 2d, 1h)),              // 1 CE%sT & 1945 Ap M>=1 2s 1 S513      tz->get_info(to_sys_seconds(1945y, std::chrono::May, 23d, 23h, 59min, 59s))); // 1 c CE%sT & 1945 May 24 2514 515  assert_range( // --516      "[1945-05-24 00:00:00, 1945-09-24 00:00:00) 03:00:00 120min CEMT",517      tz->get_info(to_sys_seconds(1945y, std::chrono::May, 24d)),                         // 1 c CE%sT & 1945 May 24 2518      tz->get_info(to_sys_seconds(1945y, std::chrono::September, 23d, 23h, 59min, 59s))); // 1945 o S 24 3 1 S519 520  assert_range(521      // 1 c CE%sT 1945 May 24 2522      "[1945-09-24 00:00:00, 1945-11-18 01:00:00) 02:00:00 60min CEST",523      tz->get_info(to_sys_seconds(1945y, std::chrono::September, 24d)),                 // 1945 o S 24 3 1 S524      tz->get_info(to_sys_seconds(1945y, std::chrono::November, 18d, 0h, 59min, 59s))); // 1945 o N 18 2s 0 -525  assert_range(                                                                         // --526                                                                                        // Merges 2 continuations527      "[1945-11-18 01:00:00, 1946-04-14 01:00:00) 01:00:00 0min CET",528      tz->get_info(to_sys_seconds(1945y, std::chrono::November, 18d, 1h)),           // 1 c CE%sT & 1945 o N 18 2s 0 -529      tz->get_info(to_sys_seconds(1946y, std::chrono::April, 14d, 0h, 59min, 59s))); // 1 So CE%sT & 1946 o Ap 14 2s 1 S530 531  assert_range(532      // 1 DE CE%sT 1980533      "[1946-04-14 01:00:00, 1946-10-07 01:00:00) 02:00:00 60min CEST",534      tz->get_info(to_sys_seconds(1946y, std::chrono::April, 14d, 1h)),               // 1946 o Ap 14 2s 1 S535      tz->get_info(to_sys_seconds(1946y, std::chrono::October, 7d, 0h, 59min, 59s))); // 1946 o O 7 2s 0 -536 537  // Note 1947 is an interesting year with 4 rules538  // R DE 1947 1949 - O Su>=1 2s 0 -539  // R DE 1947 o - Ap 6 3s 1 S540  // R DE 1947 o - May 11 2s 2 M541  // R DE 1947 o - Jun 29 3 1 S542  assert_range(543      // 1 DE CE%sT 1980544      "[1946-10-07 01:00:00, 1947-04-06 02:00:00) 01:00:00 0min CET",545      tz->get_info(to_sys_seconds(1946y, std::chrono::October, 7d, 1h)),            // 1946 o O 7 2s 0 -546      tz->get_info(to_sys_seconds(1947y, std::chrono::April, 6d, 1h, 59min, 59s))); // 1947 o Ap 6 3s 1 S547 548  assert_range(549      // 1 DE CE%sT 1980550      "[1947-04-06 02:00:00, 1947-05-11 01:00:00) 02:00:00 60min CEST",551      tz->get_info(to_sys_seconds(1947y, std::chrono::April, 6d, 2h)),             // 1947 o Ap 6 3s 1 S552      tz->get_info(to_sys_seconds(1947y, std::chrono::May, 11d, 0h, 59min, 59s))); // 1947 o May 11 2s 2 M553 554  assert_range(555      // 1 DE CE%sT 1980556      "[1947-05-11 01:00:00, 1947-06-29 00:00:00) 03:00:00 120min CEMT",557      tz->get_info(to_sys_seconds(1947y, std::chrono::May, 11d, 1h)),                // 1947 o May 11 2s 2 M558      tz->get_info(to_sys_seconds(1947y, std::chrono::June, 28d, 23h, 59min, 59s))); // 1947 o Jun 29 3 1 S559 560  assert_cycle(561      // 1 DE CE%sT 1980562      "[1947-06-29 00:00:00, 1947-10-05 01:00:00) 02:00:00 60min CEST",563      tz->get_info(to_sys_seconds(1947y, std::chrono::June, 29d)),                   // 1947 o Jun 29 3 1 S564      tz->get_info(to_sys_seconds(1947y, std::chrono::October, 5d, 0h, 59min, 59s)), // 1947 1949 O Su>=1 2s 0 -565      "[1947-10-05 01:00:00, 1948-04-18 01:00:00) 01:00:00 0min CET",566      tz->get_info(to_sys_seconds(1947y, std::chrono::October, 5d, 1h)),             // 1947 1949 O Su>=1 2s 0 -567      tz->get_info(to_sys_seconds(1948y, std::chrono::April, 18d, 0h, 59min, 59s))); // 1948 o Ap 18 2s 1 S568 569  assert_cycle(570      // 1 DE CE%sT 1980571      "[1948-04-18 01:00:00, 1948-10-03 01:00:00) 02:00:00 60min CEST",572      tz->get_info(to_sys_seconds(1948y, std::chrono::April, 18d, 1h)),              // 1948 o Ap 18 2s 1 S573      tz->get_info(to_sys_seconds(1948y, std::chrono::October, 3d, 0h, 59min, 59s)), // 1947 1949 O Su>=1 2s 0 -574      "[1948-10-03 01:00:00, 1949-04-10 01:00:00) 01:00:00 0min CET",575      tz->get_info(to_sys_seconds(1948y, std::chrono::October, 3d, 1h)),             // 1947 1949 O Su>=1 2s 0 -576      tz->get_info(to_sys_seconds(1949y, std::chrono::April, 10d, 0h, 59min, 59s))); // 1949 o Ap 10 2s 1 S577 578  assert_cycle( // Note the end time is  in a different continuation.579      "[1949-04-10 01:00:00, 1949-10-02 01:00:00) 02:00:00 60min CEST",              // 1 DE CE%sT 1980580      tz->get_info(to_sys_seconds(1949y, std::chrono::April, 10d, 1h)),              //  1949 o Ap 10 2s 1 S581      tz->get_info(to_sys_seconds(1949y, std::chrono::October, 2d, 0h, 59min, 59s)), //  1947 1949 O Su>=1 2s 0 -582      "[1949-10-02 01:00:00, 1980-04-06 01:00:00) 01:00:00 0min CET",583      tz->get_info(to_sys_seconds(1949y, std::chrono::October, 2d, 1h)),   //  1947 1949 O Su>=1 2s 0 -584      tz->get_info(                                                        // 1 E CE%sT585          to_sys_seconds(1980y, std::chrono::April, 6d, 0h, 59min, 59s))); //  1977 1980 Ap Su>=1 1u 1 S586 587  assert_cycle(588      // 1 E CE%sT589      "[2020-03-29 01:00:00, 2020-10-25 01:00:00) 02:00:00 60min CEST",590      tz->get_info(to_sys_seconds(2020y, std::chrono::March, 29d, 1h)),               // 1981 ma Mar lastSu 1u 1 S591      tz->get_info(to_sys_seconds(2020y, std::chrono::October, 25d, 0h, 59min, 59s)), // 1996 ma O lastSu 1u 0 -592      "[2020-10-25 01:00:00, 2021-03-28 01:00:00) 01:00:00 0min CET",593      tz->get_info(to_sys_seconds(2020y, std::chrono::October, 25d, 1h)),            // 1996 ma O lastSu 1u 0 -594      tz->get_info(to_sys_seconds(2021y, std::chrono::March, 28d, 0h, 59min, 59s))); // 1981 ma Mar lastSu 1u 1 S595 596  assert_cycle(597      // 1 E CE%sT598      "[2021-03-28 01:00:00, 2021-10-31 01:00:00) 02:00:00 60min CEST",599      tz->get_info(to_sys_seconds(2021y, std::chrono::March, 28d, 1h)),               // 1981 ma Mar lastSu 1u 1 S600      tz->get_info(to_sys_seconds(2021y, std::chrono::October, 31d, 0h, 59min, 59s)), // 1996 ma O lastSu 1u 0 -601      "[2021-10-31 01:00:00, 2022-03-27 01:00:00) 01:00:00 0min CET",602      tz->get_info(to_sys_seconds(2021y, std::chrono::October, 31d, 1h)),            // 1996 ma O lastSu 1u 0 -603      tz->get_info(to_sys_seconds(2022y, std::chrono::March, 27d, 0h, 59min, 59s))); // 1981 ma Mar lastSu 1u 1 S604}605 606static void test_america_st_johns() {607  // A more typical entry,608  // Uses letters both when DST is active and not and has multiple609  // letters. Uses negative offsets.610  // Switches several times between their own and Canadian rules611  // Switches the stdoff from -3:30:52 to -3:30 while observing the same rule612 613  // Z America/St_Johns -3:30:52 - LMT 1884614  // -3:30:52 j N%sT 1918615  // -3:30:52 C N%sT 1919616  // -3:30:52 j N%sT 1935 Mar 30617  // -3:30 j N%sT 1942 May 11618  // -3:30 C N%sT 1946619  // -3:30 j N%sT 2011 N620  // -3:30 C N%sT621  //622  // R j 1917 o - Ap 8 2 1 D623  // R j 1917 o - S 17 2 0 S624  // R j 1919 o - May 5 23 1 D625  // R j 1919 o - Au 12 23 0 S626  // R j 1920 1935 - May Su>=1 23 1 D627  // R j 1920 1935 - O lastSu 23 0 S628  // R j 1936 1941 - May M>=9 0 1 D629  // R j 1936 1941 - O M>=2 0 0 S630  // R j 1946 1950 - May Su>=8 2 1 D631  // R j 1946 1950 - O Su>=2 2 0 S632  // R j 1951 1986 - Ap lastSu 2 1 D633  // R j 1951 1959 - S lastSu 2 0 S634  // R j 1960 1986 - O lastSu 2 0 S635  // R j 1987 o - Ap Su>=1 0:1 1 D636  // R j 1987 2006 - O lastSu 0:1 0 S637  // R j 1988 o - Ap Su>=1 0:1 2 DD638  // R j 1989 2006 - Ap Su>=1 0:1 1 D639  // R j 2007 2011 - Mar Su>=8 0:1 1 D640  // R j 2007 2010 - N Su>=1 0:1 0 S641  //642  // R C 1918 o - Ap 14 2 1 D643  // R C 1918 o - O 27 2 0 S644  // R C 1942 o - F 9 2 1 W645  // R C 1945 o - Au 14 23u 1 P646  // R C 1945 o - S 30 2 0 S647  // R C 1974 1986 - Ap lastSu 2 1 D648  // R C 1974 2006 - O lastSu 2 0 S649  // R C 1987 2006 - Ap Su>=1 2 1 D650  // R C 2007 ma - Mar Su>=8 2 1 D651  // R C 2007 ma - N Su>=1 2 0 S652 653  using namespace std::literals::chrono_literals;654  const std::chrono::time_zone* tz = std::chrono::locate_zone("America/St_Johns");655 656  assert_equal( // --657      std::chrono::sys_info(658          std::chrono::sys_seconds::min(),659          to_sys_seconds(1884y, std::chrono::January, 1d, 3h, 30min, 52s), // -3:30:52 - LMT 1884660          -(3h + 30min + 52s),661          0min,662          "LMT"),663      tz->get_info(std::chrono::sys_seconds::min()));664 665  assert_equal( // --666      std::chrono::sys_info(667          std::chrono::sys_seconds::min(),668          to_sys_seconds(1884y, std::chrono::January, 1d, 3h, 30min, 52s), // -3:30:52 - LMT 1884669          -(3h + 30min + 52s),670          0min,671          "LMT"),672      tz->get_info(to_sys_seconds(1884y, std::chrono::January, 1d, 3h, 30min, 51s)));673 674  assert_range( // -3:30:52 j N%sT 1918675      "[1884-01-01 03:30:52, 1917-04-08 05:30:52) -03:30:52 0min NST",676      tz->get_info(to_sys_seconds(1884y, std::chrono::January, 1d, 3h, 30min, 52s)), // no rule active677      tz->get_info(to_sys_seconds(1917y, std::chrono::April, 8d, 5h, 30min, 51s)));  // 1917 o Ap 8 2 1 D678 679  assert_range( // -3:30:52 j N%sT 1918680      "[1917-04-08 05:30:52, 1917-09-17 04:30:52) -02:30:52 60min NDT",681      tz->get_info(to_sys_seconds(1917y, std::chrono::April, 8d, 5h, 30min, 52s)),       // 1917 o Ap 8 2 1 D682      tz->get_info(to_sys_seconds(1917y, std::chrono::September, 17d, 4h, 30min, 51s))); // 1917 o S 17 2 0 S683 684  assert_range("[1917-09-17 04:30:52, 1918-04-14 05:30:52) -03:30:52 0min NST",685               tz->get_info(                                                            // -3:30:52 j N%sT 1918686                   to_sys_seconds(1917y, std::chrono::September, 17d, 4h, 30min, 52s)), //   1917 o S 17 2 0 S687               tz->get_info(                                                            // -3:30:52 C N%sT 1919688                   to_sys_seconds(1918y, std::chrono::April, 14d, 5h, 30min, 51s)));    //   1918 o Ap 14 2 1 D689 690  assert_range( // -3:30:52 C N%sT 1919691      "[1918-04-14 05:30:52, 1918-10-27 04:30:52) -02:30:52 60min NDT",692      tz->get_info(to_sys_seconds(1918y, std::chrono::April, 14d, 5h, 30min, 52s)),    // 1918 o Ap 14 2 1 D693      tz->get_info(to_sys_seconds(1918y, std::chrono::October, 27d, 4h, 30min, 51s))); // 1918 o O 27 2 0 S694 695  assert_range("[1918-10-27 04:30:52, 1919-05-06 02:30:52) -03:30:52 0min NST",696               tz->get_info(                                                          // -3:30:52 C N%sT 1919697                   to_sys_seconds(1918y, std::chrono::October, 27d, 4h, 30min, 52s)), //   1918 o O 27 2 0 S698               tz->get_info(                                                          // -3:30:52 j N%sT 1935 Mar 30699                   to_sys_seconds(1919y, std::chrono::May, 6d, 2h, 30min, 51s)));     //   1919 o May 5 23 1 D700 701  assert_range( // -3:30:52 j N%sT 1935 Mar 30702      "[1934-10-29 01:30:52, 1935-03-30 03:30:52) -03:30:52 0min NST",703      tz->get_info(to_sys_seconds(1934y, std::chrono::October, 29d, 1h, 30min, 52s)), // 1920 1935 O lastSu 23 0 S704      tz->get_info(to_sys_seconds(1935y, std::chrono::March, 30d, 3h, 30min, 51s)));  // 1920 1935 May Su>=1 23 1 D705 706  assert_range( // -3:30 j N%sT 1942 May 11707                // Changed the stdoff while the same rule remains active.708      "[1935-03-30 03:30:52, 1935-05-06 02:30:00) -03:30:00 0min NST",709      tz->get_info(to_sys_seconds(1935y, std::chrono::March, 30d, 3h, 30min, 52s)), // 1920 1935 O lastSu 23 0 S710      tz->get_info(to_sys_seconds(1935y, std::chrono::May, 6d, 2h, 29min, 59s)));   // 1920 1935 May Su>=1 23 1 D711 712  assert_range( // -3:30 j N%sT 1942 May 11713      "[1935-05-06 02:30:00, 1935-10-28 01:30:00) -02:30:00 60min NDT",714      tz->get_info(to_sys_seconds(1935y, std::chrono::May, 6d, 2h, 30min, 0s)),        // 1920 1935 May Su>=1 23 1 D715      tz->get_info(to_sys_seconds(1935y, std::chrono::October, 28d, 1h, 29min, 59s))); // 1920 1935 O lastSu 23 0 S716 717  assert_range( // -3:30 j N%sT 1942 May 11718      "[1941-10-06 02:30:00, 1942-05-11 03:30:00) -03:30:00 0min NST",719      tz->get_info(to_sys_seconds(1941y, std::chrono::October, 6d, 2h, 30min, 0s)), // 1936 1941 O M>=2 0 0 S720      tz->get_info(to_sys_seconds(1942y, std::chrono::May, 11d, 3h, 29min, 59s)));  // 1946 1950 May Su>=8 2 1 D721 722  assert_range( // -3:30 C N%sT 1946723      "[1942-05-11 03:30:00, 1945-08-14 23:00:00) -02:30:00 60min NWT",724      tz->get_info(to_sys_seconds(1942y, std::chrono::May, 11d, 3h, 30min, 0s)),       // 1942 o F 9 2 1 W725      tz->get_info(to_sys_seconds(1945y, std::chrono::August, 14d, 22h, 59min, 59s))); // 1945 o Au 14 23u 1 P726 727  assert_range( // -3:30 C N%sT 1946728      "[1945-08-14 23:00:00, 1945-09-30 04:30:00) -02:30:00 60min NPT",729      tz->get_info(to_sys_seconds(1945y, std::chrono::August, 14d, 23h, 0min, 0s)),      // 1945 o Au 14 23u 1 P730      tz->get_info(to_sys_seconds(1945y, std::chrono::September, 30d, 4h, 29min, 59s))); // 1945 o S 30 2 0 S731 732  assert_range(733      "[1945-09-30 04:30:00, 1946-05-12 05:30:00) -03:30:00 0min NST",734      tz->get_info(735          to_sys_seconds(1945y, std::chrono::September, 30d, 4h, 30min, 0s)), // -3:30 C N%sT 1946 & 945 o S 30 2 0 S736      tz->get_info(to_sys_seconds(737          1946y, std::chrono::May, 12d, 5h, 29min, 59s))); // -3:30 j N%sT 2011 N & 1946 1950 May Su>=8 2 1 D738 739  assert_range( // -3:30 j N%sT 2011 N740      "[1988-04-03 03:31:00, 1988-10-30 01:31:00) -01:30:00 120min NDDT",741      tz->get_info(to_sys_seconds(1988y, std::chrono::April, 3d, 3h, 31min, 0s)),      // 1988 o Ap Su>=1 0:1 2 DD742      tz->get_info(to_sys_seconds(1988y, std::chrono::October, 30d, 1h, 30min, 59s))); // 1987 2006 O lastSu 0:1 0 S743 744  assert_range("[2011-03-13 03:31:00, 2011-11-06 04:30:00) -02:30:00 60min NDT",745               tz->get_info(                                                            // -3:30 j N%sT 2011 N746                   to_sys_seconds(2011y, std::chrono::March, 13d, 3h, 31min, 0s)),      //   2007 2011 Mar Su>=8 0:1 1 D747               tz->get_info(                                                            // -3:30 C N%sT748                   to_sys_seconds(2011y, std::chrono::November, 6d, 04h, 29min, 59s))); //   2007 ma N Su>=1 2 0 S749}750 751static void test_get_at_standard_time_universal() {752  // Z Asia/Barnaul 5:35 - LMT 1919 D 10753  // ...754  // 7 R +07/+08 1995 May 28755  // 6 R +06/+07 2011 Mar 27 2s756  // ...757  //758  // ...759  // R R 1985 2010 - Mar lastSu 2s 1 S760  // R R 1996 2010 - O lastSu 2s 0 -761 762  using namespace std::literals::chrono_literals;763  const std::chrono::time_zone* tz = std::chrono::locate_zone("Asia/Barnaul");764 765  assert_equal(766      std::chrono::sys_info(767          to_sys_seconds(2010y, std::chrono::October, 30d, 20h),768          to_sys_seconds(2011y, std::chrono::March, 26d, 20h),769          6h,770          0min,771          "+06"),772      tz->get_info(to_sys_seconds(2010y, std::chrono::October, 31d, 10h)));773}774 775static void test_get_at_standard_time_standard() {776  // Z Africa/Bissau -1:2:20 - LMT 1912 Ja 1 1u777  using namespace std::literals::chrono_literals;778  const std::chrono::time_zone* tz = std::chrono::locate_zone("Africa/Bissau");779 780  assert_equal(781      std::chrono::sys_info(782          std::chrono::sys_seconds::min(),783          to_sys_seconds(1912y, std::chrono::January, 1d, 1h),784          -(1h + 2min + 20s),785          0min,786          "LMT"),787      tz->get_info(std::chrono::sys_seconds::min()));788}789 790static void test_get_at_save_universal() {791  // Z America/Tijuana -7:48:4 - LMT 1922 Ja 1 0:11:56792  // -7 - MST 1924793  // -8 - PST 1927 Jun 10 23794  // -7 - MST 1930 N 15795  // -8 - PST 1931 Ap796  // -8 1 PDT 1931 S 30797  // -8 - PST 1942 Ap 24798  // -8 1 PWT 1945 Au 14 23u799  // ...800 801  using namespace std::literals::chrono_literals;802  const std::chrono::time_zone* tz = std::chrono::locate_zone("America/Tijuana");803 804  assert_equal(805      std::chrono::sys_info(806          to_sys_seconds(1942y, std::chrono::April, 24d, 8h),807          to_sys_seconds(1945y, std::chrono::August, 14d, 23h),808          -7h,809          60min,810          "PWT"),811      tz->get_info(to_sys_seconds(1942y, std::chrono::April, 24d, 8h)));812}813 814static void test_get_at_rule_standard() {815  // Z Antarctica/Macquarie 0 - -00 1899 N816  // 10 - AEST 1916 O 1 2817  // 10 1 AEDT 1917 F818  // 10 AU AE%sT 1919 Ap 1 0s819  // ...820  //821  // R AU 1917 o - Ja 1 2s 1 D822  // R AU 1917 o - Mar lastSu 2s 0 S823  // R AU 1942 o - Ja 1 2s 1 D824  // ...825 826  using namespace std::literals::chrono_literals;827  const std::chrono::time_zone* tz = std::chrono::locate_zone("Antarctica/Macquarie");828 829  // Another rule where the S propagates?830  assert_equal(831      std::chrono::sys_info(832          to_sys_seconds(1916y, std::chrono::September, 30d, 16h),833          to_sys_seconds(1917y, std::chrono::March, 24d, 16h),834          11h,835          60min,836          "AEDT"),837      tz->get_info(to_sys_seconds(1916y, std::chrono::September, 30d, 16h)));838}839 840static void test_get_at_rule_universal() {841  // Z America/Nuuk -3:26:56 - LMT 1916 Jul 28842  // -3 - -03 1980 Ap 6 2843  // -3 E -03/-02 2023 O 29 1u844  // -2 E -02/-01845  //846  // R E 1977 1980 - Ap Su>=1 1u 1 S847  // R E 1977 o - S lastSu 1u 0 -848  // R E 1978 o - O 1 1u 0 -849  // R E 1979 1995 - S lastSu 1u 0 -850  // R E 1981 ma - Mar lastSu 1u 1 S851  // R E 1996 ma - O lastSu 1u 0 -852 853  using namespace std::literals::chrono_literals;854  const std::chrono::time_zone* tz = std::chrono::locate_zone("America/Nuuk");855 856  assert_equal(857      std::chrono::sys_info(858          to_sys_seconds(1980y, std::chrono::April, 6d, 5h),859          to_sys_seconds(1980y, std::chrono::September, 28d, 1h),860          -2h,861          60min,862          "-02"),863      tz->get_info(to_sys_seconds(1980y, std::chrono::April, 6d, 5h)));864}865 866static void test_format_with_alternatives_west() {867  // Z America/Nuuk -3:26:56 - LMT 1916 Jul 28868  // -3 - -03 1980 Ap 6 2869  // -3 E -03/-02 2023 O 29 1u870  // -2 E -02/-01871  //872  // ...873  // R E 1981 ma - Mar lastSu 1u 1 S874  // R E 1996 ma - O lastSu 1u 0 -875 876  using namespace std::literals::chrono_literals;877  const std::chrono::time_zone* tz = std::chrono::locate_zone("America/Nuuk");878 879  assert_cycle( // -3 E -03/-02880      "[2019-10-27 01:00:00, 2020-03-29 01:00:00) -03:00:00 0min -03",881      tz->get_info(to_sys_seconds(2019y, std::chrono::October, 27d, 1h)),           // 1981 ma Mar lastSu 1u 1 S882      tz->get_info(to_sys_seconds(2020y, std::chrono::March, 29d, 0h, 59min, 59s)), // 1996 ma O lastSu 1u 0 -883      "[2020-03-29 01:00:00, 2020-10-25 01:00:00) -02:00:00 60min -02",884      tz->get_info(to_sys_seconds(2020y, std::chrono::March, 29d, 1h)),                // 1996 ma O lastSu 1u 0 -885      tz->get_info(to_sys_seconds(2020y, std::chrono::October, 25d, 0h, 59min, 59s))); // 1981 ma Mar lastSu 1u 1 S886}887 888static void test_format_with_alternatives_east() {889  // Z Asia/Barnaul 5:35 - LMT 1919 D 10890  // ...891  // 6 R +06/+07 2011 Mar 27 2s892  // ...893  //894  // ...895  // R R 1985 2010 - Mar lastSu 2s 1 S896  // R R 1996 2010 - O lastSu 2s 0 -897 898  using namespace std::literals::chrono_literals;899  const std::chrono::time_zone* tz = std::chrono::locate_zone("Asia/Barnaul");900 901  assert_cycle( // 6 R +06/+07 2011 Mar 27 2s902      "[2000-03-25 20:00:00, 2000-10-28 20:00:00) 07:00:00 60min +07",903      tz->get_info(to_sys_seconds(2000y, std::chrono::March, 25d, 20h)),               // 1985 2010 Mar lastSu 2s 1 S904      tz->get_info(to_sys_seconds(2000y, std::chrono::October, 28d, 19h, 59min, 59s)), // 1996 2010 O lastSu 2s 0 -905      "[2000-10-28 20:00:00, 2001-03-24 20:00:00) 06:00:00 0min +06",906      tz->get_info(to_sys_seconds(2000y, std::chrono::October, 28d, 20h)),            // 1996 2010 O lastSu 2s 0 -907      tz->get_info(to_sys_seconds(2001y, std::chrono::March, 24d, 19h, 59min, 59s))); // 1985 2010 Mar lastSu 2s 1 S908}909 910static void test_africa_algiers() {911  using namespace std::literals::chrono_literals;912  const std::chrono::time_zone* tz = std::chrono::locate_zone("Africa/Algiers");913 914  assert_equal(915      std::chrono::sys_info(916          to_sys_seconds(1977y, std::chrono::October, 20d, 23h),917          to_sys_seconds(1978y, std::chrono::March, 24d),918          1h,919          std::chrono::minutes(0),920          "CET"),921      tz->get_info(to_sys_seconds(1977y, std::chrono::October, 20d, 23h)));922 923  assert_range("[1977-05-06 00:00:00, 1977-10-20 23:00:00) 01:00:00 60min WEST", // 0 d WE%sT 1977 O 21924               tz->get_info(to_sys_seconds(1977y, std::chrono::May, 6d)),925               tz->get_info(to_sys_seconds(1977y, std::chrono::October, 20d, 22h, 59min, 59s)));926 927  assert_range("[1977-10-20 23:00:00, 1978-03-24 00:00:00) 01:00:00 0min CET", // 1 d CE%sT 1979 O 26928               tz->get_info(to_sys_seconds(1977y, std::chrono::October, 20d, 23h)),929               tz->get_info(to_sys_seconds(1978y, std::chrono::March, 23d, 23h, 59min, 59s)));930}931 932static void test_africa_casablanca() {933  // Z Africa/Casablanca -0:30:20 - LMT 1913 O 26934  // 0 M +00/+01 1984 Mar 16935  // 1 - +01 1986936  // 0 M +00/+01 2018 O 28 3937  // 1 M +01/+00938  //939  // ...940  // R M 2013 2018 - O lastSu 3 0 -941  // R M 2014 2018 - Mar lastSu 2 1 -942  // R M 2014 o - Jun 28 3 0 -943  // R M 2014 o - Au 2 2 1 -944  // R M 2015 o - Jun 14 3 0 -945  // R M 2015 o - Jul 19 2 1 -946  // R M 2016 o - Jun 5 3 0 -947  // R M 2016 o - Jul 10 2 1 -948  // R M 2017 o - May 21 3 0 -949  // R M 2017 o - Jul 2 2 1 -950  // R M 2018 o - May 13 3 0 -951  // R M 2018 o - Jun 17 2 1 -952  // R M 2019 o - May 5 3 -1 -953  // R M 2019 o - Jun 9 2 0 -954  // R M 2020 o - Ap 19 3 -1 -955  // ...956 957  using namespace std::literals::chrono_literals;958  const std::chrono::time_zone* tz = std::chrono::locate_zone("Africa/Casablanca");959 960  assert_range("[2018-06-17 02:00:00, 2018-10-28 02:00:00) 01:00:00 60min +01",961               tz->get_info(to_sys_seconds(2018y, std::chrono::June, 17d, 2h)),962               tz->get_info(to_sys_seconds(2018y, std::chrono::October, 28d, 1h, 59min, 59s)));963 964  assert_range("[2018-10-28 02:00:00, 2019-05-05 02:00:00) 01:00:00 0min +01",965               tz->get_info( // 1 M +01/+00 & R M 2018 o - Jun 17 2 1 -966                   to_sys_seconds(2018y, std::chrono::October, 28d, 2h)),967               tz->get_info( // 1 M +01/+00 & R M 2019 o - May 5 3 -1 -968                   to_sys_seconds(2019y, std::chrono::May, 5d, 1h, 59min, 59s)));969 970  // 1 M +01/+00971  // Note the SAVE contains a negative value972  assert_range("[2019-05-05 02:00:00, 2019-06-09 02:00:00) 00:00:00 -60min +00",973               tz->get_info(to_sys_seconds(2019y, std::chrono::May, 5d, 2h)),               // R M 2019 o - May 5 3 -1 -974               tz->get_info(to_sys_seconds(2019y, std::chrono::June, 9d, 1h, 59min, 59s))); // R M 2019 o - Jun 9 2 0 -975 976  assert_range("[2019-06-09 02:00:00, 2020-04-19 02:00:00) 01:00:00 0min +01",977               tz->get_info( // 1 M +01/+00 & R M 2019 o - Jun 9 2 0 -978                   to_sys_seconds(2019y, std::chrono::June, 9d, 2h)),979               tz->get_info( // 1 M +01/+00 & R M 2020 o - Ap 19 3 -1 -980                   to_sys_seconds(2020y, std::chrono::April, 19d, 1h, 59min, 59s))); //981}982 983static void test_africa_ceuta() {984  // Z Africa/Ceuta -0:21:16 - LMT 1900 D 31 23:38:44985  // 0 - WET 1918 May 6 23986  // 0 1 WEST 1918 O 7 23987  // 0 - WET 1924988  // 0 s WE%sT 1929989  // 0 - WET 1967990  // 0 Sp WE%sT 1984 Mar 16991  // 1 - CET 1986992  // 1 E CE%sT993  //994  // ...995  // R s 1926 o - Ap 17 23 1 S996  // R s 1926 1929 - O Sa>=1 24s 0 -997  // R s 1927 o - Ap 9 23 1 S998  // R s 1928 o - Ap 15 0 1 S999  // R s 1929 o - Ap 20 23 1 S1000  // R s 1937 o - Jun 16 23 1 S1001  // ...1002  //1003  // R Sp 1967 o - Jun 3 12 1 S1004  // R Sp 1967 o - O 1 0 0 -1005  // R Sp 1974 o - Jun 24 0 1 S1006  // R Sp 1974 o - S 1 0 0 -1007  // R Sp 1976 1977 - May 1 0 1 S1008  // R Sp 1976 o - Au 1 0 0 -1009  // R Sp 1977 o - S 28 0 0 -1010  // R Sp 1978 o - Jun 1 0 1 S1011  // R Sp 1978 o - Au 4 0 0 -1012 1013  using namespace std::literals::chrono_literals;1014  const std::chrono::time_zone* tz = std::chrono::locate_zone("Africa/Ceuta");1015 1016  assert_range(1017 1018      "[1928-10-07 00:00:00, 1967-06-03 12:00:00) 00:00:00 0min WET",1019      tz->get_info(to_sys_seconds(1928y, std::chrono::October, 7d)),       // 0 s WE%sT 1929 & 1926 1929 O Sa>=1 24s 0 -1020      tz->get_info(                                                        // No transitions in "0 - WET 1967"1021          to_sys_seconds(1967y, std::chrono::June, 3d, 11h, 59min, 59s))); // 0 - WET 1967 & 1967 o Jun 3 12 1 S1022}1023 1024static void test_africa_freetown() {1025  // Z Africa/Freetown -0:53 - LMT 18821026  // -0:53 - FMT 1913 Jul1027  // -1 SL %s 1939 S 51028  // -1 - -01 1941 D 6 241029  // 0 - GMT1030  //1031  // R SL 1932 o - D 1 0 0:20 -00401032  // R SL 1933 1938 - Mar 31 24 0 -011033  // R SL 1933 1939 - Au 31 24 0:20 -00401034  // R SL 1939 o - May 31 24 0 -011035 1036  using namespace std::literals::chrono_literals;1037  const std::chrono::time_zone* tz = std::chrono::locate_zone("Africa/Freetown");1038 1039  // When a continuation has a named rule, the transition time determined by1040  // the active rule can be wrong. The next continuation may set the clock to an1041  // earlier time. This is tested for San Luis. This tests the rule is not used1042  // when the rule is not a named rule.1043  //1044  // Fixes:1045  //   Expected output [1882-01-01 00:53:00, 1913-07-01 00:53:00) -00:53:00 0min FMT1046  //   Actual output   [1882-01-01 00:53:00, 1913-07-01 00:46:00) -00:53:00 0min FMT1047 1048  assert_range("[1882-01-01 00:53:00, 1913-07-01 00:53:00) -00:53:00 0min FMT",1049               tz->get_info(to_sys_seconds(1882y, std::chrono::January, 1d, 0h, 53min)), // -0:53 - FMT 1913 Jul1050               tz->get_info( // -1 SL %s 1939 S 5 & before first rule1051                   to_sys_seconds(1913y, std::chrono::July, 1d, 0h, 52min, 59s)));1052 1053  // Tests whether the "-1 SL %s 1939 S 5" until gets the proper local time1054  // adjustment.1055  assert_range("[1939-09-01 01:00:00, 1939-09-05 00:40:00) -00:40:00 20min -0040",1056               tz->get_info( // -1 SL %s 1939 S 5 & R SL 1933 1939 - Au 31 24 0:20 -00401057                   to_sys_seconds(1939y, std::chrono::September, 1d, 1h)),1058               tz->get_info( // -1 - -01 1941 D 6 241059                   to_sys_seconds(1939y, std::chrono::September, 5d, 0h, 39min, 59s)));1060}1061 1062static void test_africa_windhoek() {1063  // Tests the LETTER/S used before the first rule per1064  // https://data.iana.org/time-zones/tz-how-to.html1065  //   If switching to a named rule before any transition has happened,1066  //   assume standard time (SAVE zero), and use the LETTER data from1067  //   the earliest transition with a SAVE of zero.1068 1069  // Z Africa/Windhoek 1:8:24 - LMT 1892 F 81070  // 1:30 - +0130 1903 Mar1071  // 2 - SAST 1942 S 20 21072  // 2 1 SAST 1943 Mar 21 21073  // 2 - SAST 1990 Mar 211074  // 2 NA %s1075  //1076  // R NA 1994 o - Mar 21 0 -1 WAT1077  // R NA 1994 2017 - S Su>=1 2 0 CAT1078  // R NA 1995 2017 - Ap Su>=1 2 -1 WAT1079 1080  using namespace std::literals::chrono_literals;1081  const std::chrono::time_zone* tz = std::chrono::locate_zone("Africa/Windhoek");1082 1083  assert_range( // 2 - EET 2012 N 10 21084      "[1990-03-20 22:00:00, 1994-03-20 22:00:00) 02:00:00 0min CAT",1085      tz->get_info(to_sys_seconds(1990y, std::chrono::March, 20d, 22h)),1086      tz->get_info(to_sys_seconds(1994y, std::chrono::March, 20d, 21h, 59min, 59s)));1087}1088 1089static void test_america_adak() {1090  // Z America/Adak 12:13:22 - LMT 1867 O 19 12:44:351091  // ...1092  // -11 u B%sT 1983 O 30 21093  // -10 u AH%sT 1983 N 301094  // -10 u H%sT1095  //1096  // ...1097  // R u 1945 o - S 30 2 0 S1098  // R u 1967 2006 - O lastSu 2 0 S1099  // R u 1967 1973 - Ap lastSu 2 1 D1100  // R u 1974 o - Ja 6 2 1 D1101  // R u 1975 o - F lastSu 2 1 D1102  // R u 1976 1986 - Ap lastSu 2 1 D1103  // R u 1987 2006 - Ap Su>=1 2 1 D1104  // ...1105 1106  using namespace std::literals::chrono_literals;1107  const std::chrono::time_zone* tz = std::chrono::locate_zone("America/Adak");1108 1109  assert_range( // 2 - EET 2012 N 10 21110      "[1983-10-30 12:00:00, 1983-11-30 10:00:00) -10:00:00 0min AHST",1111      tz->get_info(to_sys_seconds(1983y, std::chrono::October, 30d, 12h)),              // -11 u B%sT 1983 O 30 21112      tz->get_info(to_sys_seconds(1983y, std::chrono::November, 30d, 9h, 59min, 59s))); // -10 u AH%sT 1983 N 301113}1114 1115static void test_america_auncion() {1116  // R y 2013 ma - Mar Su>=22 0 0 -1117  // Z America/Asuncion -3:50:40 - LMT 18901118  // -3:50:40 - AMT 1931 O 101119  // -4 - -04 1972 O1120  // -3 - -03 1974 Ap1121  // -4 y -04/-031122  //1123  // R y 1975 1988 - O 1 0 1 -1124  // R y 1975 1978 - Mar 1 0 0 -1125  // R y 1979 1991 - Ap 1 0 0 -1126  // ...1127 1128  using namespace std::literals::chrono_literals;1129  const std::chrono::time_zone* tz = std::chrono::locate_zone("America/Asuncion");1130 1131  assert_range("[1974-04-01 03:00:00, 1975-10-01 04:00:00) -04:00:00 0min -04",1132               tz->get_info(to_sys_seconds(1974y, std::chrono::April, 1d, 3h)),1133               tz->get_info(to_sys_seconds(1975y, std::chrono::October, 1d, 3h, 59min, 59s)));1134 1135  assert_range("[1975-10-01 04:00:00, 1976-03-01 03:00:00) -03:00:00 60min -03",1136               tz->get_info(to_sys_seconds(1975y, std::chrono::October, 1d, 4h)),1137               tz->get_info(to_sys_seconds(1976y, std::chrono::March, 1d, 2h, 59min, 59s)));1138}1139 1140static void test_america_ciudad_juarez() {1141  // Z America/Ciudad_Juarez -7:5:56 - LMT 1922 Ja 1 7u1142  // -7 - MST 1927 Jun 10 231143  // -6 - CST 1930 N 151144  // -7 m MST 1932 Ap1145  // -6 - CST 19961146  // -6 m C%sT 19981147  // ...1148  //1149  // R m 1939 o - F 5 0 1 D1150  // R m 1939 o - Jun 25 0 0 S1151  // R m 1940 o - D 9 0 1 D1152  // R m 1941 o - Ap 1 0 0 S1153  // R m 1943 o - D 16 0 1 W1154  // R m 1944 o - May 1 0 0 S1155  // R m 1950 o - F 12 0 1 D1156  // R m 1950 o - Jul 30 0 0 S1157  // R m 1996 2000 - Ap Su>=1 2 1 D1158  // R m 1996 2000 - O lastSu 2 0 S1159  // ...1160 1161  using namespace std::literals::chrono_literals;1162  const std::chrono::time_zone* tz = std::chrono::locate_zone("America/Ciudad_Juarez");1163 1164  // 1996 has a similar issue, instead of __time the __until end before1165  // the first rule in 1939. Between the two usages of RULE Mexico1166  // a different continuation RULE is active1167  assert_range("[1996-04-07 08:00:00, 1996-10-27 07:00:00) -05:00:00 60min CDT",1168               tz->get_info(to_sys_seconds(1996y, std::chrono::April, 7d, 8h)),1169               tz->get_info(to_sys_seconds(1996y, std::chrono::October, 27d, 6h, 59min, 59s)));1170}1171 1172static void test_america_argentina_buenos_aires() {1173  // Z America/Argentina/Buenos_Aires -3:53:48 - LMT 1894 O 311174  // -4:16:48 - CMT 1920 May1175  // -4 - -04 1930 D1176  // -4 A -04/-03 1969 O 51177  // -3 A -03/-02 1999 O 31178  // -4 A -04/-03 2000 Mar 31179  // -3 A -03/-021180  //1181  // ...1182  // R A 1989 1992 - O Su>=15 0 1 -1183  // R A 1999 o - O Su>=1 0 1 -1184  // R A 2000 o - Mar 3 0 0 -1185  // R A 2007 o - D 30 0 1 -1186  // ...1187 1188  // The 1999 switch uses the same rule, but with a different stdoff.1189  //   R A 1999 o - O Su>=1 0 1 -1190  //     stdoff -3 -> 1999-10-03 03:00:001191  //     stdoff -4 -> 1999-10-03 04:00:001192  // This generates an invalid entry and this is evaluated as a transition.1193  // Looking at the zdump like output in libc++ this generates jumps in1194  // the UTC time1195 1196  using namespace std::literals::chrono_literals;1197  const std::chrono::time_zone* tz = std::chrono::locate_zone("America/Argentina/Buenos_Aires");1198 1199  assert_range("[1999-10-03 03:00:00, 2000-03-03 03:00:00) -03:00:00 60min -03",1200               tz->get_info(to_sys_seconds(1999y, std::chrono::October, 3d, 3h)),1201               tz->get_info(to_sys_seconds(2000y, std::chrono::March, 3d, 2h, 59min, 59s)));1202  assert_range("[2000-03-03 03:00:00, 2007-12-30 03:00:00) -03:00:00 0min -03",1203               tz->get_info(to_sys_seconds(2000y, std::chrono::March, 3d, 3h)),1204               tz->get_info(to_sys_seconds(2007y, std::chrono::December, 30d, 2h, 59min, 59s)));1205}1206 1207static void test_america_argentina_la_rioja() {1208  // Z America/Argentina/La_Rioja -4:27:24 - LMT 1894 O 311209  // ...1210  // -4 A -04/-03 1969 O 51211  // -3 A -03/-02 1991 Mar1212  // -4 - -04 1991 May 71213  // -3 A -03/-02 1999 O 31214  // ...1215  //1216  // ...1217  // R A 1988 o - D 1 0 1 -1218  // R A 1989 1993 - Mar Su>=1 0 0 -1219  // R A 1989 1992 - O Su>=15 0 1 -1220  // R A 1999 o - O Su>=1 0 1 -1221  // ...1222 1223  using namespace std::literals::chrono_literals;1224  const std::chrono::time_zone* tz = std::chrono::locate_zone("America/Argentina/La_Rioja");1225 1226  assert_range("[1990-10-21 03:00:00, 1991-03-01 02:00:00) -02:00:00 60min -02",1227               tz->get_info(to_sys_seconds(1990y, std::chrono::October, 21d, 3h)),1228               tz->get_info(to_sys_seconds(1991y, std::chrono::March, 1d, 1h, 59min, 59s)));1229}1230 1231static void test_america_argentina_san_luis() {1232  // Z America/Argentina/San_Luis -4:25:24 - LMT 1894 O 311233  // ...1234  // -4 A -04/-03 1969 O 51235  // -3 A -03/-02 19901236  // -3 1 -02 1990 Mar 141237  // -4 - -04 1990 O 151238  // -4 1 -03 1991 Mar1239  // -4 - -04 1991 Jun1240  // -3 - -03 1999 O 31241  // -4 1 -03 2000 Mar 31242  // -4 - -04 2004 Jul 251243  // -3 A -03/-02 2008 Ja 211244  // -4 Sa -04/-03 2009 O 111245  // -3 - -031246  //1247  // ...1248  // R A 1988 o - D 1 0 1 -1249  // R A 1989 1993 - Mar Su>=1 0 0 -1250  // R A 1989 1992 - O Su>=15 0 1 -1251  // R A 1999 o - O Su>=1 0 1 -1252  // R A 2000 o - Mar 3 0 0 -1253  // R A 2007 o - D 30 0 1 -1254  // R A 2008 2009 - Mar Su>=15 0 0 -1255  // R A 2008 o - O Su>=15 0 1 -1256  //1257  // R Sa 2008 2009 - Mar Su>=8 0 0 -1258  // R Sa 2007 2008 - O Su>=8 0 1 -1259 1260  using namespace std::literals::chrono_literals;1261  const std::chrono::time_zone* tz = std::chrono::locate_zone("America/Argentina/San_Luis");1262 1263  assert_range("[1989-10-15 03:00:00, 1990-03-14 02:00:00) -02:00:00 60min -02",1264               tz->get_info( // -3 A -03/-02 1990 & R A 1989 1992 - O Su>=15 0 1 -1265                   to_sys_seconds(1989y, std::chrono::October, 15d, 3h)),1266               tz->get_info( // UNTIL -3 1 -02 1990 Mar 141267                   to_sys_seconds(1990y, std::chrono::March, 14d, 1h, 59min, 59s)));1268 1269  assert_range("[2008-01-21 02:00:00, 2008-03-09 03:00:00) -03:00:00 60min -03",1270               tz->get_info(to_sys_seconds(2008y, std::chrono::January, 21d, 2h)),1271               tz->get_info(to_sys_seconds(2008y, std::chrono::March, 9d, 2h, 59min, 59s)));1272}1273 1274static void test_america_indiana_knox() {1275  // Z America/Indiana/Knox -5:46:30 - LMT 1883 N 18 12:13:301276  // -6 u C%sT 19471277  // -6 St C%sT 1962 Ap 29 21278  // -5 - EST 1963 O 27 21279  // -6 u C%sT 1991 O 27 21280  // -5 - EST 2006 Ap 2 21281  // -6 u C%sT1282  //1283  // ...1284  // R u 1976 1986 - Ap lastSu 2 1 D1285  // R u 1987 2006 - Ap Su>=1 2 1 D1286  // R u 2007 ma - Mar Su>=8 2 1 D1287  // R u 2007 ma - N Su>=1 2 0 S1288 1289  using namespace std::literals::chrono_literals;1290  const std::chrono::time_zone* tz = std::chrono::locate_zone("America/Indiana/Knox");1291 1292  // The continuations1293  // -5 - EST1294  // -6 u C%sT1295  // have different offsets. The start time of the first active rule in1296  // RULE u should use the offset at the end of -5 - EST.1297  assert_range("[2006-04-02 07:00:00, 2006-10-29 07:00:00) -05:00:00 60min CDT",1298               tz->get_info(to_sys_seconds(2006y, std::chrono::April, 2d, 7h)),1299               tz->get_info(to_sys_seconds(2006y, std::chrono::October, 29d, 6h, 59min, 59s)));1300}1301 1302static void test_america_punta_arenas() {1303  // Z America/Punta_Arenas -4:43:40 - LMT 18901304  // ...1305  // -4 - -04 1919 Jul1306  // -4:42:45 - SMT 1927 S1307  // -5 x -05/-04 1932 S1308  // ...1309  //1310  // R x 1927 1931 - S 1 0 1 -1311  // R x 1928 1932 - Ap 1 0 0 -1312  // ...1313 1314  using namespace std::literals::chrono_literals;1315  const std::chrono::time_zone* tz = std::chrono::locate_zone("America/Punta_Arenas");1316 1317  assert_equal(1318      std::chrono::sys_info(1319          to_sys_seconds(1927y, std::chrono::September, 1d, 4h, 42min, 45s),1320          to_sys_seconds(1928y, std::chrono::April, 1d, 4h),1321          -4h,1322          60min,1323          "-04"),1324      tz->get_info(to_sys_seconds(1927y, std::chrono::September, 1d, 4h, 42min, 45s)));1325 1326  assert_equal(1327      std::chrono::sys_info(1328          to_sys_seconds(1927y, std::chrono::September, 1d, 4h, 42min, 45s),1329          to_sys_seconds(1928y, std::chrono::April, 1d, 4h),1330          -4h,1331          60min,1332          "-04"),1333      tz->get_info(to_sys_seconds(1928y, std::chrono::April, 1d, 3h, 59min, 59s)));1334}1335 1336static void test_europ_ljubljana() {1337  // Z Europe/Ljubljana 0:58:4 - LMT 18841338  // 1 - CET 1941 Ap 18 231339  // 1 c CE%sT 1945 May 8 2s1340  // 1 1 CEST 1945 S 16 2s1341  // 1 - CET 1982 N 271342  // 1 E CE%sT1343  //1344  // ...1345  // R c 1943 o - O 4 2s 0 -1346  // R c 1944 1945 - Ap M>=1 2s 1 S1347  // R c 1944 o - O 2 2s 0 -1348  // R c 1945 o - S 16 2s 0 -1349  // R c 1977 1980 - Ap Su>=1 2s 1 S1350  // ...1351 1352  using namespace std::literals::chrono_literals;1353  const std::chrono::time_zone* tz = std::chrono::locate_zone("Europe/Ljubljana");1354 1355  assert_equal(1356      std::chrono::sys_info(1357          to_sys_seconds(1945y, std::chrono::April, 2d, 1h),1358          to_sys_seconds(1945y, std::chrono::September, 16d, 1h),1359          2h,1360          60min,1361          "CEST"),1362      tz->get_info(to_sys_seconds(1945y, std::chrono::April, 2d, 1h)));1363 1364  assert_equal(1365      std::chrono::sys_info(1366          to_sys_seconds(1945y, std::chrono::April, 2d, 1h),1367          to_sys_seconds(1945y, std::chrono::September, 16d, 1h),1368          2h,1369          60min,1370          "CEST"),1371      tz->get_info(to_sys_seconds(1945y, std::chrono::September, 16d, 0h, 59min, 59s)));1372}1373 1374int main(int, const char**) {1375  // Basic tests1376  test_gmt();1377  test_durations();1378  test_antarctica_syowa();1379  test_asia_hong_kong();1380  test_europe_berlin();1381 1382  test_america_st_johns();1383 1384  // Small tests for not-yet tested conditions1385  test_get_at_standard_time_universal();1386  test_get_at_standard_time_standard();1387  test_get_at_save_universal();1388  test_get_at_rule_standard();1389  test_get_at_rule_universal();1390 1391  test_format_with_alternatives_west();1392  test_format_with_alternatives_east();1393 1394  // Tests based on bugs found1395  test_africa_algiers();1396  test_africa_casablanca();1397  test_africa_ceuta();1398  test_africa_freetown();1399  test_africa_windhoek();1400  test_america_adak();1401  test_america_argentina_buenos_aires();1402  test_america_argentina_la_rioja();1403  test_america_argentina_san_luis();1404  test_america_auncion();1405  test_america_ciudad_juarez();1406  test_america_indiana_knox();1407 1408  // Reverse search bugs1409  test_america_punta_arenas();1410  test_europ_ljubljana();1411 1412  return 0;1413}1414