diff options
author | Markus Volk <f_l_k@t-online.de> | 2024-11-22 13:27:05 +0100 |
---|---|---|
committer | Steve Sakoman <steve@sakoman.com> | 2024-11-30 05:41:59 -0800 |
commit | d7cd2e6f521dc517365fe2e737655cb68737db2f (patch) | |
tree | 31e1e9242653a3a5866957a07e1b5b7bf732c856 | |
parent | 814bde9a6b9bb9267a073b05e5307da018a6040f (diff) | |
download | poky-d7cd2e6f521dc517365fe2e737655cb68737db2f.tar.gz |
gcc: add a backport patch to fix an issue with tzdata 2024b
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.
(From OE-Core rev: 08dfd3849bd804f4760ebeca226645e65709a65a)
Signed-off-by: Markus Volk <f_l_k@t-online.de>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
(cherry picked from commit 39018429f05511053ab12e23e7f4487ea25ee529)
Signed-off-by: Steve Sakoman <steve@sakoman.com>
-rw-r--r-- | meta/recipes-devtools/gcc/gcc-14.2.inc | 1 | ||||
-rw-r--r-- | meta/recipes-devtools/gcc/gcc/gcc.git-ab884fffe3fc82a710bea66ad651720d71c938b8.patch | 549 |
2 files changed, 550 insertions, 0 deletions
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} \ | |||
68 | file://0023-Fix-install-path-of-linux64.h.patch \ | 68 | file://0023-Fix-install-path-of-linux64.h.patch \ |
69 | file://0024-Avoid-hardcoded-build-paths-into-ppc-libgcc.patch \ | 69 | file://0024-Avoid-hardcoded-build-paths-into-ppc-libgcc.patch \ |
70 | file://0025-gcc-testsuite-tweaks-for-mips-OE.patch \ | 70 | file://0025-gcc-testsuite-tweaks-for-mips-OE.patch \ |
71 | file://gcc.git-ab884fffe3fc82a710bea66ad651720d71c938b8.patch \ | ||
71 | " | 72 | " |
72 | 73 | ||
73 | S = "${TMPDIR}/work-shared/gcc-${PV}-${PR}/${SOURCEDIR}" | 74 | 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..e5abdcc703 --- /dev/null +++ b/meta/recipes-devtools/gcc/gcc/gcc.git-ab884fffe3fc82a710bea66ad651720d71c938b8.patch | |||
@@ -0,0 +1,549 @@ | |||
1 | From ab884fffe3fc82a710bea66ad651720d71c938b8 Mon Sep 17 00:00:00 2001 | ||
2 | From: Jonathan Wakely <jwakely@redhat.com> | ||
3 | Date: Tue, 30 Apr 2024 09:52:13 +0100 | ||
4 | Subject: [PATCH] libstdc++: Fix std::chrono::tzdb to work with vanguard format | ||
5 | |||
6 | I found some issues in the std::chrono::tzdb parser by testing the | ||
7 | tzdata "vanguard" format, which uses new features that aren't enabled in | ||
8 | the "main" and "rearguard" data formats. | ||
9 | |||
10 | Since 2024a the keyword "minimum" is no longer valid for the FROM and TO | ||
11 | fields in a Rule line, which means that "m" is now a valid abbreviation | ||
12 | for "maximum". Previously we expected either "mi" or "ma". For backwards | ||
13 | compatibility, a FROM field beginning with "mi" is still supported and | ||
14 | is treated as 1900. The "maximum" keyword is only allowed in TO now, | ||
15 | because it makes no sense in FROM. To support these changes the | ||
16 | minmax_year and minmax_year2 classes for parsing FROM and TO are | ||
17 | replaced with a single years_from_to class that reads both fields. | ||
18 | |||
19 | The vanguard format makes use of %z in Zone FORMAT fields, which caused | ||
20 | an exception to be thrown from ZoneInfo::set_abbrev because no % or / | ||
21 | characters were expected when a Zone doesn't use a named Rule. The | ||
22 | ZoneInfo::to(sys_info&) function now uses format_abbrev_str to replace | ||
23 | any %z with the current offset. Although format_abbrev_str also checks | ||
24 | for %s and STD/DST formats, those only make sense when a named Rule is | ||
25 | in effect, so won't occur when ZoneInfo::to(sys_info&) is used. | ||
26 | |||
27 | Since making this change on trunk, the tzdata-2024b release started | ||
28 | using %z in the main format, not just vanguard. This makes a backport to | ||
29 | release branches necessary (see PR 116657). | ||
30 | |||
31 | This change also implements a feature that has always been missing from | ||
32 | time_zone::_M_get_sys_info: finding the Rule that is active before the | ||
33 | specified time point, so that we can correctly handle %s in the FORMAT | ||
34 | for the first new sys_info that gets created. This requires implementing | ||
35 | a poorly documented feature of zic, to get the LETTERS field from a | ||
36 | later transition, as described at | ||
37 | https://mm.icann.org/pipermail/tz/2024-April/058891.html | ||
38 | In order for this to work we need to be able to distinguish an empty | ||
39 | letters field (as used by CE%sT where the variable part is either empty | ||
40 | or "S") from "the letters field is not known for this transition". The | ||
41 | tzdata file uses "-" for an empty letters field, which libstdc++ was | ||
42 | previously replacing with "" when the Rule was parsed. Instead, we now | ||
43 | preserve the "-" in the Rule object, so that "" can be used for the case | ||
44 | where we don't know the letters (and so need to decide it). | ||
45 | |||
46 | (cherry picked from commit 0ca8d56f2085715f27ee536c6c344bc47af49cdd) | ||
47 | |||
48 | Upstream-Status: Backport [https://gcc.gnu.org/git/gitweb.cgi?p=gcc.git;h=5ceea2ac106d6dd1aa8175670b15a801316cf1c9] | ||
49 | |||
50 | Signed-off-by: Markus Volk <f_l_k@t-online.de> | ||
51 | --- | ||
52 | libstdc++-v3/src/c++20/tzdb.cc | 265 +++++++++++------- | ||
53 | .../std/time/time_zone/sys_info_abbrev.cc | 106 +++++++ | ||
54 | libstdc++-v3/testsuite/std/time/tzdb/1.cc | 6 +- | ||
55 | 3 files changed, 274 insertions(+), 103 deletions(-) | ||
56 | create mode 100644 libstdc++-v3/testsuite/std/time/time_zone/sys_info_abbrev.cc | ||
57 | |||
58 | diff --git a/libstdc++-v3/src/c++20/tzdb.cc b/libstdc++-v3/src/c++20/tzdb.cc | ||
59 | index c7c7cc9deee6..7e8cce7ce8cf 100644 | ||
60 | --- a/libstdc++-v3/src/c++20/tzdb.cc | ||
61 | +++ b/libstdc++-v3/src/c++20/tzdb.cc | ||
62 | @@ -342,51 +342,103 @@ namespace std::chrono | ||
63 | friend istream& operator>>(istream&, on_day&); | ||
64 | }; | ||
65 | |||
66 | - // Wrapper for chrono::year that reads a year, or one of the keywords | ||
67 | - // "minimum" or "maximum", or an unambiguous prefix of a keyword. | ||
68 | - struct minmax_year | ||
69 | + // Wrapper for two chrono::year values, which reads the FROM and TO | ||
70 | + // fields of a Rule line. The FROM field is a year and TO is a year or | ||
71 | + // one of the keywords "maximum" or "only" (or an abbreviation of those). | ||
72 | + // For backwards compatibility, the keyword "minimum" is recognized | ||
73 | + // for FROM and interpreted as 1900. | ||
74 | + struct years_from_to | ||
75 | { | ||
76 | - year& y; | ||
77 | + year& from; | ||
78 | + year& to; | ||
79 | |||
80 | - friend istream& operator>>(istream& in, minmax_year&& y) | ||
81 | + friend istream& operator>>(istream& in, years_from_to&& yy) | ||
82 | { | ||
83 | - if (ws(in).peek() == 'm') // keywords "minimum" or "maximum" | ||
84 | + string s; | ||
85 | + auto c = ws(in).peek(); | ||
86 | + if (c == 'm') [[unlikely]] // keyword "minimum" | ||
87 | { | ||
88 | - string s; | ||
89 | - in >> s; // extract the rest of the word, but only look at s[1] | ||
90 | - if (s[1] == 'a') | ||
91 | - y.y = year::max(); | ||
92 | - else if (s[1] == 'i') | ||
93 | - y.y = year::min(); | ||
94 | - else | ||
95 | - in.setstate(ios::failbit); | ||
96 | + in >> s; // extract the rest of the word | ||
97 | + yy.from = year(1900); | ||
98 | + } | ||
99 | + else if (int num = 0; in >> num) [[likely]] | ||
100 | + yy.from = year{num}; | ||
101 | + | ||
102 | + c = ws(in).peek(); | ||
103 | + if (c == 'm') // keyword "maximum" | ||
104 | + { | ||
105 | + in >> s; // extract the rest of the word | ||
106 | + yy.to = year::max(); | ||
107 | + } | ||
108 | + else if (c == 'o') // keyword "only" | ||
109 | + { | ||
110 | + in >> s; // extract the rest of the word | ||
111 | + yy.to = yy.from; | ||
112 | } | ||
113 | else if (int num = 0; in >> num) | ||
114 | - y.y = year{num}; | ||
115 | + yy.to = year{num}; | ||
116 | + | ||
117 | return in; | ||
118 | } | ||
119 | }; | ||
120 | |||
121 | - // As above for minmax_year, but also supports the keyword "only", | ||
122 | - // meaning that the TO year is the same as the FROM year. | ||
123 | - struct minmax_year2 | ||
124 | + bool | ||
125 | + select_std_or_dst_abbrev(string& abbrev, minutes save) | ||
126 | { | ||
127 | - minmax_year to; | ||
128 | - year from; | ||
129 | + if (size_t pos = abbrev.find('/'); pos != string::npos) | ||
130 | + { | ||
131 | + // Select one of "STD/DST" for standard or daylight. | ||
132 | + if (save == 0min) | ||
133 | + abbrev.erase(pos); | ||
134 | + else | ||
135 | + abbrev.erase(0, pos + 1); | ||
136 | + return true; | ||
137 | + } | ||
138 | + return false; | ||
139 | + } | ||
140 | |||
141 | - friend istream& operator>>(istream& in, minmax_year2&& y) | ||
142 | - { | ||
143 | - if (ws(in).peek() == 'o') // keyword "only" | ||
144 | - { | ||
145 | - string s; | ||
146 | - in >> s; // extract the whole keyword | ||
147 | - y.to.y = y.from; | ||
148 | - } | ||
149 | - else | ||
150 | - in >> std::move(y.to); | ||
151 | - return in; | ||
152 | - } | ||
153 | - }; | ||
154 | + // Set the sys_info::abbrev string by expanding any placeholders. | ||
155 | + void | ||
156 | + format_abbrev_str(sys_info& info, string_view letters = {}) | ||
157 | + { | ||
158 | + if (size_t pos = info.abbrev.find('%'); pos != string::npos) | ||
159 | + { | ||
160 | + if (info.abbrev[pos + 1] == 's') | ||
161 | + { | ||
162 | + // Expand "%s" to the variable part, given by Rule::letters. | ||
163 | + if (letters == "-") | ||
164 | + info.abbrev.erase(pos, 2); | ||
165 | + else | ||
166 | + info.abbrev.replace(pos, 2, letters); | ||
167 | + } | ||
168 | + else if (info.abbrev[pos + 1] == 'z') | ||
169 | + { | ||
170 | + // Expand "%z" to the UT offset as +/-hh, +/-hhmm, or +/-hhmmss. | ||
171 | + hh_mm_ss<seconds> t(info.offset); | ||
172 | + string z(1, "+-"[t.is_negative()]); | ||
173 | + long val = t.hours().count(); | ||
174 | + int digits = 2; | ||
175 | + if (int m = t.minutes().count()) | ||
176 | + { | ||
177 | + digits = 4; | ||
178 | + val *= 100; | ||
179 | + val += m; | ||
180 | + if (int s = t.seconds().count()) | ||
181 | + { | ||
182 | + digits = 6; | ||
183 | + val *= 100; | ||
184 | + val += s; | ||
185 | + } | ||
186 | + } | ||
187 | + auto sval = std::to_string(val); | ||
188 | + z += string(digits - sval.size(), '0'); | ||
189 | + z += sval; | ||
190 | + info.abbrev.replace(pos, 2, z); | ||
191 | + } | ||
192 | + } | ||
193 | + else | ||
194 | + select_std_or_dst_abbrev(info.abbrev, info.save); | ||
195 | + } | ||
196 | |||
197 | // A time zone information record. | ||
198 | // Zone NAME STDOFF RULES FORMAT [UNTIL] | ||
199 | @@ -462,6 +514,7 @@ namespace std::chrono | ||
200 | info.offset = offset(); | ||
201 | info.save = minutes(m_save); | ||
202 | info.abbrev = format(); | ||
203 | + format_abbrev_str(info); // expand %z | ||
204 | return true; | ||
205 | } | ||
206 | |||
207 | @@ -469,12 +522,9 @@ namespace std::chrono | ||
208 | friend class time_zone; | ||
209 | |||
210 | void | ||
211 | - set_abbrev(const string& abbrev) | ||
212 | + set_abbrev(string abbrev) | ||
213 | { | ||
214 | - // In practice, the FORMAT field never needs expanding here. | ||
215 | - if (abbrev.find_first_of("/%") != abbrev.npos) | ||
216 | - __throw_runtime_error("std::chrono::time_zone: invalid data"); | ||
217 | - m_buf = abbrev; | ||
218 | + m_buf = std::move(abbrev); | ||
219 | m_pos = 0; | ||
220 | m_expanded = true; | ||
221 | } | ||
222 | @@ -544,9 +594,7 @@ namespace std::chrono | ||
223 | |||
224 | // Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S | ||
225 | |||
226 | - in >> quoted(rule.name) | ||
227 | - >> minmax_year{rule.from} | ||
228 | - >> minmax_year2{rule.to, rule.from}; | ||
229 | + in >> quoted(rule.name) >> years_from_to{rule.from, rule.to}; | ||
230 | |||
231 | if (char type; in >> type && type != '-') | ||
232 | in.setstate(ios::failbit); | ||
233 | @@ -557,7 +605,7 @@ namespace std::chrono | ||
234 | if (save_time.indicator != at_time::Wall) | ||
235 | { | ||
236 | // We don't actually store the save_time.indicator, because we | ||
237 | - // assume that it's always deducable from the actual offset value. | ||
238 | + // assume that it's always deducible from the offset value. | ||
239 | auto expected = save_time.time == 0s | ||
240 | ? at_time::Standard | ||
241 | : at_time::Daylight; | ||
242 | @@ -567,8 +615,6 @@ namespace std::chrono | ||
243 | rule.save = save_time.time; | ||
244 | |||
245 | in >> rule.letters; | ||
246 | - if (rule.letters == "-") | ||
247 | - rule.letters.clear(); | ||
248 | return in; | ||
249 | } | ||
250 | |||
251 | @@ -719,58 +765,6 @@ namespace std::chrono | ||
252 | #endif // TZDB_DISABLED | ||
253 | }; | ||
254 | |||
255 | -#ifndef TZDB_DISABLED | ||
256 | - namespace | ||
257 | - { | ||
258 | - bool | ||
259 | - select_std_or_dst_abbrev(string& abbrev, minutes save) | ||
260 | - { | ||
261 | - if (size_t pos = abbrev.find('/'); pos != string::npos) | ||
262 | - { | ||
263 | - // Select one of "STD/DST" for standard or daylight. | ||
264 | - if (save == 0min) | ||
265 | - abbrev.erase(pos); | ||
266 | - else | ||
267 | - abbrev.erase(0, pos + 1); | ||
268 | - return true; | ||
269 | - } | ||
270 | - return false; | ||
271 | - } | ||
272 | - | ||
273 | - // Set the sys_info::abbrev string by expanding any placeholders. | ||
274 | - void | ||
275 | - format_abbrev_str(sys_info& info, string_view letters = {}) | ||
276 | - { | ||
277 | - if (size_t pos = info.abbrev.find("%s"); pos != string::npos) | ||
278 | - { | ||
279 | - // Expand "%s" to the variable part, given by Rule::letters. | ||
280 | - info.abbrev.replace(pos, 2, letters); | ||
281 | - } | ||
282 | - else if (size_t pos = info.abbrev.find("%z"); pos != string::npos) | ||
283 | - { | ||
284 | - // Expand "%z" to the UT offset as +/-hh, +/-hhmm, or +/-hhmmss. | ||
285 | - hh_mm_ss<seconds> t(info.offset); | ||
286 | - string z(1, "+-"[t.is_negative()]); | ||
287 | - long val = t.hours().count(); | ||
288 | - if (minutes m = t.minutes(); m != m.zero()) | ||
289 | - { | ||
290 | - val *= 100; | ||
291 | - val += m.count(); | ||
292 | - if (seconds s = t.seconds(); s != s.zero()) | ||
293 | - { | ||
294 | - val *= 100; | ||
295 | - val += s.count(); | ||
296 | - } | ||
297 | - } | ||
298 | - z += std::to_string(val); | ||
299 | - info.abbrev.replace(pos, 2, z); | ||
300 | - } | ||
301 | - else | ||
302 | - select_std_or_dst_abbrev(info.abbrev, info.save); | ||
303 | - } | ||
304 | - } | ||
305 | -#endif // TZDB_DISABLED | ||
306 | - | ||
307 | // Implementation of std::chrono::time_zone::get_info(const sys_time<D>&) | ||
308 | sys_info | ||
309 | time_zone::_M_get_sys_info(sys_seconds tp) const | ||
310 | @@ -839,12 +833,72 @@ namespace std::chrono | ||
311 | info.abbrev = ri.format(); | ||
312 | |||
313 | string_view letters; | ||
314 | - if (i != infos.begin()) | ||
315 | + if (i != infos.begin() && i[-1].expanded()) | ||
316 | + letters = i[-1].next_letters(); | ||
317 | + | ||
318 | + if (letters.empty()) | ||
319 | { | ||
320 | - if (i[-1].expanded()) | ||
321 | - letters = i[-1].next_letters(); | ||
322 | - // XXX else need to find Rule active before this time and use it | ||
323 | - // to know the initial offset, save, and letters. | ||
324 | + sys_seconds t = info.begin - seconds(1); | ||
325 | + const year_month_day date(chrono::floor<days>(t)); | ||
326 | + | ||
327 | + // Try to find a Rule active before this time, to get initial | ||
328 | + // SAVE and LETTERS values. There may not be a Rule for the period | ||
329 | + // before the first DST transition, so find the earliest DST->STD | ||
330 | + // transition and use the LETTERS from that. | ||
331 | + const Rule* active_rule = nullptr; | ||
332 | + sys_seconds active_rule_start = sys_seconds::min(); | ||
333 | + const Rule* first_std = nullptr; | ||
334 | + for (const auto& rule : rules) | ||
335 | + { | ||
336 | + if (rule.save == minutes(0)) | ||
337 | + { | ||
338 | + if (!first_std) | ||
339 | + first_std = &rule; | ||
340 | + else if (rule.from < first_std->from) | ||
341 | + first_std = &rule; | ||
342 | + else if (rule.from == first_std->from) | ||
343 | + { | ||
344 | + if (rule.start_time(rule.from, {}) | ||
345 | + < first_std->start_time(first_std->from, {})) | ||
346 | + first_std = &rule; | ||
347 | + } | ||
348 | + } | ||
349 | + | ||
350 | + year y = date.year(); | ||
351 | + | ||
352 | + if (y > rule.to) // rule no longer applies at time t | ||
353 | + continue; | ||
354 | + if (y < rule.from) // rule doesn't apply yet at time t | ||
355 | + continue; | ||
356 | + | ||
357 | + sys_seconds rule_start; | ||
358 | + | ||
359 | + seconds offset{}; // appropriate for at_time::Universal | ||
360 | + if (rule.when.indicator == at_time::Wall) | ||
361 | + offset = info.offset; | ||
362 | + else if (rule.when.indicator == at_time::Standard) | ||
363 | + offset = ri.offset(); | ||
364 | + | ||
365 | + // Time the rule takes effect this year: | ||
366 | + rule_start = rule.start_time(y, offset); | ||
367 | + | ||
368 | + if (rule_start >= t && rule.from < y) | ||
369 | + { | ||
370 | + // Try this rule in the previous year. | ||
371 | + rule_start = rule.start_time(--y, offset); | ||
372 | + } | ||
373 | + | ||
374 | + if (active_rule_start < rule_start && rule_start < t) | ||
375 | + { | ||
376 | + active_rule_start = rule_start; | ||
377 | + active_rule = &rule; | ||
378 | + } | ||
379 | + } | ||
380 | + | ||
381 | + if (active_rule) | ||
382 | + letters = active_rule->letters; | ||
383 | + else if (first_std) | ||
384 | + letters = first_std->letters; | ||
385 | } | ||
386 | |||
387 | const Rule* curr_rule = nullptr; | ||
388 | @@ -2069,9 +2123,11 @@ namespace std::chrono | ||
389 | istringstream in2(std::move(rules)); | ||
390 | in2 >> rules_time; | ||
391 | inf.m_save = duration_cast<minutes>(rules_time.time); | ||
392 | + // If the FORMAT is "STD/DST" then we can choose the right one | ||
393 | + // now, so that we store a shorter string. | ||
394 | select_std_or_dst_abbrev(fmt, inf.m_save); | ||
395 | } | ||
396 | - inf.set_abbrev(fmt); | ||
397 | + inf.set_abbrev(std::move(fmt)); | ||
398 | } | ||
399 | |||
400 | // YEAR [MONTH [DAY [TIME]]] | ||
401 | @@ -2082,7 +2138,12 @@ namespace std::chrono | ||
402 | abbrev_month m{January}; | ||
403 | int d = 1; | ||
404 | at_time t{}; | ||
405 | + // XXX DAY should support ON format, e.g. lastSun or Sun>=8 | ||
406 | in >> m >> d >> t; | ||
407 | + // XXX UNTIL field should be interpreted | ||
408 | + // "using the rules in effect just before the transition" | ||
409 | + // so might need to store as year_month_day and hh_mm_ss and only | ||
410 | + // convert to a sys_time once we know the offset in effect. | ||
411 | inf.m_until = sys_days(year(y)/m.m/day(d)) + seconds(t.time); | ||
412 | } | ||
413 | else | ||
414 | 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 | ||
415 | new file mode 100644 | ||
416 | index 000000000000..f1a8fff02f58 | ||
417 | --- /dev/null | ||
418 | +++ b/libstdc++-v3/testsuite/std/time/time_zone/sys_info_abbrev.cc | ||
419 | @@ -0,0 +1,106 @@ | ||
420 | +// { dg-do run { target c++20 } } | ||
421 | +// { dg-require-effective-target tzdb } | ||
422 | +// { dg-require-effective-target cxx11_abi } | ||
423 | +// { dg-xfail-run-if "no weak override on AIX" { powerpc-ibm-aix* } } | ||
424 | + | ||
425 | +#include <chrono> | ||
426 | +#include <fstream> | ||
427 | +#include <testsuite_hooks.h> | ||
428 | + | ||
429 | +static bool override_used = false; | ||
430 | + | ||
431 | +namespace __gnu_cxx | ||
432 | +{ | ||
433 | + const char* zoneinfo_dir_override() { | ||
434 | + override_used = true; | ||
435 | + return "./"; | ||
436 | + } | ||
437 | +} | ||
438 | + | ||
439 | +using namespace std::chrono; | ||
440 | + | ||
441 | +void | ||
442 | +test_format() | ||
443 | +{ | ||
444 | + std::ofstream("tzdata.zi") << R"(# version test_1 | ||
445 | +Zone Africa/Bissau -1:2:20 - LMT 1912 Ja 1 1u | ||
446 | + -1 - %z 1975 | ||
447 | + 0 - GMT | ||
448 | +Zon Some/Zone 1:2:3 - %z 1900 | ||
449 | + 1:23:45 - %z 1950 | ||
450 | +Zo Another/Zone 1:2:3 - AZ0 1901 | ||
451 | + 1 Roolz A%sZ 2000 | ||
452 | + 1 Roolz SAZ/DAZ 2005 | ||
453 | + 1 Roolz %z | ||
454 | +Rule Roolz 1950 max - April 1 2 1 D | ||
455 | +Rul Roolz 1950 max - Oct 1 1 0 S | ||
456 | +Z Strange/Zone 1 - X%sX 1980 | ||
457 | + 1 - FOO/BAR 1990 | ||
458 | + 2:00 - %zzz 1995 | ||
459 | + 0:9 - %zzz 1996 | ||
460 | + 0:8:7 - %zzz 1997 | ||
461 | + 0:6:5.5 - %zzz 1998 | ||
462 | +)"; | ||
463 | + | ||
464 | + const auto& db = reload_tzdb(); | ||
465 | + VERIFY( override_used ); // If this fails then XFAIL for the target. | ||
466 | + VERIFY( db.version == "test_1" ); | ||
467 | + | ||
468 | + // Test formatting %z as | ||
469 | + auto tz = locate_zone("Africa/Bissau"); | ||
470 | + auto inf = tz->get_info(sys_days(1974y/1/1)); | ||
471 | + VERIFY( inf.abbrev == "-01" ); | ||
472 | + | ||
473 | + tz = locate_zone("Some/Zone"); | ||
474 | + inf = tz->get_info(sys_days(1899y/1/1)); | ||
475 | + VERIFY( inf.abbrev == "+010203" ); | ||
476 | + inf = tz->get_info(sys_days(1955y/1/1)); | ||
477 | + VERIFY( inf.abbrev == "+012345" ); | ||
478 | + | ||
479 | + tz = locate_zone("Another/Zone"); | ||
480 | + // Test formatting %s as the LETTER/S field from the active Rule. | ||
481 | + inf = tz->get_info(sys_days(1910y/January/1)); | ||
482 | + VERIFY( inf.abbrev == "ASZ" ); | ||
483 | + inf = tz->get_info(sys_days(1950y/January/1)); | ||
484 | + VERIFY( inf.abbrev == "ASZ" ); | ||
485 | + inf = tz->get_info(sys_days(1950y/June/1)); | ||
486 | + VERIFY( inf.abbrev == "ADZ" ); | ||
487 | + inf = tz->get_info(sys_days(1999y/January/1)); | ||
488 | + VERIFY( inf.abbrev == "ASZ" ); | ||
489 | + inf = tz->get_info(sys_days(1999y/July/1)); | ||
490 | + VERIFY( inf.abbrev == "ADZ" ); | ||
491 | + // Test formatting STD/DST according to the active Rule. | ||
492 | + inf = tz->get_info(sys_days(2000y/January/2)); | ||
493 | + VERIFY( inf.abbrev == "SAZ" ); | ||
494 | + inf = tz->get_info(sys_days(2001y/January/1)); | ||
495 | + VERIFY( inf.abbrev == "SAZ" ); | ||
496 | + inf = tz->get_info(sys_days(2001y/July/1)); | ||
497 | + VERIFY( inf.abbrev == "DAZ" ); | ||
498 | + // Test formatting %z as the offset determined by the active Rule. | ||
499 | + inf = tz->get_info(sys_days(2005y/January/2)); | ||
500 | + VERIFY( inf.abbrev == "+01" ); | ||
501 | + inf = tz->get_info(sys_days(2006y/January/1)); | ||
502 | + VERIFY( inf.abbrev == "+01" ); | ||
503 | + inf = tz->get_info(sys_days(2006y/July/1)); | ||
504 | + VERIFY( inf.abbrev == "+02" ); | ||
505 | + | ||
506 | + // Test formatting %z, %s and S/D for a Zone with no associated Rules. | ||
507 | + tz = locate_zone("Strange/Zone"); | ||
508 | + inf = tz->get_info(sys_days(1979y/January/1)); | ||
509 | + VERIFY( inf.abbrev == "XX" ); // No Rule means nothing to use for %s. | ||
510 | + inf = tz->get_info(sys_days(1981y/July/1)); | ||
511 | + VERIFY( inf.abbrev == "FOO" ); // Always standard time means first string. | ||
512 | + inf = tz->get_info(sys_days(1994y/July/1)); | ||
513 | + VERIFY( inf.abbrev == "+02zz" ); | ||
514 | + inf = tz->get_info(sys_days(1995y/July/1)); | ||
515 | + VERIFY( inf.abbrev == "+0009zz" ); | ||
516 | + inf = tz->get_info(sys_days(1996y/July/1)); | ||
517 | + VERIFY( inf.abbrev == "+000807zz" ); | ||
518 | + inf = tz->get_info(sys_days(1997y/July/1)); | ||
519 | + VERIFY( inf.abbrev == "+000606zz" ); | ||
520 | +} | ||
521 | + | ||
522 | +int main() | ||
523 | +{ | ||
524 | + test_format(); | ||
525 | +} | ||
526 | diff --git a/libstdc++-v3/testsuite/std/time/tzdb/1.cc b/libstdc++-v3/testsuite/std/time/tzdb/1.cc | ||
527 | index 796f3a8b4256..7a31c1c20ba7 100644 | ||
528 | --- a/libstdc++-v3/testsuite/std/time/tzdb/1.cc | ||
529 | +++ b/libstdc++-v3/testsuite/std/time/tzdb/1.cc | ||
530 | @@ -39,11 +39,15 @@ test_locate() | ||
531 | const tzdb& db = get_tzdb(); | ||
532 | const time_zone* tz = db.locate_zone("GMT"); | ||
533 | VERIFY( tz != nullptr ); | ||
534 | - VERIFY( tz->name() == "Etc/GMT" ); | ||
535 | VERIFY( tz == std::chrono::locate_zone("GMT") ); | ||
536 | VERIFY( tz == db.locate_zone("Etc/GMT") ); | ||
537 | VERIFY( tz == db.locate_zone("Etc/GMT+0") ); | ||
538 | |||
539 | + // Since 2022f GMT is now a Zone and Etc/GMT a link instead of vice versa, | ||
540 | + // but only when using the vanguard format. As of 2024a, the main and | ||
541 | + // rearguard formats still have Etc/GMT as a Zone and GMT as a link. | ||
542 | + VERIFY( tz->name() == "GMT" || tz->name() == "Etc/GMT" ); | ||
543 | + | ||
544 | VERIFY( db.locate_zone(db.current_zone()->name()) == db.current_zone() ); | ||
545 | } | ||
546 | |||
547 | -- | ||
548 | 2.43.5 | ||
549 | |||