On Wed, 22 Jul 2026 at 16:08, Tomasz Kaminski <[email protected]> wrote:
>
>
>
> On Mon, May 11, 2026 at 6:40 PM Jonathan Wakely <[email protected]> wrote:
>>
>> On Sun, 26 Apr 2026 at 19:51 -0400, Álvaro Begué wrote:
>> >When a Zone line specifies a numeric value as its RULES field (the
>> >constant DST save value for that zone line, e.g. Africa/Gaborone's
>> >"2 1 CAST" line), the parser stored the standard offset alone in
>> >ZoneInfo::m_offset. ZoneInfo::to() then returned that as
>> >sys_info::offset, dropping the numeric save and reporting a total
>> >offset that was wrong by the save amount.
>> >
>> >This was inconsistent with the two ZoneInfo constructors that take a
>> >sys_info, which previously stored the *total* offset (stdoff + save) in
>> >m_offset. As a result m_offset's semantics depended on which code path
>> >created the ZoneInfo, and only the parser path's lines with non-zero
>> >numeric save were observably broken.
>> >
>> >Fix by giving m_offset a single semantics: always the standard offset
>> >only. The two sys_info-taking constructors now subtract the save before
>> >storing, and to() adds it back when reconstructing the sys_info.
>> >
>> >The remaining .offset() callers inside _M_get_sys_info already expect
>> >the standard offset (they are computing rule firing times, where the
>> >save component is added separately from the active rule's save value),
>> >so no other call sites need adjustment.
>> >
>> >libstdc++-v3/ChangeLog:
>> >
>> >PR libstdc++/124851
>> >* src/c++20/tzdb.cc (ZoneInfo::ZoneInfo(sys_info&&)): Store
>> >stdoff only in m_offset (subtract info.save).
>> >(ZoneInfo::ZoneInfo(const pair<sys_info, string_view>&)):
>> >Likewise.
>> >(ZoneInfo::offset()): Document new semantics.
>> >(ZoneInfo::to(sys_info&)): Add m_save back to offset() when
>> >populating sys_info::offset.
>> >* testsuite/std/time/time_zone/numeric_save.cc: New test.
>> >
>> >Signed-off-by: Álvaro Begué <[email protected]>
>> >---
>> > libstdc++-v3/src/c++20/tzdb.cc                |  9 +--
>> > .../std/time/time_zone/numeric_save.cc        | 58 +++++++++++++++++++
>> > 2 files changed, 63 insertions(+), 4 deletions(-)
>> > create mode 100644
>> >libstdc++-v3/testsuite/std/time/time_zone/numeric_save.cc
>> >
>> >diff --git a/libstdc++-v3/src/c++20/tzdb.cc b/libstdc++-v3/src/c++20/tzdb.cc
>> >index b0fbfc46a..1e49bb749 100644
>> >--- a/libstdc++-v3/src/c++20/tzdb.cc
>> >+++ b/libstdc++-v3/src/c++20/tzdb.cc
>> >@@ -478,11 +478,12 @@ namespace std::chrono
>> >
>> >       ZoneInfo(sys_info&& info)
>> >       : m_buf(std::move(info.abbrev)), m_expanded(true), m_save(info.save),
>> >- m_offset(info.offset), m_until(info.end)
>> >+ m_offset(info.offset - seconds(info.save)), m_until(info.end)
>> >       { }
>> >
>> >       ZoneInfo(const pair<sys_info, string_view>& info)
>> >-      : m_expanded(true), m_save(info.first.save),
>> >m_offset(info.first.offset),
>> >+      : m_expanded(true), m_save(info.first.save),
>> >+ m_offset(info.first.offset - seconds(info.first.save)),
>> >  m_until(info.first.end)
>> >       {
>> >  if (info.second.size())
>> >@@ -494,7 +495,7 @@ namespace std::chrono
>> >  m_buf += info.first.abbrev;
>> >       }
>> >
>> >-      // STDOFF: Seconds from UTC during standard time.
>> >+      // STDOFF: Seconds from UTC during standard time (without any save).
>> >       seconds
>> >       offset() const noexcept { return m_offset; }
>> >
>> >@@ -539,7 +540,7 @@ namespace std::chrono
>> >   return false;
>> >
>> >  info.end = until();
>> >- info.offset = offset();
>> >+ info.offset = offset() + seconds(m_save);
>> >  info.save = minutes(m_save);
>> >  info.abbrev = format();
>> >  format_abbrev_str(info); // expand %z
>> >diff --git a/libstdc++-v3/testsuite/std/time/time_zone/numeric_save.cc
>> >b/libstdc++-v3/testsuite/std/time/time_zone/numeric_save.cc
>> >new file mode 100644
>> >index 000000000..1b5b22263
>> >--- /dev/null
>> >+++ b/libstdc++-v3/testsuite/std/time/time_zone/numeric_save.cc
>> >@@ -0,0 +1,58 @@
>> >+// { dg-do run { target c++20 } }
>> >+// { dg-require-effective-target tzdb }
>> >+// { dg-require-effective-target cxx11_abi }
>> >+// { dg-xfail-run-if "no weak override on AIX" { powerpc-ibm-aix* } }
>> >+
>> >+// When a Zone line specifies a numeric value as its RULES field, that
>> >+// value is the constant DST save value for that zone line.  Per
>> >+// [time.zone.info.sys] sys_info::offset is the total UTC offset
>> >+// (stdoff + save).
>> >+
>> >+#include <chrono>
>> >+#include <fstream>
>> >+#include <testsuite_hooks.h>
>> >+
>> >+static bool override_used = false;
>> >+
>> >+namespace __gnu_cxx
>> >+{
>> >+  const char* zoneinfo_dir_override() {
>> >+    override_used = true;
>> >+    return "./";
>> >+  }
>> >+}
>> >+
>> >+int
>> >+main()
>> >+{
>> >+  using namespace std::chrono;
>> >+
>> >+  std::ofstream("tzdata.zi") << R"(# version test_numeric_save
>> >+Z Test/Gaborone 2 -  CAT  1943 Sep 19 2
>> >+                2 1  CAST 1944 Mar 19 2
>> >+                2 -  CAT
>> >+)";
>> >+
>> >+  const auto& db = reload_tzdb();
>> >+  VERIFY( override_used );
>>
>> Please add a comment on the line above:
>>
>>    VERIFY( override_used ); // If this fails then XFAIL for the target.
>>
>> OK for trunk with that change, thanks.
>
> This patch is on turnk for some time, OK for backport to GCC 16 for 16.2?


Yes, ok for gcc-16

>>
>>
>> >+  VERIFY( db.version == "test_numeric_save" );
>> >+
>> >+  auto* tz = locate_zone("Test/Gaborone");
>> >+
>> >+  // Sample well inside the CAST (numeric-save) zone line.
>> >+  auto info = tz->get_info(sys_days(1943y/December/15));
>> >+  VERIFY( info.offset == 3h );        // stdoff +2h + save +1h
>> >+  VERIFY( info.save == 60min );
>> >+  VERIFY( info.abbrev == "CAST" );
>> >+
>> >+  // Bordering zone lines should report the standard offset with save 0.
>> >+  auto before = tz->get_info(sys_days(1943y/September/1));
>> >+  VERIFY( before.offset == 2h );
>> >+  VERIFY( before.save == 0min );
>> >+  VERIFY( before.abbrev == "CAT" );
>> >+
>> >+  auto after = tz->get_info(sys_days(1944y/April/15));
>> >+  VERIFY( after.offset == 2h );
>> >+  VERIFY( after.save == 0min );
>> >+  VERIFY( after.abbrev == "CAT" );
>> >+}
>> >--
>> >2.34.1
>>

Reply via email to