Message ID | 20241122012941.3055-1-f_l_k@t-online.de |
---|---|
State | New |
Headers | show |
Series | gcc: add a backport patch to fix an issue with tzdata 2024b | expand |
Should the backport of tzdata update like https://lists.openembedded.org/g/openembedded-core/message/207561 for scarthgap and https://lists.openembedded.org/g/openembedded-core/message/207428 for styhead be delayed a bit so that this gcc change can go at the same time? I don't know how widespread this is (or what is waybar clock module), but the .patch says: +Since making this change on trunk, the tzdata-2024b release started +using %z in the main format, not just vanguard. This makes a backport to +release branches necessary (see PR 116657). +Steve Sakoman On Fri, Nov 22, 2024 at 2:30 AM Markus Volk via lists.openembedded.org <f_l_k=t-online.de@lists.openembedded.org> wrote: > > There is an issue in the std::chrono::tzdb parser that causes problems > since the tzdata-2024b release started using %z in the main format. > > As a real world problem I encounter an issue with the waybar clock module, > which ignores the timezone setting and only shows system time. > > Signed-off-by: Markus Volk <f_l_k@t-online.de> > --- > meta/recipes-devtools/gcc/gcc-14.2.inc | 1 + > ...4fffe3fc82a710bea66ad651720d71c938b8.patch | 567 ++++++++++++++++++ > 2 files changed, 568 insertions(+) > create mode 100644 meta/recipes-devtools/gcc/gcc/gcc.git-ab884fffe3fc82a710bea66ad651720d71c938b8.patch > > diff --git a/meta/recipes-devtools/gcc/gcc-14.2.inc b/meta/recipes-devtools/gcc/gcc-14.2.inc > index f05484cfc0..9cfb246294 100644 > --- a/meta/recipes-devtools/gcc/gcc-14.2.inc > +++ b/meta/recipes-devtools/gcc/gcc-14.2.inc > @@ -68,6 +68,7 @@ SRC_URI = "${BASEURI} \ > file://0023-Fix-install-path-of-linux64.h.patch \ > file://0024-Avoid-hardcoded-build-paths-into-ppc-libgcc.patch \ > file://0025-gcc-testsuite-tweaks-for-mips-OE.patch \ > + file://gcc.git-ab884fffe3fc82a710bea66ad651720d71c938b8.patch \ > " > > S = "${TMPDIR}/work-shared/gcc-${PV}-${PR}/${SOURCEDIR}" > diff --git a/meta/recipes-devtools/gcc/gcc/gcc.git-ab884fffe3fc82a710bea66ad651720d71c938b8.patch b/meta/recipes-devtools/gcc/gcc/gcc.git-ab884fffe3fc82a710bea66ad651720d71c938b8.patch > new file mode 100644 > index 0000000000..ca6fc92e07 > --- /dev/null > +++ b/meta/recipes-devtools/gcc/gcc/gcc.git-ab884fffe3fc82a710bea66ad651720d71c938b8.patch > @@ -0,0 +1,567 @@ > +From ab884fffe3fc82a710bea66ad651720d71c938b8 Mon Sep 17 00:00:00 2001 > +From: Jonathan Wakely <jwakely@redhat.com> > +Date: Tue, 30 Apr 2024 09:52:13 +0100 > +Subject: [PATCH] libstdc++: Fix std::chrono::tzdb to work with vanguard format > + > +I found some issues in the std::chrono::tzdb parser by testing the > +tzdata "vanguard" format, which uses new features that aren't enabled in > +the "main" and "rearguard" data formats. > + > +Since 2024a the keyword "minimum" is no longer valid for the FROM and TO > +fields in a Rule line, which means that "m" is now a valid abbreviation > +for "maximum". Previously we expected either "mi" or "ma". For backwards > +compatibility, a FROM field beginning with "mi" is still supported and > +is treated as 1900. The "maximum" keyword is only allowed in TO now, > +because it makes no sense in FROM. To support these changes the > +minmax_year and minmax_year2 classes for parsing FROM and TO are > +replaced with a single years_from_to class that reads both fields. > + > +The vanguard format makes use of %z in Zone FORMAT fields, which caused > +an exception to be thrown from ZoneInfo::set_abbrev because no % or / > +characters were expected when a Zone doesn't use a named Rule. The > +ZoneInfo::to(sys_info&) function now uses format_abbrev_str to replace > +any %z with the current offset. Although format_abbrev_str also checks > +for %s and STD/DST formats, those only make sense when a named Rule is > +in effect, so won't occur when ZoneInfo::to(sys_info&) is used. > + > +Since making this change on trunk, the tzdata-2024b release started > +using %z in the main format, not just vanguard. This makes a backport to > +release branches necessary (see PR 116657). > + > +This change also implements a feature that has always been missing from > +time_zone::_M_get_sys_info: finding the Rule that is active before the > +specified time point, so that we can correctly handle %s in the FORMAT > +for the first new sys_info that gets created. This requires implementing > +a poorly documented feature of zic, to get the LETTERS field from a > +later transition, as described at > +https://mm.icann.org/pipermail/tz/2024-April/058891.html > +In order for this to work we need to be able to distinguish an empty > +letters field (as used by CE%sT where the variable part is either empty > +or "S") from "the letters field is not known for this transition". The > +tzdata file uses "-" for an empty letters field, which libstdc++ was > +previously replacing with "" when the Rule was parsed. Instead, we now > +preserve the "-" in the Rule object, so that "" can be used for the case > +where we don't know the letters (and so need to decide it). > + > +libstdc++-v3/ChangeLog: > + > + * src/c++20/tzdb.cc (minmax_year, minmax_year2): Remove. > + (years_from_to): New class replacing minmax_year and > + minmax_year2. > + (format_abbrev_str, select_std_or_dst_abbrev): Move earlier in > + the file. Handle "-" for letters. > + (ZoneInfo::to): Use format_abbrev_str to expand %z. > + (ZoneInfo::set_abbrev): Remove exception. Change parameter from > + reference to value. > + (operator>>(istream&, Rule&)): Do not clear letters when it > + contains "-". > + (time_zone::_M_get_sys_info): Add missing logic to find the Rule > + in effect before the time point. > + * testsuite/std/time/tzdb/1.cc: Adjust for vanguard format using > + "GMT" as the Zone name, not as a Link to "Etc/GMT". > + * testsuite/std/time/time_zone/sys_info_abbrev.cc: New test. > + > +(cherry picked from commit 0ca8d56f2085715f27ee536c6c344bc47af49cdd) > + > +Upstream-Status: Backport [https://gcc.gnu.org/git/gitweb.cgi?p=gcc.git;h=5ceea2ac106d6dd1aa8175670b15a801316cf1c9] > + > +Signed-off-by: Markus Volk <f_l_k@t-online.de> > +--- > + libstdc++-v3/src/c++20/tzdb.cc | 265 +++++++++++------- > + .../std/time/time_zone/sys_info_abbrev.cc | 106 +++++++ > + libstdc++-v3/testsuite/std/time/tzdb/1.cc | 6 +- > + 3 files changed, 274 insertions(+), 103 deletions(-) > + create mode 100644 libstdc++-v3/testsuite/std/time/time_zone/sys_info_abbrev.cc > + > +diff --git a/libstdc++-v3/src/c++20/tzdb.cc b/libstdc++-v3/src/c++20/tzdb.cc > +index c7c7cc9deee6..7e8cce7ce8cf 100644 > +--- a/libstdc++-v3/src/c++20/tzdb.cc > ++++ b/libstdc++-v3/src/c++20/tzdb.cc > +@@ -342,51 +342,103 @@ namespace std::chrono > + friend istream& operator>>(istream&, on_day&); > + }; > + > +- // Wrapper for chrono::year that reads a year, or one of the keywords > +- // "minimum" or "maximum", or an unambiguous prefix of a keyword. > +- struct minmax_year > ++ // Wrapper for two chrono::year values, which reads the FROM and TO > ++ // fields of a Rule line. The FROM field is a year and TO is a year or > ++ // one of the keywords "maximum" or "only" (or an abbreviation of those). > ++ // For backwards compatibility, the keyword "minimum" is recognized > ++ // for FROM and interpreted as 1900. > ++ struct years_from_to > + { > +- year& y; > ++ year& from; > ++ year& to; > + > +- friend istream& operator>>(istream& in, minmax_year&& y) > ++ friend istream& operator>>(istream& in, years_from_to&& yy) > + { > +- if (ws(in).peek() == 'm') // keywords "minimum" or "maximum" > ++ string s; > ++ auto c = ws(in).peek(); > ++ if (c == 'm') [[unlikely]] // keyword "minimum" > + { > +- string s; > +- in >> s; // extract the rest of the word, but only look at s[1] > +- if (s[1] == 'a') > +- y.y = year::max(); > +- else if (s[1] == 'i') > +- y.y = year::min(); > +- else > +- in.setstate(ios::failbit); > ++ in >> s; // extract the rest of the word > ++ yy.from = year(1900); > ++ } > ++ else if (int num = 0; in >> num) [[likely]] > ++ yy.from = year{num}; > ++ > ++ c = ws(in).peek(); > ++ if (c == 'm') // keyword "maximum" > ++ { > ++ in >> s; // extract the rest of the word > ++ yy.to = year::max(); > ++ } > ++ else if (c == 'o') // keyword "only" > ++ { > ++ in >> s; // extract the rest of the word > ++ yy.to = yy.from; > + } > + else if (int num = 0; in >> num) > +- y.y = year{num}; > ++ yy.to = year{num}; > ++ > + return in; > + } > + }; > + > +- // As above for minmax_year, but also supports the keyword "only", > +- // meaning that the TO year is the same as the FROM year. > +- struct minmax_year2 > ++ bool > ++ select_std_or_dst_abbrev(string& abbrev, minutes save) > + { > +- minmax_year to; > +- year from; > ++ if (size_t pos = abbrev.find('/'); pos != string::npos) > ++ { > ++ // Select one of "STD/DST" for standard or daylight. > ++ if (save == 0min) > ++ abbrev.erase(pos); > ++ else > ++ abbrev.erase(0, pos + 1); > ++ return true; > ++ } > ++ return false; > ++ } > + > +- friend istream& operator>>(istream& in, minmax_year2&& y) > +- { > +- if (ws(in).peek() == 'o') // keyword "only" > +- { > +- string s; > +- in >> s; // extract the whole keyword > +- y.to.y = y.from; > +- } > +- else > +- in >> std::move(y.to); > +- return in; > +- } > +- }; > ++ // Set the sys_info::abbrev string by expanding any placeholders. > ++ void > ++ format_abbrev_str(sys_info& info, string_view letters = {}) > ++ { > ++ if (size_t pos = info.abbrev.find('%'); pos != string::npos) > ++ { > ++ if (info.abbrev[pos + 1] == 's') > ++ { > ++ // Expand "%s" to the variable part, given by Rule::letters. > ++ if (letters == "-") > ++ info.abbrev.erase(pos, 2); > ++ else > ++ info.abbrev.replace(pos, 2, letters); > ++ } > ++ else if (info.abbrev[pos + 1] == 'z') > ++ { > ++ // Expand "%z" to the UT offset as +/-hh, +/-hhmm, or +/-hhmmss. > ++ hh_mm_ss<seconds> t(info.offset); > ++ string z(1, "+-"[t.is_negative()]); > ++ long val = t.hours().count(); > ++ int digits = 2; > ++ if (int m = t.minutes().count()) > ++ { > ++ digits = 4; > ++ val *= 100; > ++ val += m; > ++ if (int s = t.seconds().count()) > ++ { > ++ digits = 6; > ++ val *= 100; > ++ val += s; > ++ } > ++ } > ++ auto sval = std::to_string(val); > ++ z += string(digits - sval.size(), '0'); > ++ z += sval; > ++ info.abbrev.replace(pos, 2, z); > ++ } > ++ } > ++ else > ++ select_std_or_dst_abbrev(info.abbrev, info.save); > ++ } > + > + // A time zone information record. > + // Zone NAME STDOFF RULES FORMAT [UNTIL] > +@@ -462,6 +514,7 @@ namespace std::chrono > + info.offset = offset(); > + info.save = minutes(m_save); > + info.abbrev = format(); > ++ format_abbrev_str(info); // expand %z > + return true; > + } > + > +@@ -469,12 +522,9 @@ namespace std::chrono > + friend class time_zone; > + > + void > +- set_abbrev(const string& abbrev) > ++ set_abbrev(string abbrev) > + { > +- // In practice, the FORMAT field never needs expanding here. > +- if (abbrev.find_first_of("/%") != abbrev.npos) > +- __throw_runtime_error("std::chrono::time_zone: invalid data"); > +- m_buf = abbrev; > ++ m_buf = std::move(abbrev); > + m_pos = 0; > + m_expanded = true; > + } > +@@ -544,9 +594,7 @@ namespace std::chrono > + > + // Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S > + > +- in >> quoted(rule.name) > +- >> minmax_year{rule.from} > +- >> minmax_year2{rule.to, rule.from}; > ++ in >> quoted(rule.name) >> years_from_to{rule.from, rule.to}; > + > + if (char type; in >> type && type != '-') > + in.setstate(ios::failbit); > +@@ -557,7 +605,7 @@ namespace std::chrono > + if (save_time.indicator != at_time::Wall) > + { > + // We don't actually store the save_time.indicator, because we > +- // assume that it's always deducable from the actual offset value. > ++ // assume that it's always deducible from the offset value. > + auto expected = save_time.time == 0s > + ? at_time::Standard > + : at_time::Daylight; > +@@ -567,8 +615,6 @@ namespace std::chrono > + rule.save = save_time.time; > + > + in >> rule.letters; > +- if (rule.letters == "-") > +- rule.letters.clear(); > + return in; > + } > + > +@@ -719,58 +765,6 @@ namespace std::chrono > + #endif // TZDB_DISABLED > + }; > + > +-#ifndef TZDB_DISABLED > +- namespace > +- { > +- bool > +- select_std_or_dst_abbrev(string& abbrev, minutes save) > +- { > +- if (size_t pos = abbrev.find('/'); pos != string::npos) > +- { > +- // Select one of "STD/DST" for standard or daylight. > +- if (save == 0min) > +- abbrev.erase(pos); > +- else > +- abbrev.erase(0, pos + 1); > +- return true; > +- } > +- return false; > +- } > +- > +- // Set the sys_info::abbrev string by expanding any placeholders. > +- void > +- format_abbrev_str(sys_info& info, string_view letters = {}) > +- { > +- if (size_t pos = info.abbrev.find("%s"); pos != string::npos) > +- { > +- // Expand "%s" to the variable part, given by Rule::letters. > +- info.abbrev.replace(pos, 2, letters); > +- } > +- else if (size_t pos = info.abbrev.find("%z"); pos != string::npos) > +- { > +- // Expand "%z" to the UT offset as +/-hh, +/-hhmm, or +/-hhmmss. > +- hh_mm_ss<seconds> t(info.offset); > +- string z(1, "+-"[t.is_negative()]); > +- long val = t.hours().count(); > +- if (minutes m = t.minutes(); m != m.zero()) > +- { > +- val *= 100; > +- val += m.count(); > +- if (seconds s = t.seconds(); s != s.zero()) > +- { > +- val *= 100; > +- val += s.count(); > +- } > +- } > +- z += std::to_string(val); > +- info.abbrev.replace(pos, 2, z); > +- } > +- else > +- select_std_or_dst_abbrev(info.abbrev, info.save); > +- } > +- } > +-#endif // TZDB_DISABLED > +- > + // Implementation of std::chrono::time_zone::get_info(const sys_time<D>&) > + sys_info > + time_zone::_M_get_sys_info(sys_seconds tp) const > +@@ -839,12 +833,72 @@ namespace std::chrono > + info.abbrev = ri.format(); > + > + string_view letters; > +- if (i != infos.begin()) > ++ if (i != infos.begin() && i[-1].expanded()) > ++ letters = i[-1].next_letters(); > ++ > ++ if (letters.empty()) > + { > +- if (i[-1].expanded()) > +- letters = i[-1].next_letters(); > +- // XXX else need to find Rule active before this time and use it > +- // to know the initial offset, save, and letters. > ++ sys_seconds t = info.begin - seconds(1); > ++ const year_month_day date(chrono::floor<days>(t)); > ++ > ++ // Try to find a Rule active before this time, to get initial > ++ // SAVE and LETTERS values. There may not be a Rule for the period > ++ // before the first DST transition, so find the earliest DST->STD > ++ // transition and use the LETTERS from that. > ++ const Rule* active_rule = nullptr; > ++ sys_seconds active_rule_start = sys_seconds::min(); > ++ const Rule* first_std = nullptr; > ++ for (const auto& rule : rules) > ++ { > ++ if (rule.save == minutes(0)) > ++ { > ++ if (!first_std) > ++ first_std = &rule; > ++ else if (rule.from < first_std->from) > ++ first_std = &rule; > ++ else if (rule.from == first_std->from) > ++ { > ++ if (rule.start_time(rule.from, {}) > ++ < first_std->start_time(first_std->from, {})) > ++ first_std = &rule; > ++ } > ++ } > ++ > ++ year y = date.year(); > ++ > ++ if (y > rule.to) // rule no longer applies at time t > ++ continue; > ++ if (y < rule.from) // rule doesn't apply yet at time t > ++ continue; > ++ > ++ sys_seconds rule_start; > ++ > ++ seconds offset{}; // appropriate for at_time::Universal > ++ if (rule.when.indicator == at_time::Wall) > ++ offset = info.offset; > ++ else if (rule.when.indicator == at_time::Standard) > ++ offset = ri.offset(); > ++ > ++ // Time the rule takes effect this year: > ++ rule_start = rule.start_time(y, offset); > ++ > ++ if (rule_start >= t && rule.from < y) > ++ { > ++ // Try this rule in the previous year. > ++ rule_start = rule.start_time(--y, offset); > ++ } > ++ > ++ if (active_rule_start < rule_start && rule_start < t) > ++ { > ++ active_rule_start = rule_start; > ++ active_rule = &rule; > ++ } > ++ } > ++ > ++ if (active_rule) > ++ letters = active_rule->letters; > ++ else if (first_std) > ++ letters = first_std->letters; > + } > + > + const Rule* curr_rule = nullptr; > +@@ -2069,9 +2123,11 @@ namespace std::chrono > + istringstream in2(std::move(rules)); > + in2 >> rules_time; > + inf.m_save = duration_cast<minutes>(rules_time.time); > ++ // If the FORMAT is "STD/DST" then we can choose the right one > ++ // now, so that we store a shorter string. > + select_std_or_dst_abbrev(fmt, inf.m_save); > + } > +- inf.set_abbrev(fmt); > ++ inf.set_abbrev(std::move(fmt)); > + } > + > + // YEAR [MONTH [DAY [TIME]]] > +@@ -2082,7 +2138,12 @@ namespace std::chrono > + abbrev_month m{January}; > + int d = 1; > + at_time t{}; > ++ // XXX DAY should support ON format, e.g. lastSun or Sun>=8 > + in >> m >> d >> t; > ++ // XXX UNTIL field should be interpreted > ++ // "using the rules in effect just before the transition" > ++ // so might need to store as year_month_day and hh_mm_ss and only > ++ // convert to a sys_time once we know the offset in effect. > + inf.m_until = sys_days(year(y)/m.m/day(d)) + seconds(t.time); > + } > + else > +diff --git a/libstdc++-v3/testsuite/std/time/time_zone/sys_info_abbrev.cc b/libstdc++-v3/testsuite/std/time/time_zone/sys_info_abbrev.cc > +new file mode 100644 > +index 000000000000..f1a8fff02f58 > +--- /dev/null > ++++ b/libstdc++-v3/testsuite/std/time/time_zone/sys_info_abbrev.cc > +@@ -0,0 +1,106 @@ > ++// { 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* } } > ++ > ++#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 "./"; > ++ } > ++} > ++ > ++using namespace std::chrono; > ++ > ++void > ++test_format() > ++{ > ++ std::ofstream("tzdata.zi") << R"(# version test_1 > ++Zone Africa/Bissau -1:2:20 - LMT 1912 Ja 1 1u > ++ -1 - %z 1975 > ++ 0 - GMT > ++Zon Some/Zone 1:2:3 - %z 1900 > ++ 1:23:45 - %z 1950 > ++Zo Another/Zone 1:2:3 - AZ0 1901 > ++ 1 Roolz A%sZ 2000 > ++ 1 Roolz SAZ/DAZ 2005 > ++ 1 Roolz %z > ++Rule Roolz 1950 max - April 1 2 1 D > ++Rul Roolz 1950 max - Oct 1 1 0 S > ++Z Strange/Zone 1 - X%sX 1980 > ++ 1 - FOO/BAR 1990 > ++ 2:00 - %zzz 1995 > ++ 0:9 - %zzz 1996 > ++ 0:8:7 - %zzz 1997 > ++ 0:6:5.5 - %zzz 1998 > ++)"; > ++ > ++ const auto& db = reload_tzdb(); > ++ VERIFY( override_used ); // If this fails then XFAIL for the target. > ++ VERIFY( db.version == "test_1" ); > ++ > ++ // Test formatting %z as > ++ auto tz = locate_zone("Africa/Bissau"); > ++ auto inf = tz->get_info(sys_days(1974y/1/1)); > ++ VERIFY( inf.abbrev == "-01" ); > ++ > ++ tz = locate_zone("Some/Zone"); > ++ inf = tz->get_info(sys_days(1899y/1/1)); > ++ VERIFY( inf.abbrev == "+010203" ); > ++ inf = tz->get_info(sys_days(1955y/1/1)); > ++ VERIFY( inf.abbrev == "+012345" ); > ++ > ++ tz = locate_zone("Another/Zone"); > ++ // Test formatting %s as the LETTER/S field from the active Rule. > ++ inf = tz->get_info(sys_days(1910y/January/1)); > ++ VERIFY( inf.abbrev == "ASZ" ); > ++ inf = tz->get_info(sys_days(1950y/January/1)); > ++ VERIFY( inf.abbrev == "ASZ" ); > ++ inf = tz->get_info(sys_days(1950y/June/1)); > ++ VERIFY( inf.abbrev == "ADZ" ); > ++ inf = tz->get_info(sys_days(1999y/January/1)); > ++ VERIFY( inf.abbrev == "ASZ" ); > ++ inf = tz->get_info(sys_days(1999y/July/1)); > ++ VERIFY( inf.abbrev == "ADZ" ); > ++ // Test formatting STD/DST according to the active Rule. > ++ inf = tz->get_info(sys_days(2000y/January/2)); > ++ VERIFY( inf.abbrev == "SAZ" ); > ++ inf = tz->get_info(sys_days(2001y/January/1)); > ++ VERIFY( inf.abbrev == "SAZ" ); > ++ inf = tz->get_info(sys_days(2001y/July/1)); > ++ VERIFY( inf.abbrev == "DAZ" ); > ++ // Test formatting %z as the offset determined by the active Rule. > ++ inf = tz->get_info(sys_days(2005y/January/2)); > ++ VERIFY( inf.abbrev == "+01" ); > ++ inf = tz->get_info(sys_days(2006y/January/1)); > ++ VERIFY( inf.abbrev == "+01" ); > ++ inf = tz->get_info(sys_days(2006y/July/1)); > ++ VERIFY( inf.abbrev == "+02" ); > ++ > ++ // Test formatting %z, %s and S/D for a Zone with no associated Rules. > ++ tz = locate_zone("Strange/Zone"); > ++ inf = tz->get_info(sys_days(1979y/January/1)); > ++ VERIFY( inf.abbrev == "XX" ); // No Rule means nothing to use for %s. > ++ inf = tz->get_info(sys_days(1981y/July/1)); > ++ VERIFY( inf.abbrev == "FOO" ); // Always standard time means first string. > ++ inf = tz->get_info(sys_days(1994y/July/1)); > ++ VERIFY( inf.abbrev == "+02zz" ); > ++ inf = tz->get_info(sys_days(1995y/July/1)); > ++ VERIFY( inf.abbrev == "+0009zz" ); > ++ inf = tz->get_info(sys_days(1996y/July/1)); > ++ VERIFY( inf.abbrev == "+000807zz" ); > ++ inf = tz->get_info(sys_days(1997y/July/1)); > ++ VERIFY( inf.abbrev == "+000606zz" ); > ++} > ++ > ++int main() > ++{ > ++ test_format(); > ++} > +diff --git a/libstdc++-v3/testsuite/std/time/tzdb/1.cc b/libstdc++-v3/testsuite/std/time/tzdb/1.cc > +index 796f3a8b4256..7a31c1c20ba7 100644 > +--- a/libstdc++-v3/testsuite/std/time/tzdb/1.cc > ++++ b/libstdc++-v3/testsuite/std/time/tzdb/1.cc > +@@ -39,11 +39,15 @@ test_locate() > + const tzdb& db = get_tzdb(); > + const time_zone* tz = db.locate_zone("GMT"); > + VERIFY( tz != nullptr ); > +- VERIFY( tz->name() == "Etc/GMT" ); > + VERIFY( tz == std::chrono::locate_zone("GMT") ); > + VERIFY( tz == db.locate_zone("Etc/GMT") ); > + VERIFY( tz == db.locate_zone("Etc/GMT+0") ); > + > ++ // Since 2022f GMT is now a Zone and Etc/GMT a link instead of vice versa, > ++ // but only when using the vanguard format. As of 2024a, the main and > ++ // rearguard formats still have Etc/GMT as a Zone and GMT as a link. > ++ VERIFY( tz->name() == "GMT" || tz->name() == "Etc/GMT" ); > ++ > + VERIFY( db.locate_zone(db.current_zone()->name()) == db.current_zone() ); > + } > + > +-- > +2.43.5 > + > -- > 2.47.0 > > > -=-=-=-=-=-=-=-=-=-=-=- > Links: You receive all messages sent to this group. > View/Reply Online (#207584): https://lists.openembedded.org/g/openembedded-core/message/207584 > Mute This Topic: https://lists.openembedded.org/mt/109715703/3617156 > Group Owner: openembedded-core+owner@lists.openembedded.org > Unsubscribe: https://lists.openembedded.org/g/openembedded-core/unsub [martin.jansa@gmail.com] > -=-=-=-=-=-=-=-=-=-=-=- >
On Fri, Nov 22 2024 at 02:35:37 AM +01:00:00, Martin Jansa
<martin.jansa@gmail.com> wrote:
> I don't know how widespread this is (or what is waybar clock module)
The issue was discussed here
<https://github.com/Alexays/Waybar/issues/3024>
Patch is fine however I would suggest to remove the hunk changing changellog files it will make it easy to backport On Thu, Nov 21, 2024 at 5:30 PM Markus Volk via lists.openembedded.org <f_l_k=t-online.de@lists.openembedded.org> wrote: > There is an issue in the std::chrono::tzdb parser that causes problems > since the tzdata-2024b release started using %z in the main format. > > As a real world problem I encounter an issue with the waybar clock module, > which ignores the timezone setting and only shows system time. > > Signed-off-by: Markus Volk <f_l_k@t-online.de> > --- > meta/recipes-devtools/gcc/gcc-14.2.inc | 1 + > ...4fffe3fc82a710bea66ad651720d71c938b8.patch | 567 ++++++++++++++++++ > 2 files changed, 568 insertions(+) > create mode 100644 > meta/recipes-devtools/gcc/gcc/gcc.git-ab884fffe3fc82a710bea66ad651720d71c938b8.patch > > diff --git a/meta/recipes-devtools/gcc/gcc-14.2.inc > b/meta/recipes-devtools/gcc/gcc-14.2.inc > index f05484cfc0..9cfb246294 100644 > --- a/meta/recipes-devtools/gcc/gcc-14.2.inc > +++ b/meta/recipes-devtools/gcc/gcc-14.2.inc > @@ -68,6 +68,7 @@ SRC_URI = "${BASEURI} \ > file://0023-Fix-install-path-of-linux64.h.patch \ > file://0024-Avoid-hardcoded-build-paths-into-ppc-libgcc.patch \ > file://0025-gcc-testsuite-tweaks-for-mips-OE.patch \ > + file://gcc.git-ab884fffe3fc82a710bea66ad651720d71c938b8.patch \ > " > > S = "${TMPDIR}/work-shared/gcc-${PV}-${PR}/${SOURCEDIR}" > diff --git > a/meta/recipes-devtools/gcc/gcc/gcc.git-ab884fffe3fc82a710bea66ad651720d71c938b8.patch > b/meta/recipes-devtools/gcc/gcc/gcc.git-ab884fffe3fc82a710bea66ad651720d71c938b8.patch > new file mode 100644 > index 0000000000..ca6fc92e07 > --- /dev/null > +++ > b/meta/recipes-devtools/gcc/gcc/gcc.git-ab884fffe3fc82a710bea66ad651720d71c938b8.patch > @@ -0,0 +1,567 @@ > +From ab884fffe3fc82a710bea66ad651720d71c938b8 Mon Sep 17 00:00:00 2001 > +From: Jonathan Wakely <jwakely@redhat.com> > +Date: Tue, 30 Apr 2024 09:52:13 +0100 > +Subject: [PATCH] libstdc++: Fix std::chrono::tzdb to work with vanguard > format > + > +I found some issues in the std::chrono::tzdb parser by testing the > +tzdata "vanguard" format, which uses new features that aren't enabled in > +the "main" and "rearguard" data formats. > + > +Since 2024a the keyword "minimum" is no longer valid for the FROM and TO > +fields in a Rule line, which means that "m" is now a valid abbreviation > +for "maximum". Previously we expected either "mi" or "ma". For backwards > +compatibility, a FROM field beginning with "mi" is still supported and > +is treated as 1900. The "maximum" keyword is only allowed in TO now, > +because it makes no sense in FROM. To support these changes the > +minmax_year and minmax_year2 classes for parsing FROM and TO are > +replaced with a single years_from_to class that reads both fields. > + > +The vanguard format makes use of %z in Zone FORMAT fields, which caused > +an exception to be thrown from ZoneInfo::set_abbrev because no % or / > +characters were expected when a Zone doesn't use a named Rule. The > +ZoneInfo::to(sys_info&) function now uses format_abbrev_str to replace > +any %z with the current offset. Although format_abbrev_str also checks > +for %s and STD/DST formats, those only make sense when a named Rule is > +in effect, so won't occur when ZoneInfo::to(sys_info&) is used. > + > +Since making this change on trunk, the tzdata-2024b release started > +using %z in the main format, not just vanguard. This makes a backport to > +release branches necessary (see PR 116657). > + > +This change also implements a feature that has always been missing from > +time_zone::_M_get_sys_info: finding the Rule that is active before the > +specified time point, so that we can correctly handle %s in the FORMAT > +for the first new sys_info that gets created. This requires implementing > +a poorly documented feature of zic, to get the LETTERS field from a > +later transition, as described at > +https://mm.icann.org/pipermail/tz/2024-April/058891.html > +In order for this to work we need to be able to distinguish an empty > +letters field (as used by CE%sT where the variable part is either empty > +or "S") from "the letters field is not known for this transition". The > +tzdata file uses "-" for an empty letters field, which libstdc++ was > +previously replacing with "" when the Rule was parsed. Instead, we now > +preserve the "-" in the Rule object, so that "" can be used for the case > +where we don't know the letters (and so need to decide it). > + > +libstdc++-v3/ChangeLog: > + > + * src/c++20/tzdb.cc (minmax_year, minmax_year2): Remove. > + (years_from_to): New class replacing minmax_year and > + minmax_year2. > + (format_abbrev_str, select_std_or_dst_abbrev): Move earlier in > + the file. Handle "-" for letters. > + (ZoneInfo::to): Use format_abbrev_str to expand %z. > + (ZoneInfo::set_abbrev): Remove exception. Change parameter from > + reference to value. > + (operator>>(istream&, Rule&)): Do not clear letters when it > + contains "-". > + (time_zone::_M_get_sys_info): Add missing logic to find the Rule > + in effect before the time point. > + * testsuite/std/time/tzdb/1.cc: Adjust for vanguard format using > + "GMT" as the Zone name, not as a Link to "Etc/GMT". > + * testsuite/std/time/time_zone/sys_info_abbrev.cc: New test. > + > +(cherry picked from commit 0ca8d56f2085715f27ee536c6c344bc47af49cdd) > + > +Upstream-Status: Backport [ > https://gcc.gnu.org/git/gitweb.cgi?p=gcc.git;h=5ceea2ac106d6dd1aa8175670b15a801316cf1c9 > ] > + > +Signed-off-by: Markus Volk <f_l_k@t-online.de> > +--- > + libstdc++-v3/src/c++20/tzdb.cc | 265 +++++++++++------- > + .../std/time/time_zone/sys_info_abbrev.cc | 106 +++++++ > + libstdc++-v3/testsuite/std/time/tzdb/1.cc | 6 +- > + 3 files changed, 274 insertions(+), 103 deletions(-) > + create mode 100644 > libstdc++-v3/testsuite/std/time/time_zone/sys_info_abbrev.cc > + > +diff --git a/libstdc++-v3/src/c++20/tzdb.cc > b/libstdc++-v3/src/c++20/tzdb.cc > +index c7c7cc9deee6..7e8cce7ce8cf 100644 > +--- a/libstdc++-v3/src/c++20/tzdb.cc > ++++ b/libstdc++-v3/src/c++20/tzdb.cc > +@@ -342,51 +342,103 @@ namespace std::chrono > + friend istream& operator>>(istream&, on_day&); > + }; > + > +- // Wrapper for chrono::year that reads a year, or one of the keywords > +- // "minimum" or "maximum", or an unambiguous prefix of a keyword. > +- struct minmax_year > ++ // Wrapper for two chrono::year values, which reads the FROM and TO > ++ // fields of a Rule line. The FROM field is a year and TO is a year > or > ++ // one of the keywords "maximum" or "only" (or an abbreviation of > those). > ++ // For backwards compatibility, the keyword "minimum" is recognized > ++ // for FROM and interpreted as 1900. > ++ struct years_from_to > + { > +- year& y; > ++ year& from; > ++ year& to; > + > +- friend istream& operator>>(istream& in, minmax_year&& y) > ++ friend istream& operator>>(istream& in, years_from_to&& yy) > + { > +- if (ws(in).peek() == 'm') // keywords "minimum" or "maximum" > ++ string s; > ++ auto c = ws(in).peek(); > ++ if (c == 'm') [[unlikely]] // keyword "minimum" > + { > +- string s; > +- in >> s; // extract the rest of the word, but only look at s[1] > +- if (s[1] == 'a') > +- y.y = year::max(); > +- else if (s[1] == 'i') > +- y.y = year::min(); > +- else > +- in.setstate(ios::failbit); > ++ in >> s; // extract the rest of the word > ++ yy.from = year(1900); > ++ } > ++ else if (int num = 0; in >> num) [[likely]] > ++ yy.from = year{num}; > ++ > ++ c = ws(in).peek(); > ++ if (c == 'm') // keyword "maximum" > ++ { > ++ in >> s; // extract the rest of the word > ++ yy.to = year::max(); > ++ } > ++ else if (c == 'o') // keyword "only" > ++ { > ++ in >> s; // extract the rest of the word > ++ yy.to = yy.from; > + } > + else if (int num = 0; in >> num) > +- y.y = year{num}; > ++ yy.to = year{num}; > ++ > + return in; > + } > + }; > + > +- // As above for minmax_year, but also supports the keyword "only", > +- // meaning that the TO year is the same as the FROM year. > +- struct minmax_year2 > ++ bool > ++ select_std_or_dst_abbrev(string& abbrev, minutes save) > + { > +- minmax_year to; > +- year from; > ++ if (size_t pos = abbrev.find('/'); pos != string::npos) > ++ { > ++ // Select one of "STD/DST" for standard or daylight. > ++ if (save == 0min) > ++ abbrev.erase(pos); > ++ else > ++ abbrev.erase(0, pos + 1); > ++ return true; > ++ } > ++ return false; > ++ } > + > +- friend istream& operator>>(istream& in, minmax_year2&& y) > +- { > +- if (ws(in).peek() == 'o') // keyword "only" > +- { > +- string s; > +- in >> s; // extract the whole keyword > +- y.to.y = y.from; > +- } > +- else > +- in >> std::move(y.to); > +- return in; > +- } > +- }; > ++ // Set the sys_info::abbrev string by expanding any placeholders. > ++ void > ++ format_abbrev_str(sys_info& info, string_view letters = {}) > ++ { > ++ if (size_t pos = info.abbrev.find('%'); pos != string::npos) > ++ { > ++ if (info.abbrev[pos + 1] == 's') > ++ { > ++ // Expand "%s" to the variable part, given by Rule::letters. > ++ if (letters == "-") > ++ info.abbrev.erase(pos, 2); > ++ else > ++ info.abbrev.replace(pos, 2, letters); > ++ } > ++ else if (info.abbrev[pos + 1] == 'z') > ++ { > ++ // Expand "%z" to the UT offset as +/-hh, +/-hhmm, or > +/-hhmmss. > ++ hh_mm_ss<seconds> t(info.offset); > ++ string z(1, "+-"[t.is_negative()]); > ++ long val = t.hours().count(); > ++ int digits = 2; > ++ if (int m = t.minutes().count()) > ++ { > ++ digits = 4; > ++ val *= 100; > ++ val += m; > ++ if (int s = t.seconds().count()) > ++ { > ++ digits = 6; > ++ val *= 100; > ++ val += s; > ++ } > ++ } > ++ auto sval = std::to_string(val); > ++ z += string(digits - sval.size(), '0'); > ++ z += sval; > ++ info.abbrev.replace(pos, 2, z); > ++ } > ++ } > ++ else > ++ select_std_or_dst_abbrev(info.abbrev, info.save); > ++ } > + > + // A time zone information record. > + // Zone NAME STDOFF RULES FORMAT [UNTIL] > +@@ -462,6 +514,7 @@ namespace std::chrono > + info.offset = offset(); > + info.save = minutes(m_save); > + info.abbrev = format(); > ++ format_abbrev_str(info); // expand %z > + return true; > + } > + > +@@ -469,12 +522,9 @@ namespace std::chrono > + friend class time_zone; > + > + void > +- set_abbrev(const string& abbrev) > ++ set_abbrev(string abbrev) > + { > +- // In practice, the FORMAT field never needs expanding here. > +- if (abbrev.find_first_of("/%") != abbrev.npos) > +- __throw_runtime_error("std::chrono::time_zone: invalid data"); > +- m_buf = abbrev; > ++ m_buf = std::move(abbrev); > + m_pos = 0; > + m_expanded = true; > + } > +@@ -544,9 +594,7 @@ namespace std::chrono > + > + // Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S > + > +- in >> quoted(rule.name) > +- >> minmax_year{rule.from} > +- >> minmax_year2{rule.to, rule.from}; > ++ in >> quoted(rule.name) >> years_from_to{rule.from, rule.to}; > + > + if (char type; in >> type && type != '-') > + in.setstate(ios::failbit); > +@@ -557,7 +605,7 @@ namespace std::chrono > + if (save_time.indicator != at_time::Wall) > + { > + // We don't actually store the save_time.indicator, because we > +- // assume that it's always deducable from the actual offset > value. > ++ // assume that it's always deducible from the offset value. > + auto expected = save_time.time == 0s > + ? at_time::Standard > + : at_time::Daylight; > +@@ -567,8 +615,6 @@ namespace std::chrono > + rule.save = save_time.time; > + > + in >> rule.letters; > +- if (rule.letters == "-") > +- rule.letters.clear(); > + return in; > + } > + > +@@ -719,58 +765,6 @@ namespace std::chrono > + #endif // TZDB_DISABLED > + }; > + > +-#ifndef TZDB_DISABLED > +- namespace > +- { > +- bool > +- select_std_or_dst_abbrev(string& abbrev, minutes save) > +- { > +- if (size_t pos = abbrev.find('/'); pos != string::npos) > +- { > +- // Select one of "STD/DST" for standard or daylight. > +- if (save == 0min) > +- abbrev.erase(pos); > +- else > +- abbrev.erase(0, pos + 1); > +- return true; > +- } > +- return false; > +- } > +- > +- // Set the sys_info::abbrev string by expanding any placeholders. > +- void > +- format_abbrev_str(sys_info& info, string_view letters = {}) > +- { > +- if (size_t pos = info.abbrev.find("%s"); pos != string::npos) > +- { > +- // Expand "%s" to the variable part, given by Rule::letters. > +- info.abbrev.replace(pos, 2, letters); > +- } > +- else if (size_t pos = info.abbrev.find("%z"); pos != string::npos) > +- { > +- // Expand "%z" to the UT offset as +/-hh, +/-hhmm, or +/-hhmmss. > +- hh_mm_ss<seconds> t(info.offset); > +- string z(1, "+-"[t.is_negative()]); > +- long val = t.hours().count(); > +- if (minutes m = t.minutes(); m != m.zero()) > +- { > +- val *= 100; > +- val += m.count(); > +- if (seconds s = t.seconds(); s != s.zero()) > +- { > +- val *= 100; > +- val += s.count(); > +- } > +- } > +- z += std::to_string(val); > +- info.abbrev.replace(pos, 2, z); > +- } > +- else > +- select_std_or_dst_abbrev(info.abbrev, info.save); > +- } > +- } > +-#endif // TZDB_DISABLED > +- > + // Implementation of std::chrono::time_zone::get_info(const > sys_time<D>&) > + sys_info > + time_zone::_M_get_sys_info(sys_seconds tp) const > +@@ -839,12 +833,72 @@ namespace std::chrono > + info.abbrev = ri.format(); > + > + string_view letters; > +- if (i != infos.begin()) > ++ if (i != infos.begin() && i[-1].expanded()) > ++ letters = i[-1].next_letters(); > ++ > ++ if (letters.empty()) > + { > +- if (i[-1].expanded()) > +- letters = i[-1].next_letters(); > +- // XXX else need to find Rule active before this time and use it > +- // to know the initial offset, save, and letters. > ++ sys_seconds t = info.begin - seconds(1); > ++ const year_month_day date(chrono::floor<days>(t)); > ++ > ++ // Try to find a Rule active before this time, to get initial > ++ // SAVE and LETTERS values. There may not be a Rule for the period > ++ // before the first DST transition, so find the earliest DST->STD > ++ // transition and use the LETTERS from that. > ++ const Rule* active_rule = nullptr; > ++ sys_seconds active_rule_start = sys_seconds::min(); > ++ const Rule* first_std = nullptr; > ++ for (const auto& rule : rules) > ++ { > ++ if (rule.save == minutes(0)) > ++ { > ++ if (!first_std) > ++ first_std = &rule; > ++ else if (rule.from < first_std->from) > ++ first_std = &rule; > ++ else if (rule.from == first_std->from) > ++ { > ++ if (rule.start_time(rule.from, {}) > ++ < first_std->start_time(first_std->from, {})) > ++ first_std = &rule; > ++ } > ++ } > ++ > ++ year y = date.year(); > ++ > ++ if (y > rule.to) // rule no longer applies at time t > ++ continue; > ++ if (y < rule.from) // rule doesn't apply yet at time t > ++ continue; > ++ > ++ sys_seconds rule_start; > ++ > ++ seconds offset{}; // appropriate for at_time::Universal > ++ if (rule.when.indicator == at_time::Wall) > ++ offset = info.offset; > ++ else if (rule.when.indicator == at_time::Standard) > ++ offset = ri.offset(); > ++ > ++ // Time the rule takes effect this year: > ++ rule_start = rule.start_time(y, offset); > ++ > ++ if (rule_start >= t && rule.from < y) > ++ { > ++ // Try this rule in the previous year. > ++ rule_start = rule.start_time(--y, offset); > ++ } > ++ > ++ if (active_rule_start < rule_start && rule_start < t) > ++ { > ++ active_rule_start = rule_start; > ++ active_rule = &rule; > ++ } > ++ } > ++ > ++ if (active_rule) > ++ letters = active_rule->letters; > ++ else if (first_std) > ++ letters = first_std->letters; > + } > + > + const Rule* curr_rule = nullptr; > +@@ -2069,9 +2123,11 @@ namespace std::chrono > + istringstream in2(std::move(rules)); > + in2 >> rules_time; > + inf.m_save = duration_cast<minutes>(rules_time.time); > ++ // If the FORMAT is "STD/DST" then we can choose the right > one > ++ // now, so that we store a shorter string. > + select_std_or_dst_abbrev(fmt, inf.m_save); > + } > +- inf.set_abbrev(fmt); > ++ inf.set_abbrev(std::move(fmt)); > + } > + > + // YEAR [MONTH [DAY [TIME]]] > +@@ -2082,7 +2138,12 @@ namespace std::chrono > + abbrev_month m{January}; > + int d = 1; > + at_time t{}; > ++ // XXX DAY should support ON format, e.g. lastSun or Sun>=8 > + in >> m >> d >> t; > ++ // XXX UNTIL field should be interpreted > ++ // "using the rules in effect just before the transition" > ++ // so might need to store as year_month_day and hh_mm_ss and only > ++ // convert to a sys_time once we know the offset in effect. > + inf.m_until = sys_days(year(y)/m.m/day(d)) + seconds(t.time); > + } > + else > +diff --git a/libstdc++-v3/testsuite/std/time/time_zone/sys_info_abbrev.cc > b/libstdc++-v3/testsuite/std/time/time_zone/sys_info_abbrev.cc > +new file mode 100644 > +index 000000000000..f1a8fff02f58 > +--- /dev/null > ++++ b/libstdc++-v3/testsuite/std/time/time_zone/sys_info_abbrev.cc > +@@ -0,0 +1,106 @@ > ++// { 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* } } > ++ > ++#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 "./"; > ++ } > ++} > ++ > ++using namespace std::chrono; > ++ > ++void > ++test_format() > ++{ > ++ std::ofstream("tzdata.zi") << R"(# version test_1 > ++Zone Africa/Bissau -1:2:20 - LMT 1912 Ja 1 1u > ++ -1 - %z 1975 > ++ 0 - GMT > ++Zon Some/Zone 1:2:3 - %z 1900 > ++ 1:23:45 - %z 1950 > ++Zo Another/Zone 1:2:3 - AZ0 1901 > ++ 1 Roolz A%sZ 2000 > ++ 1 Roolz SAZ/DAZ 2005 > ++ 1 Roolz %z > ++Rule Roolz 1950 max - April 1 2 1 D > ++Rul Roolz 1950 max - Oct 1 1 0 S > ++Z Strange/Zone 1 - X%sX 1980 > ++ 1 - FOO/BAR 1990 > ++ 2:00 - %zzz 1995 > ++ 0:9 - %zzz 1996 > ++ 0:8:7 - %zzz 1997 > ++ 0:6:5.5 - %zzz 1998 > ++)"; > ++ > ++ const auto& db = reload_tzdb(); > ++ VERIFY( override_used ); // If this fails then XFAIL for the target. > ++ VERIFY( db.version == "test_1" ); > ++ > ++ // Test formatting %z as > ++ auto tz = locate_zone("Africa/Bissau"); > ++ auto inf = tz->get_info(sys_days(1974y/1/1)); > ++ VERIFY( inf.abbrev == "-01" ); > ++ > ++ tz = locate_zone("Some/Zone"); > ++ inf = tz->get_info(sys_days(1899y/1/1)); > ++ VERIFY( inf.abbrev == "+010203" ); > ++ inf = tz->get_info(sys_days(1955y/1/1)); > ++ VERIFY( inf.abbrev == "+012345" ); > ++ > ++ tz = locate_zone("Another/Zone"); > ++ // Test formatting %s as the LETTER/S field from the active Rule. > ++ inf = tz->get_info(sys_days(1910y/January/1)); > ++ VERIFY( inf.abbrev == "ASZ" ); > ++ inf = tz->get_info(sys_days(1950y/January/1)); > ++ VERIFY( inf.abbrev == "ASZ" ); > ++ inf = tz->get_info(sys_days(1950y/June/1)); > ++ VERIFY( inf.abbrev == "ADZ" ); > ++ inf = tz->get_info(sys_days(1999y/January/1)); > ++ VERIFY( inf.abbrev == "ASZ" ); > ++ inf = tz->get_info(sys_days(1999y/July/1)); > ++ VERIFY( inf.abbrev == "ADZ" ); > ++ // Test formatting STD/DST according to the active Rule. > ++ inf = tz->get_info(sys_days(2000y/January/2)); > ++ VERIFY( inf.abbrev == "SAZ" ); > ++ inf = tz->get_info(sys_days(2001y/January/1)); > ++ VERIFY( inf.abbrev == "SAZ" ); > ++ inf = tz->get_info(sys_days(2001y/July/1)); > ++ VERIFY( inf.abbrev == "DAZ" ); > ++ // Test formatting %z as the offset determined by the active Rule. > ++ inf = tz->get_info(sys_days(2005y/January/2)); > ++ VERIFY( inf.abbrev == "+01" ); > ++ inf = tz->get_info(sys_days(2006y/January/1)); > ++ VERIFY( inf.abbrev == "+01" ); > ++ inf = tz->get_info(sys_days(2006y/July/1)); > ++ VERIFY( inf.abbrev == "+02" ); > ++ > ++ // Test formatting %z, %s and S/D for a Zone with no associated Rules. > ++ tz = locate_zone("Strange/Zone"); > ++ inf = tz->get_info(sys_days(1979y/January/1)); > ++ VERIFY( inf.abbrev == "XX" ); // No Rule means nothing to use for %s. > ++ inf = tz->get_info(sys_days(1981y/July/1)); > ++ VERIFY( inf.abbrev == "FOO" ); // Always standard time means first > string. > ++ inf = tz->get_info(sys_days(1994y/July/1)); > ++ VERIFY( inf.abbrev == "+02zz" ); > ++ inf = tz->get_info(sys_days(1995y/July/1)); > ++ VERIFY( inf.abbrev == "+0009zz" ); > ++ inf = tz->get_info(sys_days(1996y/July/1)); > ++ VERIFY( inf.abbrev == "+000807zz" ); > ++ inf = tz->get_info(sys_days(1997y/July/1)); > ++ VERIFY( inf.abbrev == "+000606zz" ); > ++} > ++ > ++int main() > ++{ > ++ test_format(); > ++} > +diff --git a/libstdc++-v3/testsuite/std/time/tzdb/1.cc > b/libstdc++-v3/testsuite/std/time/tzdb/1.cc > +index 796f3a8b4256..7a31c1c20ba7 100644 > +--- a/libstdc++-v3/testsuite/std/time/tzdb/1.cc > ++++ b/libstdc++-v3/testsuite/std/time/tzdb/1.cc > +@@ -39,11 +39,15 @@ test_locate() > + const tzdb& db = get_tzdb(); > + const time_zone* tz = db.locate_zone("GMT"); > + VERIFY( tz != nullptr ); > +- VERIFY( tz->name() == "Etc/GMT" ); > + VERIFY( tz == std::chrono::locate_zone("GMT") ); > + VERIFY( tz == db.locate_zone("Etc/GMT") ); > + VERIFY( tz == db.locate_zone("Etc/GMT+0") ); > + > ++ // Since 2022f GMT is now a Zone and Etc/GMT a link instead of vice > versa, > ++ // but only when using the vanguard format. As of 2024a, the main and > ++ // rearguard formats still have Etc/GMT as a Zone and GMT as a link. > ++ VERIFY( tz->name() == "GMT" || tz->name() == "Etc/GMT" ); > ++ > + VERIFY( db.locate_zone(db.current_zone()->name()) == db.current_zone() > ); > + } > + > +-- > +2.43.5 > + > -- > 2.47.0 > > > -=-=-=-=-=-=-=-=-=-=-=- > Links: You receive all messages sent to this group. > View/Reply Online (#207584): > https://lists.openembedded.org/g/openembedded-core/message/207584 > Mute This Topic: https://lists.openembedded.org/mt/109715703/1997914 > Group Owner: openembedded-core+owner@lists.openembedded.org > Unsubscribe: https://lists.openembedded.org/g/openembedded-core/unsub [ > raj.khem@gmail.com] > -=-=-=-=-=-=-=-=-=-=-=- > >
On Thu, Nov 21 2024 at 07:04:06 PM -08:00:00, Khem Raj <raj.khem@gmail.com> wrote: > Patch is fine however I would suggest to remove the hunk changing > changellog files it will make it easy to backport Removed the comments on the changelog from the commit message. but I didn't find a hunk that patches Changelog
On Thu, Nov 21, 2024 at 5:35 PM Martin Jansa <martin.jansa@gmail.com> wrote: > > Should the backport of tzdata update like > https://lists.openembedded.org/g/openembedded-core/message/207561 > for scarthgap and > https://lists.openembedded.org/g/openembedded-core/message/207428 > for styhead be delayed a bit so that this gcc change can go at the same time? Yes, this makes sense. I'll keep the tzdata patch in my test queue but won't merge until I also have the gcc fix. Markus, could you send versions of this patch for stable branches too? (styhead, scarthgap, kirkstone) Thanks! Steve > > I don't know how widespread this is (or what is waybar clock module), > but the .patch says: > > +Since making this change on trunk, the tzdata-2024b release started > +using %z in the main format, not just vanguard. This makes a backport to > +release branches necessary (see PR 116657). > > +Steve Sakoman > > On Fri, Nov 22, 2024 at 2:30 AM Markus Volk via lists.openembedded.org > <f_l_k=t-online.de@lists.openembedded.org> wrote: > > > > There is an issue in the std::chrono::tzdb parser that causes problems > > since the tzdata-2024b release started using %z in the main format. > > > > As a real world problem I encounter an issue with the waybar clock module, > > which ignores the timezone setting and only shows system time. > > > > Signed-off-by: Markus Volk <f_l_k@t-online.de> > > --- > > meta/recipes-devtools/gcc/gcc-14.2.inc | 1 + > > ...4fffe3fc82a710bea66ad651720d71c938b8.patch | 567 ++++++++++++++++++ > > 2 files changed, 568 insertions(+) > > create mode 100644 meta/recipes-devtools/gcc/gcc/gcc.git-ab884fffe3fc82a710bea66ad651720d71c938b8.patch > > > > diff --git a/meta/recipes-devtools/gcc/gcc-14.2.inc b/meta/recipes-devtools/gcc/gcc-14.2.inc > > index f05484cfc0..9cfb246294 100644 > > --- a/meta/recipes-devtools/gcc/gcc-14.2.inc > > +++ b/meta/recipes-devtools/gcc/gcc-14.2.inc > > @@ -68,6 +68,7 @@ SRC_URI = "${BASEURI} \ > > file://0023-Fix-install-path-of-linux64.h.patch \ > > file://0024-Avoid-hardcoded-build-paths-into-ppc-libgcc.patch \ > > file://0025-gcc-testsuite-tweaks-for-mips-OE.patch \ > > + file://gcc.git-ab884fffe3fc82a710bea66ad651720d71c938b8.patch \ > > " > > > > S = "${TMPDIR}/work-shared/gcc-${PV}-${PR}/${SOURCEDIR}" > > diff --git a/meta/recipes-devtools/gcc/gcc/gcc.git-ab884fffe3fc82a710bea66ad651720d71c938b8.patch b/meta/recipes-devtools/gcc/gcc/gcc.git-ab884fffe3fc82a710bea66ad651720d71c938b8.patch > > new file mode 100644 > > index 0000000000..ca6fc92e07 > > --- /dev/null > > +++ b/meta/recipes-devtools/gcc/gcc/gcc.git-ab884fffe3fc82a710bea66ad651720d71c938b8.patch > > @@ -0,0 +1,567 @@ > > +From ab884fffe3fc82a710bea66ad651720d71c938b8 Mon Sep 17 00:00:00 2001 > > +From: Jonathan Wakely <jwakely@redhat.com> > > +Date: Tue, 30 Apr 2024 09:52:13 +0100 > > +Subject: [PATCH] libstdc++: Fix std::chrono::tzdb to work with vanguard format > > + > > +I found some issues in the std::chrono::tzdb parser by testing the > > +tzdata "vanguard" format, which uses new features that aren't enabled in > > +the "main" and "rearguard" data formats. > > + > > +Since 2024a the keyword "minimum" is no longer valid for the FROM and TO > > +fields in a Rule line, which means that "m" is now a valid abbreviation > > +for "maximum". Previously we expected either "mi" or "ma". For backwards > > +compatibility, a FROM field beginning with "mi" is still supported and > > +is treated as 1900. The "maximum" keyword is only allowed in TO now, > > +because it makes no sense in FROM. To support these changes the > > +minmax_year and minmax_year2 classes for parsing FROM and TO are > > +replaced with a single years_from_to class that reads both fields. > > + > > +The vanguard format makes use of %z in Zone FORMAT fields, which caused > > +an exception to be thrown from ZoneInfo::set_abbrev because no % or / > > +characters were expected when a Zone doesn't use a named Rule. The > > +ZoneInfo::to(sys_info&) function now uses format_abbrev_str to replace > > +any %z with the current offset. Although format_abbrev_str also checks > > +for %s and STD/DST formats, those only make sense when a named Rule is > > +in effect, so won't occur when ZoneInfo::to(sys_info&) is used. > > + > > +Since making this change on trunk, the tzdata-2024b release started > > +using %z in the main format, not just vanguard. This makes a backport to > > +release branches necessary (see PR 116657). > > + > > +This change also implements a feature that has always been missing from > > +time_zone::_M_get_sys_info: finding the Rule that is active before the > > +specified time point, so that we can correctly handle %s in the FORMAT > > +for the first new sys_info that gets created. This requires implementing > > +a poorly documented feature of zic, to get the LETTERS field from a > > +later transition, as described at > > +https://mm.icann.org/pipermail/tz/2024-April/058891.html > > +In order for this to work we need to be able to distinguish an empty > > +letters field (as used by CE%sT where the variable part is either empty > > +or "S") from "the letters field is not known for this transition". The > > +tzdata file uses "-" for an empty letters field, which libstdc++ was > > +previously replacing with "" when the Rule was parsed. Instead, we now > > +preserve the "-" in the Rule object, so that "" can be used for the case > > +where we don't know the letters (and so need to decide it). > > + > > +libstdc++-v3/ChangeLog: > > + > > + * src/c++20/tzdb.cc (minmax_year, minmax_year2): Remove. > > + (years_from_to): New class replacing minmax_year and > > + minmax_year2. > > + (format_abbrev_str, select_std_or_dst_abbrev): Move earlier in > > + the file. Handle "-" for letters. > > + (ZoneInfo::to): Use format_abbrev_str to expand %z. > > + (ZoneInfo::set_abbrev): Remove exception. Change parameter from > > + reference to value. > > + (operator>>(istream&, Rule&)): Do not clear letters when it > > + contains "-". > > + (time_zone::_M_get_sys_info): Add missing logic to find the Rule > > + in effect before the time point. > > + * testsuite/std/time/tzdb/1.cc: Adjust for vanguard format using > > + "GMT" as the Zone name, not as a Link to "Etc/GMT". > > + * testsuite/std/time/time_zone/sys_info_abbrev.cc: New test. > > + > > +(cherry picked from commit 0ca8d56f2085715f27ee536c6c344bc47af49cdd) > > + > > +Upstream-Status: Backport [https://gcc.gnu.org/git/gitweb.cgi?p=gcc.git;h=5ceea2ac106d6dd1aa8175670b15a801316cf1c9] > > + > > +Signed-off-by: Markus Volk <f_l_k@t-online.de> > > +--- > > + libstdc++-v3/src/c++20/tzdb.cc | 265 +++++++++++------- > > + .../std/time/time_zone/sys_info_abbrev.cc | 106 +++++++ > > + libstdc++-v3/testsuite/std/time/tzdb/1.cc | 6 +- > > + 3 files changed, 274 insertions(+), 103 deletions(-) > > + create mode 100644 libstdc++-v3/testsuite/std/time/time_zone/sys_info_abbrev.cc > > + > > +diff --git a/libstdc++-v3/src/c++20/tzdb.cc b/libstdc++-v3/src/c++20/tzdb.cc > > +index c7c7cc9deee6..7e8cce7ce8cf 100644 > > +--- a/libstdc++-v3/src/c++20/tzdb.cc > > ++++ b/libstdc++-v3/src/c++20/tzdb.cc > > +@@ -342,51 +342,103 @@ namespace std::chrono > > + friend istream& operator>>(istream&, on_day&); > > + }; > > + > > +- // Wrapper for chrono::year that reads a year, or one of the keywords > > +- // "minimum" or "maximum", or an unambiguous prefix of a keyword. > > +- struct minmax_year > > ++ // Wrapper for two chrono::year values, which reads the FROM and TO > > ++ // fields of a Rule line. The FROM field is a year and TO is a year or > > ++ // one of the keywords "maximum" or "only" (or an abbreviation of those). > > ++ // For backwards compatibility, the keyword "minimum" is recognized > > ++ // for FROM and interpreted as 1900. > > ++ struct years_from_to > > + { > > +- year& y; > > ++ year& from; > > ++ year& to; > > + > > +- friend istream& operator>>(istream& in, minmax_year&& y) > > ++ friend istream& operator>>(istream& in, years_from_to&& yy) > > + { > > +- if (ws(in).peek() == 'm') // keywords "minimum" or "maximum" > > ++ string s; > > ++ auto c = ws(in).peek(); > > ++ if (c == 'm') [[unlikely]] // keyword "minimum" > > + { > > +- string s; > > +- in >> s; // extract the rest of the word, but only look at s[1] > > +- if (s[1] == 'a') > > +- y.y = year::max(); > > +- else if (s[1] == 'i') > > +- y.y = year::min(); > > +- else > > +- in.setstate(ios::failbit); > > ++ in >> s; // extract the rest of the word > > ++ yy.from = year(1900); > > ++ } > > ++ else if (int num = 0; in >> num) [[likely]] > > ++ yy.from = year{num}; > > ++ > > ++ c = ws(in).peek(); > > ++ if (c == 'm') // keyword "maximum" > > ++ { > > ++ in >> s; // extract the rest of the word > > ++ yy.to = year::max(); > > ++ } > > ++ else if (c == 'o') // keyword "only" > > ++ { > > ++ in >> s; // extract the rest of the word > > ++ yy.to = yy.from; > > + } > > + else if (int num = 0; in >> num) > > +- y.y = year{num}; > > ++ yy.to = year{num}; > > ++ > > + return in; > > + } > > + }; > > + > > +- // As above for minmax_year, but also supports the keyword "only", > > +- // meaning that the TO year is the same as the FROM year. > > +- struct minmax_year2 > > ++ bool > > ++ select_std_or_dst_abbrev(string& abbrev, minutes save) > > + { > > +- minmax_year to; > > +- year from; > > ++ if (size_t pos = abbrev.find('/'); pos != string::npos) > > ++ { > > ++ // Select one of "STD/DST" for standard or daylight. > > ++ if (save == 0min) > > ++ abbrev.erase(pos); > > ++ else > > ++ abbrev.erase(0, pos + 1); > > ++ return true; > > ++ } > > ++ return false; > > ++ } > > + > > +- friend istream& operator>>(istream& in, minmax_year2&& y) > > +- { > > +- if (ws(in).peek() == 'o') // keyword "only" > > +- { > > +- string s; > > +- in >> s; // extract the whole keyword > > +- y.to.y = y.from; > > +- } > > +- else > > +- in >> std::move(y.to); > > +- return in; > > +- } > > +- }; > > ++ // Set the sys_info::abbrev string by expanding any placeholders. > > ++ void > > ++ format_abbrev_str(sys_info& info, string_view letters = {}) > > ++ { > > ++ if (size_t pos = info.abbrev.find('%'); pos != string::npos) > > ++ { > > ++ if (info.abbrev[pos + 1] == 's') > > ++ { > > ++ // Expand "%s" to the variable part, given by Rule::letters. > > ++ if (letters == "-") > > ++ info.abbrev.erase(pos, 2); > > ++ else > > ++ info.abbrev.replace(pos, 2, letters); > > ++ } > > ++ else if (info.abbrev[pos + 1] == 'z') > > ++ { > > ++ // Expand "%z" to the UT offset as +/-hh, +/-hhmm, or +/-hhmmss. > > ++ hh_mm_ss<seconds> t(info.offset); > > ++ string z(1, "+-"[t.is_negative()]); > > ++ long val = t.hours().count(); > > ++ int digits = 2; > > ++ if (int m = t.minutes().count()) > > ++ { > > ++ digits = 4; > > ++ val *= 100; > > ++ val += m; > > ++ if (int s = t.seconds().count()) > > ++ { > > ++ digits = 6; > > ++ val *= 100; > > ++ val += s; > > ++ } > > ++ } > > ++ auto sval = std::to_string(val); > > ++ z += string(digits - sval.size(), '0'); > > ++ z += sval; > > ++ info.abbrev.replace(pos, 2, z); > > ++ } > > ++ } > > ++ else > > ++ select_std_or_dst_abbrev(info.abbrev, info.save); > > ++ } > > + > > + // A time zone information record. > > + // Zone NAME STDOFF RULES FORMAT [UNTIL] > > +@@ -462,6 +514,7 @@ namespace std::chrono > > + info.offset = offset(); > > + info.save = minutes(m_save); > > + info.abbrev = format(); > > ++ format_abbrev_str(info); // expand %z > > + return true; > > + } > > + > > +@@ -469,12 +522,9 @@ namespace std::chrono > > + friend class time_zone; > > + > > + void > > +- set_abbrev(const string& abbrev) > > ++ set_abbrev(string abbrev) > > + { > > +- // In practice, the FORMAT field never needs expanding here. > > +- if (abbrev.find_first_of("/%") != abbrev.npos) > > +- __throw_runtime_error("std::chrono::time_zone: invalid data"); > > +- m_buf = abbrev; > > ++ m_buf = std::move(abbrev); > > + m_pos = 0; > > + m_expanded = true; > > + } > > +@@ -544,9 +594,7 @@ namespace std::chrono > > + > > + // Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S > > + > > +- in >> quoted(rule.name) > > +- >> minmax_year{rule.from} > > +- >> minmax_year2{rule.to, rule.from}; > > ++ in >> quoted(rule.name) >> years_from_to{rule.from, rule.to}; > > + > > + if (char type; in >> type && type != '-') > > + in.setstate(ios::failbit); > > +@@ -557,7 +605,7 @@ namespace std::chrono > > + if (save_time.indicator != at_time::Wall) > > + { > > + // We don't actually store the save_time.indicator, because we > > +- // assume that it's always deducable from the actual offset value. > > ++ // assume that it's always deducible from the offset value. > > + auto expected = save_time.time == 0s > > + ? at_time::Standard > > + : at_time::Daylight; > > +@@ -567,8 +615,6 @@ namespace std::chrono > > + rule.save = save_time.time; > > + > > + in >> rule.letters; > > +- if (rule.letters == "-") > > +- rule.letters.clear(); > > + return in; > > + } > > + > > +@@ -719,58 +765,6 @@ namespace std::chrono > > + #endif // TZDB_DISABLED > > + }; > > + > > +-#ifndef TZDB_DISABLED > > +- namespace > > +- { > > +- bool > > +- select_std_or_dst_abbrev(string& abbrev, minutes save) > > +- { > > +- if (size_t pos = abbrev.find('/'); pos != string::npos) > > +- { > > +- // Select one of "STD/DST" for standard or daylight. > > +- if (save == 0min) > > +- abbrev.erase(pos); > > +- else > > +- abbrev.erase(0, pos + 1); > > +- return true; > > +- } > > +- return false; > > +- } > > +- > > +- // Set the sys_info::abbrev string by expanding any placeholders. > > +- void > > +- format_abbrev_str(sys_info& info, string_view letters = {}) > > +- { > > +- if (size_t pos = info.abbrev.find("%s"); pos != string::npos) > > +- { > > +- // Expand "%s" to the variable part, given by Rule::letters. > > +- info.abbrev.replace(pos, 2, letters); > > +- } > > +- else if (size_t pos = info.abbrev.find("%z"); pos != string::npos) > > +- { > > +- // Expand "%z" to the UT offset as +/-hh, +/-hhmm, or +/-hhmmss. > > +- hh_mm_ss<seconds> t(info.offset); > > +- string z(1, "+-"[t.is_negative()]); > > +- long val = t.hours().count(); > > +- if (minutes m = t.minutes(); m != m.zero()) > > +- { > > +- val *= 100; > > +- val += m.count(); > > +- if (seconds s = t.seconds(); s != s.zero()) > > +- { > > +- val *= 100; > > +- val += s.count(); > > +- } > > +- } > > +- z += std::to_string(val); > > +- info.abbrev.replace(pos, 2, z); > > +- } > > +- else > > +- select_std_or_dst_abbrev(info.abbrev, info.save); > > +- } > > +- } > > +-#endif // TZDB_DISABLED > > +- > > + // Implementation of std::chrono::time_zone::get_info(const sys_time<D>&) > > + sys_info > > + time_zone::_M_get_sys_info(sys_seconds tp) const > > +@@ -839,12 +833,72 @@ namespace std::chrono > > + info.abbrev = ri.format(); > > + > > + string_view letters; > > +- if (i != infos.begin()) > > ++ if (i != infos.begin() && i[-1].expanded()) > > ++ letters = i[-1].next_letters(); > > ++ > > ++ if (letters.empty()) > > + { > > +- if (i[-1].expanded()) > > +- letters = i[-1].next_letters(); > > +- // XXX else need to find Rule active before this time and use it > > +- // to know the initial offset, save, and letters. > > ++ sys_seconds t = info.begin - seconds(1); > > ++ const year_month_day date(chrono::floor<days>(t)); > > ++ > > ++ // Try to find a Rule active before this time, to get initial > > ++ // SAVE and LETTERS values. There may not be a Rule for the period > > ++ // before the first DST transition, so find the earliest DST->STD > > ++ // transition and use the LETTERS from that. > > ++ const Rule* active_rule = nullptr; > > ++ sys_seconds active_rule_start = sys_seconds::min(); > > ++ const Rule* first_std = nullptr; > > ++ for (const auto& rule : rules) > > ++ { > > ++ if (rule.save == minutes(0)) > > ++ { > > ++ if (!first_std) > > ++ first_std = &rule; > > ++ else if (rule.from < first_std->from) > > ++ first_std = &rule; > > ++ else if (rule.from == first_std->from) > > ++ { > > ++ if (rule.start_time(rule.from, {}) > > ++ < first_std->start_time(first_std->from, {})) > > ++ first_std = &rule; > > ++ } > > ++ } > > ++ > > ++ year y = date.year(); > > ++ > > ++ if (y > rule.to) // rule no longer applies at time t > > ++ continue; > > ++ if (y < rule.from) // rule doesn't apply yet at time t > > ++ continue; > > ++ > > ++ sys_seconds rule_start; > > ++ > > ++ seconds offset{}; // appropriate for at_time::Universal > > ++ if (rule.when.indicator == at_time::Wall) > > ++ offset = info.offset; > > ++ else if (rule.when.indicator == at_time::Standard) > > ++ offset = ri.offset(); > > ++ > > ++ // Time the rule takes effect this year: > > ++ rule_start = rule.start_time(y, offset); > > ++ > > ++ if (rule_start >= t && rule.from < y) > > ++ { > > ++ // Try this rule in the previous year. > > ++ rule_start = rule.start_time(--y, offset); > > ++ } > > ++ > > ++ if (active_rule_start < rule_start && rule_start < t) > > ++ { > > ++ active_rule_start = rule_start; > > ++ active_rule = &rule; > > ++ } > > ++ } > > ++ > > ++ if (active_rule) > > ++ letters = active_rule->letters; > > ++ else if (first_std) > > ++ letters = first_std->letters; > > + } > > + > > + const Rule* curr_rule = nullptr; > > +@@ -2069,9 +2123,11 @@ namespace std::chrono > > + istringstream in2(std::move(rules)); > > + in2 >> rules_time; > > + inf.m_save = duration_cast<minutes>(rules_time.time); > > ++ // If the FORMAT is "STD/DST" then we can choose the right one > > ++ // now, so that we store a shorter string. > > + select_std_or_dst_abbrev(fmt, inf.m_save); > > + } > > +- inf.set_abbrev(fmt); > > ++ inf.set_abbrev(std::move(fmt)); > > + } > > + > > + // YEAR [MONTH [DAY [TIME]]] > > +@@ -2082,7 +2138,12 @@ namespace std::chrono > > + abbrev_month m{January}; > > + int d = 1; > > + at_time t{}; > > ++ // XXX DAY should support ON format, e.g. lastSun or Sun>=8 > > + in >> m >> d >> t; > > ++ // XXX UNTIL field should be interpreted > > ++ // "using the rules in effect just before the transition" > > ++ // so might need to store as year_month_day and hh_mm_ss and only > > ++ // convert to a sys_time once we know the offset in effect. > > + inf.m_until = sys_days(year(y)/m.m/day(d)) + seconds(t.time); > > + } > > + else > > +diff --git a/libstdc++-v3/testsuite/std/time/time_zone/sys_info_abbrev.cc b/libstdc++-v3/testsuite/std/time/time_zone/sys_info_abbrev.cc > > +new file mode 100644 > > +index 000000000000..f1a8fff02f58 > > +--- /dev/null > > ++++ b/libstdc++-v3/testsuite/std/time/time_zone/sys_info_abbrev.cc > > +@@ -0,0 +1,106 @@ > > ++// { 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* } } > > ++ > > ++#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 "./"; > > ++ } > > ++} > > ++ > > ++using namespace std::chrono; > > ++ > > ++void > > ++test_format() > > ++{ > > ++ std::ofstream("tzdata.zi") << R"(# version test_1 > > ++Zone Africa/Bissau -1:2:20 - LMT 1912 Ja 1 1u > > ++ -1 - %z 1975 > > ++ 0 - GMT > > ++Zon Some/Zone 1:2:3 - %z 1900 > > ++ 1:23:45 - %z 1950 > > ++Zo Another/Zone 1:2:3 - AZ0 1901 > > ++ 1 Roolz A%sZ 2000 > > ++ 1 Roolz SAZ/DAZ 2005 > > ++ 1 Roolz %z > > ++Rule Roolz 1950 max - April 1 2 1 D > > ++Rul Roolz 1950 max - Oct 1 1 0 S > > ++Z Strange/Zone 1 - X%sX 1980 > > ++ 1 - FOO/BAR 1990 > > ++ 2:00 - %zzz 1995 > > ++ 0:9 - %zzz 1996 > > ++ 0:8:7 - %zzz 1997 > > ++ 0:6:5.5 - %zzz 1998 > > ++)"; > > ++ > > ++ const auto& db = reload_tzdb(); > > ++ VERIFY( override_used ); // If this fails then XFAIL for the target. > > ++ VERIFY( db.version == "test_1" ); > > ++ > > ++ // Test formatting %z as > > ++ auto tz = locate_zone("Africa/Bissau"); > > ++ auto inf = tz->get_info(sys_days(1974y/1/1)); > > ++ VERIFY( inf.abbrev == "-01" ); > > ++ > > ++ tz = locate_zone("Some/Zone"); > > ++ inf = tz->get_info(sys_days(1899y/1/1)); > > ++ VERIFY( inf.abbrev == "+010203" ); > > ++ inf = tz->get_info(sys_days(1955y/1/1)); > > ++ VERIFY( inf.abbrev == "+012345" ); > > ++ > > ++ tz = locate_zone("Another/Zone"); > > ++ // Test formatting %s as the LETTER/S field from the active Rule. > > ++ inf = tz->get_info(sys_days(1910y/January/1)); > > ++ VERIFY( inf.abbrev == "ASZ" ); > > ++ inf = tz->get_info(sys_days(1950y/January/1)); > > ++ VERIFY( inf.abbrev == "ASZ" ); > > ++ inf = tz->get_info(sys_days(1950y/June/1)); > > ++ VERIFY( inf.abbrev == "ADZ" ); > > ++ inf = tz->get_info(sys_days(1999y/January/1)); > > ++ VERIFY( inf.abbrev == "ASZ" ); > > ++ inf = tz->get_info(sys_days(1999y/July/1)); > > ++ VERIFY( inf.abbrev == "ADZ" ); > > ++ // Test formatting STD/DST according to the active Rule. > > ++ inf = tz->get_info(sys_days(2000y/January/2)); > > ++ VERIFY( inf.abbrev == "SAZ" ); > > ++ inf = tz->get_info(sys_days(2001y/January/1)); > > ++ VERIFY( inf.abbrev == "SAZ" ); > > ++ inf = tz->get_info(sys_days(2001y/July/1)); > > ++ VERIFY( inf.abbrev == "DAZ" ); > > ++ // Test formatting %z as the offset determined by the active Rule. > > ++ inf = tz->get_info(sys_days(2005y/January/2)); > > ++ VERIFY( inf.abbrev == "+01" ); > > ++ inf = tz->get_info(sys_days(2006y/January/1)); > > ++ VERIFY( inf.abbrev == "+01" ); > > ++ inf = tz->get_info(sys_days(2006y/July/1)); > > ++ VERIFY( inf.abbrev == "+02" ); > > ++ > > ++ // Test formatting %z, %s and S/D for a Zone with no associated Rules. > > ++ tz = locate_zone("Strange/Zone"); > > ++ inf = tz->get_info(sys_days(1979y/January/1)); > > ++ VERIFY( inf.abbrev == "XX" ); // No Rule means nothing to use for %s. > > ++ inf = tz->get_info(sys_days(1981y/July/1)); > > ++ VERIFY( inf.abbrev == "FOO" ); // Always standard time means first string. > > ++ inf = tz->get_info(sys_days(1994y/July/1)); > > ++ VERIFY( inf.abbrev == "+02zz" ); > > ++ inf = tz->get_info(sys_days(1995y/July/1)); > > ++ VERIFY( inf.abbrev == "+0009zz" ); > > ++ inf = tz->get_info(sys_days(1996y/July/1)); > > ++ VERIFY( inf.abbrev == "+000807zz" ); > > ++ inf = tz->get_info(sys_days(1997y/July/1)); > > ++ VERIFY( inf.abbrev == "+000606zz" ); > > ++} > > ++ > > ++int main() > > ++{ > > ++ test_format(); > > ++} > > +diff --git a/libstdc++-v3/testsuite/std/time/tzdb/1.cc b/libstdc++-v3/testsuite/std/time/tzdb/1.cc > > +index 796f3a8b4256..7a31c1c20ba7 100644 > > +--- a/libstdc++-v3/testsuite/std/time/tzdb/1.cc > > ++++ b/libstdc++-v3/testsuite/std/time/tzdb/1.cc > > +@@ -39,11 +39,15 @@ test_locate() > > + const tzdb& db = get_tzdb(); > > + const time_zone* tz = db.locate_zone("GMT"); > > + VERIFY( tz != nullptr ); > > +- VERIFY( tz->name() == "Etc/GMT" ); > > + VERIFY( tz == std::chrono::locate_zone("GMT") ); > > + VERIFY( tz == db.locate_zone("Etc/GMT") ); > > + VERIFY( tz == db.locate_zone("Etc/GMT+0") ); > > + > > ++ // Since 2022f GMT is now a Zone and Etc/GMT a link instead of vice versa, > > ++ // but only when using the vanguard format. As of 2024a, the main and > > ++ // rearguard formats still have Etc/GMT as a Zone and GMT as a link. > > ++ VERIFY( tz->name() == "GMT" || tz->name() == "Etc/GMT" ); > > ++ > > + VERIFY( db.locate_zone(db.current_zone()->name()) == db.current_zone() ); > > + } > > + > > +-- > > +2.43.5 > > + > > -- > > 2.47.0 > > > > > > -=-=-=-=-=-=-=-=-=-=-=- > > Links: You receive all messages sent to this group. > > View/Reply Online (#207584): https://lists.openembedded.org/g/openembedded-core/message/207584 > > Mute This Topic: https://lists.openembedded.org/mt/109715703/3617156 > > Group Owner: openembedded-core+owner@lists.openembedded.org > > Unsubscribe: https://lists.openembedded.org/g/openembedded-core/unsub [martin.jansa@gmail.com] > > -=-=-=-=-=-=-=-=-=-=-=- > >
diff --git a/meta/recipes-devtools/gcc/gcc-14.2.inc b/meta/recipes-devtools/gcc/gcc-14.2.inc index f05484cfc0..9cfb246294 100644 --- a/meta/recipes-devtools/gcc/gcc-14.2.inc +++ b/meta/recipes-devtools/gcc/gcc-14.2.inc @@ -68,6 +68,7 @@ SRC_URI = "${BASEURI} \ file://0023-Fix-install-path-of-linux64.h.patch \ file://0024-Avoid-hardcoded-build-paths-into-ppc-libgcc.patch \ file://0025-gcc-testsuite-tweaks-for-mips-OE.patch \ + file://gcc.git-ab884fffe3fc82a710bea66ad651720d71c938b8.patch \ " S = "${TMPDIR}/work-shared/gcc-${PV}-${PR}/${SOURCEDIR}" diff --git a/meta/recipes-devtools/gcc/gcc/gcc.git-ab884fffe3fc82a710bea66ad651720d71c938b8.patch b/meta/recipes-devtools/gcc/gcc/gcc.git-ab884fffe3fc82a710bea66ad651720d71c938b8.patch new file mode 100644 index 0000000000..ca6fc92e07 --- /dev/null +++ b/meta/recipes-devtools/gcc/gcc/gcc.git-ab884fffe3fc82a710bea66ad651720d71c938b8.patch @@ -0,0 +1,567 @@ +From ab884fffe3fc82a710bea66ad651720d71c938b8 Mon Sep 17 00:00:00 2001 +From: Jonathan Wakely <jwakely@redhat.com> +Date: Tue, 30 Apr 2024 09:52:13 +0100 +Subject: [PATCH] libstdc++: Fix std::chrono::tzdb to work with vanguard format + +I found some issues in the std::chrono::tzdb parser by testing the +tzdata "vanguard" format, which uses new features that aren't enabled in +the "main" and "rearguard" data formats. + +Since 2024a the keyword "minimum" is no longer valid for the FROM and TO +fields in a Rule line, which means that "m" is now a valid abbreviation +for "maximum". Previously we expected either "mi" or "ma". For backwards +compatibility, a FROM field beginning with "mi" is still supported and +is treated as 1900. The "maximum" keyword is only allowed in TO now, +because it makes no sense in FROM. To support these changes the +minmax_year and minmax_year2 classes for parsing FROM and TO are +replaced with a single years_from_to class that reads both fields. + +The vanguard format makes use of %z in Zone FORMAT fields, which caused +an exception to be thrown from ZoneInfo::set_abbrev because no % or / +characters were expected when a Zone doesn't use a named Rule. The +ZoneInfo::to(sys_info&) function now uses format_abbrev_str to replace +any %z with the current offset. Although format_abbrev_str also checks +for %s and STD/DST formats, those only make sense when a named Rule is +in effect, so won't occur when ZoneInfo::to(sys_info&) is used. + +Since making this change on trunk, the tzdata-2024b release started +using %z in the main format, not just vanguard. This makes a backport to +release branches necessary (see PR 116657). + +This change also implements a feature that has always been missing from +time_zone::_M_get_sys_info: finding the Rule that is active before the +specified time point, so that we can correctly handle %s in the FORMAT +for the first new sys_info that gets created. This requires implementing +a poorly documented feature of zic, to get the LETTERS field from a +later transition, as described at +https://mm.icann.org/pipermail/tz/2024-April/058891.html +In order for this to work we need to be able to distinguish an empty +letters field (as used by CE%sT where the variable part is either empty +or "S") from "the letters field is not known for this transition". The +tzdata file uses "-" for an empty letters field, which libstdc++ was +previously replacing with "" when the Rule was parsed. Instead, we now +preserve the "-" in the Rule object, so that "" can be used for the case +where we don't know the letters (and so need to decide it). + +libstdc++-v3/ChangeLog: + + * src/c++20/tzdb.cc (minmax_year, minmax_year2): Remove. + (years_from_to): New class replacing minmax_year and + minmax_year2. + (format_abbrev_str, select_std_or_dst_abbrev): Move earlier in + the file. Handle "-" for letters. + (ZoneInfo::to): Use format_abbrev_str to expand %z. + (ZoneInfo::set_abbrev): Remove exception. Change parameter from + reference to value. + (operator>>(istream&, Rule&)): Do not clear letters when it + contains "-". + (time_zone::_M_get_sys_info): Add missing logic to find the Rule + in effect before the time point. + * testsuite/std/time/tzdb/1.cc: Adjust for vanguard format using + "GMT" as the Zone name, not as a Link to "Etc/GMT". + * testsuite/std/time/time_zone/sys_info_abbrev.cc: New test. + +(cherry picked from commit 0ca8d56f2085715f27ee536c6c344bc47af49cdd) + +Upstream-Status: Backport [https://gcc.gnu.org/git/gitweb.cgi?p=gcc.git;h=5ceea2ac106d6dd1aa8175670b15a801316cf1c9] + +Signed-off-by: Markus Volk <f_l_k@t-online.de> +--- + libstdc++-v3/src/c++20/tzdb.cc | 265 +++++++++++------- + .../std/time/time_zone/sys_info_abbrev.cc | 106 +++++++ + libstdc++-v3/testsuite/std/time/tzdb/1.cc | 6 +- + 3 files changed, 274 insertions(+), 103 deletions(-) + create mode 100644 libstdc++-v3/testsuite/std/time/time_zone/sys_info_abbrev.cc + +diff --git a/libstdc++-v3/src/c++20/tzdb.cc b/libstdc++-v3/src/c++20/tzdb.cc +index c7c7cc9deee6..7e8cce7ce8cf 100644 +--- a/libstdc++-v3/src/c++20/tzdb.cc ++++ b/libstdc++-v3/src/c++20/tzdb.cc +@@ -342,51 +342,103 @@ namespace std::chrono + friend istream& operator>>(istream&, on_day&); + }; + +- // Wrapper for chrono::year that reads a year, or one of the keywords +- // "minimum" or "maximum", or an unambiguous prefix of a keyword. +- struct minmax_year ++ // Wrapper for two chrono::year values, which reads the FROM and TO ++ // fields of a Rule line. The FROM field is a year and TO is a year or ++ // one of the keywords "maximum" or "only" (or an abbreviation of those). ++ // For backwards compatibility, the keyword "minimum" is recognized ++ // for FROM and interpreted as 1900. ++ struct years_from_to + { +- year& y; ++ year& from; ++ year& to; + +- friend istream& operator>>(istream& in, minmax_year&& y) ++ friend istream& operator>>(istream& in, years_from_to&& yy) + { +- if (ws(in).peek() == 'm') // keywords "minimum" or "maximum" ++ string s; ++ auto c = ws(in).peek(); ++ if (c == 'm') [[unlikely]] // keyword "minimum" + { +- string s; +- in >> s; // extract the rest of the word, but only look at s[1] +- if (s[1] == 'a') +- y.y = year::max(); +- else if (s[1] == 'i') +- y.y = year::min(); +- else +- in.setstate(ios::failbit); ++ in >> s; // extract the rest of the word ++ yy.from = year(1900); ++ } ++ else if (int num = 0; in >> num) [[likely]] ++ yy.from = year{num}; ++ ++ c = ws(in).peek(); ++ if (c == 'm') // keyword "maximum" ++ { ++ in >> s; // extract the rest of the word ++ yy.to = year::max(); ++ } ++ else if (c == 'o') // keyword "only" ++ { ++ in >> s; // extract the rest of the word ++ yy.to = yy.from; + } + else if (int num = 0; in >> num) +- y.y = year{num}; ++ yy.to = year{num}; ++ + return in; + } + }; + +- // As above for minmax_year, but also supports the keyword "only", +- // meaning that the TO year is the same as the FROM year. +- struct minmax_year2 ++ bool ++ select_std_or_dst_abbrev(string& abbrev, minutes save) + { +- minmax_year to; +- year from; ++ if (size_t pos = abbrev.find('/'); pos != string::npos) ++ { ++ // Select one of "STD/DST" for standard or daylight. ++ if (save == 0min) ++ abbrev.erase(pos); ++ else ++ abbrev.erase(0, pos + 1); ++ return true; ++ } ++ return false; ++ } + +- friend istream& operator>>(istream& in, minmax_year2&& y) +- { +- if (ws(in).peek() == 'o') // keyword "only" +- { +- string s; +- in >> s; // extract the whole keyword +- y.to.y = y.from; +- } +- else +- in >> std::move(y.to); +- return in; +- } +- }; ++ // Set the sys_info::abbrev string by expanding any placeholders. ++ void ++ format_abbrev_str(sys_info& info, string_view letters = {}) ++ { ++ if (size_t pos = info.abbrev.find('%'); pos != string::npos) ++ { ++ if (info.abbrev[pos + 1] == 's') ++ { ++ // Expand "%s" to the variable part, given by Rule::letters. ++ if (letters == "-") ++ info.abbrev.erase(pos, 2); ++ else ++ info.abbrev.replace(pos, 2, letters); ++ } ++ else if (info.abbrev[pos + 1] == 'z') ++ { ++ // Expand "%z" to the UT offset as +/-hh, +/-hhmm, or +/-hhmmss. ++ hh_mm_ss<seconds> t(info.offset); ++ string z(1, "+-"[t.is_negative()]); ++ long val = t.hours().count(); ++ int digits = 2; ++ if (int m = t.minutes().count()) ++ { ++ digits = 4; ++ val *= 100; ++ val += m; ++ if (int s = t.seconds().count()) ++ { ++ digits = 6; ++ val *= 100; ++ val += s; ++ } ++ } ++ auto sval = std::to_string(val); ++ z += string(digits - sval.size(), '0'); ++ z += sval; ++ info.abbrev.replace(pos, 2, z); ++ } ++ } ++ else ++ select_std_or_dst_abbrev(info.abbrev, info.save); ++ } + + // A time zone information record. + // Zone NAME STDOFF RULES FORMAT [UNTIL] +@@ -462,6 +514,7 @@ namespace std::chrono + info.offset = offset(); + info.save = minutes(m_save); + info.abbrev = format(); ++ format_abbrev_str(info); // expand %z + return true; + } + +@@ -469,12 +522,9 @@ namespace std::chrono + friend class time_zone; + + void +- set_abbrev(const string& abbrev) ++ set_abbrev(string abbrev) + { +- // In practice, the FORMAT field never needs expanding here. +- if (abbrev.find_first_of("/%") != abbrev.npos) +- __throw_runtime_error("std::chrono::time_zone: invalid data"); +- m_buf = abbrev; ++ m_buf = std::move(abbrev); + m_pos = 0; + m_expanded = true; + } +@@ -544,9 +594,7 @@ namespace std::chrono + + // Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S + +- in >> quoted(rule.name) +- >> minmax_year{rule.from} +- >> minmax_year2{rule.to, rule.from}; ++ in >> quoted(rule.name) >> years_from_to{rule.from, rule.to}; + + if (char type; in >> type && type != '-') + in.setstate(ios::failbit); +@@ -557,7 +605,7 @@ namespace std::chrono + if (save_time.indicator != at_time::Wall) + { + // We don't actually store the save_time.indicator, because we +- // assume that it's always deducable from the actual offset value. ++ // assume that it's always deducible from the offset value. + auto expected = save_time.time == 0s + ? at_time::Standard + : at_time::Daylight; +@@ -567,8 +615,6 @@ namespace std::chrono + rule.save = save_time.time; + + in >> rule.letters; +- if (rule.letters == "-") +- rule.letters.clear(); + return in; + } + +@@ -719,58 +765,6 @@ namespace std::chrono + #endif // TZDB_DISABLED + }; + +-#ifndef TZDB_DISABLED +- namespace +- { +- bool +- select_std_or_dst_abbrev(string& abbrev, minutes save) +- { +- if (size_t pos = abbrev.find('/'); pos != string::npos) +- { +- // Select one of "STD/DST" for standard or daylight. +- if (save == 0min) +- abbrev.erase(pos); +- else +- abbrev.erase(0, pos + 1); +- return true; +- } +- return false; +- } +- +- // Set the sys_info::abbrev string by expanding any placeholders. +- void +- format_abbrev_str(sys_info& info, string_view letters = {}) +- { +- if (size_t pos = info.abbrev.find("%s"); pos != string::npos) +- { +- // Expand "%s" to the variable part, given by Rule::letters. +- info.abbrev.replace(pos, 2, letters); +- } +- else if (size_t pos = info.abbrev.find("%z"); pos != string::npos) +- { +- // Expand "%z" to the UT offset as +/-hh, +/-hhmm, or +/-hhmmss. +- hh_mm_ss<seconds> t(info.offset); +- string z(1, "+-"[t.is_negative()]); +- long val = t.hours().count(); +- if (minutes m = t.minutes(); m != m.zero()) +- { +- val *= 100; +- val += m.count(); +- if (seconds s = t.seconds(); s != s.zero()) +- { +- val *= 100; +- val += s.count(); +- } +- } +- z += std::to_string(val); +- info.abbrev.replace(pos, 2, z); +- } +- else +- select_std_or_dst_abbrev(info.abbrev, info.save); +- } +- } +-#endif // TZDB_DISABLED +- + // Implementation of std::chrono::time_zone::get_info(const sys_time<D>&) + sys_info + time_zone::_M_get_sys_info(sys_seconds tp) const +@@ -839,12 +833,72 @@ namespace std::chrono + info.abbrev = ri.format(); + + string_view letters; +- if (i != infos.begin()) ++ if (i != infos.begin() && i[-1].expanded()) ++ letters = i[-1].next_letters(); ++ ++ if (letters.empty()) + { +- if (i[-1].expanded()) +- letters = i[-1].next_letters(); +- // XXX else need to find Rule active before this time and use it +- // to know the initial offset, save, and letters. ++ sys_seconds t = info.begin - seconds(1); ++ const year_month_day date(chrono::floor<days>(t)); ++ ++ // Try to find a Rule active before this time, to get initial ++ // SAVE and LETTERS values. There may not be a Rule for the period ++ // before the first DST transition, so find the earliest DST->STD ++ // transition and use the LETTERS from that. ++ const Rule* active_rule = nullptr; ++ sys_seconds active_rule_start = sys_seconds::min(); ++ const Rule* first_std = nullptr; ++ for (const auto& rule : rules) ++ { ++ if (rule.save == minutes(0)) ++ { ++ if (!first_std) ++ first_std = &rule; ++ else if (rule.from < first_std->from) ++ first_std = &rule; ++ else if (rule.from == first_std->from) ++ { ++ if (rule.start_time(rule.from, {}) ++ < first_std->start_time(first_std->from, {})) ++ first_std = &rule; ++ } ++ } ++ ++ year y = date.year(); ++ ++ if (y > rule.to) // rule no longer applies at time t ++ continue; ++ if (y < rule.from) // rule doesn't apply yet at time t ++ continue; ++ ++ sys_seconds rule_start; ++ ++ seconds offset{}; // appropriate for at_time::Universal ++ if (rule.when.indicator == at_time::Wall) ++ offset = info.offset; ++ else if (rule.when.indicator == at_time::Standard) ++ offset = ri.offset(); ++ ++ // Time the rule takes effect this year: ++ rule_start = rule.start_time(y, offset); ++ ++ if (rule_start >= t && rule.from < y) ++ { ++ // Try this rule in the previous year. ++ rule_start = rule.start_time(--y, offset); ++ } ++ ++ if (active_rule_start < rule_start && rule_start < t) ++ { ++ active_rule_start = rule_start; ++ active_rule = &rule; ++ } ++ } ++ ++ if (active_rule) ++ letters = active_rule->letters; ++ else if (first_std) ++ letters = first_std->letters; + } + + const Rule* curr_rule = nullptr; +@@ -2069,9 +2123,11 @@ namespace std::chrono + istringstream in2(std::move(rules)); + in2 >> rules_time; + inf.m_save = duration_cast<minutes>(rules_time.time); ++ // If the FORMAT is "STD/DST" then we can choose the right one ++ // now, so that we store a shorter string. + select_std_or_dst_abbrev(fmt, inf.m_save); + } +- inf.set_abbrev(fmt); ++ inf.set_abbrev(std::move(fmt)); + } + + // YEAR [MONTH [DAY [TIME]]] +@@ -2082,7 +2138,12 @@ namespace std::chrono + abbrev_month m{January}; + int d = 1; + at_time t{}; ++ // XXX DAY should support ON format, e.g. lastSun or Sun>=8 + in >> m >> d >> t; ++ // XXX UNTIL field should be interpreted ++ // "using the rules in effect just before the transition" ++ // so might need to store as year_month_day and hh_mm_ss and only ++ // convert to a sys_time once we know the offset in effect. + inf.m_until = sys_days(year(y)/m.m/day(d)) + seconds(t.time); + } + else +diff --git a/libstdc++-v3/testsuite/std/time/time_zone/sys_info_abbrev.cc b/libstdc++-v3/testsuite/std/time/time_zone/sys_info_abbrev.cc +new file mode 100644 +index 000000000000..f1a8fff02f58 +--- /dev/null ++++ b/libstdc++-v3/testsuite/std/time/time_zone/sys_info_abbrev.cc +@@ -0,0 +1,106 @@ ++// { 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* } } ++ ++#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 "./"; ++ } ++} ++ ++using namespace std::chrono; ++ ++void ++test_format() ++{ ++ std::ofstream("tzdata.zi") << R"(# version test_1 ++Zone Africa/Bissau -1:2:20 - LMT 1912 Ja 1 1u ++ -1 - %z 1975 ++ 0 - GMT ++Zon Some/Zone 1:2:3 - %z 1900 ++ 1:23:45 - %z 1950 ++Zo Another/Zone 1:2:3 - AZ0 1901 ++ 1 Roolz A%sZ 2000 ++ 1 Roolz SAZ/DAZ 2005 ++ 1 Roolz %z ++Rule Roolz 1950 max - April 1 2 1 D ++Rul Roolz 1950 max - Oct 1 1 0 S ++Z Strange/Zone 1 - X%sX 1980 ++ 1 - FOO/BAR 1990 ++ 2:00 - %zzz 1995 ++ 0:9 - %zzz 1996 ++ 0:8:7 - %zzz 1997 ++ 0:6:5.5 - %zzz 1998 ++)"; ++ ++ const auto& db = reload_tzdb(); ++ VERIFY( override_used ); // If this fails then XFAIL for the target. ++ VERIFY( db.version == "test_1" ); ++ ++ // Test formatting %z as ++ auto tz = locate_zone("Africa/Bissau"); ++ auto inf = tz->get_info(sys_days(1974y/1/1)); ++ VERIFY( inf.abbrev == "-01" ); ++ ++ tz = locate_zone("Some/Zone"); ++ inf = tz->get_info(sys_days(1899y/1/1)); ++ VERIFY( inf.abbrev == "+010203" ); ++ inf = tz->get_info(sys_days(1955y/1/1)); ++ VERIFY( inf.abbrev == "+012345" ); ++ ++ tz = locate_zone("Another/Zone"); ++ // Test formatting %s as the LETTER/S field from the active Rule. ++ inf = tz->get_info(sys_days(1910y/January/1)); ++ VERIFY( inf.abbrev == "ASZ" ); ++ inf = tz->get_info(sys_days(1950y/January/1)); ++ VERIFY( inf.abbrev == "ASZ" ); ++ inf = tz->get_info(sys_days(1950y/June/1)); ++ VERIFY( inf.abbrev == "ADZ" ); ++ inf = tz->get_info(sys_days(1999y/January/1)); ++ VERIFY( inf.abbrev == "ASZ" ); ++ inf = tz->get_info(sys_days(1999y/July/1)); ++ VERIFY( inf.abbrev == "ADZ" ); ++ // Test formatting STD/DST according to the active Rule. ++ inf = tz->get_info(sys_days(2000y/January/2)); ++ VERIFY( inf.abbrev == "SAZ" ); ++ inf = tz->get_info(sys_days(2001y/January/1)); ++ VERIFY( inf.abbrev == "SAZ" ); ++ inf = tz->get_info(sys_days(2001y/July/1)); ++ VERIFY( inf.abbrev == "DAZ" ); ++ // Test formatting %z as the offset determined by the active Rule. ++ inf = tz->get_info(sys_days(2005y/January/2)); ++ VERIFY( inf.abbrev == "+01" ); ++ inf = tz->get_info(sys_days(2006y/January/1)); ++ VERIFY( inf.abbrev == "+01" ); ++ inf = tz->get_info(sys_days(2006y/July/1)); ++ VERIFY( inf.abbrev == "+02" ); ++ ++ // Test formatting %z, %s and S/D for a Zone with no associated Rules. ++ tz = locate_zone("Strange/Zone"); ++ inf = tz->get_info(sys_days(1979y/January/1)); ++ VERIFY( inf.abbrev == "XX" ); // No Rule means nothing to use for %s. ++ inf = tz->get_info(sys_days(1981y/July/1)); ++ VERIFY( inf.abbrev == "FOO" ); // Always standard time means first string. ++ inf = tz->get_info(sys_days(1994y/July/1)); ++ VERIFY( inf.abbrev == "+02zz" ); ++ inf = tz->get_info(sys_days(1995y/July/1)); ++ VERIFY( inf.abbrev == "+0009zz" ); ++ inf = tz->get_info(sys_days(1996y/July/1)); ++ VERIFY( inf.abbrev == "+000807zz" ); ++ inf = tz->get_info(sys_days(1997y/July/1)); ++ VERIFY( inf.abbrev == "+000606zz" ); ++} ++ ++int main() ++{ ++ test_format(); ++} +diff --git a/libstdc++-v3/testsuite/std/time/tzdb/1.cc b/libstdc++-v3/testsuite/std/time/tzdb/1.cc +index 796f3a8b4256..7a31c1c20ba7 100644 +--- a/libstdc++-v3/testsuite/std/time/tzdb/1.cc ++++ b/libstdc++-v3/testsuite/std/time/tzdb/1.cc +@@ -39,11 +39,15 @@ test_locate() + const tzdb& db = get_tzdb(); + const time_zone* tz = db.locate_zone("GMT"); + VERIFY( tz != nullptr ); +- VERIFY( tz->name() == "Etc/GMT" ); + VERIFY( tz == std::chrono::locate_zone("GMT") ); + VERIFY( tz == db.locate_zone("Etc/GMT") ); + VERIFY( tz == db.locate_zone("Etc/GMT+0") ); + ++ // Since 2022f GMT is now a Zone and Etc/GMT a link instead of vice versa, ++ // but only when using the vanguard format. As of 2024a, the main and ++ // rearguard formats still have Etc/GMT as a Zone and GMT as a link. ++ VERIFY( tz->name() == "GMT" || tz->name() == "Etc/GMT" ); ++ + VERIFY( db.locate_zone(db.current_zone()->name()) == db.current_zone() ); + } + +-- +2.43.5 +
There is an issue in the std::chrono::tzdb parser that causes problems since the tzdata-2024b release started using %z in the main format. As a real world problem I encounter an issue with the waybar clock module, which ignores the timezone setting and only shows system time. Signed-off-by: Markus Volk <f_l_k@t-online.de> --- meta/recipes-devtools/gcc/gcc-14.2.inc | 1 + ...4fffe3fc82a710bea66ad651720d71c938b8.patch | 567 ++++++++++++++++++ 2 files changed, 568 insertions(+) create mode 100644 meta/recipes-devtools/gcc/gcc/gcc.git-ab884fffe3fc82a710bea66ad651720d71c938b8.patch