| 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-exception |
| 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | |
| 9 | // TODO TZDB review the test based on review comments in |
| 10 | // https://github.com/llvm/llvm-project/pull/85619 |
| 11 | |
| 12 | // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23, c++26 |
| 13 | // UNSUPPORTED: no-filesystem, no-localization, no-tzdb |
| 14 | |
| 15 | // XFAIL: libcpp-has-no-experimental-tzdb |
| 16 | // XFAIL: availability-tzdb-missing |
| 17 | |
| 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 data |
| 27 | // may change if new facts are uncovered, future data may change when regions |
| 28 | // change their time zone or daylight saving time. Most tests will not look in |
| 29 | // the future to attempt to avoid issues. All tests list the data on which they |
| 30 | // are based, this makes debugging easier upon failure; including to see whether |
| 31 | // the provided data has not been changed |
| 32 | // |
| 33 | // |
| 34 | // The data in the tests can be validated by using the zdump tool. For |
| 35 | // example |
| 36 | // zdump -v Asia/Hong_Kong |
| 37 | // show all transistions in the Hong Kong time zone. Or |
| 38 | // zdump -c1970,1980 -v Asia/Hong_Kong |
| 39 | // 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 | |
| 64 | static 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 | |
| 79 | static void assert_equal(std::string_view expected, const std::chrono::sys_info& value) { |
| 80 | // Note the output of operator<< is implementation defined, use this |
| 81 | // 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 | |
| 94 | static void |
| 95 | assert_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 | |
| 100 | static 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_2 |
| 107 | |
| 108 | ) { |
| 109 | assert_range(expected_1, begin_1, end_1); |
| 110 | assert_range(expected_2, begin_2, end_2); |
| 111 | } |
| 112 | |
| 113 | /***** ***** TESTS ***** *****/ |
| 114 | |
| 115 | static void test_gmt() { |
| 116 | // Simple zone always valid, no rule entries, lookup using a link. |
| 117 | // L Etc/GMT GMT |
| 118 | // Z Etc/GMT 0 - GMT |
| 119 | |
| 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 valid |
| 147 | } |
| 148 | |
| 149 | static void test_durations() { |
| 150 | // Doesn't test a location, instead tests whether different duration |
| 151 | // 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 | |
| 175 | static void test_antarctica_syowa() { |
| 176 | // One change, no rules, no dst changes |
| 177 | // This change uses an ON field with a day number |
| 178 | // |
| 179 | // There don't seem to be rule-less zones that use last day or a |
| 180 | // contrained day |
| 181 | |
| 182 | // Z Antarctica/Syowa 0 - -00 1957 Ja 29 |
| 183 | // 3 - +03 |
| 184 | |
| 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 | |
| 218 | static void test_asia_hong_kong() { |
| 219 | // A more typical entry, first some hard-coded entires and then at the |
| 220 | // end a rules based entry. This rule is valid for its entire period |
| 221 | // |
| 222 | // Z Asia/Hong_Kong 7:36:42 - LMT 1904 O 30 0:36:42 |
| 223 | // 8 - HKT 1941 Jun 15 3 |
| 224 | // 8 1 HKST 1941 O 1 4 |
| 225 | // 8 0:30 HKWT 1941 D 25 |
| 226 | // 9 - JST 1945 N 18 2 |
| 227 | // 8 HK HK%sT |
| 228 | // |
| 229 | // R HK 1946 o - Ap 21 0 1 S |
| 230 | // R HK 1946 o - D 1 3:30s 0 - |
| 231 | // R HK 1947 o - Ap 13 3:30s 1 S |
| 232 | // R HK 1947 o - N 30 3:30s 0 - |
| 233 | // R HK 1948 o - May 2 3:30s 1 S |
| 234 | // R HK 1948 1952 - O Su>=28 3:30s 0 - |
| 235 | // R HK 1949 1953 - Ap Su>=1 3:30 1 S |
| 236 | // R HK 1953 1964 - O Su>=31 3:30 0 - |
| 237 | // R HK 1954 1964 - Mar Su>=18 3:30 1 S |
| 238 | // R HK 1965 1976 - Ap Su>=16 3:30 1 S |
| 239 | // R HK 1965 1976 - O Su>=16 3:30 0 - |
| 240 | // R HK 1973 o - D 30 3:30 1 S |
| 241 | // R HK 1979 o - May 13 3:30 1 S |
| 242 | // 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:42 |
| 251 | 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:42 |
| 260 | 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 3 |
| 266 | 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 4 |
| 270 | 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 25 |
| 274 | 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 2 |
| 278 | 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%sT |
| 282 | 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%sT |
| 286 | "[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 S |
| 288 | 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 S |
| 292 | |
| 293 | assert_cycle( // 8 HK%sT |
| 294 | "[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 S |
| 296 | 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 S |
| 300 | |
| 301 | assert_cycle( // 8 HK%sT |
| 302 | "[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 S |
| 304 | 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 S |
| 308 | |
| 309 | assert_cycle( // 8 HK%sT |
| 310 | "[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 S |
| 312 | tz->get_info(to_sys_seconds(1949y, std::chrono::October, 29d, 19h, 29min, 59s)), // 1948 1952 O Su>=28 3:30s 0 |
| 313 | "[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 0 |
| 315 | tz->get_info(to_sys_seconds(1950y, std::chrono::April, 1d, 19h, 29min, 59s))); // 1949 1953 Ap Su>=1 3:30 1 S |
| 316 | |
| 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 S |
| 321 | |
| 322 | assert_cycle( // 8 HK%sT |
| 323 | "[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 S |
| 325 | 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 S |
| 329 | |
| 330 | assert_cycle( // 8 HK%sT |
| 331 | "[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 S |
| 333 | 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 S |
| 337 | |
| 338 | assert_range( // 8 HK%sT |
| 339 | "[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 S |
| 341 | 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:30 |
| 346 | tz->get_info(to_sys_seconds(1973y, std::chrono::December, 29d, 19h, 29min, 59s))); // 1973 o - D 30 3:30 1 S |
| 347 | |
| 348 | assert_range( // 8 HK%sT |
| 349 | "[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 S |
| 351 | tz->get_info(to_sys_seconds(1974y, std::chrono::October, 19d, 18h, 29min, 59s))); // 1965 1976 - O Su>=16 3:30 |
| 352 | |
| 353 | assert_range( // 8 HK%sT, between 1973 and 1979 no rule is active so falls back to default |
| 354 | "[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 S |
| 356 | 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 default |
| 359 | "[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 S |
| 362 | |
| 363 | assert_range( // 8 HK%sT |
| 364 | "[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 S |
| 366 | 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 valid |
| 385 | } |
| 386 | |
| 387 | static void test_europe_berlin() { |
| 388 | // A more typical entry, first some hard-coded entires and then at the |
| 389 | // end a rules based entry. This rule is valid for its entire period |
| 390 | // |
| 391 | |
| 392 | // Z Europe/Berlin 0:53:28 - LMT 1893 Ap |
| 393 | // 1 c CE%sT 1945 May 24 2 |
| 394 | // 1 So CE%sT 1946 |
| 395 | // 1 DE CE%sT 1980 |
| 396 | // 1 E CE%sT |
| 397 | // |
| 398 | // R c 1916 o - Ap 30 23 1 S |
| 399 | // R c 1916 o - O 1 1 0 - |
| 400 | // R c 1917 1918 - Ap M>=15 2s 1 S |
| 401 | // R c 1917 1918 - S M>=15 2s 0 - |
| 402 | // R c 1940 o - Ap 1 2s 1 S |
| 403 | // R c 1942 o - N 2 2s 0 - |
| 404 | // R c 1943 o - Mar 29 2s 1 S |
| 405 | // R c 1943 o - O 4 2s 0 - |
| 406 | // R c 1944 1945 - Ap M>=1 2s 1 S |
| 407 | // 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 S |
| 410 | // 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 S |
| 414 | // R c 1996 ma - O lastSu 2s 0 - |
| 415 | // |
| 416 | // R So 1945 o - May 24 2 2 M |
| 417 | // R So 1945 o - S 24 3 1 S |
| 418 | // R So 1945 o - N 18 2s 0 - |
| 419 | // |
| 420 | // R DE 1946 o - Ap 14 2s 1 S |
| 421 | // 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 S |
| 424 | // R DE 1947 o - May 11 2s 2 M |
| 425 | // R DE 1947 o - Jun 29 3 1 S |
| 426 | // R DE 1948 o - Ap 18 2s 1 S |
| 427 | // R DE 1949 o - Ap 10 2s 1 S |
| 428 | // |
| 429 | // R E 1977 1980 - Ap Su>=1 1u 1 S |
| 430 | // 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 S |
| 434 | // R E 1996 ma - O lastSu 1u 0 - |
| 435 | // |
| 436 | // Note the European Union decided to stop the seasonal change in |
| 437 | // 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 Ap |
| 446 | 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 Ap |
| 455 | 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 S |
| 462 | "[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%sT |
| 468 | "[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 S |
| 470 | 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 S |
| 474 | |
| 475 | assert_cycle( |
| 476 | // 1 CE%sT |
| 477 | "[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 S |
| 479 | 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 S |
| 483 | |
| 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 S |
| 488 | 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 S |
| 492 | |
| 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 S |
| 497 | 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 S |
| 501 | |
| 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/time |
| 505 | // There is a tricky part in the time |
| 506 | // "1 c CE%sT" has an offset of 1 at the moment the rule |
| 507 | // ends there is a save of 60 minutes. This means the |
| 508 | // local offset to UTC is 2 hours. The rule ends at |
| 509 | // 1945-05-24 02:00:00 local time, which is |
| 510 | // 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 S |
| 513 | tz->get_info(to_sys_seconds(1945y, std::chrono::May, 23d, 23h, 59min, 59s))); // 1 c CE%sT & 1945 May 24 2 |
| 514 | |
| 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 2 |
| 518 | tz->get_info(to_sys_seconds(1945y, std::chrono::September, 23d, 23h, 59min, 59s))); // 1945 o S 24 3 1 S |
| 519 | |
| 520 | assert_range( |
| 521 | // 1 c CE%sT 1945 May 24 2 |
| 522 | "[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 S |
| 524 | 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 continuations |
| 527 | "[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 S |
| 530 | |
| 531 | assert_range( |
| 532 | // 1 DE CE%sT 1980 |
| 533 | "[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 S |
| 535 | 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 rules |
| 538 | // R DE 1947 1949 - O Su>=1 2s 0 - |
| 539 | // R DE 1947 o - Ap 6 3s 1 S |
| 540 | // R DE 1947 o - May 11 2s 2 M |
| 541 | // R DE 1947 o - Jun 29 3 1 S |
| 542 | assert_range( |
| 543 | // 1 DE CE%sT 1980 |
| 544 | "[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 S |
| 547 | |
| 548 | assert_range( |
| 549 | // 1 DE CE%sT 1980 |
| 550 | "[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 S |
| 552 | tz->get_info(to_sys_seconds(1947y, std::chrono::May, 11d, 0h, 59min, 59s))); // 1947 o May 11 2s 2 M |
| 553 | |
| 554 | assert_range( |
| 555 | // 1 DE CE%sT 1980 |
| 556 | "[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 M |
| 558 | tz->get_info(to_sys_seconds(1947y, std::chrono::June, 28d, 23h, 59min, 59s))); // 1947 o Jun 29 3 1 S |
| 559 | |
| 560 | assert_cycle( |
| 561 | // 1 DE CE%sT 1980 |
| 562 | "[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 S |
| 564 | 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 S |
| 568 | |
| 569 | assert_cycle( |
| 570 | // 1 DE CE%sT 1980 |
| 571 | "[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 S |
| 573 | 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 S |
| 577 | |
| 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 1980 |
| 580 | tz->get_info(to_sys_seconds(1949y, std::chrono::April, 10d, 1h)), // 1949 o Ap 10 2s 1 S |
| 581 | 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%sT |
| 585 | to_sys_seconds(1980y, std::chrono::April, 6d, 0h, 59min, 59s))); // 1977 1980 Ap Su>=1 1u 1 S |
| 586 | |
| 587 | assert_cycle( |
| 588 | // 1 E CE%sT |
| 589 | "[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 S |
| 591 | 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 S |
| 595 | |
| 596 | assert_cycle( |
| 597 | // 1 E CE%sT |
| 598 | "[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 S |
| 600 | 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 S |
| 604 | } |
| 605 | |
| 606 | static void test_america_st_johns() { |
| 607 | // A more typical entry, |
| 608 | // Uses letters both when DST is ative and not and has multiple |
| 609 | // letters. Uses negetive offsets. |
| 610 | // Switches several times between their own and Canadian rules |
| 611 | // Switches the stdoff from -3:30:52 to -3:30 while observing the same rule |
| 612 | |
| 613 | // Z America/St_Johns -3:30:52 - LMT 1884 |
| 614 | // -3:30:52 j N%sT 1918 |
| 615 | // -3:30:52 C N%sT 1919 |
| 616 | // -3:30:52 j N%sT 1935 Mar 30 |
| 617 | // -3:30 j N%sT 1942 May 11 |
| 618 | // -3:30 C N%sT 1946 |
| 619 | // -3:30 j N%sT 2011 N |
| 620 | // -3:30 C N%sT |
| 621 | // |
| 622 | // R j 1917 o - Ap 8 2 1 D |
| 623 | // R j 1917 o - S 17 2 0 S |
| 624 | // R j 1919 o - May 5 23 1 D |
| 625 | // R j 1919 o - Au 12 23 0 S |
| 626 | // R j 1920 1935 - May Su>=1 23 1 D |
| 627 | // R j 1920 1935 - O lastSu 23 0 S |
| 628 | // R j 1936 1941 - May M>=9 0 1 D |
| 629 | // R j 1936 1941 - O M>=2 0 0 S |
| 630 | // R j 1946 1950 - May Su>=8 2 1 D |
| 631 | // R j 1946 1950 - O Su>=2 2 0 S |
| 632 | // R j 1951 1986 - Ap lastSu 2 1 D |
| 633 | // R j 1951 1959 - S lastSu 2 0 S |
| 634 | // R j 1960 1986 - O lastSu 2 0 S |
| 635 | // R j 1987 o - Ap Su>=1 0:1 1 D |
| 636 | // R j 1987 2006 - O lastSu 0:1 0 S |
| 637 | // R j 1988 o - Ap Su>=1 0:1 2 DD |
| 638 | // R j 1989 2006 - Ap Su>=1 0:1 1 D |
| 639 | // R j 2007 2011 - Mar Su>=8 0:1 1 D |
| 640 | // R j 2007 2010 - N Su>=1 0:1 0 S |
| 641 | // |
| 642 | // R C 1918 o - Ap 14 2 1 D |
| 643 | // R C 1918 o - O 27 2 0 S |
| 644 | // R C 1942 o - F 9 2 1 W |
| 645 | // R C 1945 o - Au 14 23u 1 P |
| 646 | // R C 1945 o - S 30 2 0 S |
| 647 | // R C 1974 1986 - Ap lastSu 2 1 D |
| 648 | // R C 1974 2006 - O lastSu 2 0 S |
| 649 | // R C 1987 2006 - Ap Su>=1 2 1 D |
| 650 | // R C 2007 ma - Mar Su>=8 2 1 D |
| 651 | // R C 2007 ma - N Su>=1 2 0 S |
| 652 | |
| 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 1884 |
| 660 | -(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 1884 |
| 669 | -(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 1918 |
| 675 | "[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 active |
| 677 | tz->get_info(to_sys_seconds(1917y, std::chrono::April, 8d, 5h, 30min, 51s))); // 1917 o Ap 8 2 1 D |
| 678 | |
| 679 | assert_range( // -3:30:52 j N%sT 1918 |
| 680 | "[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 D |
| 682 | tz->get_info(to_sys_seconds(1917y, std::chrono::September, 17d, 4h, 30min, 51s))); // 1917 o S 17 2 0 S |
| 683 | |
| 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 1918 |
| 686 | to_sys_seconds(1917y, std::chrono::September, 17d, 4h, 30min, 52s)), // 1917 o S 17 2 0 S |
| 687 | tz->get_info( // -3:30:52 C N%sT 1919 |
| 688 | to_sys_seconds(1918y, std::chrono::April, 14d, 5h, 30min, 51s))); // 1918 o Ap 14 2 1 D |
| 689 | |
| 690 | assert_range( // -3:30:52 C N%sT 1919 |
| 691 | "[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 D |
| 693 | tz->get_info(to_sys_seconds(1918y, std::chrono::October, 27d, 4h, 30min, 51s))); // 1918 o O 27 2 0 S |
| 694 | |
| 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 1919 |
| 697 | to_sys_seconds(1918y, std::chrono::October, 27d, 4h, 30min, 52s)), // 1918 o O 27 2 0 S |
| 698 | tz->get_info( // -3:30:52 j N%sT 1935 Mar 30 |
| 699 | to_sys_seconds(1919y, std::chrono::May, 6d, 2h, 30min, 51s))); // 1919 o May 5 23 1 D |
| 700 | |
| 701 | assert_range( // -3:30:52 j N%sT 1935 Mar 30 |
| 702 | "[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 S |
| 704 | tz->get_info(to_sys_seconds(1935y, std::chrono::March, 30d, 3h, 30min, 51s))); // 1920 1935 May Su>=1 23 1 D |
| 705 | |
| 706 | assert_range( // -3:30 j N%sT 1942 May 11 |
| 707 | // 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 S |
| 710 | tz->get_info(to_sys_seconds(1935y, std::chrono::May, 6d, 2h, 29min, 59s))); // 1920 1935 May Su>=1 23 1 D |
| 711 | |
| 712 | assert_range( // -3:30 j N%sT 1942 May 11 |
| 713 | "[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 D |
| 715 | tz->get_info(to_sys_seconds(1935y, std::chrono::October, 28d, 1h, 29min, 59s))); // 1920 1935 O lastSu 23 0 S |
| 716 | |
| 717 | assert_range( // -3:30 j N%sT 1942 May 11 |
| 718 | "[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 S |
| 720 | tz->get_info(to_sys_seconds(1942y, std::chrono::May, 11d, 3h, 29min, 59s))); // 1946 1950 May Su>=8 2 1 D |
| 721 | |
| 722 | assert_range( // -3:30 C N%sT 1946 |
| 723 | "[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 W |
| 725 | tz->get_info(to_sys_seconds(1945y, std::chrono::August, 14d, 22h, 59min, 59s))); // 1945 o Au 14 23u 1 P |
| 726 | |
| 727 | assert_range( // -3:30 C N%sT 1946 |
| 728 | "[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 P |
| 730 | tz->get_info(to_sys_seconds(1945y, std::chrono::September, 30d, 4h, 29min, 59s))); // 1945 o S 30 2 0 S |
| 731 | |
| 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 S |
| 736 | 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 D |
| 738 | |
| 739 | assert_range( // -3:30 j N%sT 2011 N |
| 740 | "[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 DD |
| 742 | tz->get_info(to_sys_seconds(1988y, std::chrono::October, 30d, 1h, 30min, 59s))); // 1987 2006 O lastSu 0:1 0 S |
| 743 | |
| 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 N |
| 746 | to_sys_seconds(2011y, std::chrono::March, 13d, 3h, 31min, 0s)), // 2007 2011 Mar Su>=8 0:1 1 D |
| 747 | tz->get_info( // -3:30 C N%sT |
| 748 | to_sys_seconds(2011y, std::chrono::November, 6d, 04h, 29min, 59s))); // 2007 ma N Su>=1 2 0 S |
| 749 | } |
| 750 | |
| 751 | static void test_get_at_standard_time_universal() { |
| 752 | // Z Asia/Barnaul 5:35 - LMT 1919 D 10 |
| 753 | // ... |
| 754 | // 7 R +07/+08 1995 May 28 |
| 755 | // 6 R +06/+07 2011 Mar 27 2s |
| 756 | // ... |
| 757 | // |
| 758 | // ... |
| 759 | // R R 1985 2010 - Mar lastSu 2s 1 S |
| 760 | // 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 | |
| 775 | static void test_get_at_standard_time_standard() { |
| 776 | // Z Africa/Bissau -1:2:20 - LMT 1912 Ja 1 1u |
| 777 | 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 | |
| 790 | static void test_get_at_save_universal() { |
| 791 | // Z America/Tijuana -7:48:4 - LMT 1922 Ja 1 0:11:56 |
| 792 | // -7 - MST 1924 |
| 793 | // -8 - PST 1927 Jun 10 23 |
| 794 | // -7 - MST 1930 N 15 |
| 795 | // -8 - PST 1931 Ap |
| 796 | // -8 1 PDT 1931 S 30 |
| 797 | // -8 - PST 1942 Ap 24 |
| 798 | // -8 1 PWT 1945 Au 14 23u |
| 799 | // ... |
| 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 | |
| 814 | static void test_get_at_rule_standard() { |
| 815 | // Z Antarctica/Macquarie 0 - -00 1899 N |
| 816 | // 10 - AEST 1916 O 1 2 |
| 817 | // 10 1 AEDT 1917 F |
| 818 | // 10 AU AE%sT 1919 Ap 1 0s |
| 819 | // ... |
| 820 | // |
| 821 | // R AU 1917 o - Ja 1 2s 1 D |
| 822 | // R AU 1917 o - Mar lastSu 2s 0 S |
| 823 | // R AU 1942 o - Ja 1 2s 1 D |
| 824 | // ... |
| 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 | |
| 840 | static void test_get_at_rule_universal() { |
| 841 | // Z America/Nuuk -3:26:56 - LMT 1916 Jul 28 |
| 842 | // -3 - -03 1980 Ap 6 2 |
| 843 | // -3 E -03/-02 2023 O 29 1u |
| 844 | // -2 E -02/-01 |
| 845 | // |
| 846 | // R E 1977 1980 - Ap Su>=1 1u 1 S |
| 847 | // 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 S |
| 851 | // 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 | |
| 866 | static void test_format_with_alternatives_west() { |
| 867 | // Z America/Nuuk -3:26:56 - LMT 1916 Jul 28 |
| 868 | // -3 - -03 1980 Ap 6 2 |
| 869 | // -3 E -03/-02 2023 O 29 1u |
| 870 | // -2 E -02/-01 |
| 871 | // |
| 872 | // ... |
| 873 | // R E 1981 ma - Mar lastSu 1u 1 S |
| 874 | // 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/-02 |
| 880 | "[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 S |
| 882 | 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 S |
| 886 | } |
| 887 | |
| 888 | static void test_format_with_alternatives_east() { |
| 889 | // Z Asia/Barnaul 5:35 - LMT 1919 D 10 |
| 890 | // ... |
| 891 | // 6 R +06/+07 2011 Mar 27 2s |
| 892 | // ... |
| 893 | // |
| 894 | // ... |
| 895 | // R R 1985 2010 - Mar lastSu 2s 1 S |
| 896 | // 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 2s |
| 902 | "[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 S |
| 904 | 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 S |
| 908 | } |
| 909 | |
| 910 | static 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 21 |
| 924 | 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 26 |
| 928 | 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 | |
| 932 | static void test_africa_casablanca() { |
| 933 | // Z Africa/Casablanca -0:30:20 - LMT 1913 O 26 |
| 934 | // 0 M +00/+01 1984 Mar 16 |
| 935 | // 1 - +01 1986 |
| 936 | // 0 M +00/+01 2018 O 28 3 |
| 937 | // 1 M +01/+00 |
| 938 | // |
| 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/+00 |
| 971 | // Note the SAVE contains a negative value |
| 972 | 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 | |
| 983 | static void test_africa_ceuta() { |
| 984 | // Z Africa/Ceuta -0:21:16 - LMT 1900 D 31 23:38:44 |
| 985 | // 0 - WET 1918 May 6 23 |
| 986 | // 0 1 WEST 1918 O 7 23 |
| 987 | // 0 - WET 1924 |
| 988 | // 0 s WE%sT 1929 |
| 989 | // 0 - WET 1967 |
| 990 | // 0 Sp WE%sT 1984 Mar 16 |
| 991 | // 1 - CET 1986 |
| 992 | // 1 E CE%sT |
| 993 | // |
| 994 | // ... |
| 995 | // R s 1926 o - Ap 17 23 1 S |
| 996 | // R s 1926 1929 - O Sa>=1 24s 0 - |
| 997 | // R s 1927 o - Ap 9 23 1 S |
| 998 | // R s 1928 o - Ap 15 0 1 S |
| 999 | // R s 1929 o - Ap 20 23 1 S |
| 1000 | // R s 1937 o - Jun 16 23 1 S |
| 1001 | // ... |
| 1002 | // |
| 1003 | // R Sp 1967 o - Jun 3 12 1 S |
| 1004 | // R Sp 1967 o - O 1 0 0 - |
| 1005 | // R Sp 1974 o - Jun 24 0 1 S |
| 1006 | // R Sp 1974 o - S 1 0 0 - |
| 1007 | // R Sp 1976 1977 - May 1 0 1 S |
| 1008 | // 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 S |
| 1011 | // 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 S |
| 1022 | } |
| 1023 | |
| 1024 | static void test_africa_freetown() { |
| 1025 | // Z Africa/Freetown -0:53 - LMT 1882 |
| 1026 | // -0:53 - FMT 1913 Jul |
| 1027 | // -1 SL %s 1939 S 5 |
| 1028 | // -1 - -01 1941 D 6 24 |
| 1029 | // 0 - GMT |
| 1030 | // |
| 1031 | // R SL 1932 o - D 1 0 0:20 -0040 |
| 1032 | // R SL 1933 1938 - Mar 31 24 0 -01 |
| 1033 | // R SL 1933 1939 - Au 31 24 0:20 -0040 |
| 1034 | // R SL 1939 o - May 31 24 0 -01 |
| 1035 | |
| 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 tranisition time determined by |
| 1040 | // the active rule can be wrong. The next continuation may set the clock to an |
| 1041 | // earlier time. This is tested for San Luis. This tests the rule is not used |
| 1042 | // 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 FMT |
| 1046 | // Actual output [1882-01-01 00:53:00, 1913-07-01 00:46:00) -00:53:00 0min FMT |
| 1047 | |
| 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 Jul |
| 1050 | tz->get_info( // -1 SL %s 1939 S 5 & before first rule |
| 1051 | 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 time |
| 1054 | // 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 -0040 |
| 1057 | to_sys_seconds(1939y, std::chrono::September, 1d, 1h)), |
| 1058 | tz->get_info( // -1 - -01 1941 D 6 24 |
| 1059 | to_sys_seconds(1939y, std::chrono::September, 5d, 0h, 39min, 59s))); |
| 1060 | } |
| 1061 | |
| 1062 | static void test_africa_windhoek() { |
| 1063 | // Tests the LETTER/S used before the first rule per |
| 1064 | // https://data.iana.org/time-zones/tz-how-to.html |
| 1065 | // If switching to a named rule before any transition has happened, |
| 1066 | // assume standard time (SAVE zero), and use the LETTER data from |
| 1067 | // the earliest transition with a SAVE of zero. |
| 1068 | |
| 1069 | // Z Africa/Windhoek 1:8:24 - LMT 1892 F 8 |
| 1070 | // 1:30 - +0130 1903 Mar |
| 1071 | // 2 - SAST 1942 S 20 2 |
| 1072 | // 2 1 SAST 1943 Mar 21 2 |
| 1073 | // 2 - SAST 1990 Mar 21 |
| 1074 | // 2 NA %s |
| 1075 | // |
| 1076 | // R NA 1994 o - Mar 21 0 -1 WAT |
| 1077 | // R NA 1994 2017 - S Su>=1 2 0 CAT |
| 1078 | // R NA 1995 2017 - Ap Su>=1 2 -1 WAT |
| 1079 | |
| 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 2 |
| 1084 | "[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 | |
| 1089 | static void test_america_adak() { |
| 1090 | // Z America/Adak 12:13:22 - LMT 1867 O 19 12:44:35 |
| 1091 | // ... |
| 1092 | // -11 u B%sT 1983 O 30 2 |
| 1093 | // -10 u AH%sT 1983 N 30 |
| 1094 | // -10 u H%sT |
| 1095 | // |
| 1096 | // ... |
| 1097 | // R u 1945 o - S 30 2 0 S |
| 1098 | // R u 1967 2006 - O lastSu 2 0 S |
| 1099 | // R u 1967 1973 - Ap lastSu 2 1 D |
| 1100 | // R u 1974 o - Ja 6 2 1 D |
| 1101 | // R u 1975 o - F lastSu 2 1 D |
| 1102 | // R u 1976 1986 - Ap lastSu 2 1 D |
| 1103 | // R u 1987 2006 - Ap Su>=1 2 1 D |
| 1104 | // ... |
| 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 2 |
| 1110 | "[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 2 |
| 1112 | tz->get_info(to_sys_seconds(1983y, std::chrono::November, 30d, 9h, 59min, 59s))); // -10 u AH%sT 1983 N 30 |
| 1113 | } |
| 1114 | |
| 1115 | static void test_america_auncion() { |
| 1116 | // R y 2013 ma - Mar Su>=22 0 0 - |
| 1117 | // Z America/Asuncion -3:50:40 - LMT 1890 |
| 1118 | // -3:50:40 - AMT 1931 O 10 |
| 1119 | // -4 - -04 1972 O |
| 1120 | // -3 - -03 1974 Ap |
| 1121 | // -4 y -04/-03 |
| 1122 | // |
| 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 | |
| 1140 | static void test_america_ciudad_juarez() { |
| 1141 | // Z America/Ciudad_Juarez -7:5:56 - LMT 1922 Ja 1 7u |
| 1142 | // -7 - MST 1927 Jun 10 23 |
| 1143 | // -6 - CST 1930 N 15 |
| 1144 | // -7 m MST 1932 Ap |
| 1145 | // -6 - CST 1996 |
| 1146 | // -6 m C%sT 1998 |
| 1147 | // ... |
| 1148 | // |
| 1149 | // R m 1939 o - F 5 0 1 D |
| 1150 | // R m 1939 o - Jun 25 0 0 S |
| 1151 | // R m 1940 o - D 9 0 1 D |
| 1152 | // R m 1941 o - Ap 1 0 0 S |
| 1153 | // R m 1943 o - D 16 0 1 W |
| 1154 | // R m 1944 o - May 1 0 0 S |
| 1155 | // R m 1950 o - F 12 0 1 D |
| 1156 | // R m 1950 o - Jul 30 0 0 S |
| 1157 | // R m 1996 2000 - Ap Su>=1 2 1 D |
| 1158 | // R m 1996 2000 - O lastSu 2 0 S |
| 1159 | // ... |
| 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 before |
| 1165 | // the first rule in 1939. Between the two usages of RULE Mexico |
| 1166 | // a different continuation RULE is active |
| 1167 | 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 | |
| 1172 | static void test_america_argentina_buenos_aires() { |
| 1173 | // Z America/Argentina/Buenos_Aires -3:53:48 - LMT 1894 O 31 |
| 1174 | // -4:16:48 - CMT 1920 May |
| 1175 | // -4 - -04 1930 D |
| 1176 | // -4 A -04/-03 1969 O 5 |
| 1177 | // -3 A -03/-02 1999 O 3 |
| 1178 | // -4 A -04/-03 2000 Mar 3 |
| 1179 | // -3 A -03/-02 |
| 1180 | // |
| 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:00 |
| 1191 | // stdoff -4 -> 1999-10-03 04:00:00 |
| 1192 | // This generates an invalid entry and this is evaluated as a transition. |
| 1193 | // Looking at the zdump like output in libc++ this generates jumps in |
| 1194 | // the UTC time |
| 1195 | |
| 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 | |
| 1207 | static void test_america_argentina_la_rioja() { |
| 1208 | // Z America/Argentina/La_Rioja -4:27:24 - LMT 1894 O 31 |
| 1209 | // ... |
| 1210 | // -4 A -04/-03 1969 O 5 |
| 1211 | // -3 A -03/-02 1991 Mar |
| 1212 | // -4 - -04 1991 May 7 |
| 1213 | // -3 A -03/-02 1999 O 3 |
| 1214 | // ... |
| 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 | |
| 1231 | static void test_america_argentina_san_luis() { |
| 1232 | // Z America/Argentina/San_Luis -4:25:24 - LMT 1894 O 31 |
| 1233 | // ... |
| 1234 | // -4 A -04/-03 1969 O 5 |
| 1235 | // -3 A -03/-02 1990 |
| 1236 | // -3 1 -02 1990 Mar 14 |
| 1237 | // -4 - -04 1990 O 15 |
| 1238 | // -4 1 -03 1991 Mar |
| 1239 | // -4 - -04 1991 Jun |
| 1240 | // -3 - -03 1999 O 3 |
| 1241 | // -4 1 -03 2000 Mar 3 |
| 1242 | // -4 - -04 2004 Jul 25 |
| 1243 | // -3 A -03/-02 2008 Ja 21 |
| 1244 | // -4 Sa -04/-03 2009 O 11 |
| 1245 | // -3 - -03 |
| 1246 | // |
| 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 14 |
| 1267 | 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 | |
| 1274 | static void test_america_indiana_knox() { |
| 1275 | // Z America/Indiana/Knox -5:46:30 - LMT 1883 N 18 12:13:30 |
| 1276 | // -6 u C%sT 1947 |
| 1277 | // -6 St C%sT 1962 Ap 29 2 |
| 1278 | // -5 - EST 1963 O 27 2 |
| 1279 | // -6 u C%sT 1991 O 27 2 |
| 1280 | // -5 - EST 2006 Ap 2 2 |
| 1281 | // -6 u C%sT |
| 1282 | // |
| 1283 | // ... |
| 1284 | // R u 1976 1986 - Ap lastSu 2 1 D |
| 1285 | // R u 1987 2006 - Ap Su>=1 2 1 D |
| 1286 | // R u 2007 ma - Mar Su>=8 2 1 D |
| 1287 | // R u 2007 ma - N Su>=1 2 0 S |
| 1288 | |
| 1289 | using namespace std::literals::chrono_literals; |
| 1290 | const std::chrono::time_zone* tz = std::chrono::locate_zone("America/Indiana/Knox" ); |
| 1291 | |
| 1292 | // The continuations |
| 1293 | // -5 - EST |
| 1294 | // -6 u C%sT |
| 1295 | // have different offsets. The start time of the first active rule in |
| 1296 | // 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 | |
| 1302 | static void test_america_punta_arenas() { |
| 1303 | // Z America/Punta_Arenas -4:43:40 - LMT 1890 |
| 1304 | // ... |
| 1305 | // -4 - -04 1919 Jul |
| 1306 | // -4:42:45 - SMT 1927 S |
| 1307 | // -5 x -05/-04 1932 S |
| 1308 | // ... |
| 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 | |
| 1336 | static void test_europ_ljubljana() { |
| 1337 | // Z Europe/Ljubljana 0:58:4 - LMT 1884 |
| 1338 | // 1 - CET 1941 Ap 18 23 |
| 1339 | // 1 c CE%sT 1945 May 8 2s |
| 1340 | // 1 1 CEST 1945 S 16 2s |
| 1341 | // 1 - CET 1982 N 27 |
| 1342 | // 1 E CE%sT |
| 1343 | // |
| 1344 | // ... |
| 1345 | // R c 1943 o - O 4 2s 0 - |
| 1346 | // R c 1944 1945 - Ap M>=1 2s 1 S |
| 1347 | // 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 S |
| 1350 | // ... |
| 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 | |
| 1374 | int main(int, const char**) { |
| 1375 | // Basic tests |
| 1376 | 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 conditions |
| 1385 | 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 found |
| 1395 | 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 bugs |
| 1409 | test_america_punta_arenas(); |
| 1410 | test_europ_ljubljana(); |
| 1411 | |
| 1412 | return 0; |
| 1413 | } |
| 1414 | |