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:
Zone 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
So the AN 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.
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.
---
Tested x86_64-linux.
libstdc++-v3/src/c++20/tzdb.cc | 6 ++++-
.../testsuite/std/time/time_zone/116110.cc | 22 +++++++++++++++++++
2 files changed, 27 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..b52e83b293cc
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/time/time_zone/116110.cc
@@ -0,0 +1,22 @@
+// { dg-do run { target c++20 } }
+// { dg-require-effective-target tzdb }
+// { dg-require-effective-target cxx11_abi }
+
+#include <chrono>
+#include <testsuite_hooks.h>
+
+void
+test_broken_hill()
+{
+ using namespace std::chrono;
+ 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" );
+}
+
+int main()
+{
+ test_broken_hill();
+}
--
2.53.0