[PATCH 0/5] libstdc++: chrono tzdb correctness fixes

Álvaro Begué alvaro.begue@gmail.com
Tue Apr 28 13:47:00 GMT 2026


I prepared a "v2" series of patches, and I included the DCO sign-off line.
Will this suffice?

--Á.


On Mon, Apr 13, 2026 at 10:24 AM Jonathan Wakely <jwakely@redhat.com> wrote:

> On Sat, 11 Apr 2026 at 14:33, Alvaro Begue <alvaro.begue@gmail.com> wrote:
> >
> > This series fixes five distinct correctness issues in libstdc++'s
> > <chrono> tzdb implementation that cause time-zone conversions to
> > disagree with zic.c / libc localtime_r for specific real-world zones.
>
> This is really great, thanks. Some of the smaller patches might be
> possible to merge now for GCC 16 but the larger ones will have to wait
> for GCC 17 (and then maybe get backported later for GCC 16.2).
>
> For all significant patches to GCC we require either copyright
> assignment to the FSF or a DCO sign-off, please see
> https://gcc.gnu.org/contribute.html#legal and let us know which route
> you want to take.
>
>
> >
> > The motivation was a brute-force comparison harness that walks every
> > IANA zone hourly across 1850-2150 (~563k transition samples) and
> > compares chrono::time_zone::to_local() against libc's localtime_r().
> > Against current master HEAD that harness reports thousands of
> > mismatches across ~190 zones; with this series applied it reports
> > zero mismatches across all 447 zones.  An abbreviation-only sweep
> > (169k samples) likewise reports zero offset and zero abbrev diffs.
> >
> > The series builds on Jonathan Wakely's recent PR 116110 / PR 124513
> > work (commits 663e5ade1, cddf4111c, fbc5d2b1a).  Patch 3 in
> > particular resolves the "FIXME: PR 116110" left in operator>>(istream&,
> > ZoneInfo&) for the named-rule wall-UNTIL case.
> >
> > The five commits are deliberately small and independently testable;
> > each adds a hermetic regression test using the same
> > __gnu_cxx::zoneinfo_dir_override pattern as the existing 124513.cc.
> >
> >   1. Fix numeric save offset on Zone lines [PR 124851].
> >
> >      ZoneInfo::m_offset had inconsistent semantics: the parser path
> >      stored stdoff alone, but the two sys_info-taking constructors
> >      stored the total (stdoff + save).  ZoneInfo::to() returned
> >      m_offset as sys_info::offset, dropping the numeric save for
> >      parser-path lines like Africa/Gaborone's "2 1 CAST" middle line.
> >      Normalize m_offset to stdoff alone everywhere; to() adds save
> >      back when reconstructing.
> >
> >   2. Support ON-format DAY in Zone UNTIL field [PR 124852].
> >
> >      The UNTIL parser only accepted a plain integer as the DAY,
> >      silently misparsing tzdata.zi entries like Europe/Simferopol's
> >      "1997 Mar lastSu 1u".  Reuse the on_day machinery and the
> >      parse_on_day_body helper.
> >
> >   3. Resolve named-rule UNTIL save adjustment [PR 116110].
> >
> >      The remaining FIXME in operator>>(istream&, ZoneInfo&) for
> >      wall-time UNTILs on named-rule zone lines.  At parse time the
> >      active rule cannot be evaluated (rule records aren't all
> >      loaded yet), so the parser leaves the SAVE adjustment pending
> >      and a new fixup pass in reload_tzdb walks every pending
> >      ZoneInfo and applies the adjustment using a new
> >      find_pre_until_rule helper with iterative-boundary cascade
> >      semantics.
> >
> >      A new bit (m_until_save_pending, stolen from m_pos) marks
> >      pending entries.  The seeding code is also updated to use
> >      `t = info.begin + 1s` so a rule firing at exactly info.begin
> >      is included.
> >
> >      Removes the +11h workaround from test_apia in 116110.cc.
> >
> >   4. Cascade wall-time saves in lazy expansion seeding [PR 124853].
> >
> >      The seeding code in _M_get_sys_info 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 zones whose rule set has wall-time
> >      rules whose effective firing time depends on a prior rule's
> >      save (Europe/Paris around 1945), this gives a wrong answer.
> >
> >      Replace with a chronological cascade walker (matching zic.c's
> >      outzone() logic) that maintains a running save and interprets
> >      each Wall-time rule's at_time relative to the cascaded state.
> >
> >   5. Implement zic writezone merge optimization [PR 124854].
> >
> >      Two distinct fixes that together let lazy expansion match
> >      zic.c's writezone output for zones with rule firings near
> >      zone-line boundaries:
> >
> >      a. Always seed info.offset and info.save from find_active_rule,
> >         not just when letters is empty.  Previously, partial-
> >         expansion re-entry left info.offset/save at their
> >         (ri.offset(), 0) init values because the seeding was
> >         skipped when letters was already populated from
> >         i[-1].next_letters().  This caused zones like Europe/Berlin
> >         around 1947-06-29 to emit a 2-hour CEST sys_info with
> >         offset=3600 / save=0 — observably wrong.
> >
> >      b. Add the writezone merge optimization itself: when adjacent
> >         zone lines have different total offsets and the new line's
> >         rule set has a rule firing within |jump| of the boundary
> >         (where jump is a backward local-time jump), fold that rule
> >         into the boundary transition.  Canonical cases handled:
> >         America/Argentina/Buenos_Aires 1999-10-03 and Europe/Berlin
> >         1945-05-24.
> >
> > Test plan:
> >   * make check-target-libstdc++-v3
> RUNTESTFLAGS="conformance.exp=std/time/*"
> >     -- all existing chrono tests pass, plus the five new ones added
> >     by this series.
> >   * The comparison harness reports zero mismatches across all 447
> >     zones (563600 samples).
> >   * The abbrev sweep reports zero offset and zero abbrev diffs
> >     (169080 samples).
> >
> > Alvaro Begue (5):
> >   libstdc++: Fix numeric save offset on Zone lines [PR 124851]
> >   libstdc++: Support ON-format DAY in Zone UNTIL field [PR 124852]
> >   libstdc++: Resolve named-rule UNTIL save adjustment [PR116110]
> >   libstdc++: Cascade wall-time saves in lazy expansion seeding [PR
> >     124853]
> >   libstdc++: Implement zic writezone merge optimization [PR 124854]
> >
> >  libstdc++-v3/src/c++20/tzdb.cc                | 464 ++++++++++++++----
> >  .../testsuite/std/time/time_zone/116110.cc    |   7 +-
> >  .../std/time/time_zone/numeric_save.cc        |  66 +++
> >  .../std/time/time_zone/pr116110_named.cc      | 106 ++++
> >  .../std/time/time_zone/until_day_on.cc        | 177 +++++++
> >  .../std/time/time_zone/wall_cascade.cc        |  87 ++++
> >  .../std/time/time_zone/zone_merge.cc          | 101 ++++
> >  7 files changed, 920 insertions(+), 88 deletions(-)
> >  create mode 100644
> libstdc++-v3/testsuite/std/time/time_zone/numeric_save.cc
> >  create mode 100644
> libstdc++-v3/testsuite/std/time/time_zone/pr116110_named.cc
> >  create mode 100644
> libstdc++-v3/testsuite/std/time/time_zone/until_day_on.cc
> >  create mode 100644
> libstdc++-v3/testsuite/std/time/time_zone/wall_cascade.cc
> >  create mode 100644
> libstdc++-v3/testsuite/std/time/time_zone/zone_merge.cc
> >
> > --
> > 2.34.1
> >
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://gcc.gnu.org/pipermail/libstdc++/attachments/20260428/b4300674/attachment.htm>


More information about the Libstdc++ mailing list