https://gcc.gnu.org/bugzilla/show_bug.cgi?id=124853
--- Comment #2 from GCC Commits <cvs-commit at gcc dot gnu.org> --- The master branch has been updated by Tomasz Kaminski <[email protected]>: https://gcc.gnu.org/g:f7cde200320e0800e4fcc5cea399e9faef50f8d4 commit r17-2060-gf7cde200320e0800e4fcc5cea399e9faef50f8d4 Author: Tomasz KamiÅski <[email protected]> Date: Tue Jun 30 09:46:07 2026 +0200 libstdc++: Cascade wall-time saves in lazy expansion seeding [PR124853] When _M_get_sys_info seeds a Zone line by looking up the active rule just before info.begin, the previous code interpreted each rule in isolation against ri.offset() (the line's standard offset alone), ignoring the running save accumulated by earlier rules in the same year. For most zones this gives the right answer because the search only matters when no rule has fired yet, but for zones whose rule set has wall-time rules whose effective firing time depends on a prior rule's save it produces wrong answers. Canonical case: Europe/Paris around 1945. France's rules R Fr 1945 o - Apr 2 2 2 M R Fr 1945 o - Sep 16 3 0 - both use plain wall time. In Paris's stdoff=1 frame, the September rule's at_time of 03:00 wall translates to UT Sep 16 02:00 if no prior save is applied, but to UT Sep 16 00:00 once the running save of 2h from the April rule is taken into account. When seeding a sys_info whose info.begin falls between those two values, the simple search picks the April rule (save=2 â CEMT, total offset 3h) when the correct answer is the September rule (save=0 â CET, total offset 1h). libstdc++ reports this as a sustained CEMT stretch where zic and libc agree on CET. To address above the finding algorithm, is now expanded to collect three rule transitions around specified time t, while continuing to ignore the save. * curr_tran: transition happening before or at time t, * prev_tran: transition preceding above transition, * next_tran: transition happening after time t. This collects sufficient information to adjust the start_time (if Wall time is used) for curr_tran (save of prev_tran) and next_tran (save of curr_tran). Assuming that applying save value does not change order of transition (cascading save would be ill-defined otherwise), after the adjustment the actual active rule is: * next_tran.rule: if the adjustment pushed next_tran.when to time before or at t, which happen for positive save (see test_positive), * prev_tran.rule: if adjustment pushed curr_tran.when to time after time t, which happens for negative save (see test_negative), * curr_tran.rule. For the time at the start (Jan/1) or end of the year (December/31), for each rule, in addition to transition in year of t, we check transitions in previous or next year respectively (years in range [first_year, last_year]). This handle rules whose firing (specified in local time) crosses a year boundary due to a large stdoff or save. One example is Pacific/Auckland's 1946 Jan 1 rule, in stdoff=12h, fires at 1945-12-31 11:30 UT, see test_next_year. The fallback "earliest STD rule" logic is preserved for the case where no rule has fired yet, but is extracted to separate function. This lookup is optimized, by searching the rules by name, from, and save in that order, grouping std rules in given year together. PR libstdc++/124853 libstdc++-v3/ChangeLog: * src/c++20/tzdb.cc (time_zone::_M_get_sys_info): Extract code blocks to separate functions, and invoke them. (<unnamed>::find_active_rule): Modify algorithm to handle cascading saves. (<unnamed>::find_first_std): Simplified implementation benefiting from reordering of rules. (chrono::reload_tzdb): Sort rules by name, from and save. * testsuite/std/time/time_zone/wall_cascade.cc: New test. Reviewed-by: Tomasz KamiÅski <[email protected]> Co-authored-by: Álvaro Begué <[email protected]> Signed-off-by: Tomasz KamiÅski <[email protected]> Signed-off-by: Álvaro Begué <[email protected]>
