Skip to content

Commit 4e9decf

Browse files
authored
[libc++][TZDB] Fixes reverse time lookups. (#89502)
Testing with the get_info() returning a local_info revealed some issues in the reverse lookup. This needed an additional quirk. Also the skipping when not in the current continuation optimization was wrong. It prevented merging two sys_info objects.
1 parent 837dab9 commit 4e9decf

File tree

2 files changed

+91
-4
lines changed

2 files changed

+91
-4
lines changed

libcxx/src/time_zone.cpp

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -567,11 +567,22 @@ __first_rule(seconds __stdoff, const vector<__tz::__rule>& __rules) {
567567
false};
568568
}
569569

570-
__named_rule_until __continuation_end{__continuation};
571-
if (__time >= __continuation_end.__until() && !__continuation_end.__needs_adjustment())
572-
// note std::unexpected<sys_seconds>(__end); is ambiguous with std::unexpected() in <exception>,
573-
return __sys_info_result{std::unexpect, __continuation_end.__until()};
570+
if (__rule->__save.__time != 0s) {
571+
// another fix for America/Punta_Arenas when not at the start of the
572+
// sys_info object.
573+
seconds __save = __rule->__save.__time;
574+
if (__continuation_begin >= __rule_begin - __save && __time < __next.first) {
575+
return __sys_info{
576+
sys_info{__continuation_begin,
577+
__next.first,
578+
__continuation.__stdoff + __save,
579+
chrono::duration_cast<minutes>(__save),
580+
chrono::__format(__continuation, __rule->__letters, __save)},
581+
false};
582+
}
583+
}
574584

585+
__named_rule_until __continuation_end{__continuation};
575586
while (__next.second != __rules.end()) {
576587
#ifdef PRINT
577588
std::print(

libcxx/test/std/time/time.zone/time.zone.timezone/time.zone.members/get_info.sys_time.pass.cpp

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1299,6 +1299,78 @@ static void test_america_indiana_knox() {
12991299
tz->get_info(to_sys_seconds(2006y, std::chrono::October, 29d, 6h, 59min, 59s)));
13001300
}
13011301

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+
13021374
int main(int, const char**) {
13031375
// Basic tests
13041376
test_gmt();
@@ -1333,5 +1405,9 @@ int main(int, const char**) {
13331405
test_america_ciudad_juarez();
13341406
test_america_indiana_knox();
13351407

1408+
// Reverse search bugs
1409+
test_america_punta_arenas();
1410+
test_europ_ljubljana();
1411+
13361412
return 0;
13371413
}

0 commit comments

Comments
 (0)