[PATCH v2 1/3] libstdc++: Fix time zone transitions for Rule changes during DST [PR116110]
Tomasz Kaminski
tkaminsk@redhat.com
Thu Mar 19 07:05:14 GMT 2026
On Wed, Mar 18, 2026 at 11:23 PM Jonathan Wakely <jwakely@redhat.com> wrote:
> The Australia/Broken_Hill example in PR libstdc++/116110 demonstrates a
> bug in the time zone code. The current code gives incorrect results when
> a zone changes from one named Rule to another during DST, e.g. the
> Broken_Hill time zone uses:
>
> 9:30 AN AC%sT 2000
> 9:30 AS AC%sT
>
> So the AS Rules take effect on 2000 Jan 1 which is during DST (which
> runs from October to March).
>
> The fix for this is to update info.offset and info.save when we find an
> active rule, instead of only updating the 'letters' variable.
>
> The new tests for Pacific/Kiritimati and Pacific/Apia have some FIXME
> comments. The UNTIL times of the zone changes are incorrectly
> interpreted as UTC not wall time (due to the main topic of Bug 116110),
> and the "24" time for the Pacific/Apia zone is incorrectly ignored so
> that the change happens 24h too early (due to Bug 124554). Those tests
> will need to be adjusted later when the bugs are fixed.
>
> libstdc++-v3/ChangeLog:
>
> PR libstdc++/116110
> * src/c++20/tzdb.cc (time_zone::_M_get_sys_info): Update
> info.offset and info.save to values from the active rule.
> * testsuite/std/time/time_zone/116110.cc: New test.
>
> ---
>
> v2: Additional tests for the Pacific time zones Tomasz identified.
>
LGTM.
>
> Tested x86_64-linux.
>
> libstdc++-v3/src/c++20/tzdb.cc | 6 +-
> .../testsuite/std/time/time_zone/116110.cc | 85 +++++++++++++++++++
> 2 files changed, 90 insertions(+), 1 deletion(-)
> create mode 100644 libstdc++-v3/testsuite/std/time/time_zone/116110.cc
>
> diff --git a/libstdc++-v3/src/c++20/tzdb.cc
> b/libstdc++-v3/src/c++20/tzdb.cc
> index 53441880ae6e..e26a9ee38072 100644
> --- a/libstdc++-v3/src/c++20/tzdb.cc
> +++ b/libstdc++-v3/src/c++20/tzdb.cc
> @@ -917,7 +917,11 @@ namespace std::chrono
> }
>
> if (active_rule)
> - letters = active_rule->letters;
> + {
> + info.offset = ri.offset() + active_rule->save;
> + info.save = chrono::duration_cast<minutes>(active_rule->save);
> + letters = active_rule->letters;
> + }
> else if (first_std)
> letters = first_std->letters;
> }
> diff --git a/libstdc++-v3/testsuite/std/time/time_zone/116110.cc
> b/libstdc++-v3/testsuite/std/time/time_zone/116110.cc
> new file mode 100644
> index 000000000000..d86011cf5739
> --- /dev/null
> +++ b/libstdc++-v3/testsuite/std/time/time_zone/116110.cc
> @@ -0,0 +1,85 @@
> +// { dg-do run { target c++20 } }
> +// { dg-require-effective-target tzdb }
> +// { dg-require-effective-target cxx11_abi }
> +
> +#include <chrono>
> +#include <testsuite_hooks.h>
> +
> +using namespace std::chrono;
> +
> +void
> +test_broken_hill()
> +{
> + /*
> + R AN 1996 2005 - Mar lastSun 2s 0 S
> + R AN 2000 o - Aug lastSun 2s 1 D
> + Z Australia/Broken_Hill 9:25:48 - LMT 1895 Feb
> + 10 - AEST 1896 Aug 23
> + 9 - ACST 1899 May
> + 9:30 AU AC%sT 1971
> + 9:30 AN AC%sT 2000
> + 9:30 AS AC%sT
> + */
> + auto* tz = locate_zone("Australia/Broken_Hill");
> + auto info = tz->get_info(sys_days(2000y/February/29d) + 23h + 23min +
> 23s);
> + VERIFY( info.offset == 630min );
> + VERIFY( info.save == 60min );
> + VERIFY( info.abbrev == "ACDT" );
> +}
> +
> +void
> +test_kiritimati()
> +{
> + /* No named rules involved here, just change of fixed STDOFF at
> 1994-12-31:
> + Z Pacific/Kiritimati -10:29:20 - LMT 1901
> + -10:40 - %z 1979 Oct
> + -10 - %z 1994 Dec 31
> + 14 - %z
> + */
> + auto* tz = locate_zone("Pacific/Kiritimati");
> + local_seconds t = local_days(1994y/December/31);
> +
> + sys_seconds ut(t.time_since_epoch() /* FIXME: should be + 10h */);
> + sys_info info;
> + info = tz->get_info(ut - 1s);
> + VERIFY( info.offset == -10h );
> + VERIFY( info.save == 0h );
> + VERIFY( info.abbrev == "-10" );
> + info = tz->get_info(ut);
> + VERIFY( info.offset == 14h );
> + VERIFY( info.save == 0h );
> + VERIFY( info.abbrev == "+14" );
> +}
> +
> +void
> +test_apia()
> +{
> + /* Refers to same named rule before/after change at 2011-12-29 24:00
> + but the offset changed from -11h+1h to +13h+1h
> + Z Pacific/Apia 12:33:4 - LMT 1892 Jul 5
> + -11:26:56 - LMT 1911
> + -11:30 - %z 1950
> + -11 WS %z 2011 Dec 29 24
> + 13 WS %z
> + */
> + auto* tz = locate_zone("Pacific/Apia");
> + local_seconds t = local_days(2011y/December/29) + 24h;
> +
> + sys_seconds ut(t.time_since_epoch() /* FIXME: should be + 10h */ - 24h
> );
> + sys_info info;
> + info = tz->get_info(ut - 1s);
> + VERIFY( info.offset == (-11h + info.save) );
> + VERIFY( info.save == 1h );
> + VERIFY( info.abbrev == "-10" );
> + info = tz->get_info(ut);
> + VERIFY( info.offset == (13h + info.save) );
> + VERIFY( info.save == 1h );
> + VERIFY( info.abbrev == "+14" );
> +}
> +
> +int main()
> +{
> + test_broken_hill();
> + test_kiritimati();
> + test_apia();
> +}
> --
> 2.53.0
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://gcc.gnu.org/pipermail/libstdc++/attachments/20260319/08b008a2/attachment.htm>
More information about the Libstdc++
mailing list