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();
 }

Reply via email to