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 // UNSUPPORTED: c++03, c++11, c++14, c++17
10 // UNSUPPORTED: no-filesystem, no-localization, no-tzdb
11 // REQUIRES: long_tests
12
13 // XFAIL: libcpp-has-no-experimental-tzdb
14 // XFAIL: availability-tzdb-missing
15
16 // TODO TZDB Investigate why this fails.
17 // UNSUPPORTED: target={{.*}}
18
19 // <chrono>
20
21 // class time_zone;
22
23 // template <class _Duration>
24 // local_info get_info(const local_time<_Duration>& time) const;
25
26 // This test uses the system provided database. This makes the test portable,
27 // but may cause failures when the database information changes. Historic data
28 // may change if new facts are uncovered, future data may change when regions
29 // change their time zone or daylight saving time. Most tests will not look in
30 // the future to attempt to avoid issues. All tests list the data on which they
31 // are based, this makes debugging easier upon failure; including to see whether
32 // the provided data has not been changed.
33 //
34 // The first part of the test is manually crafted, the second part compares the
35 // transitions for all time zones in the database.
36
37 #include <algorithm>
38 #include <cassert>
39 #include <chrono>
40 #include <format>
41
42 #include "test_macros.h"
43 #include "assert_macros.h"
44 #include "concat_macros.h"
45
46 // The year range to validate. The dates used in practice are expected to be
47 // inside the tested range.
48 constexpr std::chrono::year first{1800};
49 constexpr std::chrono::year last{2100};
50
51 /***** ***** HELPERS ***** *****/
52
to_sys_seconds(std::chrono::year year,std::chrono::month month,std::chrono::day day,std::chrono::hours h=std::chrono::hours (0),std::chrono::minutes m=std::chrono::minutes{0},std::chrono::seconds s=std::chrono::seconds{0})53 [[nodiscard]] static std::chrono::sys_seconds to_sys_seconds(
54 std::chrono::year year,
55 std::chrono::month month,
56 std::chrono::day day,
57 std::chrono::hours h = std::chrono::hours(0),
58 std::chrono::minutes m = std::chrono::minutes{0},
59 std::chrono::seconds s = std::chrono::seconds{0}) {
60 std::chrono::year_month_day result{year, month, day};
61
62 return std::chrono::time_point_cast<std::chrono::seconds>(static_cast<std::chrono::sys_days>(result)) + h + m + s;
63 }
64
to_local_seconds(std::chrono::year year,std::chrono::month month,std::chrono::day day,std::chrono::hours h=std::chrono::hours (0),std::chrono::minutes m=std::chrono::minutes{0},std::chrono::seconds s=std::chrono::seconds{0})65 [[nodiscard]] static std::chrono::local_seconds to_local_seconds(
66 std::chrono::year year,
67 std::chrono::month month,
68 std::chrono::day day,
69 std::chrono::hours h = std::chrono::hours(0),
70 std::chrono::minutes m = std::chrono::minutes{0},
71 std::chrono::seconds s = std::chrono::seconds{0}) {
72 std::chrono::year_month_day result{year, month, day};
73
74 return std::chrono::time_point_cast<std::chrono::seconds>(static_cast<std::chrono::local_days>(result)) + h + m + s;
75 }
76
assert_equal(const std::chrono::sys_info & lhs,const std::chrono::sys_info & rhs)77 static void assert_equal(const std::chrono::sys_info& lhs, const std::chrono::sys_info& rhs) {
78 TEST_REQUIRE(lhs.begin == rhs.begin,
79 TEST_WRITE_CONCATENATED("\nBegin:\nExpected output ", lhs.begin, "\nActual output ", rhs.begin, '\n'));
80 TEST_REQUIRE(lhs.end == rhs.end,
81 TEST_WRITE_CONCATENATED("\nEnd:\nExpected output ", lhs.end, "\nActual output ", rhs.end, '\n'));
82 TEST_REQUIRE(
83 lhs.offset == rhs.offset,
84 TEST_WRITE_CONCATENATED("\nOffset:\nExpected output ", lhs.offset, "\nActual output ", rhs.offset, '\n'));
85 TEST_REQUIRE(lhs.save == rhs.save,
86 TEST_WRITE_CONCATENATED("\nSave:\nExpected output ", lhs.save, "\nActual output ", rhs.save, '\n'));
87 TEST_REQUIRE(
88 lhs.abbrev == rhs.abbrev,
89 TEST_WRITE_CONCATENATED("\nAbbrev:\nExpected output ", lhs.abbrev, "\nActual output ", rhs.abbrev, '\n'));
90 }
91
assert_equal(const std::chrono::local_info & lhs,const std::chrono::local_info & rhs)92 static void assert_equal(const std::chrono::local_info& lhs, const std::chrono::local_info& rhs) {
93 TEST_REQUIRE(
94 lhs.result == rhs.result,
95 TEST_WRITE_CONCATENATED("\nResult:\nExpected output ", lhs.result, "\nActual output ", rhs.result, '\n'));
96
97 assert_equal(lhs.first, rhs.first);
98 assert_equal(lhs.second, rhs.second);
99 }
100
101 /***** ***** TESTS ***** *****/
102
test_gmt()103 static void test_gmt() {
104 // Simple zone always valid, no rule entries, lookup using a link.
105 // L Etc/GMT GMT
106 // Z Etc/GMT 0 - GMT
107
108 using namespace std::literals::chrono_literals;
109 const std::chrono::time_zone* tz = std::chrono::locate_zone("GMT");
110
111 assert_equal(
112 std::chrono::local_info(
113 std::chrono::local_info::unique,
114 std::chrono::sys_info(std::chrono::sys_seconds::min(), std::chrono::sys_seconds::max(), 0s, 0min, "GMT"),
115 std::chrono::sys_info(std::chrono::sys_seconds(0s), std::chrono::sys_seconds(0s), 0s, 0min, "")),
116 tz->get_info(std::chrono::local_seconds::min()));
117 }
118
test_local_time_out_of_range()119 static void test_local_time_out_of_range() {
120 // Fixed positive offset
121 // Etc/GMT-1 1 - +01
122
123 using namespace std::literals::chrono_literals;
124 { // lower bound
125 const std::chrono::time_zone* tz = std::chrono::locate_zone("Etc/GMT-1");
126
127 assert_equal(
128 std::chrono::local_info(
129 -1,
130 std::chrono::sys_info(std::chrono::sys_seconds::min(), std::chrono::sys_seconds::max(), 1h, 0min, "+01"),
131 std::chrono::sys_info(std::chrono::sys_seconds(0s), std::chrono::sys_seconds(0s), 0s, 0min, "")),
132 tz->get_info(std::chrono::local_seconds::min()));
133
134 assert_equal(
135 std::chrono::local_info(
136 -1,
137 std::chrono::sys_info(std::chrono::sys_seconds::min(), std::chrono::sys_seconds::max(), 1h, 0min, "+01"),
138 std::chrono::sys_info(std::chrono::sys_seconds(0s), std::chrono::sys_seconds(0s), 0s, 0min, "")),
139 tz->get_info(std::chrono::local_seconds::min() + 59min + 59s));
140
141 assert_equal(
142 std::chrono::local_info(
143 std::chrono::local_info::unique,
144 std::chrono::sys_info(std::chrono::sys_seconds::min(), std::chrono::sys_seconds::max(), 1h, 0min, "+01"),
145 std::chrono::sys_info(std::chrono::sys_seconds(0s), std::chrono::sys_seconds(0s), 0s, 0min, "")),
146 tz->get_info(std::chrono::local_seconds::min() + 1h));
147 }
148
149 { // upper bound
150 const std::chrono::time_zone* tz = std::chrono::locate_zone("Etc/GMT+1");
151
152 assert_equal(
153 std::chrono::local_info(
154 -2,
155 std::chrono::sys_info(std::chrono::sys_seconds::min(), std::chrono::sys_seconds::max(), -1h, 0min, "-01"),
156 std::chrono::sys_info(std::chrono::sys_seconds(0s), std::chrono::sys_seconds(0s), 0s, 0min, "")),
157 tz->get_info(std::chrono::local_seconds::max() - 1s));
158
159 assert_equal(
160 std::chrono::local_info(
161 std::chrono::local_info::unique,
162 std::chrono::sys_info(std::chrono::sys_seconds::min(), std::chrono::sys_seconds::max(), -1h, 0min, "-01"),
163 std::chrono::sys_info(std::chrono::sys_seconds(0s), std::chrono::sys_seconds(0s), 0s, 0min, "")),
164 tz->get_info(std::chrono::local_seconds::max() - 1h - 1s));
165 }
166 }
167
test_indian_kerguelen()168 static void test_indian_kerguelen() {
169 // One change, no rules, no dst changes.
170
171 // Z Indian/Kerguelen 0 - -00 1950
172 // 5 - +05
173
174 using namespace std::literals::chrono_literals;
175 const std::chrono::time_zone* tz = std::chrono::locate_zone("Indian/Kerguelen");
176
177 assert_equal(
178 std::chrono::local_info(
179 std::chrono::local_info::unique,
180 std::chrono::sys_info(
181 std::chrono::sys_seconds::min(), to_sys_seconds(1950y, std::chrono::January, 1d), 0s, 0min, "-00"),
182 std::chrono::sys_info(std::chrono::sys_seconds(0s), std::chrono::sys_seconds(0s), 0s, 0min, "")),
183 tz->get_info(std::chrono::local_seconds::min()));
184
185 assert_equal(
186 std::chrono::local_info(
187 std::chrono::local_info::nonexistent,
188 std::chrono::sys_info(
189 std::chrono::sys_seconds::min(), to_sys_seconds(1950y, std::chrono::January, 1d), 0s, 0min, "-00"),
190 std::chrono::sys_info(
191 to_sys_seconds(1950y, std::chrono::January, 1d), std::chrono::sys_seconds::max(), 5h, 0min, "+05")),
192 tz->get_info(to_local_seconds(1950y, std::chrono::January, 1d)));
193
194 assert_equal(
195 std::chrono::local_info(
196 std::chrono::local_info::unique,
197 std::chrono::sys_info(
198 to_sys_seconds(1950y, std::chrono::January, 1d), std::chrono::sys_seconds::max(), 5h, 0min, "+05"),
199 std::chrono::sys_info(std::chrono::sys_seconds(0s), std::chrono::sys_seconds(0s), 0s, 0min, "")),
200 tz->get_info(to_local_seconds(1950y, std::chrono::January, 1d, 5h)));
201
202 assert_equal(
203 std::chrono::local_info(
204 std::chrono::local_info::unique,
205 std::chrono::sys_info(
206 to_sys_seconds(1950y, std::chrono::January, 1d), std::chrono::sys_seconds::max(), 5h, 0min, "+05"),
207 std::chrono::sys_info(std::chrono::sys_seconds(0s), std::chrono::sys_seconds(0s), 0s, 0min, "")),
208 tz->get_info(std::chrono::local_seconds::max() - 1s));
209 }
210
test_antarctica_rothera()211 static void test_antarctica_rothera() {
212 // One change, no rules, no dst changes
213
214 // Z Antarctica/Rothera 0 - -00 1976 D
215 // -3 - -03
216
217 using namespace std::literals::chrono_literals;
218 const std::chrono::time_zone* tz = std::chrono::locate_zone("Antarctica/Rothera");
219
220 assert_equal(
221 std::chrono::local_info(
222 std::chrono::local_info::unique,
223 std::chrono::sys_info(
224 std::chrono::sys_seconds::min(), to_sys_seconds(1976y, std::chrono::December, 1d), 0s, 0min, "-00"),
225 std::chrono::sys_info(std::chrono::sys_seconds(0s), std::chrono::sys_seconds(0s), 0s, 0min, "")),
226 tz->get_info(std::chrono::local_seconds::min()));
227
228 assert_equal(
229 std::chrono::local_info(
230 std::chrono::local_info::unique,
231 std::chrono::sys_info(
232 std::chrono::sys_seconds::min(), to_sys_seconds(1976y, std::chrono::December, 1d), 0s, 0min, "-00"),
233 std::chrono::sys_info(std::chrono::sys_seconds(0s), std::chrono::sys_seconds(0s), 0s, 0min, "")),
234 tz->get_info(to_local_seconds(1976y, std::chrono::November, 30d, 20h, 59min, 59s)));
235
236 assert_equal(
237 std::chrono::local_info(
238 std::chrono::local_info::ambiguous,
239 std::chrono::sys_info(
240 std::chrono::sys_seconds::min(), to_sys_seconds(1976y, std::chrono::December, 1d), 0s, 0min, "-00"),
241 std::chrono::sys_info(
242 to_sys_seconds(1976y, std::chrono::December, 1d), std::chrono::sys_seconds::max(), -3h, 0min, "-03")),
243 tz->get_info(to_local_seconds(1976y, std::chrono::November, 30d, 21h)));
244
245 assert_equal(
246 std::chrono::local_info(
247 std::chrono::local_info::ambiguous,
248 std::chrono::sys_info(
249 std::chrono::sys_seconds::min(), to_sys_seconds(1976y, std::chrono::December, 1d), 0s, 0min, "-00"),
250 std::chrono::sys_info(
251 to_sys_seconds(1976y, std::chrono::December, 1d), std::chrono::sys_seconds::max(), -3h, 0min, "-03")),
252 tz->get_info(to_local_seconds(1976y, std::chrono::November, 30d, 23h, 59min, 59s)));
253
254 assert_equal(
255 std::chrono::local_info(
256 std::chrono::local_info::unique,
257 std::chrono::sys_info(
258 to_sys_seconds(1976y, std::chrono::December, 1d), std::chrono::sys_seconds::max(), -3h, 0min, "-03"),
259 std::chrono::sys_info(std::chrono::sys_seconds(0s), std::chrono::sys_seconds(0s), 0s, 0min, "")),
260 tz->get_info(to_local_seconds(1976y, std::chrono::December, 1d)));
261
262 assert_equal(
263 std::chrono::local_info(
264 std::chrono::local_info::unique,
265 std::chrono::sys_info(
266 to_sys_seconds(1976y, std::chrono::December, 1d), std::chrono::sys_seconds::max(), -3h, 0min, "-03"),
267 std::chrono::sys_info(std::chrono::sys_seconds(0s), std::chrono::sys_seconds(0s), 0s, 0min, "")),
268 tz->get_info(std::chrono::local_seconds::max() - 3h - 1s));
269
270 assert_equal(
271 std::chrono::local_info(
272 -2,
273 std::chrono::sys_info(
274 to_sys_seconds(1976y, std::chrono::December, 1d), std::chrono::sys_seconds::max(), -3h, 0min, "-03"),
275 std::chrono::sys_info(std::chrono::sys_seconds(0s), std::chrono::sys_seconds(0s), 0s, 0min, "")),
276 tz->get_info(std::chrono::local_seconds::max() - 1s));
277 }
278
test_asia_hong_kong()279 static void test_asia_hong_kong() {
280 // A more typical entry, first some hard-coded entires and then at the
281 // end a rules based entry. This rule is valid for its entire period
282 //
283 // Z Asia/Hong_Kong 7:36:42 - LMT 1904 O 30 0:36:42
284 // 8 - HKT 1941 Jun 15 3
285 // 8 1 HKST 1941 O 1 4
286 // 8 0:30 HKWT 1941 D 25
287 // 9 - JST 1945 N 18 2
288 // 8 HK HK%sT
289 //
290 // R HK 1946 o - Ap 21 0 1 S
291 // R HK 1946 o - D 1 3:30s 0 -
292 // R HK 1947 o - Ap 13 3:30s 1 S
293 // R HK 1947 o - N 30 3:30s 0 -
294 // R HK 1948 o - May 2 3:30s 1 S
295 // R HK 1948 1952 - O Su>=28 3:30s 0 -
296 // R HK 1949 1953 - Ap Su>=1 3:30 1 S
297 // R HK 1953 1964 - O Su>=31 3:30 0 -
298 // R HK 1954 1964 - Mar Su>=18 3:30 1 S
299 // R HK 1965 1976 - Ap Su>=16 3:30 1 S
300 // R HK 1965 1976 - O Su>=16 3:30 0 -
301 // R HK 1973 o - D 30 3:30 1 S
302 // R HK 1979 o - May 13 3:30 1 S
303 // R HK 1979 o - O 21 3:30 0 -
304
305 using namespace std::literals::chrono_literals;
306 const std::chrono::time_zone* tz = std::chrono::locate_zone("Asia/Hong_Kong");
307
308 assert_equal(
309 std::chrono::local_info(
310 -1,
311 std::chrono::sys_info(
312 std::chrono::sys_seconds::min(),
313 to_sys_seconds(1904y, std::chrono::October, 29d, 17h),
314 7h + 36min + 42s,
315 0min,
316 "LMT"),
317 std::chrono::sys_info(std::chrono::sys_seconds(0s), std::chrono::sys_seconds(0s), 0s, 0min, "")),
318 tz->get_info(std::chrono::local_seconds::min()));
319
320 assert_equal(
321 std::chrono::local_info(
322 -1,
323 std::chrono::sys_info(
324 std::chrono::sys_seconds::min(),
325 to_sys_seconds(1904y, std::chrono::October, 29d, 17h),
326 7h + 36min + 42s,
327 0min,
328 "LMT"),
329 std::chrono::sys_info(std::chrono::sys_seconds(0s), std::chrono::sys_seconds(0s), 0s, 0min, "")),
330 tz->get_info(std::chrono::local_seconds::min() + 7h + 36min + 41s));
331
332 assert_equal(
333 std::chrono::local_info(
334 std::chrono::local_info::unique,
335 std::chrono::sys_info(
336 std::chrono::sys_seconds::min(),
337 to_sys_seconds(1904y, std::chrono::October, 29d, 17h),
338 7h + 36min + 42s,
339 0min,
340 "LMT"),
341 std::chrono::sys_info(std::chrono::sys_seconds(0s), std::chrono::sys_seconds(0s), 0s, 0min, "")),
342 tz->get_info(std::chrono::local_seconds::min() + 7h + 36min + 42s));
343
344 assert_equal(
345 std::chrono::local_info(
346 std::chrono::local_info::unique,
347 std::chrono::sys_info(
348 std::chrono::sys_seconds::min(),
349 to_sys_seconds(1904y, std::chrono::October, 29d, 17h),
350 7h + 36min + 42s,
351 0min,
352 "LMT"),
353 std::chrono::sys_info(std::chrono::sys_seconds(0s), std::chrono::sys_seconds(0s), 0s, 0min, "")),
354 tz->get_info(to_local_seconds(1904y, std::chrono::October, 30d, 0h, 36min, 41s)));
355
356 assert_equal(
357 std::chrono::local_info(
358 std::chrono::local_info::nonexistent,
359 std::chrono::sys_info(
360 std::chrono::sys_seconds::min(),
361 to_sys_seconds(1904y, std::chrono::October, 29d, 17h),
362 7h + 36min + 42s,
363 0min,
364 "LMT"),
365 std::chrono::sys_info(
366 to_sys_seconds(1904y, std::chrono::October, 29d, 17h),
367 to_sys_seconds(1941y, std::chrono::June, 14d, 19h),
368 8h,
369 0min,
370 "HKT")),
371 tz->get_info(to_local_seconds(1904y, std::chrono::October, 30d, 0h, 36min, 42s)));
372
373 assert_equal(
374 std::chrono::local_info(
375 std::chrono::local_info::nonexistent,
376 std::chrono::sys_info(
377 std::chrono::sys_seconds::min(),
378 to_sys_seconds(1904y, std::chrono::October, 29d, 17h),
379 7h + 36min + 42s,
380 0min,
381 "LMT"),
382 std::chrono::sys_info(
383 to_sys_seconds(1904y, std::chrono::October, 29d, 17h),
384 to_sys_seconds(1941y, std::chrono::June, 14d, 19h),
385 8h,
386 0min,
387 "HKT")),
388 tz->get_info(to_local_seconds(1904y, std::chrono::October, 30d, 0h, 59min, 59s)));
389
390 assert_equal(
391 std::chrono::local_info(
392 std::chrono::local_info::unique,
393 std::chrono::sys_info(
394 to_sys_seconds(1904y, std::chrono::October, 29d, 17h),
395 to_sys_seconds(1941y, std::chrono::June, 14d, 19h),
396 8h,
397 0min,
398 "HKT"),
399 std::chrono::sys_info(std::chrono::sys_seconds(0s), std::chrono::sys_seconds(0s), 0s, 0min, "")),
400 tz->get_info(to_local_seconds(1904y, std::chrono::October, 30d, 1h)));
401
402 assert_equal(
403 std::chrono::local_info(
404 std::chrono::local_info::unique,
405 std::chrono::sys_info(
406 to_sys_seconds(1904y, std::chrono::October, 29d, 17h),
407 to_sys_seconds(1941y, std::chrono::June, 14d, 19h),
408 8h,
409 0min,
410 "HKT"),
411 std::chrono::sys_info(std::chrono::sys_seconds(0s), std::chrono::sys_seconds(0s), 0s, 0min, "")),
412 tz->get_info(to_local_seconds(1941y, std::chrono::June, 15d, 2h, 59min, 59s)));
413
414 assert_equal(
415 std::chrono::local_info(
416 std::chrono::local_info::nonexistent,
417 std::chrono::sys_info(
418 to_sys_seconds(1904y, std::chrono::October, 29d, 17h),
419 to_sys_seconds(1941y, std::chrono::June, 14d, 19h),
420 8h,
421 0min,
422 "HKT"),
423 std::chrono::sys_info(
424 to_sys_seconds(1941y, std::chrono::June, 14d, 19h),
425 to_sys_seconds(1941y, std::chrono::September, 30d, 19h),
426 9h,
427 60min,
428 "HKST")),
429 tz->get_info(to_local_seconds(1941y, std::chrono::June, 15d, 3h)));
430
431 assert_equal(
432 std::chrono::local_info(
433 std::chrono::local_info::nonexistent,
434 std::chrono::sys_info(
435 to_sys_seconds(1904y, std::chrono::October, 29d, 17h),
436 to_sys_seconds(1941y, std::chrono::June, 14d, 19h),
437 8h,
438 0min,
439 "HKT"),
440 std::chrono::sys_info(
441 to_sys_seconds(1941y, std::chrono::June, 14d, 19h),
442 to_sys_seconds(1941y, std::chrono::September, 30d, 19h),
443 9h,
444 60min,
445 "HKST")),
446 tz->get_info(to_local_seconds(1941y, std::chrono::June, 15d, 3h, 59min, 59s)));
447
448 assert_equal(
449 std::chrono::local_info(
450 std::chrono::local_info::unique,
451 std::chrono::sys_info(
452 to_sys_seconds(1941y, std::chrono::June, 14d, 19h),
453 to_sys_seconds(1941y, std::chrono::September, 30d, 19h),
454 9h,
455 60min,
456 "HKST"),
457 std::chrono::sys_info(std::chrono::sys_seconds(0s), std::chrono::sys_seconds(0s), 0s, 0min, "")),
458 tz->get_info(to_local_seconds(1941y, std::chrono::June, 15d, 4h)));
459
460 assert_equal(
461 std::chrono::local_info(
462 std::chrono::local_info::unique,
463 std::chrono::sys_info(
464 to_sys_seconds(1941y, std::chrono::June, 14d, 19h),
465 to_sys_seconds(1941y, std::chrono::September, 30d, 19h),
466 9h,
467 60min,
468 "HKST"),
469 std::chrono::sys_info(std::chrono::sys_seconds(0s), std::chrono::sys_seconds(0s), 0s, 0min, "")),
470 tz->get_info(to_local_seconds(1941y, std::chrono::October, 1d, 3h, 29min, 29s)));
471
472 assert_equal(
473 std::chrono::local_info(
474 std::chrono::local_info::ambiguous,
475 std::chrono::sys_info(
476 to_sys_seconds(1941y, std::chrono::June, 14d, 19h),
477 to_sys_seconds(1941y, std::chrono::September, 30d, 19h),
478 9h,
479 60min,
480 "HKST"),
481 std::chrono::sys_info(
482 to_sys_seconds(1941y, std::chrono::September, 30d, 19h),
483 to_sys_seconds(1941y, std::chrono::December, 24d, 15h, 30min),
484 8h + 30min,
485 30min,
486 "HKWT")),
487 tz->get_info(to_local_seconds(1941y, std::chrono::October, 1d, 3h, 30min)));
488
489 assert_equal(
490 std::chrono::local_info(
491 std::chrono::local_info::ambiguous,
492 std::chrono::sys_info(
493 to_sys_seconds(1941y, std::chrono::June, 14d, 19h),
494 to_sys_seconds(1941y, std::chrono::September, 30d, 19h),
495 9h,
496 60min,
497 "HKST"),
498 std::chrono::sys_info(
499 to_sys_seconds(1941y, std::chrono::September, 30d, 19h),
500 to_sys_seconds(1941y, std::chrono::December, 24d, 15h, 30min),
501 8h + 30min,
502 30min,
503 "HKWT")),
504 tz->get_info(to_local_seconds(1941y, std::chrono::October, 1d, 3h, 59min, 59s)));
505
506 assert_equal(
507 std::chrono::local_info(
508 std::chrono::local_info::unique,
509 std::chrono::sys_info(
510 to_sys_seconds(1941y, std::chrono::September, 30d, 19h),
511 to_sys_seconds(1941y, std::chrono::December, 24d, 15h, 30min),
512 8h + 30min,
513 30min,
514 "HKWT"),
515 std::chrono::sys_info(std::chrono::sys_seconds(0s), std::chrono::sys_seconds(0s), 0s, 0min, "")),
516 tz->get_info(to_local_seconds(1941y, std::chrono::October, 1d, 4h)));
517 }
518
test_europe_berlin()519 static void test_europe_berlin() {
520 // A more typical entry, first some hard-coded entires and then at the
521 // end a rules based entry. This rule is valid for its entire period
522 //
523
524 // Z Europe/Berlin 0:53:28 - LMT 1893 Ap
525 // 1 c CE%sT 1945 May 24 2
526 // 1 So CE%sT 1946
527 // 1 DE CE%sT 1980
528 // 1 E CE%sT
529 //
530 // R c 1916 o - Ap 30 23 1 S
531 // R c 1916 o - O 1 1 0 -
532 // R c 1917 1918 - Ap M>=15 2s 1 S
533 // R c 1917 1918 - S M>=15 2s 0 -
534 // R c 1940 o - Ap 1 2s 1 S
535 // R c 1942 o - N 2 2s 0 -
536 // R c 1943 o - Mar 29 2s 1 S
537 // R c 1943 o - O 4 2s 0 -
538 // R c 1944 1945 - Ap M>=1 2s 1 S
539 // R c 1944 o - O 2 2s 0 -
540 // R c 1945 o - S 16 2s 0 -
541 // R c 1977 1980 - Ap Su>=1 2s 1 S
542 // R c 1977 o - S lastSu 2s 0 -
543 // R c 1978 o - O 1 2s 0 -
544 // R c 1979 1995 - S lastSu 2s 0 -
545 // R c 1981 ma - Mar lastSu 2s 1 S
546 // R c 1996 ma - O lastSu 2s 0 -
547 //
548 // R So 1945 o - May 24 2 2 M
549 // R So 1945 o - S 24 3 1 S
550 // R So 1945 o - N 18 2s 0 -
551 //
552 // R DE 1946 o - Ap 14 2s 1 S
553 // R DE 1946 o - O 7 2s 0 -
554 // R DE 1947 1949 - O Su>=1 2s 0 -
555 // R DE 1947 o - Ap 6 3s 1 S
556 // R DE 1947 o - May 11 2s 2 M
557 // R DE 1947 o - Jun 29 3 1 S
558 // R DE 1948 o - Ap 18 2s 1 S
559 // R DE 1949 o - Ap 10 2s 1 S
560 //
561 // R E 1977 1980 - Ap Su>=1 1u 1 S
562 // R E 1977 o - S lastSu 1u 0 -
563 // R E 1978 o - O 1 1u 0 -
564 // R E 1979 1995 - S lastSu 1u 0 -
565 // R E 1981 ma - Mar lastSu 1u 1 S
566 // R E 1996 ma - O lastSu 1u 0 -
567 //
568 // Note the European Union decided to stop the seasonal change in
569 // 2021. In 2023 seasonal changes are still in effect.
570
571 using namespace std::literals::chrono_literals;
572 const std::chrono::time_zone* tz = std::chrono::locate_zone("Europe/Berlin");
573
574 assert_equal(
575 std::chrono::local_info(
576 -1,
577 std::chrono::sys_info(
578 std::chrono::sys_seconds::min(),
579 to_sys_seconds(1893y, std::chrono::March, 31d, 23h, 6min, 32s),
580 53min + 28s,
581 0min,
582 "LMT"),
583 std::chrono::sys_info(std::chrono::sys_seconds(0s), std::chrono::sys_seconds(0s), 0s, 0min, "")),
584 tz->get_info(std::chrono::local_seconds::min()));
585
586 assert_equal(
587 std::chrono::local_info(
588 -1,
589 std::chrono::sys_info(
590 std::chrono::sys_seconds::min(),
591 to_sys_seconds(1893y, std::chrono::March, 31d, 23h, 6min, 32s),
592 53min + 28s,
593 0min,
594 "LMT"),
595 std::chrono::sys_info(std::chrono::sys_seconds(0s), std::chrono::sys_seconds(0s), 0s, 0min, "")),
596 tz->get_info(std::chrono::local_seconds::min() + 53min + 27s));
597
598 assert_equal(
599 std::chrono::local_info(
600 std::chrono::local_info::unique,
601 std::chrono::sys_info(
602 std::chrono::sys_seconds::min(),
603 to_sys_seconds(1893y, std::chrono::March, 31d, 23h, 6min, 32s),
604 53min + 28s,
605 0min,
606 "LMT"),
607 std::chrono::sys_info(std::chrono::sys_seconds(0s), std::chrono::sys_seconds(0s), 0s, 0min, "")),
608 tz->get_info(std::chrono::local_seconds::min() + 53min + 28s));
609
610 assert_equal(
611 std::chrono::local_info(
612 std::chrono::local_info::unique,
613 std::chrono::sys_info(
614 std::chrono::sys_seconds::min(),
615 to_sys_seconds(1893y, std::chrono::March, 31d, 23h, 6min, 32s),
616 53min + 28s,
617 0min,
618 "LMT"),
619 std::chrono::sys_info(std::chrono::sys_seconds(0s), std::chrono::sys_seconds(0s), 0s, 0min, "")),
620 tz->get_info(to_local_seconds(1893y, std::chrono::March, 31d, 23h, 59min, 59s)));
621
622 assert_equal(
623 std::chrono::local_info(
624 std::chrono::local_info::unique,
625 std::chrono::sys_info(
626 to_sys_seconds(1946y, std::chrono::October, 7d, 1h),
627 to_sys_seconds(1947y, std::chrono::April, 6d, 2h),
628 1h,
629 0min,
630 "CET"),
631 std::chrono::sys_info(std::chrono::sys_seconds(0s), std::chrono::sys_seconds(0s), 0s, 0min, "")),
632 tz->get_info(to_local_seconds(1947y, std::chrono::April, 6d, 2h, 59min, 59s)));
633
634 assert_equal(
635 std::chrono::local_info(
636 std::chrono::local_info::nonexistent,
637 std::chrono::sys_info(
638 to_sys_seconds(1946y, std::chrono::October, 7d, 1h),
639 to_sys_seconds(1947y, std::chrono::April, 6d, 2h),
640 1h,
641 0min,
642 "CET"),
643 std::chrono::sys_info(
644 to_sys_seconds(1947y, std::chrono::April, 6d, 2h),
645 to_sys_seconds(1947y, std::chrono::May, 11d, 1h),
646 2h,
647 60min,
648 "CEST")),
649 tz->get_info(to_local_seconds(1947y, std::chrono::April, 6d, 3h)));
650
651 assert_equal(
652 std::chrono::local_info(
653 std::chrono::local_info::nonexistent,
654 std::chrono::sys_info(
655 to_sys_seconds(1946y, std::chrono::October, 7d, 1h),
656 to_sys_seconds(1947y, std::chrono::April, 6d, 2h),
657 1h,
658 0min,
659 "CET"),
660 std::chrono::sys_info(
661 to_sys_seconds(1947y, std::chrono::April, 6d, 2h),
662 to_sys_seconds(1947y, std::chrono::May, 11d, 1h),
663 2h,
664 60min,
665 "CEST")),
666 tz->get_info(to_local_seconds(1947y, std::chrono::April, 6d, 3h, 59min, 59s)));
667
668 assert_equal(
669 std::chrono::local_info(
670 std::chrono::local_info::unique,
671 std::chrono::sys_info(
672 to_sys_seconds(1947y, std::chrono::April, 6d, 2h),
673 to_sys_seconds(1947y, std::chrono::May, 11d, 1h),
674 2h,
675 60min,
676 "CEST"),
677 std::chrono::sys_info(std::chrono::sys_seconds(0s), std::chrono::sys_seconds(0s), 0s, 0min, "")),
678 tz->get_info(to_local_seconds(1947y, std::chrono::April, 6d, 4h)));
679
680 assert_equal(
681 std::chrono::local_info(
682 std::chrono::local_info::unique,
683 std::chrono::sys_info(
684 to_sys_seconds(1947y, std::chrono::April, 6d, 2h),
685 to_sys_seconds(1947y, std::chrono::May, 11d, 1h),
686 2h,
687 60min,
688 "CEST"),
689 std::chrono::sys_info(std::chrono::sys_seconds(0s), std::chrono::sys_seconds(0s), 0s, 0min, "")),
690 tz->get_info(to_local_seconds(1947y, std::chrono::May, 11d, 2h, 59min, 59s)));
691
692 assert_equal(
693 std::chrono::local_info(
694 std::chrono::local_info::nonexistent,
695 std::chrono::sys_info(
696 to_sys_seconds(1947y, std::chrono::April, 6d, 2h),
697 to_sys_seconds(1947y, std::chrono::May, 11d, 1h),
698 2h,
699 60min,
700 "CEST"),
701 std::chrono::sys_info(
702 to_sys_seconds(1947y, std::chrono::May, 11d, 1h),
703 to_sys_seconds(1947y, std::chrono::June, 29d),
704 3h,
705 120min,
706 "CEMT")),
707 tz->get_info(to_local_seconds(1947y, std::chrono::May, 11d, 3h)));
708
709 assert_equal(
710 std::chrono::local_info(
711 std::chrono::local_info::nonexistent,
712 std::chrono::sys_info(
713 to_sys_seconds(1947y, std::chrono::April, 6d, 2h),
714 to_sys_seconds(1947y, std::chrono::May, 11d, 1h),
715 2h,
716 60min,
717 "CEST"),
718 std::chrono::sys_info(
719 to_sys_seconds(1947y, std::chrono::May, 11d, 1h),
720 to_sys_seconds(1947y, std::chrono::June, 29d),
721 3h,
722 120min,
723 "CEMT")),
724 tz->get_info(to_local_seconds(1947y, std::chrono::May, 11d, 3h, 59min, 59s)));
725
726 assert_equal(
727 std::chrono::local_info(
728 std::chrono::local_info::unique,
729 std::chrono::sys_info(
730 to_sys_seconds(1947y, std::chrono::May, 11d, 1h),
731 to_sys_seconds(1947y, std::chrono::June, 29d),
732 3h,
733 120min,
734 "CEMT"),
735 std::chrono::sys_info(std::chrono::sys_seconds(0s), std::chrono::sys_seconds(0s), 0s, 0min, "")),
736 tz->get_info(to_local_seconds(1947y, std::chrono::May, 11d, 4h)));
737
738 assert_equal(
739 std::chrono::local_info(
740 std::chrono::local_info::unique,
741 std::chrono::sys_info(
742 to_sys_seconds(1947y, std::chrono::May, 11d, 1h),
743 to_sys_seconds(1947y, std::chrono::June, 29d),
744 3h,
745 120min,
746 "CEMT"),
747 std::chrono::sys_info(std::chrono::sys_seconds(0s), std::chrono::sys_seconds(0s), 0s, 0min, "")),
748 tz->get_info(to_local_seconds(1947y, std::chrono::June, 29d, 1h, 59min, 59s)));
749
750 assert_equal(
751 std::chrono::local_info(
752 std::chrono::local_info::ambiguous,
753 std::chrono::sys_info(
754 to_sys_seconds(1947y, std::chrono::May, 11d, 1h),
755 to_sys_seconds(1947y, std::chrono::June, 29d),
756 3h,
757 120min,
758 "CEMT"),
759 std::chrono::sys_info(
760 to_sys_seconds(1947y, std::chrono::June, 29d),
761 to_sys_seconds(1947y, std::chrono::October, 5d, 1h),
762 2h,
763 60min,
764 "CEST")),
765 tz->get_info(to_local_seconds(1947y, std::chrono::June, 29d, 2h)));
766
767 assert_equal(
768 std::chrono::local_info(
769 std::chrono::local_info::ambiguous,
770 std::chrono::sys_info(
771 to_sys_seconds(1947y, std::chrono::May, 11d, 1h),
772 to_sys_seconds(1947y, std::chrono::June, 29d),
773 3h,
774 120min,
775 "CEMT"),
776 std::chrono::sys_info(
777 to_sys_seconds(1947y, std::chrono::June, 29d),
778 to_sys_seconds(1947y, std::chrono::October, 5d, 1h),
779 2h,
780 60min,
781 "CEST")),
782 tz->get_info(to_local_seconds(1947y, std::chrono::June, 29d, 2h, 59min, 59s)));
783
784 assert_equal(
785 std::chrono::local_info(
786 std::chrono::local_info::unique,
787 std::chrono::sys_info(
788 to_sys_seconds(1947y, std::chrono::June, 29d),
789 to_sys_seconds(1947y, std::chrono::October, 5d, 1h),
790 2h,
791 60min,
792 "CEST"),
793 std::chrono::sys_info(std::chrono::sys_seconds(0s), std::chrono::sys_seconds(0s), 0s, 0min, "")),
794 tz->get_info(to_local_seconds(1947y, std::chrono::June, 29d, 3h)));
795
796 assert_equal(
797 std::chrono::local_info(
798 std::chrono::local_info::unique,
799 std::chrono::sys_info(
800 to_sys_seconds(1947y, std::chrono::June, 29d),
801 to_sys_seconds(1947y, std::chrono::October, 5d, 1h),
802 2h,
803 60min,
804 "CEST"),
805 std::chrono::sys_info(std::chrono::sys_seconds(0s), std::chrono::sys_seconds(0s), 0s, 0min, "")),
806 tz->get_info(to_local_seconds(1947y, std::chrono::October, 5d, 1h, 59min, 59s)));
807
808 assert_equal(
809 std::chrono::local_info(
810 std::chrono::local_info::ambiguous,
811 std::chrono::sys_info(
812 to_sys_seconds(1947y, std::chrono::June, 29d),
813 to_sys_seconds(1947y, std::chrono::October, 5d, 1h),
814 2h,
815 60min,
816 "CEST"),
817 std::chrono::sys_info(
818 to_sys_seconds(1947y, std::chrono::October, 5d, 1h),
819 to_sys_seconds(1948y, std::chrono::April, 18d, 1h),
820 1h,
821 0min,
822 "CET")),
823 tz->get_info(to_local_seconds(1947y, std::chrono::October, 5d, 2h)));
824
825 assert_equal(
826 std::chrono::local_info(
827 std::chrono::local_info::ambiguous,
828 std::chrono::sys_info(
829 to_sys_seconds(1947y, std::chrono::June, 29d),
830 to_sys_seconds(1947y, std::chrono::October, 5d, 1h),
831 2h,
832 60min,
833 "CEST"),
834 std::chrono::sys_info(
835 to_sys_seconds(1947y, std::chrono::October, 5d, 1h),
836 to_sys_seconds(1948y, std::chrono::April, 18d, 1h),
837 1h,
838 0min,
839 "CET")),
840 tz->get_info(to_local_seconds(1947y, std::chrono::October, 5d, 2h, 59min, 59s)));
841
842 assert_equal(
843 std::chrono::local_info(
844 std::chrono::local_info::unique,
845 std::chrono::sys_info(
846 to_sys_seconds(1947y, std::chrono::October, 5d, 1h),
847 to_sys_seconds(1948y, std::chrono::April, 18d, 1h),
848 1h,
849 0min,
850 "CET"),
851 std::chrono::sys_info(std::chrono::sys_seconds(0s), std::chrono::sys_seconds(0s), 0s, 0min, "")),
852 tz->get_info(to_local_seconds(1947y, std::chrono::October, 5d, 3h)));
853 }
854
test_europe_dublin()855 static void test_europe_dublin() {
856 // Z Europe/Dublin -0:25:21 - LMT 1880 Au 2
857 // -0:25:21 - DMT 1916 May 21 2s
858 // -0:25:21 1 IST 1916 O 1 2s
859 // 0 G %s 1921 D 6
860 // ...
861 //
862 // R G 1916 o - May 21 2s 1 BST
863 // R G 1916 o - O 1 2s 0 GMT
864 // R G 1917 o - Ap 8 2s 1 BST
865 // ...
866
867 using namespace std::literals::chrono_literals;
868 const std::chrono::time_zone* tz = std::chrono::locate_zone("Europe/Dublin");
869
870 assert_equal(
871 std::chrono::local_info(
872 std::chrono::local_info::unique,
873 std::chrono::sys_info(
874 std::chrono::sys_seconds::min(),
875 to_sys_seconds(1880y, std::chrono::August, 2d, 0h, 25min, 21s),
876 -(25min + 21s),
877 0min,
878 "LMT"),
879 std::chrono::sys_info(std::chrono::sys_seconds(0s), std::chrono::sys_seconds(0s), 0s, 0min, "")),
880 tz->get_info(std::chrono::local_seconds::min()));
881
882 assert_equal(
883 std::chrono::local_info(
884 std::chrono::local_info::unique,
885 std::chrono::sys_info(
886 std::chrono::sys_seconds::min(),
887 to_sys_seconds(1880y, std::chrono::August, 2d, 0h, 25min, 21s),
888 -(25min + 21s),
889 0min,
890 "LMT"),
891 std::chrono::sys_info(std::chrono::sys_seconds(0s), std::chrono::sys_seconds(0s), 0s, 0min, "")),
892 tz->get_info(to_local_seconds(1880y, std::chrono::August, 1d, 23h, 59min, 59s)));
893
894 assert_equal(
895 std::chrono::local_info(
896 std::chrono::local_info::unique,
897 std::chrono::sys_info(
898 to_sys_seconds(1880y, std::chrono::August, 2d, 0h, 25min, 21s),
899 to_sys_seconds(1916y, std::chrono::May, 21d, 2h, 25min, 21s),
900 -(25min + 21s),
901 0min,
902 "DMT"),
903 std::chrono::sys_info(std::chrono::sys_seconds(0s), std::chrono::sys_seconds(0s), 0s, 0min, "")),
904 tz->get_info(to_local_seconds(1880y, std::chrono::August, 2d)));
905
906 assert_equal(
907 std::chrono::local_info(
908 std::chrono::local_info::unique,
909 std::chrono::sys_info(
910 to_sys_seconds(1880y, std::chrono::August, 2d, 0h, 25min, 21s),
911 to_sys_seconds(1916y, std::chrono::May, 21d, 2h, 25min, 21s),
912 -(25min + 21s),
913 0min,
914 "DMT"),
915 std::chrono::sys_info(std::chrono::sys_seconds(0s), std::chrono::sys_seconds(0s), 0s, 0min, "")),
916 tz->get_info(to_local_seconds(1916y, std::chrono::May, 21d, 1h, 59min, 59s)));
917
918 assert_equal(
919 std::chrono::local_info(
920 std::chrono::local_info::nonexistent,
921 std::chrono::sys_info(
922 to_sys_seconds(1880y, std::chrono::August, 2d, 0h, 25min, 21s),
923 to_sys_seconds(1916y, std::chrono::May, 21d, 2h, 25min, 21s),
924 -(25min + 21s),
925 0min,
926 "DMT"),
927 std::chrono::sys_info(
928 to_sys_seconds(1916y, std::chrono::May, 21d, 2h, 25min, 21s),
929 to_sys_seconds(1916y, std::chrono::October, 1d, 02h, 25min, 21s),
930 34min + 39s,
931 60min,
932 "IST")),
933 tz->get_info(to_local_seconds(1916y, std::chrono::May, 21d, 2h)));
934
935 assert_equal(
936 std::chrono::local_info(
937 std::chrono::local_info::nonexistent,
938 std::chrono::sys_info(
939 to_sys_seconds(1880y, std::chrono::August, 2d, 0h, 25min, 21s),
940 to_sys_seconds(1916y, std::chrono::May, 21d, 2h, 25min, 21s),
941 -(25min + 21s),
942 0min,
943 "DMT"),
944 std::chrono::sys_info(
945 to_sys_seconds(1916y, std::chrono::May, 21d, 2h, 25min, 21s),
946 to_sys_seconds(1916y, std::chrono::October, 1d, 02h, 25min, 21s),
947 34min + 39s,
948 60min,
949 "IST")),
950 tz->get_info(to_local_seconds(1916y, std::chrono::May, 21d, 2h, 59min, 59s)));
951
952 assert_equal(
953 std::chrono::local_info(
954 std::chrono::local_info::unique,
955 std::chrono::sys_info(
956 to_sys_seconds(1916y, std::chrono::May, 21d, 2h, 25min, 21s),
957 to_sys_seconds(1916y, std::chrono::October, 1d, 02h, 25min, 21s),
958 34min + 39s,
959 60min,
960 "IST"),
961 std::chrono::sys_info(std::chrono::sys_seconds(0s), std::chrono::sys_seconds(0s), 0s, 0min, "")),
962 tz->get_info(to_local_seconds(1916y, std::chrono::May, 21d, 6h)));
963
964 assert_equal(
965 std::chrono::local_info(
966 std::chrono::local_info::unique,
967 std::chrono::sys_info(
968 to_sys_seconds(1916y, std::chrono::May, 21d, 2h, 25min, 21s),
969 to_sys_seconds(1916y, std::chrono::October, 1d, 02h, 25min, 21s),
970 34min + 39s,
971 60min,
972 "IST"),
973 std::chrono::sys_info(std::chrono::sys_seconds(0s), std::chrono::sys_seconds(0s), 0s, 0min, "")),
974 tz->get_info(to_local_seconds(1916y, std::chrono::October, 1d, 2h, 25min, 20s)));
975
976 assert_equal(
977 std::chrono::local_info(
978 std::chrono::local_info::ambiguous,
979 std::chrono::sys_info(
980 to_sys_seconds(1916y, std::chrono::May, 21d, 2h, 25min, 21s),
981 to_sys_seconds(1916y, std::chrono::October, 1d, 02h, 25min, 21s),
982 34min + 39s,
983 60min,
984 "IST"),
985 std::chrono::sys_info(
986 to_sys_seconds(1916y, std::chrono::October, 1d, 02h, 25min, 21s),
987 to_sys_seconds(1917y, std::chrono::April, 8d, 2h),
988 0s,
989 0min,
990 "GMT")),
991 tz->get_info(to_local_seconds(1916y, std::chrono::October, 1d, 2h, 59min, 59s)));
992
993 assert_equal(
994 std::chrono::local_info(
995 std::chrono::local_info::unique,
996 std::chrono::sys_info(
997 to_sys_seconds(1916y, std::chrono::October, 1d, 02h, 25min, 21s),
998 to_sys_seconds(1917y, std::chrono::April, 8d, 2h),
999 0s,
1000 0min,
1001 "GMT"),
1002 std::chrono::sys_info(std::chrono::sys_seconds(0s), std::chrono::sys_seconds(0s), 0s, 0min, "")),
1003 tz->get_info(to_local_seconds(1916y, std::chrono::October, 1d, 3h)));
1004
1005 assert_equal(
1006 std::chrono::local_info(
1007 std::chrono::local_info::unique,
1008 std::chrono::sys_info(
1009 to_sys_seconds(1916y, std::chrono::October, 1d, 02h, 25min, 21s),
1010 to_sys_seconds(1917y, std::chrono::April, 8d, 2h),
1011 0s,
1012 0min,
1013 "GMT"),
1014 std::chrono::sys_info(std::chrono::sys_seconds(0s), std::chrono::sys_seconds(0s), 0s, 0min, "")),
1015 tz->get_info(to_local_seconds(1917y, std::chrono::April, 8d, 1h, 59min, 59s)));
1016 }
1017
test_america_st_johns()1018 static void test_america_st_johns() {
1019 // A more typical entry,
1020 // Uses letters both when DST is ative and not and has multiple
1021 // letters. Uses negetive offsets.
1022 // Switches several times between their own and Canadian rules
1023 // Switches the stdoff from -3:30:52 to -3:30 while observing the same rule
1024
1025 // Z America/St_Johns -3:30:52 - LMT 1884
1026 // -3:30:52 j N%sT 1918
1027 // -3:30:52 C N%sT 1919
1028 // ...
1029 //
1030 // R j 1917 o - Ap 8 2 1 D
1031 // R j 1917 o - S 17 2 0 S
1032 // R j 1919 o - May 5 23 1 D
1033 // R j 1919 o - Au 12 23 0 S
1034 // R j 1920 1935 - May Su>=1 23 1 D
1035 // ...
1036 //
1037 // R C 1918 o - Ap 14 2 1 D
1038 // R C 1918 o - O 27 2 0 S
1039 // R C 1942 o - F 9 2 1 W
1040 // ...
1041
1042 using namespace std::literals::chrono_literals;
1043 const std::chrono::time_zone* tz = std::chrono::locate_zone("America/St_Johns");
1044
1045 assert_equal(
1046 std::chrono::local_info(
1047 std::chrono::local_info::unique,
1048 std::chrono::sys_info(
1049 std::chrono::sys_seconds::min(),
1050 to_sys_seconds(1884y, std::chrono::January, 1d, 3h, 30min, 52s),
1051 -(3h + 30min + 52s),
1052 0min,
1053 "LMT"),
1054 std::chrono::sys_info(std::chrono::sys_seconds(0s), std::chrono::sys_seconds(0s), 0s, 0min, "")),
1055 tz->get_info(std::chrono::local_seconds::min()));
1056
1057 assert_equal(
1058 std::chrono::local_info(
1059 std::chrono::local_info::unique,
1060 std::chrono::sys_info(
1061 std::chrono::sys_seconds::min(),
1062 to_sys_seconds(1884y, std::chrono::January, 1d, 3h, 30min, 52s),
1063 -(3h + 30min + 52s),
1064 0min,
1065 "LMT"),
1066 std::chrono::sys_info(std::chrono::sys_seconds(0s), std::chrono::sys_seconds(0s), 0s, 0min, "")),
1067 tz->get_info(to_local_seconds(1883y, std::chrono::December, 31d, 23h, 59min, 59s)));
1068
1069 assert_equal(
1070 std::chrono::local_info(
1071 std::chrono::local_info::unique,
1072 std::chrono::sys_info(
1073 to_sys_seconds(1884y, std::chrono::January, 1d, 3h, 30min, 52s),
1074 to_sys_seconds(1917y, std::chrono::April, 8d, 5h, 30min, 52s),
1075 -(3h + 30min + 52s),
1076 0min,
1077 "NST"),
1078 std::chrono::sys_info(std::chrono::sys_seconds(0s), std::chrono::sys_seconds(0s), 0s, 0min, "")),
1079 tz->get_info(to_local_seconds(1884y, std::chrono::January, 1d)));
1080
1081 assert_equal(
1082 std::chrono::local_info(
1083 std::chrono::local_info::unique,
1084 std::chrono::sys_info(
1085 to_sys_seconds(1884y, std::chrono::January, 1d, 3h, 30min, 52s),
1086 to_sys_seconds(1917y, std::chrono::April, 8d, 5h, 30min, 52s),
1087 -(3h + 30min + 52s),
1088 0min,
1089 "NST"),
1090 std::chrono::sys_info(std::chrono::sys_seconds(0s), std::chrono::sys_seconds(0s), 0s, 0min, "")),
1091 tz->get_info(to_local_seconds(1917y, std::chrono::April, 8d, 1h, 59min, 59s)));
1092
1093 assert_equal(
1094 std::chrono::local_info(
1095 std::chrono::local_info::nonexistent,
1096 std::chrono::sys_info(
1097 to_sys_seconds(1884y, std::chrono::January, 1d, 3h, 30min, 52s),
1098 to_sys_seconds(1917y, std::chrono::April, 8d, 5h, 30min, 52s),
1099 -(3h + 30min + 52s),
1100 0min,
1101 "NST"),
1102 std::chrono::sys_info(
1103 to_sys_seconds(1917y, std::chrono::April, 8d, 5h, 30min, 52s),
1104 to_sys_seconds(1917y, std::chrono::September, 17d, 4h, 30min, 52s),
1105 -(2h + 30min + 52s),
1106 60min,
1107 "NDT")),
1108 tz->get_info(to_local_seconds(1917y, std::chrono::April, 8d, 2h)));
1109
1110 assert_equal(
1111 std::chrono::local_info(
1112 std::chrono::local_info::nonexistent,
1113 std::chrono::sys_info(
1114 to_sys_seconds(1884y, std::chrono::January, 1d, 3h, 30min, 52s),
1115 to_sys_seconds(1917y, std::chrono::April, 8d, 5h, 30min, 52s),
1116 -(3h + 30min + 52s),
1117 0min,
1118 "NST"),
1119 std::chrono::sys_info(
1120 to_sys_seconds(1917y, std::chrono::April, 8d, 5h, 30min, 52s),
1121 to_sys_seconds(1917y, std::chrono::September, 17d, 4h, 30min, 52s),
1122 -(2h + 30min + 52s),
1123 60min,
1124 "NDT")),
1125 tz->get_info(to_local_seconds(1917y, std::chrono::April, 8d, 2h, 59min, 59s)));
1126
1127 assert_equal(
1128 std::chrono::local_info(
1129 std::chrono::local_info::unique,
1130 std::chrono::sys_info(
1131 to_sys_seconds(1917y, std::chrono::April, 8d, 5h, 30min, 52s),
1132 to_sys_seconds(1917y, std::chrono::September, 17d, 4h, 30min, 52s),
1133 -(2h + 30min + 52s),
1134 60min,
1135 "NDT"),
1136 std::chrono::sys_info(std::chrono::sys_seconds(0s), std::chrono::sys_seconds(0s), 0s, 0min, "")),
1137 tz->get_info(to_local_seconds(1917y, std::chrono::April, 8d, 3h)));
1138
1139 assert_equal(
1140 std::chrono::local_info(
1141 std::chrono::local_info::unique,
1142 std::chrono::sys_info(
1143 to_sys_seconds(1917y, std::chrono::April, 8d, 5h, 30min, 52s),
1144 to_sys_seconds(1917y, std::chrono::September, 17d, 4h, 30min, 52s),
1145 -(2h + 30min + 52s),
1146 60min,
1147 "NDT"),
1148 std::chrono::sys_info(std::chrono::sys_seconds(0s), std::chrono::sys_seconds(0s), 0s, 0min, "")),
1149 tz->get_info(to_local_seconds(1917y, std::chrono::September, 17d, 0h, 59min, 59s)));
1150
1151 assert_equal(
1152 std::chrono::local_info(
1153 std::chrono::local_info::ambiguous,
1154 std::chrono::sys_info(
1155 to_sys_seconds(1917y, std::chrono::April, 8d, 5h, 30min, 52s),
1156 to_sys_seconds(1917y, std::chrono::September, 17d, 4h, 30min, 52s),
1157 -(2h + 30min + 52s),
1158 60min,
1159 "NDT"),
1160 std::chrono::sys_info(
1161 to_sys_seconds(1917y, std::chrono::September, 17d, 4h, 30min, 52s),
1162 to_sys_seconds(1918y, std::chrono::April, 14d, 5h, 30min, 52s),
1163 -(3h + 30min + 52s),
1164 0min,
1165 "NST")),
1166 tz->get_info(to_local_seconds(1917y, std::chrono::September, 17d, 1h)));
1167
1168 assert_equal(
1169 std::chrono::local_info(
1170 std::chrono::local_info::ambiguous,
1171 std::chrono::sys_info(
1172 to_sys_seconds(1917y, std::chrono::April, 8d, 5h, 30min, 52s),
1173 to_sys_seconds(1917y, std::chrono::September, 17d, 4h, 30min, 52s),
1174 -(2h + 30min + 52s),
1175 60min,
1176 "NDT"),
1177 std::chrono::sys_info(
1178 to_sys_seconds(1917y, std::chrono::September, 17d, 4h, 30min, 52s),
1179 to_sys_seconds(1918y, std::chrono::April, 14d, 5h, 30min, 52s),
1180 -(3h + 30min + 52s),
1181 0min,
1182 "NST")),
1183 tz->get_info(to_local_seconds(1917y, std::chrono::September, 17d, 1h, 59min, 59s)));
1184
1185 assert_equal(
1186 std::chrono::local_info(
1187 std::chrono::local_info::unique,
1188 std::chrono::sys_info(
1189 to_sys_seconds(1917y, std::chrono::September, 17d, 4h, 30min, 52s),
1190 to_sys_seconds(1918y, std::chrono::April, 14d, 5h, 30min, 52s),
1191 -(3h + 30min + 52s),
1192 0min,
1193 "NST"),
1194 std::chrono::sys_info(std::chrono::sys_seconds(0s), std::chrono::sys_seconds(0s), 0s, 0min, "")),
1195 tz->get_info(to_local_seconds(1917y, std::chrono::September, 17d, 2h)));
1196 }
1197
validate_transitions(const std::chrono::time_zone & zone)1198 static void validate_transitions(const std::chrono::time_zone& zone) {
1199 using namespace std::literals::chrono_literals;
1200
1201 constexpr auto begin = std::chrono::time_point_cast<std::chrono::seconds>(
1202 static_cast<std::chrono::sys_days>(std::chrono::year_month_day{first, std::chrono::January, 1d}));
1203 constexpr auto end = std::chrono::time_point_cast<std::chrono::seconds>(
1204 static_cast<std::chrono::sys_days>(std::chrono::year_month_day{last, std::chrono::January, 1d}));
1205
1206 // Builds the set of sys_info objects for the selected time range.
1207 std::vector<std::chrono::sys_info> input;
1208 std::chrono::sys_seconds s = begin;
1209 do {
1210 input.emplace_back(zone.get_info(s));
1211 s = input.back().end;
1212 } while (s < end);
1213
1214 for (auto previous = input.begin(), next = previous + 1; next != input.end(); ++previous, ++next) {
1215 // Now iterates to all adjacent objects.
1216 // For every transition gets the locate time of the
1217 // - end of the first (a)
1218 // - the start if the second (b)
1219 // Depending on the difference between 'a' and 'b' different tests are done.
1220 std::chrono::local_seconds end_previous{previous->end.time_since_epoch() + previous->offset};
1221 std::chrono::local_seconds begin_next{next->begin.time_since_epoch() + next->offset};
1222
1223 if (end_previous == begin_next) {
1224 // unique transition
1225 // a |------------|
1226 // b |----------|
1227 // T
1228 assert_equal(std::chrono::local_info(
1229 std::chrono::local_info::unique,
1230 *previous,
1231 std::chrono::sys_info(std::chrono::sys_seconds(0s), std::chrono::sys_seconds(0s), 0s, 0min, "")),
1232 zone.get_info(end_previous - 1s));
1233
1234 assert_equal(std::chrono::local_info(
1235 std::chrono::local_info::unique,
1236 *next,
1237 std::chrono::sys_info(std::chrono::sys_seconds(0s), std::chrono::sys_seconds(0s), 0s, 0min, "")),
1238 zone.get_info(begin_next));
1239
1240 } else if (end_previous < begin_next) {
1241 // non-existent transition
1242 // a |------------|
1243 // b |----------|
1244 // T T
1245 assert_equal(std::chrono::local_info(
1246 std::chrono::local_info::unique,
1247 *previous,
1248 std::chrono::sys_info(std::chrono::sys_seconds(0s), std::chrono::sys_seconds(0s), 0s, 0min, "")),
1249 zone.get_info(end_previous - 1s));
1250
1251 assert_equal(std::chrono::local_info(std::chrono::local_info::nonexistent, *previous, *next),
1252 zone.get_info(end_previous));
1253
1254 assert_equal(std::chrono::local_info(std::chrono::local_info::nonexistent, *previous, *next),
1255 zone.get_info(begin_next - 1s));
1256
1257 assert_equal(std::chrono::local_info(
1258 std::chrono::local_info::unique,
1259 *next,
1260 std::chrono::sys_info(std::chrono::sys_seconds(0s), std::chrono::sys_seconds(0s), 0s, 0min, "")),
1261 zone.get_info(begin_next));
1262
1263 } else {
1264 // ambiguous transition
1265 // a |------------|
1266 // b |----------|
1267 // T T
1268 assert_equal(std::chrono::local_info(
1269 std::chrono::local_info::unique,
1270 *previous,
1271 std::chrono::sys_info(std::chrono::sys_seconds(0s), std::chrono::sys_seconds(0s), 0s, 0min, "")),
1272 zone.get_info(begin_next - 1s));
1273
1274 assert_equal(std::chrono::local_info(std::chrono::local_info::ambiguous, *previous, *next),
1275 zone.get_info(begin_next));
1276
1277 assert_equal(std::chrono::local_info(std::chrono::local_info::ambiguous, *previous, *next),
1278 zone.get_info(end_previous - 1s));
1279
1280 assert_equal(std::chrono::local_info(
1281 std::chrono::local_info::unique,
1282 *next,
1283 std::chrono::sys_info(std::chrono::sys_seconds(0s), std::chrono::sys_seconds(0s), 0s, 0min, "")),
1284 zone.get_info(end_previous));
1285 }
1286 }
1287 }
1288
main(int,const char **)1289 int main(int, const char**) {
1290 test_gmt();
1291 test_local_time_out_of_range();
1292 test_indian_kerguelen();
1293 test_antarctica_rothera();
1294
1295 test_asia_hong_kong();
1296 test_europe_berlin();
1297 test_europe_dublin();
1298 test_america_st_johns();
1299
1300 const std::chrono::tzdb& tzdb = std::chrono::get_tzdb();
1301 for (const auto& zone : tzdb.zones) {
1302 validate_transitions(zone);
1303 }
1304
1305 return 0;
1306 }
1307