https://gcc.gnu.org/g:57a09e2f362ab8a8be84250fd4266b333a74b977
commit r17-2537-g57a09e2f362ab8a8be84250fd4266b333a74b977 Author: Tomasz Kamiński <[email protected]> Date: Fri Jul 17 21:14:42 2026 +0200 libstdc++: Fix condition for stopping lazy zone expansion [PR116110] At indicated by the pre-existing comment, the lazy zone expansion can be only resumed from STD (save == 0) zone. However, the current condition for stopping on DST (save != 0) doesn't ensure that, as some rule specify transitions between DST zones. For example August 1945 of Y rule used by America/Dawson only change letters: Y 1942 o - F 9 2 1 W Y 1945 o - Au 14 23u 1 P This patch correct the condition, by using next_rule (i.e. one applying after last expanded zone): either there is no zone (last expanded range) or it have save zero. libstdc++-v3/ChangeLog: PR libstdc++/116110 * src/c++20/tzdb.cc (time_zone::_M_get_sys_info): Correct condition for stopping zone expansion before STD zone. * testsuite/std/time/time_zone/116110.cc (test_dawson): Add test for America/Dawson August 1945 transition. Reviewed-by: Jonathan Wakely <[email protected]> Signed-off-by: Tomasz Kamiński <[email protected]> Diff: --- libstdc++-v3/src/c++20/tzdb.cc | 4 +-- .../testsuite/std/time/time_zone/116110.cc | 41 ++++++++++++++++++++++ 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/libstdc++-v3/src/c++20/tzdb.cc b/libstdc++-v3/src/c++20/tzdb.cc index c2a036bc2cae..43f6a0dbb846 100644 --- a/libstdc++-v3/src/c++20/tzdb.cc +++ b/libstdc++-v3/src/c++20/tzdb.cc @@ -1232,10 +1232,10 @@ namespace std::chrono result_index = new_infos.size() - 1; else if (result_index >= 0 && !merged) { - // Finish on a DST sys_info if possible, so that if we resume + // Finish before a STD sys_info if possible, so that if we resume // generating sys_info objects after this time point, save=0 // should be correct for the next sys_info. - if (num_after > 1 || info.save != 0min) + if (num_after > 1 || !next_rule || next_rule->save == 0s) --num_after; } diff --git a/libstdc++-v3/testsuite/std/time/time_zone/116110.cc b/libstdc++-v3/testsuite/std/time/time_zone/116110.cc index 1ec01d359552..45daed8c0509 100644 --- a/libstdc++-v3/testsuite/std/time/time_zone/116110.cc +++ b/libstdc++-v3/testsuite/std/time/time_zone/116110.cc @@ -78,9 +78,50 @@ test_apia() VERIFY( info.abbrev == "+14" ); } +void +test_dawson() +{ + /* 1945 August rule change changes letters (abbrev) + and remains in DST: + R Y 1942 o - F 9 2 1 W + R Y 1945 o - Au 14 23u 1 P + R Y 1945 o - S 30 2 0 S + Z America/Dawson -9:17:40 - LMT 1900 Au 20 + -9 Y Y%sT 1965 + -9 Yu Y%sT 1973 O 28 + */ + + auto* tz = locate_zone("America/Dawson"); + + // Triggers rule transitions from the start. + sys_info info = tz->get_info(sys_days(1900y/August/20) + 10h); + VERIFY( info.offset == -9h ); + VERIFY( info.save == 0min ); + VERIFY( info.abbrev == "YST" ); + + // Check YWT transition at 02:00 + 9h UT, that is DST + info = tz->get_info(sys_days(1942y/February/9) + 11h); + VERIFY( info.offset == -8h ); + VERIFY( info.save == 60min ); + VERIFY( info.abbrev == "YWT" ); + + // Check YPT transition at 23:00 UT, remains DST + info = tz->get_info(sys_days(1945y/August/14) + 23h); + VERIFY( info.offset == -8h ); + VERIFY( info.save == 60min ); + VERIFY( info.abbrev == "YPT" ); + + // Check YST transition at 02:00 + 8h UT, switches to STD + info = tz->get_info(sys_days(1945y/September/30) + 10h); + VERIFY( info.offset == -9h ); + VERIFY( info.save == 0min ); + VERIFY( info.abbrev == "YST" ); +} + int main() { test_broken_hill(); test_kiritimati(); test_apia(); + test_dawson(); }
