On Tue, 30 Jun 2026 at 11:00, Tomasz Kamiński <[email protected]> wrote:
>
> 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 tiem 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.
>
> Co-authored-by: Álvaro Begué <[email protected]>
> Signed-off-by: Tomasz Kamiński <[email protected]>
> Signed-off-by: Álvaro Begué <[email protected]>
> ---
> v4 restores the expansion of the year range to previous/next year
> from Álvaro v2 versions. It also adds a test for situations when
> expansion is necessary (based on Pacific/Auckland). This version
> is more targeted, and only expands the range for Dec/31 and Jan/1.
> We do not check local time (t - stdoff) date, as save may still
> move the date to previous/next year.
>
> Futhermore:
> * we record last transition for the rules that no longer applies,
>   as one happening before (see test_eariel)

That should probably be test_earlier, and s/eariel/earlier/g?

Reply via email to