]>
Commit | Line | Data |
---|---|---|
f99b9486 JW |
1 | // <chrono> Formatting -*- C++ -*- |
2 | ||
3 | // Copyright The GNU Toolchain Authors. | |
4 | // | |
5 | // This file is part of the GNU ISO C++ Library. This library is free | |
6 | // software; you can redistribute it and/or modify it under the | |
7 | // terms of the GNU General Public License as published by the | |
8 | // Free Software Foundation; either version 3, or (at your option) | |
9 | // any later version. | |
10 | ||
11 | // This library is distributed in the hope that it will be useful, | |
12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | // GNU General Public License for more details. | |
15 | ||
16 | // Under Section 7 of GPL version 3, you are granted additional | |
17 | // permissions described in the GCC Runtime Library Exception, version | |
18 | // 3.1, as published by the Free Software Foundation. | |
19 | ||
20 | // You should have received a copy of the GNU General Public License and | |
21 | // a copy of the GCC Runtime Library Exception along with this program; | |
22 | // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see | |
23 | // <http://www.gnu.org/licenses/>. | |
24 | ||
25 | /** @file include/bits/chrono_io.h | |
26 | * This is an internal header file, included by other library headers. | |
27 | * Do not attempt to use it directly. @headername{chrono} | |
28 | */ | |
29 | ||
30 | #ifndef _GLIBCXX_CHRONO_IO_H | |
31 | #define _GLIBCXX_CHRONO_IO_H 1 | |
32 | ||
33 | #pragma GCC system_header | |
34 | ||
35 | #if __cplusplus >= 202002L | |
36 | ||
37 | #include <sstream> // ostringstream | |
38 | #include <iomanip> // setw, setfill | |
39 | #include <format> | |
715127b6 | 40 | #include <charconv> // from_chars |
f99b9486 | 41 | |
c992acdc | 42 | #include <bits/streambuf_iterator.h> |
f99b9486 JW |
43 | |
44 | namespace std _GLIBCXX_VISIBILITY(default) | |
45 | { | |
46 | _GLIBCXX_BEGIN_NAMESPACE_VERSION | |
47 | ||
48 | namespace chrono | |
49 | { | |
50 | /// @addtogroup chrono | |
51 | /// @{ | |
52 | ||
53 | /// @cond undocumented | |
54 | namespace __detail | |
55 | { | |
56 | // STATICALLY-WIDEN, see C++20 [time.general] | |
57 | // It doesn't matter for format strings (which can only be char or wchar_t) | |
58 | // but this returns the narrow string for anything that isn't wchar_t. This | |
59 | // is done because const char* can be inserted into any ostream type, and | |
60 | // will be widened at runtime if necessary. | |
61 | template<typename _CharT> | |
62 | consteval auto | |
63 | _Widen(const char* __narrow, const wchar_t* __wide) | |
64 | { | |
65 | if constexpr (is_same_v<_CharT, wchar_t>) | |
66 | return __wide; | |
67 | else | |
68 | return __narrow; | |
69 | } | |
70 | #define _GLIBCXX_WIDEN_(C, S) ::std::chrono::__detail::_Widen<C>(S, L##S) | |
71 | #define _GLIBCXX_WIDEN(S) _GLIBCXX_WIDEN_(_CharT, S) | |
72 | ||
f99b9486 | 73 | template<typename _Period, typename _CharT> |
c992acdc JW |
74 | constexpr basic_string_view<_CharT> |
75 | __units_suffix() noexcept | |
f99b9486 JW |
76 | { |
77 | // The standard say these are all narrow strings, which would need to | |
78 | // be widened at run-time when inserted into a wide stream. We use | |
79 | // STATICALLY-WIDEN to widen at compile-time. | |
80 | #define _GLIBCXX_UNITS_SUFFIX(period, suffix) \ | |
81 | if constexpr (is_same_v<_Period, period>) \ | |
82 | return _GLIBCXX_WIDEN(suffix); \ | |
83 | else | |
84 | ||
85 | _GLIBCXX_UNITS_SUFFIX(atto, "as") | |
86 | _GLIBCXX_UNITS_SUFFIX(femto, "fs") | |
87 | _GLIBCXX_UNITS_SUFFIX(pico, "ps") | |
88 | _GLIBCXX_UNITS_SUFFIX(nano, "ns") | |
89 | _GLIBCXX_UNITS_SUFFIX(milli, "ms") | |
90 | #if _GLIBCXX_USE_ALT_MICROSECONDS_SUFFIX | |
91 | // Deciding this at compile-time is wrong, maybe use nl_langinfo(CODESET) | |
92 | // to check runtime environment and return u8"\u00b5s", "\xb5s", or "us". | |
93 | _GLIBCXX_UNITS_SUFFIX(micro, "\u00b5s") | |
94 | #else | |
95 | _GLIBCXX_UNITS_SUFFIX(micro, "us") | |
96 | #endif | |
97 | _GLIBCXX_UNITS_SUFFIX(centi, "cs") | |
98 | _GLIBCXX_UNITS_SUFFIX(deci, "ds") | |
99 | _GLIBCXX_UNITS_SUFFIX(ratio<1>, "s") | |
100 | _GLIBCXX_UNITS_SUFFIX(deca, "das") | |
101 | _GLIBCXX_UNITS_SUFFIX(hecto, "hs") | |
102 | _GLIBCXX_UNITS_SUFFIX(kilo, "ks") | |
103 | _GLIBCXX_UNITS_SUFFIX(mega, "Ms") | |
104 | _GLIBCXX_UNITS_SUFFIX(giga, "Gs") | |
105 | _GLIBCXX_UNITS_SUFFIX(tera, "Ts") | |
106 | _GLIBCXX_UNITS_SUFFIX(tera, "Ts") | |
107 | _GLIBCXX_UNITS_SUFFIX(peta, "Ps") | |
108 | _GLIBCXX_UNITS_SUFFIX(exa, "Es") | |
109 | _GLIBCXX_UNITS_SUFFIX(ratio<60>, "min") | |
110 | _GLIBCXX_UNITS_SUFFIX(ratio<3600>, "h") | |
111 | _GLIBCXX_UNITS_SUFFIX(ratio<86400>, "d") | |
112 | #undef _GLIBCXX_UNITS_SUFFIX | |
c992acdc JW |
113 | return {}; |
114 | } | |
115 | ||
116 | template<typename _Period, typename _CharT, typename _Out> | |
117 | inline _Out | |
118 | __fmt_units_suffix(_Out __out) noexcept | |
119 | { | |
120 | if (auto __s = __detail::__units_suffix<_Period, _CharT>(); __s.size()) | |
121 | return __format::__write(std::move(__out), __s); | |
122 | else if constexpr (_Period::den == 1) | |
123 | return std::format_to(std::move(__out), _GLIBCXX_WIDEN("[{}]s"), | |
124 | (uintmax_t)_Period::num); | |
125 | else | |
126 | return std::format_to(std::move(__out), _GLIBCXX_WIDEN("[{}/{}]s"), | |
127 | (uintmax_t)_Period::num, | |
128 | (uintmax_t)_Period::den); | |
f99b9486 JW |
129 | } |
130 | } // namespace __detail | |
131 | /// @endcond | |
132 | ||
133 | /** Write a `chrono::duration` to an ostream. | |
134 | * | |
135 | * @since C++20 | |
136 | */ | |
137 | template<typename _CharT, typename _Traits, | |
138 | typename _Rep, typename _Period> | |
139 | inline basic_ostream<_CharT, _Traits>& | |
140 | operator<<(std::basic_ostream<_CharT, _Traits>& __os, | |
141 | const duration<_Rep, _Period>& __d) | |
142 | { | |
c992acdc | 143 | using _Out = ostreambuf_iterator<_CharT, _Traits>; |
f99b9486 | 144 | using period = typename _Period::type; |
f99b9486 JW |
145 | std::basic_ostringstream<_CharT, _Traits> __s; |
146 | __s.flags(__os.flags()); | |
147 | __s.imbue(__os.getloc()); | |
148 | __s.precision(__os.precision()); | |
149 | __s << __d.count(); | |
c992acdc | 150 | __detail::__fmt_units_suffix<period, _CharT>(_Out(__s)); |
f99b9486 JW |
151 | __os << std::move(__s).str(); |
152 | return __os; | |
153 | } | |
154 | ||
155 | /// @cond undocumented | |
156 | namespace __detail | |
157 | { | |
158 | // An unspecified type returned by `chrono::local_time_format`. | |
159 | template<typename _Duration> | |
160 | struct __local_time_fmt | |
161 | { | |
162 | local_time<_Duration> _M_time; | |
163 | const string* _M_abbrev; | |
164 | const seconds* _M_offset_sec; | |
165 | }; | |
166 | ||
167 | struct __local_fmt_t; | |
168 | } | |
169 | /// @endcond | |
170 | ||
171 | /** Return an object that asssociates timezone info with a local time. | |
172 | * | |
173 | * A `chrono::local_time` object has no timezone associated with it. This | |
174 | * function creates an object that allows formatting a `local_time` as | |
175 | * though it refers to a timezone with the given abbreviated name and | |
176 | * offset from UTC. | |
177 | * | |
178 | * @since C++20 | |
179 | */ | |
180 | template<typename _Duration> | |
181 | inline __detail::__local_time_fmt<_Duration> | |
182 | local_time_format(local_time<_Duration> __time, | |
183 | const string* __abbrev = nullptr, | |
184 | const seconds* __offset_sec = nullptr) | |
185 | { return {__time, __abbrev, __offset_sec}; } | |
186 | ||
187 | /// @} | |
188 | } // namespace chrono | |
189 | ||
190 | /// @cond undocumented | |
191 | namespace __format | |
192 | { | |
193 | [[noreturn,__gnu__::__always_inline__]] | |
194 | inline void | |
195 | __no_timezone_available() | |
196 | { __throw_format_error("format error: no timezone available for %Z or %z"); } | |
197 | ||
198 | [[noreturn,__gnu__::__always_inline__]] | |
199 | inline void | |
200 | __not_valid_for_duration() | |
201 | { __throw_format_error("format error: chrono-format-spec not valid for " | |
202 | "chrono::duration"); } | |
203 | ||
204 | [[noreturn,__gnu__::__always_inline__]] | |
205 | inline void | |
206 | __invalid_chrono_spec() | |
207 | { __throw_format_error("format error: chrono-format-spec not valid for " | |
208 | "argument type"); } | |
209 | ||
210 | template<typename _CharT> | |
211 | struct _ChronoSpec : _Spec<_CharT> | |
212 | { | |
213 | basic_string_view<_CharT> _M_chrono_specs; | |
214 | }; | |
215 | ||
216 | // Represents the information provided by a chrono type. | |
217 | // e.g. month_weekday has month and weekday but no year or time of day, | |
218 | // hh_mm_ss has time of day but no date, sys_time is time_point+timezone. | |
219 | enum _ChronoParts { | |
220 | _Year = 1, _Month = 2, _Day = 4, _Weekday = 8, _TimeOfDay = 16, | |
221 | _TimeZone = 32, | |
222 | _Date = _Year | _Month | _Day | _Weekday, | |
223 | _DateTime = _Date | _TimeOfDay, | |
224 | _ZonedDateTime = _DateTime | _TimeZone, | |
225 | _Duration = 128 // special case | |
226 | }; | |
227 | ||
228 | constexpr _ChronoParts | |
ce6c4d3b | 229 | operator|(_ChronoParts __x, _ChronoParts __y) noexcept |
f99b9486 JW |
230 | { return static_cast<_ChronoParts>((int)__x | (int)__y); } |
231 | ||
ce6c4d3b JW |
232 | constexpr _ChronoParts& |
233 | operator|=(_ChronoParts& __x, _ChronoParts __y) noexcept | |
234 | { return __x = __x | __y; } | |
235 | ||
f99b9486 JW |
236 | // TODO rename this to chrono::__formatter? or chrono::__detail::__formatter? |
237 | template<typename _CharT> | |
238 | struct __formatter_chrono | |
239 | { | |
240 | using __string_view = basic_string_view<_CharT>; | |
241 | using __string = basic_string<_CharT>; | |
242 | ||
243 | template<typename _ParseContext> | |
244 | constexpr typename _ParseContext::iterator | |
245 | _M_parse(_ParseContext& __pc, _ChronoParts __parts) | |
246 | { | |
247 | auto __first = __pc.begin(); | |
248 | auto __last = __pc.end(); | |
249 | ||
250 | _ChronoSpec<_CharT> __spec{}; | |
251 | ||
252 | auto __finalize = [this, &__spec] { | |
253 | _M_spec = __spec; | |
254 | }; | |
255 | ||
256 | auto __finished = [&] { | |
257 | if (__first == __last || *__first == '}') | |
258 | { | |
259 | __finalize(); | |
260 | return true; | |
261 | } | |
262 | return false; | |
263 | }; | |
264 | ||
265 | if (__finished()) | |
266 | return __first; | |
267 | ||
268 | __first = __spec._M_parse_fill_and_align(__first, __last); | |
269 | if (__finished()) | |
270 | return __first; | |
271 | ||
272 | __first = __spec._M_parse_width(__first, __last, __pc); | |
273 | if (__finished()) | |
274 | return __first; | |
275 | ||
276 | if (__parts & _ChronoParts::_Duration) | |
277 | { | |
278 | __first = __spec._M_parse_precision(__first, __last, __pc); | |
279 | if (__finished()) | |
280 | return __first; | |
281 | } | |
282 | ||
283 | __first = __spec._M_parse_locale(__first, __last); | |
284 | if (__finished()) | |
285 | return __first; | |
286 | ||
287 | // Everything up to the end of the string or the first '}' is a | |
288 | // chrono-specs string. Check it is valid. | |
289 | { | |
290 | __string_view __str(__first, __last - __first); | |
291 | auto __end = __str.find('}'); | |
292 | if (__end != __str.npos) | |
293 | { | |
294 | __str.remove_suffix(__str.length() - __end); | |
295 | __last = __first + __end; | |
296 | } | |
297 | if (__str.find('{') != __str.npos) | |
298 | __throw_format_error("chrono format error: '{' in chrono-specs"); | |
299 | } | |
300 | ||
301 | // Parse chrono-specs in [first,last), checking each conversion-spec | |
302 | // against __parts (so fail for %Y if no year in parts). | |
303 | // Save range in __spec._M_chrono_specs. | |
304 | ||
305 | const auto __chrono_specs = __first++; // Skip leading '%' | |
306 | if (*__chrono_specs != '%') | |
307 | __throw_format_error("chrono format error: no '%' at start of " | |
308 | "chrono-specs"); | |
309 | ||
310 | _CharT __mod{}; | |
311 | bool __conv = true; | |
312 | int __needed = 0; | |
313 | ||
314 | while (__first != __last) | |
315 | { | |
316 | enum _Mods { _Mod_none, _Mod_E, _Mod_O, _Mod_E_O }; | |
317 | _Mods __allowed_mods = _Mod_none; | |
318 | ||
319 | _CharT __c = *__first++; | |
320 | switch (__c) | |
321 | { | |
322 | case 'a': | |
323 | case 'A': | |
324 | __needed = _Weekday; | |
325 | break; | |
326 | case 'b': | |
327 | case 'h': | |
328 | case 'B': | |
329 | __needed = _Month; | |
330 | break; | |
331 | case 'c': | |
332 | __needed = _DateTime; | |
333 | __allowed_mods = _Mod_E; | |
334 | break; | |
335 | case 'C': | |
336 | __needed = _Year; | |
337 | __allowed_mods = _Mod_E; | |
338 | break; | |
339 | case 'd': | |
340 | case 'e': | |
341 | __needed = _Day; | |
342 | __allowed_mods = _Mod_O; | |
343 | break; | |
344 | case 'D': | |
345 | case 'F': | |
346 | __needed = _Date; | |
347 | break; | |
348 | case 'g': | |
349 | case 'G': | |
350 | __needed = _Date; | |
351 | break; | |
352 | case 'H': | |
353 | case 'I': | |
354 | __needed = _TimeOfDay; | |
355 | __allowed_mods = _Mod_O; | |
356 | break; | |
357 | case 'j': | |
358 | if (!(__parts & _Duration)) | |
359 | __needed = _Date; | |
360 | break; | |
361 | case 'm': | |
362 | __needed = _Month; | |
363 | __allowed_mods = _Mod_O; | |
364 | break; | |
365 | case 'M': | |
366 | __needed = _TimeOfDay; | |
367 | __allowed_mods = _Mod_O; | |
368 | break; | |
369 | case 'p': | |
370 | case 'r': | |
371 | case 'R': | |
372 | case 'T': | |
373 | __needed = _TimeOfDay; | |
374 | break; | |
375 | case 'q': | |
376 | case 'Q': | |
377 | __needed = _Duration; | |
378 | break; | |
379 | case 'S': | |
380 | __needed = _TimeOfDay; | |
381 | __allowed_mods = _Mod_O; | |
382 | break; | |
383 | case 'u': | |
384 | case 'w': | |
385 | __needed = _Weekday; | |
386 | __allowed_mods = _Mod_O; | |
387 | break; | |
388 | case 'U': | |
389 | case 'V': | |
390 | case 'W': | |
391 | __needed = _Date; | |
392 | __allowed_mods = _Mod_O; | |
393 | break; | |
394 | case 'x': | |
395 | __needed = _Date; | |
396 | __allowed_mods = _Mod_E; | |
397 | break; | |
398 | case 'X': | |
399 | __needed = _TimeOfDay; | |
400 | __allowed_mods = _Mod_E; | |
401 | break; | |
402 | case 'y': | |
403 | __needed = _Year; | |
404 | __allowed_mods = _Mod_E_O; | |
405 | break; | |
406 | case 'Y': | |
407 | __needed = _Year; | |
408 | __allowed_mods = _Mod_E; | |
409 | break; | |
410 | case 'z': | |
411 | __needed = _TimeZone; | |
f4bce119 | 412 | __allowed_mods = _Mod_E_O; |
f99b9486 JW |
413 | break; |
414 | case 'Z': | |
415 | __needed = _TimeZone; | |
f99b9486 JW |
416 | break; |
417 | case 'n': | |
418 | case 't': | |
419 | case '%': | |
420 | break; | |
421 | case 'O': | |
422 | case 'E': | |
52bfec7e JW |
423 | if (__mod) [[unlikely]] |
424 | { | |
425 | __allowed_mods = _Mod_none; | |
426 | break; | |
427 | } | |
f99b9486 JW |
428 | __mod = __c; |
429 | continue; | |
430 | default: | |
431 | __throw_format_error("chrono format error: invalid " | |
432 | " specifier in chrono-specs"); | |
433 | } | |
434 | ||
435 | if ((__mod == 'E' && !(__allowed_mods & _Mod_E)) | |
f4bce119 | 436 | || (__mod == 'O' && !(__allowed_mods & _Mod_O))) |
f99b9486 JW |
437 | __throw_format_error("chrono format error: invalid " |
438 | " modifier in chrono-specs"); | |
439 | __mod = _CharT(); | |
440 | ||
441 | if ((__parts & __needed) != __needed) | |
442 | __throw_format_error("chrono format error: format argument " | |
443 | "does not contain the information " | |
444 | "required by the chrono-specs"); | |
445 | ||
446 | // Scan for next '%', ignoring literal-chars before it. | |
447 | size_t __pos = __string_view(__first, __last - __first).find('%'); | |
448 | if (__pos == 0) | |
449 | ++__first; | |
450 | else | |
451 | { | |
452 | if (__pos == __string_view::npos) | |
453 | { | |
454 | __first = __last; | |
455 | __conv = false; | |
456 | } | |
457 | else | |
458 | __first += __pos + 1; | |
459 | } | |
460 | } | |
461 | ||
462 | // Check for a '%' conversion-spec without a type. | |
463 | if (__conv || __mod != _CharT()) | |
464 | __throw_format_error("chrono format error: unescaped '%' in " | |
465 | "chrono-specs"); | |
466 | ||
467 | _M_spec = __spec; | |
f4bce119 JW |
468 | _M_spec._M_chrono_specs |
469 | = __string_view(__chrono_specs, __first - __chrono_specs); | |
f99b9486 JW |
470 | |
471 | return __first; | |
472 | } | |
473 | ||
474 | // TODO this function template is instantiated for every different _Tp. | |
475 | // Consider creating a polymorphic interface for calendar types so | |
476 | // that we instantiate fewer different specializations. Similar to | |
477 | // _Sink_iter for std::format. Replace each _S_year, _S_day etc. with | |
478 | // member functions of that type. | |
479 | template<typename _Tp, typename _FormatContext> | |
480 | typename _FormatContext::iterator | |
481 | _M_format(const _Tp& __t, _FormatContext& __fc, | |
482 | bool __is_neg = false) const | |
483 | { | |
f99b9486 JW |
484 | auto __first = _M_spec._M_chrono_specs.begin(); |
485 | const auto __last = _M_spec._M_chrono_specs.end(); | |
486 | if (__first == __last) | |
487 | return _M_format_to_ostream(__t, __fc, __is_neg); | |
488 | ||
489 | _Sink_iter<_CharT> __out; | |
490 | __format::_Str_sink<_CharT> __sink; | |
491 | bool __write_direct = false; | |
492 | if constexpr (is_same_v<typename _FormatContext::iterator, | |
493 | _Sink_iter<_CharT>>) | |
494 | { | |
495 | if (_M_spec._M_width_kind == __format::_WP_none) | |
496 | { | |
497 | __out = __fc.out(); | |
498 | __write_direct = true; | |
499 | } | |
500 | else | |
501 | __out = __sink.out(); | |
502 | } | |
503 | else | |
504 | __out = __sink.out(); | |
505 | ||
344f4132 JW |
506 | // formatter<duration> passes the correct value of __is_neg |
507 | // for durations but for hh_mm_ss we decide it here. | |
508 | if constexpr (__is_specialization_of<_Tp, chrono::hh_mm_ss>) | |
509 | __is_neg = __t.is_negative(); | |
510 | ||
f99b9486 | 511 | auto __print_sign = [&__is_neg, &__out] { |
344f4132 JW |
512 | if constexpr (chrono::__is_duration_v<_Tp> |
513 | || __is_specialization_of<_Tp, chrono::hh_mm_ss>) | |
514 | if (__is_neg) | |
515 | { | |
516 | *__out++ = _S_plus_minus[1]; | |
517 | __is_neg = false; | |
518 | } | |
f99b9486 JW |
519 | return std::move(__out); |
520 | }; | |
521 | ||
522 | // Characters to output for "%n", "%t" and "%%" specifiers. | |
523 | constexpr const _CharT* __literals = _GLIBCXX_WIDEN("\n\t%"); | |
524 | ||
525 | ++__first; // Skip leading '%' at start of chrono-specs. | |
526 | ||
527 | _CharT __mod{}; | |
528 | do | |
529 | { | |
530 | _CharT __c = *__first++; | |
531 | switch (__c) | |
532 | { | |
533 | case 'a': | |
534 | case 'A': | |
535 | __out = _M_a_A(__t, std::move(__out), __fc, __c == 'A'); | |
536 | break; | |
537 | case 'b': | |
538 | case 'h': | |
539 | case 'B': | |
540 | __out = _M_b_B(__t, std::move(__out), __fc, __c == 'B'); | |
541 | break; | |
542 | case 'c': | |
543 | __out = _M_c(__t, std::move(__out), __fc, __mod == 'E'); | |
544 | break; | |
545 | case 'C': | |
546 | case 'y': | |
547 | case 'Y': | |
548 | __out = _M_C_y_Y(__t, std::move(__out), __fc, __c, __mod); | |
549 | break; | |
550 | case 'd': | |
f4bce119 JW |
551 | case 'e': |
552 | __out = _M_d_e(__t, std::move(__out), __fc, __c, __mod == 'O'); | |
f99b9486 JW |
553 | break; |
554 | case 'D': | |
555 | __out = _M_D(__t, std::move(__out), __fc); | |
556 | break; | |
f99b9486 JW |
557 | case 'F': |
558 | __out = _M_F(__t, std::move(__out), __fc); | |
559 | break; | |
560 | case 'g': | |
561 | case 'G': | |
562 | __out = _M_g_G(__t, std::move(__out), __fc, __c == 'G'); | |
563 | break; | |
564 | case 'H': | |
f99b9486 | 565 | case 'I': |
f4bce119 | 566 | __out = _M_H_I(__t, __print_sign(), __fc, __c, __mod == 'O'); |
f99b9486 JW |
567 | break; |
568 | case 'j': | |
569 | __out = _M_j(__t, __print_sign(), __fc); | |
570 | break; | |
571 | case 'm': | |
f4bce119 | 572 | __out = _M_m(__t, std::move(__out), __fc, __mod == 'O'); |
f99b9486 JW |
573 | break; |
574 | case 'M': | |
f4bce119 | 575 | __out = _M_M(__t, __print_sign(), __fc, __mod == 'O'); |
f99b9486 JW |
576 | break; |
577 | case 'p': | |
578 | __out = _M_p(__t, std::move(__out), __fc); | |
579 | break; | |
580 | case 'q': | |
581 | __out = _M_q(__t, std::move(__out), __fc); | |
582 | break; | |
583 | case 'Q': | |
584 | // %Q The duration's numeric value. | |
585 | if constexpr (chrono::__is_duration_v<_Tp>) | |
586 | __out = std::format_to(__print_sign(), _S_empty_spec, | |
587 | __t.count()); | |
588 | else | |
589 | __throw_format_error("chrono format error: argument is " | |
590 | "not a duration"); | |
591 | break; | |
592 | case 'r': | |
593 | __out = _M_r(__t, __print_sign(), __fc); | |
594 | break; | |
595 | case 'R': | |
596 | case 'T': | |
597 | __out = _M_R_T(__t, __print_sign(), __fc, __c == 'T'); | |
598 | break; | |
599 | case 'S': | |
600 | __out = _M_S(__t, __print_sign(), __fc, __mod == 'O'); | |
601 | break; | |
602 | case 'u': | |
603 | case 'w': | |
604 | __out = _M_u_w(__t, std::move(__out), __fc, __c, __mod == 'O'); | |
605 | break; | |
606 | case 'U': | |
607 | case 'V': | |
608 | case 'W': | |
609 | __out = _M_U_V_W(__t, std::move(__out), __fc, __c, | |
610 | __mod == 'O'); | |
611 | break; | |
612 | case 'x': | |
613 | __out = _M_x(__t, std::move(__out), __fc, __mod == 'E'); | |
614 | break; | |
615 | case 'X': | |
616 | __out = _M_X(__t, __print_sign(), __fc, __mod == 'E'); | |
617 | break; | |
618 | case 'z': | |
619 | __out = _M_z(__t, std::move(__out), __fc, (bool)__mod); | |
620 | break; | |
621 | case 'Z': | |
622 | __out = _M_Z(__t, std::move(__out), __fc); | |
623 | break; | |
624 | case 'n': | |
625 | *__out++ = __literals[0]; | |
626 | break; | |
627 | case 't': | |
628 | *__out++ = __literals[1]; | |
629 | break; | |
630 | case '%': | |
631 | *__out++ = __literals[2]; | |
632 | break; | |
633 | case 'O': | |
634 | case 'E': | |
635 | __mod = __c; | |
636 | continue; | |
637 | case '}': | |
638 | __first = __last; | |
639 | break; | |
640 | } | |
641 | __mod = _CharT(); | |
642 | // Scan for next '%' and write out everything before it. | |
643 | __string_view __str(__first, __last - __first); | |
644 | size_t __pos = __str.find('%'); | |
645 | if (__pos == 0) | |
646 | ++__first; | |
647 | else | |
648 | { | |
649 | if (__pos == __str.npos) | |
650 | __first = __last; | |
651 | else | |
652 | { | |
653 | __str.remove_suffix(__str.length() - __pos); | |
654 | __first += __pos + 1; | |
655 | } | |
656 | __out = __format::__write(std::move(__out), __str); | |
657 | } | |
658 | } | |
659 | while (__first != __last); | |
660 | ||
661 | if constexpr (is_same_v<typename _FormatContext::iterator, | |
662 | _Sink_iter<_CharT>>) | |
663 | if (__write_direct) | |
664 | return __out; | |
665 | ||
666 | auto __str = std::move(__sink).get(); | |
667 | return __format::__write_padded_as_spec(__str, __str.size(), | |
668 | __fc, _M_spec); | |
669 | } | |
670 | ||
671 | _ChronoSpec<_CharT> _M_spec; | |
672 | ||
673 | private: | |
674 | // Return the formatting locale. | |
675 | template<typename _FormatContext> | |
676 | std::locale | |
677 | _M_locale(_FormatContext& __fc) const | |
678 | { | |
679 | if (!_M_spec._M_localized) | |
680 | return std::locale::classic(); | |
681 | else | |
682 | return __fc.locale(); | |
683 | } | |
684 | ||
7431fcea | 685 | // Format for empty chrono-specs, e.g. "{}" (C++20 [time.format] p6). |
f99b9486 JW |
686 | // TODO: consider moving body of every operator<< into this function |
687 | // and use std::format("{}", t) to implement those operators. That | |
688 | // would avoid std::format("{}", t) calling operator<< which calls | |
689 | // std::format again. | |
690 | template<typename _Tp, typename _FormatContext> | |
691 | typename _FormatContext::iterator | |
692 | _M_format_to_ostream(const _Tp& __t, _FormatContext& __fc, | |
693 | bool __is_neg) const | |
694 | { | |
695 | using ::std::chrono::__detail::__utc_leap_second; | |
696 | using ::std::chrono::__detail::__local_time_fmt; | |
697 | ||
698 | if constexpr (__is_specialization_of<_Tp, __local_time_fmt>) | |
699 | return _M_format_to_ostream(__t._M_time, __fc, false); | |
700 | else | |
701 | { | |
702 | basic_ostringstream<_CharT> __os; | |
703 | __os.imbue(_M_locale(__fc)); | |
704 | ||
705 | if constexpr (__is_specialization_of<_Tp, __utc_leap_second>) | |
706 | __os << __t._M_date << ' ' << __t._M_time; | |
7431fcea JW |
707 | else if constexpr (chrono::__is_time_point_v<_Tp>) |
708 | { | |
709 | // Need to be careful here because not all specializations | |
710 | // of chrono::sys_time can be written to an ostream. | |
711 | // For the specializations of time_point that can be | |
712 | // formatted with an empty chrono-specs, either it's a | |
713 | // sys_time with period greater or equal to days: | |
714 | if constexpr (is_convertible_v<_Tp, chrono::sys_days>) | |
715 | __os << _S_date(__t); | |
716 | else // Or it's formatted as "{:L%F %T}": | |
717 | { | |
718 | auto __days = chrono::floor<chrono::days>(__t); | |
719 | __os << chrono::year_month_day(__days) << ' ' | |
720 | << chrono::hh_mm_ss(__t - __days); | |
721 | } | |
722 | } | |
f99b9486 JW |
723 | else |
724 | { | |
344f4132 JW |
725 | if constexpr (chrono::__is_duration_v<_Tp>) |
726 | if (__is_neg) [[unlikely]] | |
727 | __os << _S_plus_minus[1]; | |
f99b9486 JW |
728 | __os << __t; |
729 | } | |
730 | ||
731 | auto __str = std::move(__os).str(); | |
732 | return __format::__write_padded_as_spec(__str, __str.size(), | |
733 | __fc, _M_spec); | |
734 | } | |
735 | } | |
736 | ||
737 | static constexpr const _CharT* _S_chars | |
738 | = _GLIBCXX_WIDEN("0123456789+-:/ {}"); | |
739 | static constexpr const _CharT* _S_plus_minus = _S_chars + 10; | |
740 | static constexpr _CharT _S_colon = _S_chars[12]; | |
741 | static constexpr _CharT _S_slash = _S_chars[13]; | |
742 | static constexpr _CharT _S_space = _S_chars[14]; | |
743 | static constexpr const _CharT* _S_empty_spec = _S_chars + 15; | |
744 | ||
745 | template<typename _Tp, typename _FormatContext> | |
746 | typename _FormatContext::iterator | |
747 | _M_a_A(const _Tp& __t, typename _FormatContext::iterator __out, | |
748 | _FormatContext& __ctx, bool __full) const | |
749 | { | |
750 | // %a Locale's abbreviated weekday name. | |
751 | // %A Locale's full weekday name. | |
752 | chrono::weekday __wd = _S_weekday(__t); | |
753 | if (!__wd.ok()) | |
754 | __throw_format_error("format error: invalid weekday"); | |
755 | ||
756 | locale __loc = _M_locale(__ctx); | |
757 | const auto& __tp = use_facet<__timepunct<_CharT>>(__loc); | |
758 | const _CharT* __days[7]; | |
759 | if (__full) | |
760 | __tp._M_days(__days); | |
761 | else | |
762 | __tp._M_days_abbreviated(__days); | |
763 | __string_view __str(__days[__wd.c_encoding()]); | |
764 | return __format::__write(std::move(__out), __str); | |
765 | } | |
766 | ||
767 | template<typename _Tp, typename _FormatContext> | |
768 | typename _FormatContext::iterator | |
769 | _M_b_B(const _Tp& __t, typename _FormatContext::iterator __out, | |
770 | _FormatContext& __ctx, bool __full) const | |
771 | { | |
772 | // %b Locale's abbreviated month name. | |
773 | // %B Locale's full month name. | |
774 | chrono::month __m = _S_month(__t); | |
775 | if (!__m.ok()) | |
776 | __throw_format_error("format error: invalid month"); | |
777 | locale __loc = _M_locale(__ctx); | |
778 | const auto& __tp = use_facet<__timepunct<_CharT>>(__loc); | |
779 | const _CharT* __months[12]; | |
780 | if (__full) | |
781 | __tp._M_months(__months); | |
782 | else | |
783 | __tp._M_months_abbreviated(__months); | |
784 | __string_view __str(__months[(unsigned)__m - 1]); | |
785 | return __format::__write(std::move(__out), __str); | |
786 | } | |
787 | ||
788 | template<typename _Tp, typename _FormatContext> | |
789 | typename _FormatContext::iterator | |
f4bce119 | 790 | _M_c(const _Tp& __tt, typename _FormatContext::iterator __out, |
f99b9486 JW |
791 | _FormatContext& __ctx, bool __mod = false) const |
792 | { | |
793 | // %c Locale's date and time representation. | |
794 | // %Ec Locale's alternate date and time representation. | |
795 | ||
f4bce119 | 796 | auto __t = _S_floor_seconds(__tt); |
f99b9486 JW |
797 | locale __loc = _M_locale(__ctx); |
798 | const auto& __tp = use_facet<__timepunct<_CharT>>(__loc); | |
799 | const _CharT* __formats[2]; | |
800 | __tp._M_date_time_formats(__formats); | |
801 | const _CharT* __rep = __formats[__mod]; | |
802 | if (!*__rep) | |
803 | __rep = _GLIBCXX_WIDEN("%a %b %e %H:%M:%S %Y"); | |
804 | basic_string<_CharT> __fmt(_S_empty_spec); | |
805 | __fmt.insert(1u, 1u, _S_colon); | |
806 | __fmt.insert(2u, __rep); | |
807 | return std::vformat_to(std::move(__out), __loc, __fmt, | |
808 | std::make_format_args<_FormatContext>(__t)); | |
809 | } | |
810 | ||
811 | template<typename _Tp, typename _FormatContext> | |
812 | typename _FormatContext::iterator | |
813 | _M_C_y_Y(const _Tp& __t, typename _FormatContext::iterator __out, | |
f4bce119 | 814 | _FormatContext& __ctx, _CharT __conv, _CharT __mod = 0) const |
f99b9486 JW |
815 | { |
816 | // %C Year divided by 100 using floored division. | |
817 | // %EC Locale's alternative preresentation of the century (era name). | |
818 | // %y Last two decimal digits of the year. | |
f4bce119 | 819 | // %Oy Locale's alternative representation. |
f99b9486 JW |
820 | // %Ey Locale's alternative representation of offset from %EC. |
821 | // %Y Year as a decimal number. | |
f4bce119 | 822 | // %EY Locale's alternative full year representation. |
f99b9486 JW |
823 | |
824 | chrono::year __y = _S_year(__t); | |
825 | ||
f4bce119 | 826 | if (__mod) [[unlikely]] |
f99b9486 | 827 | { |
f4bce119 JW |
828 | struct tm __tm{}; |
829 | __tm.tm_year = (int)__y - 1900; | |
830 | return _M_locale_fmt(std::move(__out), _M_locale(__ctx), __tm, | |
831 | __conv, __mod); | |
f99b9486 JW |
832 | } |
833 | ||
834 | basic_string<_CharT> __s; | |
835 | int __yi = (int)__y; | |
836 | const bool __is_neg = __yi < 0; | |
837 | __yi = __builtin_abs(__yi); | |
838 | ||
839 | if (__conv == 'Y' || __conv == 'C') | |
840 | { | |
f99b9486 | 841 | int __ci = __yi / 100; |
a01462ae JW |
842 | if (__is_neg) [[unlikely]] |
843 | { | |
844 | __s.assign(1, _S_plus_minus[1]); | |
845 | // For floored division -123//100 is -2 and -100//100 is -1 | |
ad537ccd | 846 | if (__conv == 'C' && (__ci * 100) != __yi) |
a01462ae JW |
847 | ++__ci; |
848 | } | |
f99b9486 JW |
849 | if (__ci >= 100) [[unlikely]] |
850 | { | |
851 | __s += std::format(_S_empty_spec, __ci / 100); | |
852 | __ci %= 100; | |
853 | } | |
854 | __s += _S_two_digits(__ci); | |
855 | } | |
856 | ||
857 | if (__conv == 'Y' || __conv == 'y') | |
858 | __s += _S_two_digits(__yi % 100); | |
859 | ||
f99b9486 JW |
860 | return __format::__write(std::move(__out), __string_view(__s)); |
861 | } | |
862 | ||
863 | template<typename _Tp, typename _FormatContext> | |
864 | typename _FormatContext::iterator | |
865 | _M_D(const _Tp& __t, typename _FormatContext::iterator __out, | |
866 | _FormatContext&) const | |
867 | { | |
868 | auto __ymd = _S_date(__t); | |
869 | basic_string<_CharT> __s; | |
870 | #if ! _GLIBCXX_USE_CXX11_ABI | |
871 | __s.reserve(8); | |
872 | #endif | |
873 | __s = _S_two_digits((unsigned)__ymd.month()); | |
874 | __s += _S_slash; | |
875 | __s += _S_two_digits((unsigned)__ymd.day()); | |
876 | __s += _S_slash; | |
877 | __s += _S_two_digits(__builtin_abs((int)__ymd.year()) % 100); | |
878 | return __format::__write(std::move(__out), __string_view(__s)); | |
879 | } | |
880 | ||
881 | template<typename _Tp, typename _FormatContext> | |
882 | typename _FormatContext::iterator | |
f4bce119 JW |
883 | _M_d_e(const _Tp& __t, typename _FormatContext::iterator __out, |
884 | _FormatContext& __ctx, _CharT __conv, bool __mod = false) const | |
f99b9486 | 885 | { |
f4bce119 JW |
886 | // %d The day of month as a decimal number. |
887 | // %Od Locale's alternative representation. | |
f99b9486 JW |
888 | // %e Day of month as decimal number, padded with space. |
889 | // %Oe Locale's alternative digits. | |
f4bce119 | 890 | |
f99b9486 JW |
891 | chrono::day __d = _S_day(__t); |
892 | unsigned __i = (unsigned)__d; | |
f4bce119 JW |
893 | |
894 | if (__mod) [[unlikely]] | |
895 | { | |
896 | struct tm __tm{}; | |
897 | __tm.tm_mday = __i; | |
898 | return _M_locale_fmt(std::move(__out), _M_locale(__ctx), __tm, | |
899 | (char)__conv, 'O'); | |
900 | } | |
901 | ||
f99b9486 | 902 | auto __sv = _S_two_digits(__i); |
f4bce119 JW |
903 | _CharT __buf[2]; |
904 | if (__conv == _CharT('e') && __i < 10) | |
905 | { | |
906 | __buf[0] = _S_space; | |
907 | __buf[1] = __sv[1]; | |
908 | __sv = {__buf, 2}; | |
909 | } | |
f99b9486 JW |
910 | return __format::__write(std::move(__out), __sv); |
911 | } | |
912 | ||
913 | template<typename _Tp, typename _FormatContext> | |
914 | typename _FormatContext::iterator | |
915 | _M_F(const _Tp& __t, typename _FormatContext::iterator __out, | |
916 | _FormatContext&) const | |
917 | { | |
918 | auto __ymd = _S_date(__t); | |
8ae50799 JW |
919 | auto __s = std::format(_GLIBCXX_WIDEN("{:04d}- - "), |
920 | (int)__ymd.year()); | |
f99b9486 JW |
921 | auto __sv = _S_two_digits((unsigned)__ymd.month()); |
922 | __s[__s.size() - 5] = __sv[0]; | |
923 | __s[__s.size() - 4] = __sv[1]; | |
924 | __sv = _S_two_digits((unsigned)__ymd.day()); | |
925 | __s[__s.size() - 2] = __sv[0]; | |
926 | __s[__s.size() - 1] = __sv[1]; | |
927 | __sv = __s; | |
928 | return __format::__write(std::move(__out), __sv); | |
929 | } | |
930 | ||
931 | template<typename _Tp, typename _FormatContext> | |
932 | typename _FormatContext::iterator | |
933 | _M_g_G(const _Tp& __t, typename _FormatContext::iterator __out, | |
934 | _FormatContext& __ctx, bool __full) const | |
935 | { | |
936 | // %g last two decimal digits of the ISO week-based year. | |
937 | // %G ISO week-based year. | |
938 | using namespace chrono; | |
939 | auto __d = _S_days(__t); | |
940 | // Move to nearest Thursday: | |
941 | __d -= (weekday(__d) - Monday) - days(3); | |
942 | // ISO week-based year is the year that contains that Thursday: | |
943 | year __y = year_month_day(__d).year(); | |
944 | return _M_C_y_Y(__y, std::move(__out), __ctx, "yY"[__full]); | |
945 | } | |
946 | ||
947 | template<typename _Tp, typename _FormatContext> | |
948 | typename _FormatContext::iterator | |
f4bce119 JW |
949 | _M_H_I(const _Tp& __t, typename _FormatContext::iterator __out, |
950 | _FormatContext& __ctx, _CharT __conv, bool __mod = false) const | |
f99b9486 | 951 | { |
f4bce119 JW |
952 | // %H The hour (24-hour clock) as a decimal number. |
953 | // %OH Locale's alternative representation. | |
954 | // %I The hour (12-hour clock) as a decimal number. | |
955 | // %OI Locale's alternative representation. | |
956 | ||
957 | const auto __hms = _S_hms(__t); | |
f99b9486 | 958 | int __i = __hms.hours().count(); |
f4bce119 JW |
959 | |
960 | if (__mod) [[unlikely]] | |
961 | { | |
962 | struct tm __tm{}; | |
963 | __tm.tm_hour = __i; | |
964 | return _M_locale_fmt(std::move(__out), _M_locale(__ctx), __tm, | |
965 | (char)__conv, 'O'); | |
966 | } | |
967 | ||
968 | if (__conv == _CharT('I')) | |
969 | { | |
970 | if (__i == 0) | |
971 | __i = 12; | |
972 | else if (__i > 12) | |
973 | __i -= 12; | |
974 | } | |
975 | return __format::__write(std::move(__out), _S_two_digits(__i)); | |
f99b9486 JW |
976 | } |
977 | ||
978 | template<typename _Tp, typename _FormatContext> | |
979 | typename _FormatContext::iterator | |
980 | _M_j(const _Tp& __t, typename _FormatContext::iterator __out, | |
f4bce119 | 981 | _FormatContext&) const |
f99b9486 JW |
982 | { |
983 | if constexpr (chrono::__is_duration_v<_Tp>) | |
984 | { | |
985 | // Decimal number of days, without padding. | |
986 | unsigned __d = chrono::duration_cast<chrono::days>(__t).count(); | |
987 | return std::format_to(std::move(__out), _S_empty_spec, __d); | |
988 | } | |
989 | else | |
990 | { | |
991 | // Day of the year as a decimal number, padding with zero. | |
992 | using namespace chrono; | |
993 | auto __day = _S_days(__t); | |
994 | auto __ymd = _S_date(__t); | |
995 | days __d; | |
996 | // See "Calculating Ordinal Dates" at | |
997 | // https://github.com/HowardHinnant/date/wiki/Examples-and-Recipes | |
998 | if constexpr (is_same_v<typename decltype(__day)::clock, local_t>) | |
999 | __d = __day - local_days(__ymd.year()/January/0); | |
1000 | else | |
1001 | __d = __day - sys_days(__ymd.year()/January/0); | |
1002 | return std::format_to(std::move(__out), _GLIBCXX_WIDEN("{:03d}"), | |
1003 | __d.count()); | |
1004 | } | |
1005 | } | |
1006 | ||
f4bce119 JW |
1007 | template<typename _Tp, typename _FormatContext> |
1008 | typename _FormatContext::iterator | |
1009 | _M_m(const _Tp& __t, typename _FormatContext::iterator __out, | |
1010 | _FormatContext& __ctx, bool __mod) const | |
1011 | { | |
1012 | // %m month as a decimal number. | |
1013 | // %Om Locale's alternative representation. | |
1014 | ||
1015 | auto __m = _S_month(__t); | |
1016 | auto __i = (unsigned)__m; | |
1017 | ||
1018 | if (__mod) [[unlikely]] // %Om | |
1019 | { | |
1020 | struct tm __tm{}; | |
1021 | __tm.tm_mon = __i - 1; | |
1022 | return _M_locale_fmt(std::move(__out), _M_locale(__ctx), __tm, | |
1023 | 'm', 'O'); | |
1024 | } | |
1025 | ||
1026 | return __format::__write(std::move(__out), _S_two_digits(__i)); | |
1027 | } | |
1028 | ||
1029 | template<typename _Tp, typename _FormatContext> | |
1030 | typename _FormatContext::iterator | |
1031 | _M_M(const _Tp& __t, typename _FormatContext::iterator __out, | |
1032 | _FormatContext& __ctx, bool __mod) const | |
1033 | { | |
1034 | // %M The minute as a decimal number. | |
1035 | // %OM Locale's alternative representation. | |
1036 | ||
1037 | auto __m = _S_hms(__t).minutes(); | |
1038 | auto __i = __m.count(); | |
1039 | ||
1040 | if (__mod) [[unlikely]] // %OM | |
1041 | { | |
1042 | struct tm __tm{}; | |
1043 | __tm.tm_min = __i; | |
1044 | return _M_locale_fmt(std::move(__out), _M_locale(__ctx), __tm, | |
1045 | 'M', 'O'); | |
1046 | } | |
1047 | ||
1048 | return __format::__write(std::move(__out), _S_two_digits(__i)); | |
1049 | } | |
1050 | ||
f99b9486 JW |
1051 | template<typename _Tp, typename _FormatContext> |
1052 | typename _FormatContext::iterator | |
1053 | _M_p(const _Tp& __t, typename _FormatContext::iterator __out, | |
1054 | _FormatContext& __ctx) const | |
1055 | { | |
1056 | // %p The locale's equivalent of the AM/PM designations. | |
1057 | auto __hms = _S_hms(__t); | |
1058 | locale __loc = _M_locale(__ctx); | |
1059 | const auto& __tp = use_facet<__timepunct<_CharT>>(__loc); | |
1060 | const _CharT* __ampm[2]; | |
1061 | __tp._M_am_pm(__ampm); | |
1062 | return std::format_to(std::move(__out), _S_empty_spec, | |
1063 | __ampm[__hms.hours().count() >= 12]); | |
1064 | } | |
1065 | ||
1066 | template<typename _Tp, typename _FormatContext> | |
1067 | typename _FormatContext::iterator | |
f4bce119 | 1068 | _M_q(const _Tp&, typename _FormatContext::iterator __out, |
c992acdc | 1069 | _FormatContext&) const |
f99b9486 JW |
1070 | { |
1071 | // %q The duration's unit suffix | |
1072 | if constexpr (!chrono::__is_duration_v<_Tp>) | |
1073 | __throw_format_error("format error: argument is not a duration"); | |
1074 | else | |
1075 | { | |
c992acdc | 1076 | namespace __d = chrono::__detail; |
f99b9486 | 1077 | using period = typename _Tp::period; |
c992acdc | 1078 | return __d::__fmt_units_suffix<period, _CharT>(std::move(__out)); |
f99b9486 JW |
1079 | } |
1080 | } | |
1081 | ||
f4bce119 JW |
1082 | // %Q handled in _M_format |
1083 | ||
f99b9486 JW |
1084 | template<typename _Tp, typename _FormatContext> |
1085 | typename _FormatContext::iterator | |
f4bce119 | 1086 | _M_r(const _Tp& __tt, typename _FormatContext::iterator __out, |
f99b9486 JW |
1087 | _FormatContext& __ctx) const |
1088 | { | |
1089 | // %r locale's 12-hour clock time. | |
f4bce119 | 1090 | auto __t = _S_floor_seconds(__tt); |
f99b9486 JW |
1091 | locale __loc = _M_locale(__ctx); |
1092 | const auto& __tp = use_facet<__timepunct<_CharT>>(__loc); | |
1093 | const _CharT* __ampm_fmt; | |
1094 | __tp._M_am_pm_format(&__ampm_fmt); | |
1095 | basic_string<_CharT> __fmt(_S_empty_spec); | |
1096 | __fmt.insert(1u, 1u, _S_colon); | |
1097 | __fmt.insert(2u, __ampm_fmt); | |
1098 | return std::vformat_to(std::move(__out), __fmt, | |
1099 | std::make_format_args<_FormatContext>(__t)); | |
1100 | } | |
1101 | ||
1102 | template<typename _Tp, typename _FormatContext> | |
1103 | typename _FormatContext::iterator | |
1104 | _M_R_T(const _Tp& __t, typename _FormatContext::iterator __out, | |
1105 | _FormatContext& __ctx, bool __secs) const | |
1106 | { | |
1107 | // %R Equivalent to %H:%M | |
1108 | // %T Equivalent to %H:%M:%S | |
1109 | auto __hms = _S_hms(__t); | |
1110 | ||
8ae50799 JW |
1111 | auto __s = std::format(_GLIBCXX_WIDEN("{:02d}:00"), |
1112 | __hms.hours().count()); | |
f99b9486 JW |
1113 | auto __sv = _S_two_digits(__hms.minutes().count()); |
1114 | __s[__s.size() - 2] = __sv[0]; | |
1115 | __s[__s.size() - 1] = __sv[1]; | |
1116 | __sv = __s; | |
1117 | __out = __format::__write(std::move(__out), __sv); | |
1118 | if (__secs) | |
1119 | { | |
1120 | *__out++ = _S_colon; | |
1121 | __out = _M_S(__hms, std::move(__out), __ctx); | |
1122 | } | |
1123 | return __out; | |
1124 | } | |
1125 | ||
1126 | template<typename _Tp, typename _FormatContext> | |
1127 | typename _FormatContext::iterator | |
1128 | _M_S(const _Tp& __t, typename _FormatContext::iterator __out, | |
1129 | _FormatContext& __ctx, bool __mod = false) const | |
1130 | { | |
1131 | // %S Seconds as a decimal number. | |
f4bce119 | 1132 | // %OS The locale's alternative representation. |
f99b9486 | 1133 | auto __hms = _S_hms(__t); |
f4bce119 JW |
1134 | |
1135 | if (__mod) [[unlikely]] // %OS | |
1136 | { | |
1137 | struct tm __tm{}; | |
1138 | __tm.tm_sec = (int)__hms.seconds().count(); | |
1139 | return _M_locale_fmt(std::move(__out), _M_locale(__ctx), __tm, | |
1140 | 'S', 'O'); | |
1141 | } | |
1142 | ||
7431fcea JW |
1143 | if constexpr (__hms.fractional_width == 0) |
1144 | __out = __format::__write(std::move(__out), | |
1145 | _S_two_digits(__hms.seconds().count())); | |
1146 | else | |
f99b9486 JW |
1147 | { |
1148 | locale __loc = _M_locale(__ctx); | |
7431fcea | 1149 | auto __s = __hms.seconds(); |
f99b9486 | 1150 | auto __ss = __hms.subseconds(); |
86b36e9f | 1151 | using rep = typename decltype(__ss)::rep; |
f99b9486 JW |
1152 | if constexpr (is_floating_point_v<rep>) |
1153 | { | |
7431fcea | 1154 | chrono::duration<rep> __fs = __s + __ss; |
2ef5200a | 1155 | __out = std::format_to(std::move(__out), __loc, |
7431fcea JW |
1156 | _GLIBCXX_WIDEN("{:#0{}.{}Lf}"), |
1157 | __fs.count(), | |
1158 | 3 + __hms.fractional_width, | |
f99b9486 JW |
1159 | __hms.fractional_width); |
1160 | } | |
1161 | else | |
1162 | { | |
1163 | const auto& __np | |
1164 | = use_facet<numpunct<_CharT>>(__loc); | |
7431fcea JW |
1165 | __out = __format::__write(std::move(__out), |
1166 | _S_two_digits(__s.count())); | |
f99b9486 | 1167 | *__out++ = __np.decimal_point(); |
7431fcea JW |
1168 | if constexpr (is_integral_v<rep>) |
1169 | __out = std::format_to(std::move(__out), | |
1170 | _GLIBCXX_WIDEN("{:0{}}"), | |
1171 | __ss.count(), | |
1172 | __hms.fractional_width); | |
1173 | else | |
1174 | { | |
1175 | auto __str = std::format(_S_empty_spec, __ss.count()); | |
1176 | __out = std::format_to(_GLIBCXX_WIDEN("{:0>{}s}"), | |
1177 | __str, | |
1178 | __hms.fractional_width); | |
1179 | } | |
f99b9486 JW |
1180 | } |
1181 | } | |
1182 | return __out; | |
1183 | } | |
1184 | ||
1185 | // %t handled in _M_format | |
1186 | ||
1187 | template<typename _Tp, typename _FormatContext> | |
1188 | typename _FormatContext::iterator | |
1189 | _M_u_w(const _Tp& __t, typename _FormatContext::iterator __out, | |
1190 | _FormatContext& __ctx, _CharT __conv, bool __mod = false) const | |
1191 | { | |
1192 | // %u ISO weekday as a decimal number (1-7), where Monday is 1. | |
1193 | // %Ou Locale's alternative numeric rep. | |
1194 | // %w Weekday as a decimal number (0-6), where Sunday is 0. | |
1195 | // %Ow Locale's alternative numeric rep. | |
f4bce119 | 1196 | |
f99b9486 | 1197 | chrono::weekday __wd = _S_weekday(__t); |
f4bce119 JW |
1198 | |
1199 | if (__mod) [[unlikely]] | |
1200 | { | |
1201 | struct tm __tm{}; | |
1202 | __tm.tm_wday = __wd.c_encoding(); | |
1203 | return _M_locale_fmt(std::move(__out), _M_locale(__ctx), __tm, | |
1204 | (char)__conv, 'O'); | |
1205 | } | |
1206 | ||
f99b9486 JW |
1207 | unsigned __wdi = __conv == 'u' ? __wd.iso_encoding() |
1208 | : __wd.c_encoding(); | |
f4bce119 JW |
1209 | const _CharT __d = _S_digit(__wdi); |
1210 | return __format::__write(std::move(__out), __string_view(&__d, 1)); | |
f99b9486 JW |
1211 | } |
1212 | ||
1213 | template<typename _Tp, typename _FormatContext> | |
1214 | typename _FormatContext::iterator | |
1215 | _M_U_V_W(const _Tp& __t, typename _FormatContext::iterator __out, | |
1216 | _FormatContext& __ctx, _CharT __conv, bool __mod = false) const | |
1217 | { | |
1218 | // %U Week number of the year as a decimal number, from first Sunday. | |
1219 | // %OU Locale's alternative numeric rep. | |
1220 | // %V ISO week-based week number as a decimal number. | |
1221 | // %OV Locale's alternative numeric rep. | |
1222 | // %W Week number of the year as a decimal number, from first Monday. | |
1223 | // %OW Locale's alternative numeric rep. | |
1224 | using namespace chrono; | |
1225 | auto __d = _S_days(__t); | |
1226 | using _TDays = decltype(__d); // Either sys_days or local_days. | |
1227 | ||
f4bce119 JW |
1228 | if (__mod) [[unlikely]] |
1229 | { | |
1230 | const year_month_day __ymd(__d); | |
1231 | const year __y = __ymd.year(); | |
1232 | struct tm __tm{}; | |
1233 | __tm.tm_year = (int)__y - 1900; | |
1234 | __tm.tm_yday = (__d - _TDays(__y/January/1)).count(); | |
1235 | __tm.tm_wday = weekday(__d).c_encoding(); | |
1236 | return _M_locale_fmt(std::move(__out), _M_locale(__ctx), __tm, | |
1237 | (char)__conv, 'O'); | |
1238 | } | |
1239 | ||
f99b9486 JW |
1240 | _TDays __first; // First day of week 1. |
1241 | if (__conv == 'V') // W01 begins on Monday before first Thursday. | |
1242 | { | |
1243 | // Move to nearest Thursday: | |
1244 | __d -= (weekday(__d) - Monday) - days(3); | |
1245 | // ISO week of __t is number of weeks since January 1 of the | |
1246 | // same year as that nearest Thursday. | |
1247 | __first = _TDays(year_month_day(__d).year()/January/1); | |
1248 | } | |
1249 | else | |
1250 | { | |
1251 | year __y; | |
1252 | if constexpr (requires { __t.year(); }) | |
1253 | __y = __t.year(); | |
1254 | else | |
1255 | __y = year_month_day(__d).year(); | |
1256 | const weekday __weekstart = __conv == 'U' ? Sunday : Monday; | |
1257 | __first = _TDays(__y/January/__weekstart[1]); | |
1258 | } | |
1259 | auto __weeks = chrono::floor<weeks>(__d - __first); | |
1260 | __string_view __sv = _S_two_digits(__weeks.count() + 1); | |
f99b9486 JW |
1261 | return __format::__write(std::move(__out), __sv); |
1262 | } | |
1263 | ||
1264 | template<typename _Tp, typename _FormatContext> | |
1265 | typename _FormatContext::iterator | |
1266 | _M_x(const _Tp& __t, typename _FormatContext::iterator __out, | |
1267 | _FormatContext& __ctx, bool __mod = false) const | |
1268 | { | |
1269 | // %x Locale's date rep | |
1270 | // %Ex Locale's alternative date representation. | |
1271 | locale __loc = _M_locale(__ctx); | |
1272 | const auto& __tp = use_facet<__timepunct<_CharT>>(__loc); | |
1273 | const _CharT* __date_reps[2]; | |
1274 | __tp._M_date_formats(__date_reps); | |
1275 | const _CharT* __rep = __date_reps[__mod]; | |
1276 | if (!*__rep) | |
1277 | return _M_D(__t, std::move(__out), __ctx); | |
1278 | ||
1279 | basic_string<_CharT> __fmt(_S_empty_spec); | |
1280 | __fmt.insert(1u, 1u, _S_colon); | |
1281 | __fmt.insert(2u, __rep); | |
1282 | return std::vformat_to(std::move(__out), __fmt, | |
1283 | std::make_format_args<_FormatContext>(__t)); | |
1284 | } | |
1285 | ||
1286 | template<typename _Tp, typename _FormatContext> | |
1287 | typename _FormatContext::iterator | |
f4bce119 | 1288 | _M_X(const _Tp& __tt, typename _FormatContext::iterator __out, |
f99b9486 JW |
1289 | _FormatContext& __ctx, bool __mod = false) const |
1290 | { | |
1291 | // %X Locale's time rep | |
1292 | // %EX Locale's alternative time representation. | |
f4bce119 | 1293 | auto __t = _S_floor_seconds(__tt); |
f99b9486 JW |
1294 | locale __loc = _M_locale(__ctx); |
1295 | const auto& __tp = use_facet<__timepunct<_CharT>>(__loc); | |
1296 | const _CharT* __time_reps[2]; | |
1297 | __tp._M_time_formats(__time_reps); | |
1298 | const _CharT* __rep = __time_reps[__mod]; | |
1299 | if (!*__rep) | |
1300 | return _M_R_T(__t, std::move(__out), __ctx, true); | |
1301 | ||
1302 | basic_string<_CharT> __fmt(_S_empty_spec); | |
1303 | __fmt.insert(1u, 1u, _S_colon); | |
1304 | __fmt.insert(2u, __rep); | |
1305 | return std::vformat_to(std::move(__out), __fmt, | |
1306 | std::make_format_args<_FormatContext>(__t)); | |
1307 | } | |
1308 | ||
1309 | template<typename _Tp, typename _FormatContext> | |
1310 | typename _FormatContext::iterator | |
1311 | _M_z(const _Tp& __t, typename _FormatContext::iterator __out, | |
f4bce119 | 1312 | _FormatContext&, bool __mod = false) const |
f99b9486 JW |
1313 | { |
1314 | using ::std::chrono::__detail::__utc_leap_second; | |
1315 | using ::std::chrono::__detail::__local_time_fmt; | |
1316 | ||
1317 | auto __utc = __mod ? __string_view(_GLIBCXX_WIDEN("+00:00"), 6) | |
1318 | : __string_view(_GLIBCXX_WIDEN("+0000"), 5); | |
1319 | ||
1320 | if constexpr (chrono::__is_time_point_v<_Tp>) | |
1321 | { | |
1322 | if constexpr (is_same_v<typename _Tp::clock, | |
1323 | chrono::system_clock>) | |
1324 | return __format::__write(std::move(__out), __utc); | |
1325 | } | |
1326 | else if constexpr (__is_specialization_of<_Tp, __local_time_fmt>) | |
1327 | { | |
1328 | if (__t._M_offset_sec) | |
1329 | { | |
1330 | auto __sv = __utc; | |
1331 | basic_string<_CharT> __s; | |
1332 | if (*__t._M_offset_sec != 0s) | |
1333 | { | |
1334 | chrono:: hh_mm_ss __hms(*__t._M_offset_sec); | |
1335 | __s = _S_plus_minus[__hms.is_negative()]; | |
1336 | __s += _S_two_digits(__hms.hours().count()); | |
1337 | if (__mod) | |
1338 | __s += _S_colon; | |
1339 | __s += _S_two_digits(__hms.minutes().count()); | |
1340 | __sv = __s; | |
1341 | } | |
1342 | return __format::__write(std::move(__out), __sv); | |
1343 | } | |
1344 | } | |
1345 | else if constexpr (__is_specialization_of<_Tp, __utc_leap_second>) | |
1346 | return __format::__write(std::move(__out), __utc); | |
1347 | ||
1348 | __no_timezone_available(); | |
1349 | } | |
1350 | ||
1351 | template<typename _Tp, typename _FormatContext> | |
1352 | typename _FormatContext::iterator | |
1353 | _M_Z(const _Tp& __t, typename _FormatContext::iterator __out, | |
1354 | _FormatContext& __ctx) const | |
1355 | { | |
1356 | using ::std::chrono::__detail::__utc_leap_second; | |
1357 | using ::std::chrono::__detail::__local_time_fmt; | |
1358 | ||
1359 | __string_view __utc(_GLIBCXX_WIDEN("UTC"), 3); | |
1360 | if constexpr (chrono::__is_time_point_v<_Tp>) | |
1361 | { | |
1362 | if constexpr (is_same_v<typename _Tp::clock, | |
1363 | chrono::system_clock>) | |
1364 | return __format::__write(std::move(__out), __utc); | |
1365 | } | |
1366 | else if constexpr (__is_specialization_of<_Tp, __local_time_fmt>) | |
1367 | { | |
1368 | if (__t._M_abbrev) | |
1369 | { | |
c992acdc | 1370 | string_view __sv = *__t._M_abbrev; |
f99b9486 | 1371 | if constexpr (is_same_v<_CharT, char>) |
c992acdc | 1372 | return __format::__write(std::move(__out), __sv); |
f99b9486 JW |
1373 | else |
1374 | { | |
c992acdc | 1375 | // TODO use resize_and_overwrite |
f4bce119 | 1376 | basic_string<_CharT> __ws(__sv.size(), _CharT()); |
f99b9486 | 1377 | auto& __ct = use_facet<ctype<_CharT>>(_M_locale(__ctx)); |
f4bce119 | 1378 | __ct.widen(__sv.begin(), __sv.end(), __ws.data()); |
c992acdc JW |
1379 | __string_view __wsv = __ws; |
1380 | return __format::__write(std::move(__out), __wsv); | |
f99b9486 | 1381 | } |
f99b9486 JW |
1382 | } |
1383 | } | |
1384 | else if constexpr (__is_specialization_of<_Tp, __utc_leap_second>) | |
1385 | return __format::__write(std::move(__out), __utc); | |
1386 | ||
1387 | __no_timezone_available(); | |
1388 | } | |
1389 | ||
1390 | // %% handled in _M_format | |
1391 | ||
1392 | // A single digit character in the range '0'..'9'. | |
1393 | static _CharT | |
1394 | _S_digit(int __n) noexcept | |
1395 | { | |
1396 | // Extra 9s avoid past-the-end read on bad input. | |
1397 | return _GLIBCXX_WIDEN("0123456789999999")[__n & 0xf]; | |
1398 | } | |
1399 | ||
1400 | // A string view of two digit characters, "00".."99". | |
1401 | static basic_string_view<_CharT> | |
1402 | _S_two_digits(int __n) noexcept | |
1403 | { | |
1404 | return { | |
1405 | _GLIBCXX_WIDEN("0001020304050607080910111213141516171819" | |
1406 | "2021222324252627282930313233343536373839" | |
1407 | "4041424344454647484950515253545556575859" | |
1408 | "6061626364656667686970717273747576777879" | |
1409 | "8081828384858687888990919293949596979899" | |
1410 | "9999999999999999999999999999999999999999" | |
1411 | "9999999999999999") + 2 * (__n & 0x7f), | |
1412 | 2 | |
1413 | }; | |
1414 | } | |
1415 | ||
f99b9486 JW |
1416 | // Accessors for the components of chrono types: |
1417 | ||
1418 | // Returns a hh_mm_ss. | |
1419 | template<typename _Tp> | |
1420 | static decltype(auto) | |
1421 | _S_hms(const _Tp& __t) | |
1422 | { | |
1423 | using ::std::chrono::__detail::__utc_leap_second; | |
1424 | using ::std::chrono::__detail::__local_time_fmt; | |
1425 | ||
1426 | if constexpr (__is_specialization_of<_Tp, chrono::hh_mm_ss>) | |
1427 | return __t; | |
1428 | else if constexpr (__is_specialization_of<_Tp, __utc_leap_second>) | |
1429 | return __t._M_time; | |
1430 | else if constexpr (chrono::__is_duration_v<_Tp>) | |
1431 | return chrono::hh_mm_ss<_Tp>(__t); | |
1432 | else if constexpr (chrono::__is_time_point_v<_Tp>) | |
1433 | return chrono::hh_mm_ss(__t - chrono::floor<chrono::days>(__t)); | |
1434 | else if constexpr (__is_specialization_of<_Tp, __local_time_fmt>) | |
1435 | return _S_hms(__t._M_time); | |
1436 | else | |
1437 | { | |
1438 | __invalid_chrono_spec(); | |
1439 | return chrono::hh_mm_ss<chrono::seconds>(); | |
1440 | } | |
1441 | } | |
1442 | ||
1443 | // Returns a sys_days or local_days. | |
1444 | template<typename _Tp> | |
1445 | static auto | |
1446 | _S_days(const _Tp& __t) | |
1447 | { | |
1448 | using namespace chrono; | |
1449 | using ::std::chrono::__detail::__utc_leap_second; | |
1450 | using ::std::chrono::__detail::__local_time_fmt; | |
1451 | ||
1452 | if constexpr (__is_time_point_v<_Tp>) | |
1453 | return chrono::floor<days>(__t); | |
1454 | else if constexpr (__is_specialization_of<_Tp, __utc_leap_second>) | |
1455 | return __t._M_date; | |
1456 | else if constexpr (__is_specialization_of<_Tp, __local_time_fmt>) | |
1457 | return chrono::floor<days>(__t._M_time); | |
1458 | else if constexpr (is_same_v<_Tp, year_month_day> | |
1459 | || is_same_v<_Tp, year_month_day_last> | |
1460 | || is_same_v<_Tp, year_month_weekday> | |
1461 | || is_same_v<_Tp, year_month_weekday_last>) | |
1462 | return sys_days(__t); | |
1463 | else | |
1464 | { | |
1465 | if constexpr (__is_duration_v<_Tp>) | |
1466 | __not_valid_for_duration(); | |
1467 | else | |
1468 | __invalid_chrono_spec(); | |
1469 | return chrono::sys_days(); | |
1470 | } | |
1471 | } | |
1472 | ||
1473 | // Returns a year_month_day. | |
1474 | template<typename _Tp> | |
1475 | static chrono::year_month_day | |
1476 | _S_date(const _Tp& __t) | |
1477 | { | |
1478 | if constexpr (is_same_v<_Tp, chrono::year_month_day>) | |
1479 | return __t; | |
1480 | else | |
1481 | return chrono::year_month_day(_S_days(__t)); | |
1482 | } | |
1483 | ||
1484 | template<typename _Tp> | |
1485 | static chrono::day | |
1486 | _S_day(const _Tp& __t) | |
1487 | { | |
1488 | using namespace chrono; | |
1489 | ||
1490 | if constexpr (is_same_v<_Tp, day>) | |
1491 | return __t; | |
1492 | else if constexpr (requires { __t.day(); }) | |
1493 | return __t.day(); | |
1494 | else | |
1495 | return _S_date(__t).day(); | |
1496 | } | |
1497 | ||
1498 | template<typename _Tp> | |
1499 | static chrono::month | |
1500 | _S_month(const _Tp& __t) | |
1501 | { | |
1502 | using namespace chrono; | |
1503 | ||
1504 | if constexpr (is_same_v<_Tp, month>) | |
1505 | return __t; | |
1506 | else if constexpr (requires { __t.month(); }) | |
1507 | return __t.month(); | |
1508 | else | |
1509 | return _S_date(__t).month(); | |
1510 | } | |
1511 | ||
1512 | template<typename _Tp> | |
1513 | static chrono::year | |
1514 | _S_year(const _Tp& __t) | |
1515 | { | |
1516 | using namespace chrono; | |
1517 | ||
1518 | if constexpr (is_same_v<_Tp, year>) | |
1519 | return __t; | |
1520 | else if constexpr (requires { __t.year(); }) | |
1521 | return __t.year(); | |
1522 | else | |
1523 | return _S_date(__t).year(); | |
1524 | } | |
1525 | ||
1526 | template<typename _Tp> | |
1527 | static chrono::weekday | |
1528 | _S_weekday(const _Tp& __t) | |
1529 | { | |
1530 | using namespace ::std::chrono; | |
1531 | using ::std::chrono::__detail::__local_time_fmt; | |
1532 | ||
1533 | if constexpr (is_same_v<_Tp, weekday>) | |
1534 | return __t; | |
1535 | else if constexpr (requires { __t.weekday(); }) | |
1536 | return __t.weekday(); | |
1537 | else if constexpr (is_same_v<_Tp, month_weekday>) | |
1538 | return __t.weekday_indexed().weekday(); | |
1539 | else if constexpr (is_same_v<_Tp, month_weekday_last>) | |
1540 | return __t.weekday_last().weekday(); | |
1541 | else | |
1542 | return weekday(_S_days(__t)); | |
1543 | } | |
f4bce119 JW |
1544 | |
1545 | // Remove subsecond precision from a time_point. | |
1546 | template<typename _Tp> | |
1547 | static auto | |
1548 | _S_floor_seconds(const _Tp& __t) | |
1549 | { | |
1550 | using chrono::__detail::__local_time_fmt; | |
86b36e9f JW |
1551 | if constexpr (chrono::__is_time_point_v<_Tp> |
1552 | || chrono::__is_duration_v<_Tp>) | |
1553 | { | |
1554 | if constexpr (_Tp::period::den != 1) | |
1555 | return chrono::floor<chrono::seconds>(__t); | |
1556 | else | |
1557 | return __t; | |
1558 | } | |
1559 | else if constexpr (__is_specialization_of<_Tp, chrono::hh_mm_ss>) | |
1560 | { | |
1561 | if constexpr (_Tp::fractional_width != 0) | |
1562 | return chrono::floor<chrono::seconds>(__t.to_duration()); | |
1563 | else | |
1564 | return __t; | |
1565 | } | |
f4bce119 JW |
1566 | else if constexpr (__is_specialization_of<_Tp, __local_time_fmt>) |
1567 | return _S_floor_seconds(__t._M_time); | |
1568 | else | |
1569 | return __t; | |
1570 | } | |
1571 | ||
1572 | // Use the formatting locale's std::time_put facet to produce | |
1573 | // a locale-specific representation. | |
1574 | template<typename _Iter> | |
1575 | _Iter | |
1576 | _M_locale_fmt(_Iter __out, const locale& __loc, const struct tm& __tm, | |
1577 | char __fmt, char __mod) const | |
1578 | { | |
1579 | basic_ostringstream<_CharT> __os; | |
1580 | const auto& __tp = use_facet<time_put<_CharT>>(__loc); | |
1581 | __tp.put(__os, __os, _S_space, &__tm, __fmt, __mod); | |
1582 | if (__os) | |
1583 | __out = __format::__write(std::move(__out), __os.view()); | |
1584 | return __out; | |
1585 | } | |
f99b9486 JW |
1586 | }; |
1587 | ||
1588 | } // namespace __format | |
1589 | /// @endcond | |
1590 | ||
1591 | template<typename _Rep, typename _Period, typename _CharT> | |
1592 | struct formatter<chrono::duration<_Rep, _Period>, _CharT> | |
1593 | { | |
1594 | constexpr typename basic_format_parse_context<_CharT>::iterator | |
1595 | parse(basic_format_parse_context<_CharT>& __pc) | |
1596 | { | |
1597 | using namespace __format; | |
1598 | auto __it = _M_f._M_parse(__pc, _Duration|_TimeOfDay); | |
1599 | if constexpr (!is_floating_point_v<_Rep>) | |
1600 | if (_M_f._M_spec._M_prec_kind != __format::_WP_none) | |
1601 | __throw_format_error("format error: invalid precision for duration"); | |
1602 | return __it; | |
1603 | } | |
1604 | ||
1605 | template<typename _Out> | |
1606 | typename basic_format_context<_Out, _CharT>::iterator | |
1607 | format(const chrono::duration<_Rep, _Period>& __d, | |
1608 | basic_format_context<_Out, _CharT>& __fc) const | |
1609 | { | |
1610 | return _M_f._M_format(chrono::abs(__d), __fc, __d < __d.zero()); | |
1611 | } | |
1612 | ||
1613 | private: | |
1614 | __format::__formatter_chrono<_CharT> _M_f; | |
1615 | }; | |
1616 | ||
1617 | template<typename _CharT> | |
1618 | struct formatter<chrono::day, _CharT> | |
1619 | { | |
1620 | template<typename _ParseContext> | |
1621 | constexpr typename _ParseContext::iterator | |
1622 | parse(_ParseContext& __pc) | |
1623 | { return _M_f._M_parse(__pc, __format::_Day); } | |
1624 | ||
1625 | template<typename _FormatContext> | |
1626 | typename _FormatContext::iterator | |
1627 | format(const chrono::day& __t, _FormatContext& __fc) const | |
1628 | { return _M_f._M_format(__t, __fc); } | |
1629 | ||
1630 | private: | |
1631 | __format::__formatter_chrono<_CharT> _M_f; | |
1632 | }; | |
1633 | ||
1634 | template<typename _CharT> | |
1635 | struct formatter<chrono::month, _CharT> | |
1636 | { | |
1637 | template<typename _ParseContext> | |
1638 | constexpr typename _ParseContext::iterator | |
1639 | parse(_ParseContext& __pc) | |
1640 | { return _M_f._M_parse(__pc, __format::_Month); } | |
1641 | ||
1642 | template<typename _FormatContext> | |
1643 | typename _FormatContext::iterator | |
1644 | format(const chrono::month& __t, _FormatContext& __fc) const | |
1645 | { return _M_f._M_format(__t, __fc); } | |
1646 | ||
1647 | private: | |
1648 | __format::__formatter_chrono<_CharT> _M_f; | |
1649 | }; | |
1650 | ||
1651 | template<typename _CharT> | |
1652 | struct formatter<chrono::year, _CharT> | |
1653 | { | |
1654 | template<typename _ParseContext> | |
1655 | constexpr typename _ParseContext::iterator | |
1656 | parse(_ParseContext& __pc) | |
1657 | { return _M_f._M_parse(__pc, __format::_Year); } | |
1658 | ||
1659 | template<typename _FormatContext> | |
1660 | typename _FormatContext::iterator | |
1661 | format(const chrono::year& __t, _FormatContext& __fc) const | |
1662 | { return _M_f._M_format(__t, __fc); } | |
1663 | ||
1664 | private: | |
1665 | __format::__formatter_chrono<_CharT> _M_f; | |
1666 | }; | |
1667 | ||
1668 | template<typename _CharT> | |
1669 | struct formatter<chrono::weekday, _CharT> | |
1670 | { | |
1671 | template<typename _ParseContext> | |
1672 | constexpr typename _ParseContext::iterator | |
1673 | parse(_ParseContext& __pc) | |
1674 | { return _M_f._M_parse(__pc, __format::_Weekday); } | |
1675 | ||
1676 | template<typename _FormatContext> | |
1677 | typename _FormatContext::iterator | |
1678 | format(const chrono::weekday& __t, _FormatContext& __fc) const | |
1679 | { return _M_f._M_format(__t, __fc); } | |
1680 | ||
1681 | private: | |
1682 | __format::__formatter_chrono<_CharT> _M_f; | |
1683 | }; | |
1684 | ||
1685 | template<typename _CharT> | |
1686 | struct formatter<chrono::weekday_indexed, _CharT> | |
1687 | { | |
1688 | template<typename _ParseContext> | |
1689 | constexpr typename _ParseContext::iterator | |
1690 | parse(_ParseContext& __pc) | |
1691 | { return _M_f._M_parse(__pc, __format::_Weekday); } | |
1692 | ||
1693 | template<typename _FormatContext> | |
1694 | typename _FormatContext::iterator | |
1695 | format(const chrono::weekday_indexed& __t, _FormatContext& __fc) const | |
1696 | { return _M_f._M_format(__t, __fc); } | |
1697 | ||
1698 | private: | |
1699 | __format::__formatter_chrono<_CharT> _M_f; | |
1700 | }; | |
1701 | ||
1702 | template<typename _CharT> | |
1703 | struct formatter<chrono::weekday_last, _CharT> | |
1704 | { | |
1705 | template<typename _ParseContext> | |
1706 | constexpr typename _ParseContext::iterator | |
1707 | parse(_ParseContext& __pc) | |
1708 | { return _M_f._M_parse(__pc, __format::_Weekday); } | |
1709 | ||
1710 | template<typename _FormatContext> | |
1711 | typename _FormatContext::iterator | |
1712 | format(const chrono::weekday_last& __t, _FormatContext& __fc) const | |
1713 | { return _M_f._M_format(__t, __fc); } | |
1714 | ||
1715 | private: | |
1716 | __format::__formatter_chrono<_CharT> _M_f; | |
1717 | }; | |
1718 | ||
1719 | template<typename _CharT> | |
1720 | struct formatter<chrono::month_day, _CharT> | |
1721 | { | |
1722 | template<typename _ParseContext> | |
1723 | constexpr typename _ParseContext::iterator | |
1724 | parse(_ParseContext& __pc) | |
1725 | { return _M_f._M_parse(__pc, __format::_Month|__format::_Day); } | |
1726 | ||
1727 | template<typename _FormatContext> | |
1728 | typename _FormatContext::iterator | |
1729 | format(const chrono::month_day& __t, _FormatContext& __fc) const | |
1730 | { return _M_f._M_format(__t, __fc); } | |
1731 | ||
1732 | private: | |
1733 | __format::__formatter_chrono<_CharT> _M_f; | |
1734 | }; | |
1735 | ||
1736 | template<typename _CharT> | |
1737 | struct formatter<chrono::month_day_last, _CharT> | |
1738 | { | |
1739 | template<typename _ParseContext> | |
1740 | constexpr typename _ParseContext::iterator | |
1741 | parse(_ParseContext& __pc) | |
1742 | { return _M_f._M_parse(__pc, __format::_Month|__format::_Day); } | |
1743 | ||
1744 | template<typename _FormatContext> | |
1745 | typename _FormatContext::iterator | |
1746 | format(const chrono::month_day_last& __t, _FormatContext& __fc) const | |
1747 | { return _M_f._M_format(__t, __fc); } | |
1748 | ||
1749 | private: | |
1750 | __format::__formatter_chrono<_CharT> _M_f; | |
1751 | }; | |
1752 | ||
1753 | template<typename _CharT> | |
1754 | struct formatter<chrono::month_weekday, _CharT> | |
1755 | { | |
1756 | template<typename _ParseContext> | |
1757 | constexpr typename _ParseContext::iterator | |
1758 | parse(_ParseContext& __pc) | |
1759 | { return _M_f._M_parse(__pc, __format::_Month|__format::_Weekday); } | |
1760 | ||
1761 | template<typename _FormatContext> | |
1762 | typename _FormatContext::iterator | |
1763 | format(const chrono::month_weekday& __t, _FormatContext& __fc) const | |
1764 | { return _M_f._M_format(__t, __fc); } | |
1765 | ||
1766 | private: | |
1767 | __format::__formatter_chrono<_CharT> _M_f; | |
1768 | }; | |
1769 | ||
1770 | template<typename _CharT> | |
1771 | struct formatter<chrono::month_weekday_last, _CharT> | |
1772 | { | |
1773 | template<typename _ParseContext> | |
1774 | constexpr typename _ParseContext::iterator | |
1775 | parse(_ParseContext& __pc) | |
1776 | { return _M_f._M_parse(__pc, __format::_Month|__format::_Weekday); } | |
1777 | ||
1778 | template<typename _FormatContext> | |
1779 | typename _FormatContext::iterator | |
1780 | format(const chrono::month_weekday_last& __t, | |
1781 | _FormatContext& __fc) const | |
1782 | { return _M_f._M_format(__t, __fc); } | |
1783 | ||
1784 | private: | |
1785 | __format::__formatter_chrono<_CharT> _M_f; | |
1786 | }; | |
1787 | ||
1788 | template<typename _CharT> | |
1789 | struct formatter<chrono::year_month, _CharT> | |
1790 | { | |
1791 | template<typename _ParseContext> | |
1792 | constexpr typename _ParseContext::iterator | |
1793 | parse(_ParseContext& __pc) | |
1794 | { return _M_f._M_parse(__pc, __format::_Year|__format::_Month); } | |
1795 | ||
1796 | template<typename _FormatContext> | |
1797 | typename _FormatContext::iterator | |
1798 | format(const chrono::year_month& __t, _FormatContext& __fc) const | |
1799 | { return _M_f._M_format(__t, __fc); } | |
1800 | ||
1801 | private: | |
1802 | __format::__formatter_chrono<_CharT> _M_f; | |
1803 | }; | |
1804 | ||
1805 | template<typename _CharT> | |
1806 | struct formatter<chrono::year_month_day, _CharT> | |
1807 | { | |
1808 | template<typename _ParseContext> | |
1809 | constexpr typename _ParseContext::iterator | |
1810 | parse(_ParseContext& __pc) | |
1811 | { return _M_f._M_parse(__pc, __format::_Date); } | |
1812 | ||
1813 | template<typename _FormatContext> | |
1814 | typename _FormatContext::iterator | |
1815 | format(const chrono::year_month_day& __t, _FormatContext& __fc) const | |
1816 | { return _M_f._M_format(__t, __fc); } | |
1817 | ||
1818 | private: | |
1819 | __format::__formatter_chrono<_CharT> _M_f; | |
1820 | }; | |
1821 | ||
1822 | template<typename _CharT> | |
1823 | struct formatter<chrono::year_month_day_last, _CharT> | |
1824 | { | |
1825 | template<typename _ParseContext> | |
1826 | constexpr typename _ParseContext::iterator | |
1827 | parse(_ParseContext& __pc) | |
1828 | { return _M_f._M_parse(__pc, __format::_Date); } | |
1829 | ||
1830 | template<typename _FormatContext> | |
1831 | typename _FormatContext::iterator | |
1832 | format(const chrono::year_month_day_last& __t, | |
1833 | _FormatContext& __fc) const | |
1834 | { return _M_f._M_format(__t, __fc); } | |
1835 | ||
1836 | private: | |
1837 | __format::__formatter_chrono<_CharT> _M_f; | |
1838 | }; | |
1839 | ||
1840 | template<typename _CharT> | |
1841 | struct formatter<chrono::year_month_weekday, _CharT> | |
1842 | { | |
1843 | template<typename _ParseContext> | |
1844 | constexpr typename _ParseContext::iterator | |
1845 | parse(_ParseContext& __pc) | |
1846 | { return _M_f._M_parse(__pc, __format::_Date); } | |
1847 | ||
1848 | template<typename _FormatContext> | |
1849 | typename _FormatContext::iterator | |
1850 | format(const chrono::year_month_weekday& __t, | |
1851 | _FormatContext& __fc) const | |
1852 | { return _M_f._M_format(__t, __fc); } | |
1853 | ||
1854 | private: | |
1855 | __format::__formatter_chrono<_CharT> _M_f; | |
1856 | }; | |
1857 | ||
1858 | template<typename _CharT> | |
1859 | struct formatter<chrono::year_month_weekday_last, _CharT> | |
1860 | { | |
1861 | template<typename _ParseContext> | |
1862 | constexpr typename _ParseContext::iterator | |
1863 | parse(_ParseContext& __pc) | |
1864 | { return _M_f._M_parse(__pc, __format::_Date); } | |
1865 | ||
1866 | template<typename _FormatContext> | |
1867 | typename _FormatContext::iterator | |
1868 | format(const chrono::year_month_weekday_last& __t, | |
1869 | _FormatContext& __fc) const | |
1870 | { return _M_f._M_format(__t, __fc); } | |
1871 | ||
1872 | private: | |
1873 | __format::__formatter_chrono<_CharT> _M_f; | |
1874 | }; | |
1875 | ||
1876 | template<typename _Rep, typename _Period, typename _CharT> | |
1877 | struct formatter<chrono::hh_mm_ss<chrono::duration<_Rep, _Period>>, _CharT> | |
1878 | { | |
1879 | template<typename _ParseContext> | |
1880 | constexpr typename _ParseContext::iterator | |
1881 | parse(_ParseContext& __pc) | |
1882 | { return _M_f._M_parse(__pc, __format::_TimeOfDay); } | |
1883 | ||
1884 | template<typename _FormatContext> | |
1885 | typename _FormatContext::iterator | |
1886 | format(const chrono::hh_mm_ss<chrono::duration<_Rep, _Period>>& __t, | |
1887 | _FormatContext& __fc) const | |
1888 | { return _M_f._M_format(__t, __fc); } | |
1889 | ||
1890 | private: | |
1891 | __format::__formatter_chrono<_CharT> _M_f; | |
1892 | }; | |
1893 | ||
1894 | #if _GLIBCXX_USE_CXX11_ABI || ! _GLIBCXX_USE_DUAL_ABI | |
1895 | template<typename _CharT> | |
1896 | struct formatter<chrono::sys_info, _CharT> | |
1897 | { | |
1898 | template<typename _ParseContext> | |
1899 | constexpr typename _ParseContext::iterator | |
1900 | parse(_ParseContext& __pc) | |
1901 | { return _M_f._M_parse(__pc, __format::_ChronoParts{}); } | |
1902 | ||
1903 | template<typename _FormatContext> | |
1904 | typename _FormatContext::iterator | |
1905 | format(const chrono::sys_info& __i, _FormatContext& __fc) const | |
1906 | { return _M_f._M_format(__i, __fc); } | |
1907 | ||
1908 | private: | |
1909 | __format::__formatter_chrono<_CharT> _M_f; | |
1910 | }; | |
1911 | ||
1912 | template<typename _CharT> | |
1913 | struct formatter<chrono::local_info, _CharT> | |
1914 | { | |
1915 | template<typename _ParseContext> | |
1916 | constexpr typename _ParseContext::iterator | |
1917 | parse(_ParseContext& __pc) | |
1918 | { return _M_f._M_parse(__pc, __format::_ChronoParts{}); } | |
1919 | ||
1920 | template<typename _FormatContext> | |
1921 | typename _FormatContext::iterator | |
1922 | format(const chrono::local_info& __i, _FormatContext& __fc) const | |
1923 | { return _M_f._M_format(__i, __fc); } | |
1924 | ||
1925 | private: | |
1926 | __format::__formatter_chrono<_CharT> _M_f; | |
1927 | }; | |
1928 | #endif | |
1929 | ||
1930 | template<typename _Duration, typename _CharT> | |
1931 | struct formatter<chrono::sys_time<_Duration>, _CharT> | |
1932 | { | |
1933 | template<typename _ParseContext> | |
1934 | constexpr typename _ParseContext::iterator | |
1935 | parse(_ParseContext& __pc) | |
7431fcea JW |
1936 | { |
1937 | auto __next = _M_f._M_parse(__pc, __format::_ZonedDateTime); | |
1938 | if constexpr (!__stream_insertable) | |
1939 | if (_M_f._M_spec._M_chrono_specs.empty()) | |
1940 | __format::__invalid_chrono_spec(); // chrono-specs can't be empty | |
1941 | return __next; | |
1942 | } | |
f99b9486 JW |
1943 | |
1944 | template<typename _FormatContext> | |
1945 | typename _FormatContext::iterator | |
1946 | format(const chrono::sys_time<_Duration>& __t, | |
1947 | _FormatContext& __fc) const | |
1948 | { return _M_f._M_format(__t, __fc); } | |
1949 | ||
1950 | private: | |
7431fcea JW |
1951 | static constexpr bool __stream_insertable |
1952 | = requires (basic_ostream<_CharT>& __os, | |
1953 | chrono::sys_time<_Duration> __t) { __os << __t; }; | |
1954 | ||
f99b9486 JW |
1955 | __format::__formatter_chrono<_CharT> _M_f; |
1956 | }; | |
1957 | ||
1958 | template<typename _Duration, typename _CharT> | |
1959 | struct formatter<chrono::utc_time<_Duration>, _CharT> | |
1960 | : __format::__formatter_chrono<_CharT> | |
1961 | { | |
1962 | template<typename _ParseContext> | |
1963 | constexpr typename _ParseContext::iterator | |
1964 | parse(_ParseContext& __pc) | |
1965 | { return _M_f._M_parse(__pc, __format::_ZonedDateTime); } | |
1966 | ||
1967 | template<typename _FormatContext> | |
1968 | typename _FormatContext::iterator | |
1969 | format(const chrono::utc_time<_Duration>& __t, | |
1970 | _FormatContext& __fc) const | |
1971 | { | |
1972 | // Adjust by removing leap seconds to get equivalent sys_time. | |
1973 | // We can't just use clock_cast because we want to know if the time | |
1974 | // falls within a leap second insertion, and format seconds as "60". | |
1975 | using chrono::__detail::__utc_leap_second; | |
1976 | using chrono::seconds; | |
1977 | using chrono::sys_time; | |
1978 | using _CDur = common_type_t<_Duration, seconds>; | |
1979 | const auto __li = chrono::get_leap_second_info(__t); | |
1980 | sys_time<_CDur> __s{__t.time_since_epoch() - __li.elapsed}; | |
1981 | if (!__li.is_leap_second) [[likely]] | |
1982 | return _M_f._M_format(__s, __fc); | |
1983 | else | |
1984 | return _M_f._M_format(__utc_leap_second(__s), __fc); | |
1985 | } | |
1986 | ||
1987 | private: | |
1988 | friend formatter<chrono::__detail::__utc_leap_second<_Duration>, _CharT>; | |
1989 | ||
1990 | __format::__formatter_chrono<_CharT> _M_f; | |
1991 | }; | |
1992 | ||
1993 | template<typename _Duration, typename _CharT> | |
1994 | struct formatter<chrono::tai_time<_Duration>, _CharT> | |
1995 | : __format::__formatter_chrono<_CharT> | |
1996 | { | |
1997 | template<typename _ParseContext> | |
1998 | constexpr typename _ParseContext::iterator | |
1999 | parse(_ParseContext& __pc) | |
2000 | { return _M_f._M_parse(__pc, __format::_ZonedDateTime); } | |
2001 | ||
2002 | template<typename _FormatContext> | |
2003 | typename _FormatContext::iterator | |
2004 | format(const chrono::tai_time<_Duration>& __t, | |
2005 | _FormatContext& __fc) const | |
2006 | { | |
2007 | // Convert to __local_time_fmt with abbrev "TAI" and offset 0s. | |
2008 | ||
2009 | // Offset is 1970y/January/1 - 1958y/January/1 | |
2010 | constexpr chrono::days __tai_offset = chrono::days(4383); | |
2011 | using _CDur = common_type_t<_Duration, chrono::days>; | |
2012 | chrono::local_time<_CDur> __lt(__t.time_since_epoch() - __tai_offset); | |
2013 | const string __abbrev("TAI", 3); | |
2014 | const chrono::seconds __off = 0s; | |
2015 | const auto __lf = chrono::local_time_format(__lt, &__abbrev, &__off); | |
2016 | return _M_f._M_format(__lf, __fc); | |
2017 | } | |
2018 | ||
2019 | private: | |
2020 | __format::__formatter_chrono<_CharT> _M_f; | |
2021 | }; | |
2022 | ||
2023 | template<typename _Duration, typename _CharT> | |
2024 | struct formatter<chrono::gps_time<_Duration>, _CharT> | |
2025 | : __format::__formatter_chrono<_CharT> | |
2026 | { | |
2027 | template<typename _ParseContext> | |
2028 | constexpr typename _ParseContext::iterator | |
2029 | parse(_ParseContext& __pc) | |
2030 | { return _M_f._M_parse(__pc, __format::_ZonedDateTime); } | |
2031 | ||
2032 | template<typename _FormatContext> | |
2033 | typename _FormatContext::iterator | |
2034 | format(const chrono::gps_time<_Duration>& __t, | |
2035 | _FormatContext& __fc) const | |
2036 | { | |
2037 | // Convert to __local_time_fmt with abbrev "GPS" and offset 0s. | |
2038 | ||
2039 | // Offset is 1980y/January/Sunday[1] - 1970y/January/1 | |
2040 | constexpr chrono::days __gps_offset = chrono::days(3657); | |
2041 | using _CDur = common_type_t<_Duration, chrono::days>; | |
2042 | chrono::local_time<_CDur> __lt(__t.time_since_epoch() + __gps_offset); | |
2043 | const string __abbrev("GPS", 3); | |
2044 | const chrono::seconds __off = 0s; | |
2045 | const auto __lf = chrono::local_time_format(__lt, &__abbrev, &__off); | |
2046 | return _M_f._M_format(__lf, __fc); | |
2047 | } | |
2048 | ||
2049 | private: | |
2050 | __format::__formatter_chrono<_CharT> _M_f; | |
2051 | }; | |
2052 | ||
2053 | template<typename _Duration, typename _CharT> | |
2054 | struct formatter<chrono::file_time<_Duration>, _CharT> | |
2055 | { | |
2056 | template<typename _ParseContext> | |
2057 | constexpr typename _ParseContext::iterator | |
2058 | parse(_ParseContext& __pc) | |
2059 | { return _M_f._M_parse(__pc, __format::_ZonedDateTime); } | |
2060 | ||
2061 | template<typename _FormatContext> | |
2062 | typename _FormatContext::iterator | |
2063 | format(const chrono::file_time<_Duration>& __t, | |
2064 | _FormatContext& __ctx) const | |
2065 | { | |
2066 | using namespace chrono; | |
2067 | return _M_f._M_format(chrono::clock_cast<system_clock>(__t), __ctx); | |
2068 | } | |
2069 | ||
2070 | private: | |
2071 | __format::__formatter_chrono<_CharT> _M_f; | |
2072 | }; | |
2073 | ||
2074 | template<typename _Duration, typename _CharT> | |
2075 | struct formatter<chrono::local_time<_Duration>, _CharT> | |
2076 | { | |
2077 | template<typename _ParseContext> | |
2078 | constexpr typename _ParseContext::iterator | |
2079 | parse(_ParseContext& __pc) | |
2080 | { return _M_f._M_parse(__pc, __format::_DateTime); } | |
2081 | ||
2082 | template<typename _FormatContext> | |
2083 | typename _FormatContext::iterator | |
2084 | format(const chrono::local_time<_Duration>& __t, | |
2085 | _FormatContext& __ctx) const | |
2086 | { return _M_f._M_format(__t, __ctx); } | |
2087 | ||
2088 | private: | |
2089 | __format::__formatter_chrono<_CharT> _M_f; | |
2090 | }; | |
2091 | ||
2092 | template<typename _Duration, typename _CharT> | |
2093 | struct formatter<chrono::__detail::__local_time_fmt<_Duration>, _CharT> | |
2094 | { | |
2095 | template<typename _ParseContext> | |
2096 | constexpr typename _ParseContext::iterator | |
2097 | parse(_ParseContext& __pc) | |
2098 | { return _M_f._M_parse(__pc, __format::_ZonedDateTime); } | |
2099 | ||
2100 | template<typename _FormatContext> | |
2101 | typename _FormatContext::iterator | |
2102 | format(const chrono::__detail::__local_time_fmt<_Duration>& __t, | |
2103 | _FormatContext& __ctx) const | |
2104 | { return _M_f._M_format(__t, __ctx); } | |
2105 | ||
2106 | private: | |
2107 | __format::__formatter_chrono<_CharT> _M_f; | |
2108 | }; | |
2109 | ||
2110 | #if _GLIBCXX_USE_CXX11_ABI || ! _GLIBCXX_USE_DUAL_ABI | |
2111 | template<typename _Duration, typename _TimeZonePtr, typename _CharT> | |
2112 | struct formatter<chrono::zoned_time<_Duration, _TimeZonePtr>, _CharT> | |
2113 | : formatter<chrono::__detail::__local_time_fmt<_Duration>, _CharT> | |
2114 | { | |
2115 | template<typename _FormatContext> | |
2116 | typename _FormatContext::iterator | |
2117 | format(const chrono::zoned_time<_Duration, _TimeZonePtr>& __tp, | |
2118 | _FormatContext& __ctx) const | |
2119 | { | |
2120 | using chrono::__detail::__local_time_fmt; | |
2121 | using _Base = formatter<__local_time_fmt<_Duration>, _CharT>; | |
2122 | const chrono::sys_info __info = __tp.get_info(); | |
2123 | const auto __lf = chrono::local_time_format(__tp.get_local_time(), | |
2124 | &__info.abbrev, | |
2125 | &__info.offset); | |
2126 | return _Base::format(__lf, __ctx); | |
2127 | } | |
2128 | }; | |
2129 | #endif | |
2130 | ||
2131 | // Partial specialization needed for %c formatting of __utc_leap_second. | |
2132 | template<typename _Duration, typename _CharT> | |
2133 | struct formatter<chrono::__detail::__utc_leap_second<_Duration>, _CharT> | |
2134 | : formatter<chrono::utc_time<_Duration>, _CharT> | |
2135 | { | |
2136 | template<typename _FormatContext> | |
2137 | typename _FormatContext::iterator | |
2138 | format(const chrono::__detail::__utc_leap_second<_Duration>& __t, | |
2139 | _FormatContext& __fc) const | |
2140 | { return this->_M_f._M_format(__t, __fc); } | |
2141 | }; | |
2142 | ||
2143 | namespace chrono | |
2144 | { | |
2145 | /// @addtogroup chrono | |
2146 | /// @{ | |
2147 | ||
ce6c4d3b JW |
2148 | /// @cond undocumented |
2149 | namespace __detail | |
2150 | { | |
2151 | template<typename _Duration = seconds> | |
2152 | struct _Parser | |
2153 | { | |
2154 | static_assert(is_same_v<common_type_t<_Duration, seconds>, _Duration>); | |
2155 | ||
2156 | explicit | |
2157 | _Parser(__format::_ChronoParts __need) : _M_need(__need) { } | |
2158 | ||
2159 | _Parser(_Parser&&) = delete; | |
2160 | void operator=(_Parser&&) = delete; | |
2161 | ||
2162 | _Duration _M_time{}; // since midnight | |
2163 | sys_days _M_sys_days{}; | |
2164 | year_month_day _M_ymd{}; | |
2165 | weekday _M_wd{}; | |
2166 | __format::_ChronoParts _M_need; | |
f4a52c18 JW |
2167 | unsigned _M_is_leap_second : 1 {}; |
2168 | unsigned _M_reserved : 15 {}; | |
ce6c4d3b JW |
2169 | |
2170 | template<typename _CharT, typename _Traits, typename _Alloc> | |
2171 | basic_istream<_CharT, _Traits>& | |
2172 | operator()(basic_istream<_CharT, _Traits>& __is, const _CharT* __fmt, | |
2173 | basic_string<_CharT, _Traits, _Alloc>* __abbrev = nullptr, | |
2174 | minutes* __offset = nullptr); | |
2175 | ||
2176 | private: | |
2177 | // Read an unsigned integer from the stream and return it. | |
2178 | // Extract no more than __n digits. Set failbit if an integer isn't read. | |
2179 | template<typename _CharT, typename _Traits> | |
2180 | static int_least32_t | |
2181 | _S_read_unsigned(basic_istream<_CharT, _Traits>& __is, | |
2182 | ios_base::iostate& __err, int __n) | |
2183 | { | |
2184 | int_least32_t __val = _S_try_read_digit(__is, __err); | |
2185 | if (__val == -1) [[unlikely]] | |
2186 | __err |= ios_base::failbit; | |
2187 | else | |
2188 | { | |
2189 | int __n1 = (std::min)(__n, 9); | |
2190 | // Cannot overflow __val unless we read more than 9 digits | |
2191 | for (int __i = 1; __i < __n1; ++__i) | |
2192 | if (auto __dig = _S_try_read_digit(__is, __err); __dig != -1) | |
2193 | { | |
2194 | __val *= 10; | |
2195 | __val += __dig; | |
2196 | } | |
2197 | ||
2198 | while (__n1++ < __n) [[unlikely]] | |
2199 | if (auto __dig = _S_try_read_digit(__is, __err); __dig != -1) | |
2200 | { | |
2201 | if (__builtin_mul_overflow(__val, 10, &__val) | |
2202 | || __builtin_add_overflow(__val, __dig, &__val)) | |
2203 | { | |
2204 | __err |= ios_base::failbit; | |
2205 | return -1; | |
2206 | } | |
2207 | } | |
2208 | } | |
2209 | return __val; | |
2210 | } | |
2211 | ||
2212 | // Read an unsigned integer from the stream and return it. | |
2213 | // Extract no more than __n digits. Set failbit if an integer isn't read. | |
2214 | template<typename _CharT, typename _Traits> | |
2215 | static int_least32_t | |
2216 | _S_read_signed(basic_istream<_CharT, _Traits>& __is, | |
2217 | ios_base::iostate& __err, int __n) | |
2218 | { | |
2219 | auto __sign = __is.peek(); | |
2220 | if (__sign == '-' || __sign == '+') | |
2221 | (void) __is.get(); | |
2222 | int_least32_t __val = _S_read_unsigned(__is, __err, __n); | |
2223 | if (__err & ios_base::failbit) | |
2224 | { | |
2225 | if (__sign == '-') [[unlikely]] | |
2226 | __val *= -1; | |
2227 | } | |
2228 | return __val; | |
2229 | } | |
2230 | ||
2231 | // Read a digit from the stream and return it, or return -1. | |
2232 | // If no digit is read eofbit will be set (but not failbit). | |
2233 | template<typename _CharT, typename _Traits> | |
2234 | static int_least32_t | |
2235 | _S_try_read_digit(basic_istream<_CharT, _Traits>& __is, | |
2236 | ios_base::iostate& __err) | |
2237 | { | |
2238 | int_least32_t __val = -1; | |
2239 | auto __i = __is.peek(); | |
2240 | if (!_Traits::eq_int_type(__i, _Traits::eof())) [[likely]] | |
2241 | { | |
2242 | _CharT __c = _Traits::to_char_type(__i); | |
2243 | if (_CharT('0') <= __c && __c <= _CharT('9')) [[likely]] | |
2244 | { | |
2245 | (void) __is.get(); | |
2246 | __val = __c - _CharT('0'); | |
2247 | } | |
2248 | } | |
2249 | else | |
2250 | __err |= ios_base::eofbit; | |
2251 | return __val; | |
2252 | } | |
2253 | ||
2254 | // Read the specified character and return true. | |
2255 | // If the character is not found, set failbit and return false. | |
2256 | template<typename _CharT, typename _Traits> | |
2257 | static bool | |
2258 | _S_read_chr(basic_istream<_CharT, _Traits>& __is, | |
2259 | ios_base::iostate& __err, _CharT __c) | |
2260 | { | |
2261 | auto __i = __is.peek(); | |
2262 | if (_Traits::eq_int_type(__i, _Traits::eof())) | |
2263 | __err |= ios_base::eofbit; | |
2264 | else if (_Traits::to_char_type(__i) == __c) [[likely]] | |
2265 | { | |
2266 | (void) __is.get(); | |
2267 | return true; | |
2268 | } | |
2269 | __err |= ios_base::failbit; | |
2270 | return false; | |
2271 | } | |
2272 | }; | |
2273 | ||
2274 | template<typename _Duration> | |
2275 | using _Parser_t = _Parser<common_type_t<_Duration, seconds>>; | |
2276 | ||
2277 | } // namespace __detail | |
9c950c0a | 2278 | /// @endcond |
ce6c4d3b | 2279 | |
f99b9486 JW |
2280 | template<typename _CharT, typename _Traits, typename _Rep, typename _Period, |
2281 | typename _Alloc = allocator<_CharT>> | |
ce6c4d3b | 2282 | inline basic_istream<_CharT, _Traits>& |
f99b9486 JW |
2283 | from_stream(basic_istream<_CharT, _Traits>& __is, const _CharT* __fmt, |
2284 | duration<_Rep, _Period>& __d, | |
2285 | basic_string<_CharT, _Traits, _Alloc>* __abbrev = nullptr, | |
2286 | minutes* __offset = nullptr) | |
2287 | { | |
ce6c4d3b JW |
2288 | auto __need = __format::_ChronoParts::_TimeOfDay; |
2289 | __detail::_Parser_t<duration<_Rep, _Period>> __p(__need); | |
2290 | if (__p(__is, __fmt, __abbrev, __offset)) | |
2291 | __d = chrono::duration_cast<duration<_Rep, _Period>>(__p._M_time); | |
2292 | return __is; | |
f99b9486 | 2293 | } |
f99b9486 JW |
2294 | |
2295 | template<typename _CharT, typename _Traits> | |
2296 | inline basic_ostream<_CharT, _Traits>& | |
2297 | operator<<(basic_ostream<_CharT, _Traits>& __os, const day& __d) | |
2298 | { | |
7f8d730a | 2299 | using _Ctx = __format::__format_context<_CharT>; |
f99b9486 JW |
2300 | using _Str = basic_string_view<_CharT>; |
2301 | _Str __s = _GLIBCXX_WIDEN("{:02d} is not a valid day"); | |
2302 | if (__d.ok()) | |
2303 | __s = __s.substr(0, 6); | |
2a8ee259 JW |
2304 | auto __u = (unsigned)__d; |
2305 | __os << std::vformat(__s, make_format_args<_Ctx>(__u)); | |
f99b9486 JW |
2306 | return __os; |
2307 | } | |
2308 | ||
ce6c4d3b JW |
2309 | template<typename _CharT, typename _Traits, |
2310 | typename _Alloc = allocator<_CharT>> | |
2311 | inline basic_istream<_CharT, _Traits>& | |
2312 | from_stream(basic_istream<_CharT, _Traits>& __is, const _CharT* __fmt, | |
2313 | day& __d, | |
2314 | basic_string<_CharT, _Traits, _Alloc>* __abbrev = nullptr, | |
2315 | minutes* __offset = nullptr) | |
2316 | { | |
2317 | __detail::_Parser<> __p(__format::_ChronoParts::_Day); | |
2318 | if (__p(__is, __fmt, __abbrev, __offset)) | |
2319 | __d = __p._M_ymd.day(); | |
2320 | return __is; | |
2321 | } | |
f99b9486 JW |
2322 | |
2323 | template<typename _CharT, typename _Traits> | |
2324 | inline basic_ostream<_CharT, _Traits>& | |
2325 | operator<<(basic_ostream<_CharT, _Traits>& __os, const month& __m) | |
2326 | { | |
7f8d730a | 2327 | using _Ctx = __format::__format_context<_CharT>; |
f99b9486 JW |
2328 | using _Str = basic_string_view<_CharT>; |
2329 | _Str __s = _GLIBCXX_WIDEN("{:L%b}{} is not a valid month"); | |
2330 | if (__m.ok()) | |
2331 | __os << std::vformat(__os.getloc(), __s.substr(0, 6), | |
2332 | make_format_args<_Ctx>(__m)); | |
2333 | else | |
2a8ee259 JW |
2334 | { |
2335 | auto __u = (unsigned)__m; | |
2336 | __os << std::vformat(__s.substr(6), make_format_args<_Ctx>(__u)); | |
2337 | } | |
f99b9486 JW |
2338 | return __os; |
2339 | } | |
2340 | ||
ce6c4d3b JW |
2341 | template<typename _CharT, typename _Traits, |
2342 | typename _Alloc = allocator<_CharT>> | |
2343 | inline basic_istream<_CharT, _Traits>& | |
2344 | from_stream(basic_istream<_CharT, _Traits>& __is, const _CharT* __fmt, | |
2345 | month& __m, | |
2346 | basic_string<_CharT, _Traits, _Alloc>* __abbrev = nullptr, | |
2347 | minutes* __offset = nullptr) | |
2348 | { | |
2349 | __detail::_Parser<> __p(__format::_ChronoParts::_Month); | |
2350 | if (__p(__is, __fmt, __abbrev, __offset)) | |
2351 | __m = __p._M_ymd.month(); | |
2352 | return __is; | |
2353 | } | |
f99b9486 JW |
2354 | |
2355 | template<typename _CharT, typename _Traits> | |
2356 | inline basic_ostream<_CharT, _Traits>& | |
2357 | operator<<(basic_ostream<_CharT, _Traits>& __os, const year& __y) | |
2358 | { | |
7f8d730a | 2359 | using _Ctx = __format::__format_context<_CharT>; |
f99b9486 JW |
2360 | using _Str = basic_string_view<_CharT>; |
2361 | _Str __s = _GLIBCXX_WIDEN("-{:04d} is not a valid year"); | |
2362 | if (__y.ok()) | |
2363 | __s = __s.substr(0, 7); | |
2364 | int __i = (int)__y; | |
2365 | if (__i >= 0) [[likely]] | |
2366 | __s.remove_prefix(1); | |
2367 | else | |
2368 | __i = -__i; | |
2369 | __os << std::vformat(__s, make_format_args<_Ctx>(__i)); | |
2370 | return __os; | |
2371 | } | |
2372 | ||
ce6c4d3b JW |
2373 | template<typename _CharT, typename _Traits, |
2374 | typename _Alloc = allocator<_CharT>> | |
2375 | inline basic_istream<_CharT, _Traits>& | |
2376 | from_stream(basic_istream<_CharT, _Traits>& __is, const _CharT* __fmt, | |
2377 | year& __y, | |
2378 | basic_string<_CharT, _Traits, _Alloc>* __abbrev = nullptr, | |
2379 | minutes* __offset = nullptr) | |
2380 | { | |
2381 | __detail::_Parser<> __p(__format::_ChronoParts::_Year); | |
2382 | if (__p(__is, __fmt, __abbrev, __offset)) | |
2383 | __y = __p._M_ymd.year(); | |
2384 | return __is; | |
2385 | } | |
f99b9486 JW |
2386 | |
2387 | template<typename _CharT, typename _Traits> | |
2388 | inline basic_ostream<_CharT, _Traits>& | |
2389 | operator<<(basic_ostream<_CharT, _Traits>& __os, const weekday& __wd) | |
2390 | { | |
7f8d730a | 2391 | using _Ctx = __format::__format_context<_CharT>; |
f99b9486 JW |
2392 | using _Str = basic_string_view<_CharT>; |
2393 | _Str __s = _GLIBCXX_WIDEN("{:L%a}{} is not a valid weekday"); | |
2394 | if (__wd.ok()) | |
2395 | __os << std::vformat(__os.getloc(), __s.substr(0, 6), | |
2396 | make_format_args<_Ctx>(__wd)); | |
2397 | else | |
2a8ee259 JW |
2398 | { |
2399 | auto __c = __wd.c_encoding(); | |
2400 | __os << std::vformat(__s.substr(6), make_format_args<_Ctx>(__c)); | |
2401 | } | |
f99b9486 JW |
2402 | return __os; |
2403 | } | |
2404 | ||
ce6c4d3b JW |
2405 | template<typename _CharT, typename _Traits, |
2406 | typename _Alloc = allocator<_CharT>> | |
2407 | inline basic_istream<_CharT, _Traits>& | |
2408 | from_stream(basic_istream<_CharT, _Traits>& __is, const _CharT* __fmt, | |
2409 | weekday& __wd, | |
2410 | basic_string<_CharT, _Traits, _Alloc>* __abbrev = nullptr, | |
2411 | minutes* __offset = nullptr) | |
2412 | { | |
2413 | __detail::_Parser<> __p(__format::_ChronoParts::_Weekday); | |
2414 | if (__p(__is, __fmt, __abbrev, __offset)) | |
2415 | __wd = __p._M_wd; | |
2416 | return __is; | |
2417 | } | |
f99b9486 JW |
2418 | |
2419 | template<typename _CharT, typename _Traits> | |
2420 | inline basic_ostream<_CharT, _Traits>& | |
2421 | operator<<(basic_ostream<_CharT, _Traits>& __os, | |
2422 | const weekday_indexed& __wdi) | |
2423 | { | |
2424 | // The standard says to format wdi.weekday() and wdi.index() using | |
2425 | // either "{:L}[{}]" or "{:L}[{} is not a valid index]". The {:L} spec | |
2426 | // means to format the weekday using ostringstream, so just do that. | |
2427 | basic_stringstream<_CharT> __os2; | |
9afc9148 | 2428 | __os2.imbue(__os.getloc()); |
f99b9486 JW |
2429 | __os2 << __wdi.weekday(); |
2430 | const auto __i = __wdi.index(); | |
6fabf8f2 JW |
2431 | basic_string_view<_CharT> __s |
2432 | = _GLIBCXX_WIDEN("[ is not a valid index]"); | |
2433 | __os2 << __s[0]; | |
2434 | __os2 << std::format(_GLIBCXX_WIDEN("{}"), __i); | |
f99b9486 JW |
2435 | if (__i >= 1 && __i <= 5) |
2436 | __os2 << __s.back(); | |
2437 | else | |
6fabf8f2 | 2438 | __os2 << __s.substr(1); |
f99b9486 JW |
2439 | __os << __os2.view(); |
2440 | return __os; | |
2441 | } | |
2442 | ||
2443 | template<typename _CharT, typename _Traits> | |
2444 | inline basic_ostream<_CharT, _Traits>& | |
2445 | operator<<(basic_ostream<_CharT, _Traits>& __os, | |
2446 | const weekday_last& __wdl) | |
2447 | { | |
2448 | // As above, just write straight to a stringstream, as if by "{:L}[last]" | |
2449 | basic_stringstream<_CharT> __os2; | |
9afc9148 | 2450 | __os2.imbue(__os.getloc()); |
f99b9486 JW |
2451 | __os2 << __wdl.weekday() << _GLIBCXX_WIDEN("[last]"); |
2452 | __os << __os2.view(); | |
2453 | return __os; | |
2454 | } | |
2455 | ||
2456 | template<typename _CharT, typename _Traits> | |
2457 | inline basic_ostream<_CharT, _Traits>& | |
2458 | operator<<(basic_ostream<_CharT, _Traits>& __os, const month_day& __md) | |
2459 | { | |
2460 | // As above, just write straight to a stringstream, as if by "{:L}/{}" | |
2461 | basic_stringstream<_CharT> __os2; | |
9afc9148 | 2462 | __os2.imbue(__os.getloc()); |
f99b9486 JW |
2463 | __os2 << __md.month(); |
2464 | if constexpr (is_same_v<_CharT, char>) | |
2465 | __os2 << '/'; | |
2466 | else | |
2467 | __os2 << L'/'; | |
2468 | __os2 << __md.day(); | |
2469 | __os << __os2.view(); | |
2470 | return __os; | |
2471 | } | |
2472 | ||
ce6c4d3b JW |
2473 | template<typename _CharT, typename _Traits, |
2474 | typename _Alloc = allocator<_CharT>> | |
2475 | inline basic_istream<_CharT, _Traits>& | |
2476 | from_stream(basic_istream<_CharT, _Traits>& __is, const _CharT* __fmt, | |
2477 | month_day& __md, | |
2478 | basic_string<_CharT, _Traits, _Alloc>* __abbrev = nullptr, | |
2479 | minutes* __offset = nullptr) | |
2480 | { | |
2481 | using __format::_ChronoParts; | |
2482 | auto __need = _ChronoParts::_Month | _ChronoParts::_Day; | |
2483 | __detail::_Parser<> __p(__need); | |
2484 | if (__p(__is, __fmt, __abbrev, __offset)) | |
2485 | __md = month_day(__p._M_ymd.month(), __p._M_ymd.day()); | |
2486 | return __is; | |
2487 | } | |
f99b9486 JW |
2488 | |
2489 | template<typename _CharT, typename _Traits> | |
2490 | inline basic_ostream<_CharT, _Traits>& | |
2491 | operator<<(basic_ostream<_CharT, _Traits>& __os, | |
2492 | const month_day_last& __mdl) | |
2493 | { | |
2494 | // As above, just write straight to a stringstream, as if by "{:L}/last" | |
2495 | basic_stringstream<_CharT> __os2; | |
9afc9148 | 2496 | __os2.imbue(__os.getloc()); |
6fabf8f2 | 2497 | __os2 << __mdl.month() << _GLIBCXX_WIDEN("/last"); |
f99b9486 JW |
2498 | __os << __os2.view(); |
2499 | return __os; | |
2500 | } | |
2501 | ||
2502 | template<typename _CharT, typename _Traits> | |
2503 | inline basic_ostream<_CharT, _Traits>& | |
2504 | operator<<(basic_ostream<_CharT, _Traits>& __os, | |
2505 | const month_weekday& __mwd) | |
2506 | { | |
2507 | // As above, just write straight to a stringstream, as if by "{:L}/{:L}" | |
2508 | basic_stringstream<_CharT> __os2; | |
9afc9148 | 2509 | __os2.imbue(__os.getloc()); |
f99b9486 JW |
2510 | __os2 << __mwd.month(); |
2511 | if constexpr (is_same_v<_CharT, char>) | |
2512 | __os2 << '/'; | |
2513 | else | |
2514 | __os2 << L'/'; | |
2515 | __os2 << __mwd.weekday_indexed(); | |
2516 | __os << __os2.view(); | |
2517 | return __os; | |
2518 | } | |
2519 | ||
2520 | template<typename _CharT, typename _Traits> | |
2521 | inline basic_ostream<_CharT, _Traits>& | |
2522 | operator<<(basic_ostream<_CharT, _Traits>& __os, | |
2523 | const month_weekday_last& __mwdl) | |
2524 | { | |
2525 | // As above, just write straight to a stringstream, as if by "{:L}/{:L}" | |
2526 | basic_stringstream<_CharT> __os2; | |
9afc9148 | 2527 | __os2.imbue(__os.getloc()); |
f99b9486 JW |
2528 | __os2 << __mwdl.month(); |
2529 | if constexpr (is_same_v<_CharT, char>) | |
2530 | __os2 << '/'; | |
2531 | else | |
2532 | __os2 << L'/'; | |
2533 | __os2 << __mwdl.weekday_last(); | |
2534 | __os << __os2.view(); | |
2535 | return __os; | |
2536 | } | |
2537 | ||
2538 | template<typename _CharT, typename _Traits> | |
2539 | inline basic_ostream<_CharT, _Traits>& | |
2540 | operator<<(basic_ostream<_CharT, _Traits>& __os, const year_month& __ym) | |
2541 | { | |
2542 | // As above, just write straight to a stringstream, as if by "{}/{:L}" | |
2543 | basic_stringstream<_CharT> __os2; | |
9afc9148 | 2544 | __os2.imbue(__os.getloc()); |
f99b9486 JW |
2545 | __os2 << __ym.year(); |
2546 | if constexpr (is_same_v<_CharT, char>) | |
2547 | __os2 << '/'; | |
2548 | else | |
2549 | __os2 << L'/'; | |
2550 | __os2 << __ym.month(); | |
2551 | __os << __os2.view(); | |
2552 | return __os; | |
2553 | } | |
2554 | ||
ce6c4d3b JW |
2555 | template<typename _CharT, typename _Traits, |
2556 | typename _Alloc = allocator<_CharT>> | |
2557 | inline basic_istream<_CharT, _Traits>& | |
2558 | from_stream(basic_istream<_CharT, _Traits>& __is, const _CharT* __fmt, | |
2559 | year_month& __ym, | |
2560 | basic_string<_CharT, _Traits, _Alloc>* __abbrev = nullptr, | |
2561 | minutes* __offset = nullptr) | |
2562 | { | |
2563 | using __format::_ChronoParts; | |
2564 | auto __need = _ChronoParts::_Year | _ChronoParts::_Month; | |
2565 | __detail::_Parser<> __p(__need); | |
2566 | if (__p(__is, __fmt, __abbrev, __offset)) | |
2567 | __ym = year_month(__p._M_ymd.year(), __p._M_ymd.month()); | |
2568 | return __is; | |
2569 | } | |
f99b9486 JW |
2570 | |
2571 | template<typename _CharT, typename _Traits> | |
2572 | inline basic_ostream<_CharT, _Traits>& | |
2573 | operator<<(basic_ostream<_CharT, _Traits>& __os, | |
2574 | const year_month_day& __ymd) | |
2575 | { | |
7f8d730a | 2576 | using _Ctx = __format::__format_context<_CharT>; |
f99b9486 JW |
2577 | using _Str = basic_string_view<_CharT>; |
2578 | _Str __s = _GLIBCXX_WIDEN("{:%F} is not a valid date"); | |
2579 | __os << std::vformat(__ymd.ok() ? __s.substr(0, 5) : __s, | |
2580 | make_format_args<_Ctx>(__ymd)); | |
2581 | return __os; | |
2582 | } | |
2583 | ||
ce6c4d3b JW |
2584 | template<typename _CharT, typename _Traits, |
2585 | typename _Alloc = allocator<_CharT>> | |
2586 | inline basic_istream<_CharT, _Traits>& | |
2587 | from_stream(basic_istream<_CharT, _Traits>& __is, const _CharT* __fmt, | |
2588 | year_month_day& __ymd, | |
2589 | basic_string<_CharT, _Traits, _Alloc>* __abbrev = nullptr, | |
2590 | minutes* __offset = nullptr) | |
2591 | { | |
2592 | using __format::_ChronoParts; | |
2593 | auto __need = _ChronoParts::_Year | _ChronoParts::_Month | |
2594 | | _ChronoParts::_Day; | |
2595 | __detail::_Parser<> __p(__need); | |
2596 | if (__p(__is, __fmt, __abbrev, __offset)) | |
2597 | __ymd = __p._M_ymd; | |
2598 | return __is; | |
2599 | } | |
f99b9486 JW |
2600 | |
2601 | template<typename _CharT, typename _Traits> | |
2602 | inline basic_ostream<_CharT, _Traits>& | |
2603 | operator<<(basic_ostream<_CharT, _Traits>& __os, | |
2604 | const year_month_day_last& __ymdl) | |
2605 | { | |
2606 | // As above, just write straight to a stringstream, as if by "{}/{:L}" | |
2607 | basic_stringstream<_CharT> __os2; | |
9afc9148 | 2608 | __os2.imbue(__os.getloc()); |
f99b9486 JW |
2609 | __os2 << __ymdl.year(); |
2610 | if constexpr (is_same_v<_CharT, char>) | |
2611 | __os2 << '/'; | |
2612 | else | |
2613 | __os2 << L'/'; | |
2614 | __os2 << __ymdl.month_day_last(); | |
2615 | __os << __os2.view(); | |
2616 | return __os; | |
2617 | } | |
2618 | ||
2619 | template<typename _CharT, typename _Traits> | |
2620 | inline basic_ostream<_CharT, _Traits>& | |
2621 | operator<<(basic_ostream<_CharT, _Traits>& __os, | |
2622 | const year_month_weekday& __ymwd) | |
2623 | { | |
2624 | // As above, just write straight to a stringstream, as if by | |
2625 | // "{}/{:L}/{:L}" | |
2626 | basic_stringstream<_CharT> __os2; | |
9afc9148 | 2627 | __os2.imbue(__os.getloc()); |
f99b9486 JW |
2628 | _CharT __slash; |
2629 | if constexpr (is_same_v<_CharT, char>) | |
2630 | __slash = '/'; | |
2631 | else | |
2632 | __slash = L'/'; | |
2633 | __os2 << __ymwd.year() << __slash << __ymwd.month() << __slash | |
2634 | << __ymwd.weekday_indexed(); | |
2635 | __os << __os2.view(); | |
2636 | return __os; | |
2637 | } | |
2638 | ||
2639 | template<typename _CharT, typename _Traits> | |
2640 | inline basic_ostream<_CharT, _Traits>& | |
2641 | operator<<(basic_ostream<_CharT, _Traits>& __os, | |
2642 | const year_month_weekday_last& __ymwdl) | |
2643 | { | |
2644 | // As above, just write straight to a stringstream, as if by | |
2645 | // "{}/{:L}/{:L}" | |
2646 | basic_stringstream<_CharT> __os2; | |
9afc9148 | 2647 | __os2.imbue(__os.getloc()); |
f99b9486 JW |
2648 | _CharT __slash; |
2649 | if constexpr (is_same_v<_CharT, char>) | |
2650 | __slash = '/'; | |
2651 | else | |
2652 | __slash = L'/'; | |
2653 | __os2 << __ymwdl.year() << __slash << __ymwdl.month() << __slash | |
2654 | << __ymwdl.weekday_last(); | |
2655 | __os << __os2.view(); | |
2656 | return __os; | |
2657 | } | |
2658 | ||
2659 | template<typename _CharT, typename _Traits, typename _Duration> | |
2660 | inline basic_ostream<_CharT, _Traits>& | |
2661 | operator<<(basic_ostream<_CharT, _Traits>& __os, | |
2662 | const hh_mm_ss<_Duration>& __hms) | |
2663 | { | |
2664 | return __os << format(__os.getloc(), _GLIBCXX_WIDEN("{:L%T}"), __hms); | |
2665 | } | |
2666 | ||
2667 | #if _GLIBCXX_USE_CXX11_ABI || ! _GLIBCXX_USE_DUAL_ABI | |
2668 | /// Writes a sys_info object to an ostream in an unspecified format. | |
2669 | template<typename _CharT, typename _Traits> | |
2670 | basic_ostream<_CharT, _Traits>& | |
2671 | operator<<(basic_ostream<_CharT, _Traits>& __os, const sys_info& __i) | |
2672 | { | |
2673 | __os << '[' << __i.begin << ',' << __i.end | |
2674 | << ',' << hh_mm_ss(__i.offset) << ',' << __i.save | |
2675 | << ',' << __i.abbrev << ']'; | |
2676 | return __os; | |
2677 | } | |
2678 | ||
2679 | /// Writes a local_info object to an ostream in an unspecified format. | |
2680 | template<typename _CharT, typename _Traits> | |
2681 | basic_ostream<_CharT, _Traits>& | |
2682 | operator<<(basic_ostream<_CharT, _Traits>& __os, const local_info& __li) | |
2683 | { | |
2684 | __os << '['; | |
2685 | if (__li.result == local_info::unique) | |
2686 | __os << __li.first; | |
2687 | else | |
2688 | { | |
2689 | if (__li.result == local_info::nonexistent) | |
2690 | __os << "nonexistent"; | |
2691 | else | |
2692 | __os << "ambiguous"; | |
2693 | __os << " local time between " << __li.first; | |
2694 | __os << " and " << __li.second; | |
2695 | } | |
2696 | __os << ']'; | |
2697 | return __os; | |
2698 | } | |
2699 | ||
2700 | template<typename _CharT, typename _Traits, typename _Duration, | |
2701 | typename _TimeZonePtr> | |
2702 | inline basic_ostream<_CharT, _Traits>& | |
2703 | operator<<(basic_ostream<_CharT, _Traits>& __os, | |
2704 | const zoned_time<_Duration, _TimeZonePtr>& __t) | |
2705 | { | |
2706 | __os << format(__os.getloc(), _GLIBCXX_WIDEN("{:L%F %T %Z}"), __t); | |
2707 | return __os; | |
2708 | } | |
2709 | #endif | |
2710 | ||
2711 | template<typename _CharT, typename _Traits, typename _Duration> | |
2712 | requires (!treat_as_floating_point_v<typename _Duration::rep>) | |
2713 | && ratio_less_v<typename _Duration::period, days::period> | |
2714 | inline basic_ostream<_CharT, _Traits>& | |
2715 | operator<<(basic_ostream<_CharT, _Traits>& __os, | |
2716 | const sys_time<_Duration>& __tp) | |
2717 | { | |
2718 | __os << std::format(__os.getloc(), _GLIBCXX_WIDEN("{:L%F %T}"), __tp); | |
2719 | return __os; | |
2720 | } | |
2721 | ||
2722 | template<typename _CharT, typename _Traits> | |
2723 | inline basic_ostream<_CharT, _Traits>& | |
2724 | operator<<(basic_ostream<_CharT, _Traits>& __os, const sys_days& __dp) | |
2725 | { | |
2726 | __os << year_month_day{__dp}; | |
2727 | return __os; | |
2728 | } | |
2729 | ||
ce6c4d3b JW |
2730 | template<typename _CharT, typename _Traits, typename _Duration, |
2731 | typename _Alloc = allocator<_CharT>> | |
2732 | basic_istream<_CharT, _Traits>& | |
2733 | from_stream(basic_istream<_CharT, _Traits>& __is, const _CharT* __fmt, | |
2734 | sys_time<_Duration>& __tp, | |
2735 | basic_string<_CharT, _Traits, _Alloc>* __abbrev = nullptr, | |
2736 | minutes* __offset = nullptr) | |
2737 | { | |
2738 | minutes __off{}; | |
2739 | if (!__offset) | |
2740 | __offset = &__off; | |
2741 | using __format::_ChronoParts; | |
2742 | auto __need = _ChronoParts::_Year | _ChronoParts::_Month | |
2743 | | _ChronoParts::_Day | _ChronoParts::_TimeOfDay; | |
2744 | __detail::_Parser_t<_Duration> __p(__need); | |
2745 | if (__p(__is, __fmt, __abbrev, __offset)) | |
2746 | { | |
f4a52c18 JW |
2747 | if (__p._M_is_leap_second) |
2748 | __is.setstate(ios_base::failbit); | |
2749 | else | |
2750 | { | |
2751 | auto __st = __p._M_sys_days + __p._M_time - *__offset; | |
2752 | __tp = chrono::time_point_cast<_Duration>(__st); | |
2753 | } | |
ce6c4d3b JW |
2754 | } |
2755 | return __is; | |
2756 | } | |
f99b9486 JW |
2757 | |
2758 | template<typename _CharT, typename _Traits, typename _Duration> | |
2759 | inline basic_ostream<_CharT, _Traits>& | |
2760 | operator<<(basic_ostream<_CharT, _Traits>& __os, | |
2761 | const utc_time<_Duration>& __t) | |
2762 | { | |
2763 | __os << std::format(__os.getloc(), _GLIBCXX_WIDEN("{:L%F %T}"), __t); | |
2764 | return __os; | |
2765 | } | |
2766 | ||
ce6c4d3b JW |
2767 | template<typename _CharT, typename _Traits, typename _Duration, |
2768 | typename _Alloc = allocator<_CharT>> | |
2769 | inline basic_istream<_CharT, _Traits>& | |
2770 | from_stream(basic_istream<_CharT, _Traits>& __is, const _CharT* __fmt, | |
2771 | utc_time<_Duration>& __tp, | |
2772 | basic_string<_CharT, _Traits, _Alloc>* __abbrev = nullptr, | |
2773 | minutes* __offset = nullptr) | |
2774 | { | |
f4a52c18 JW |
2775 | minutes __off{}; |
2776 | if (!__offset) | |
2777 | __offset = &__off; | |
2778 | using __format::_ChronoParts; | |
2779 | auto __need = _ChronoParts::_Year | _ChronoParts::_Month | |
2780 | | _ChronoParts::_Day | _ChronoParts::_TimeOfDay; | |
2781 | __detail::_Parser_t<_Duration> __p(__need); | |
2782 | if (__p(__is, __fmt, __abbrev, __offset)) | |
2783 | { | |
2784 | // Converting to utc_time before adding _M_time is necessary for | |
2785 | // "23:59:60" to correctly produce a time within a leap second. | |
2786 | auto __ut = utc_clock::from_sys(__p._M_sys_days) + __p._M_time | |
2787 | - *__offset; | |
2788 | __tp = chrono::time_point_cast<_Duration>(__ut); | |
2789 | } | |
ce6c4d3b JW |
2790 | return __is; |
2791 | } | |
f99b9486 JW |
2792 | |
2793 | template<typename _CharT, typename _Traits, typename _Duration> | |
2794 | inline basic_ostream<_CharT, _Traits>& | |
2795 | operator<<(basic_ostream<_CharT, _Traits>& __os, | |
2796 | const tai_time<_Duration>& __t) | |
2797 | { | |
2798 | __os << std::format(__os.getloc(), _GLIBCXX_WIDEN("{:L%F %T}"), __t); | |
2799 | return __os; | |
2800 | } | |
2801 | ||
ce6c4d3b JW |
2802 | template<typename _CharT, typename _Traits, typename _Duration, |
2803 | typename _Alloc = allocator<_CharT>> | |
2804 | inline basic_istream<_CharT, _Traits>& | |
2805 | from_stream(basic_istream<_CharT, _Traits>& __is, const _CharT* __fmt, | |
2806 | tai_time<_Duration>& __tp, | |
2807 | basic_string<_CharT, _Traits, _Alloc>* __abbrev = nullptr, | |
2808 | minutes* __offset = nullptr) | |
2809 | { | |
f4a52c18 JW |
2810 | minutes __off{}; |
2811 | if (!__offset) | |
2812 | __offset = &__off; | |
2813 | using __format::_ChronoParts; | |
2814 | auto __need = _ChronoParts::_Year | _ChronoParts::_Month | |
2815 | | _ChronoParts::_Day | _ChronoParts::_TimeOfDay; | |
2816 | __detail::_Parser_t<_Duration> __p(__need); | |
2817 | if (__p(__is, __fmt, __abbrev, __offset)) | |
2818 | { | |
2819 | if (__p._M_is_leap_second) | |
2820 | __is.setstate(ios_base::failbit); | |
2821 | else | |
2822 | { | |
2823 | auto __st = __p._M_sys_days + __p._M_time - *__offset; | |
2824 | auto __tt = tai_clock::from_utc(utc_clock::from_sys(__st)); | |
2825 | __tp = chrono::time_point_cast<_Duration>(__tt); | |
2826 | } | |
2827 | } | |
ce6c4d3b JW |
2828 | return __is; |
2829 | } | |
f99b9486 JW |
2830 | |
2831 | template<typename _CharT, typename _Traits, typename _Duration> | |
2832 | inline basic_ostream<_CharT, _Traits>& | |
2833 | operator<<(basic_ostream<_CharT, _Traits>& __os, | |
2834 | const gps_time<_Duration>& __t) | |
2835 | { | |
2836 | __os << std::format(__os.getloc(), _GLIBCXX_WIDEN("{:L%F %T}"), __t); | |
2837 | return __os; | |
2838 | } | |
2839 | ||
ce6c4d3b JW |
2840 | template<typename _CharT, typename _Traits, typename _Duration, |
2841 | typename _Alloc = allocator<_CharT>> | |
2842 | inline basic_istream<_CharT, _Traits>& | |
2843 | from_stream(basic_istream<_CharT, _Traits>& __is, const _CharT* __fmt, | |
2844 | gps_time<_Duration>& __tp, | |
2845 | basic_string<_CharT, _Traits, _Alloc>* __abbrev = nullptr, | |
2846 | minutes* __offset = nullptr) | |
2847 | { | |
f4a52c18 JW |
2848 | minutes __off{}; |
2849 | if (!__offset) | |
2850 | __offset = &__off; | |
2851 | using __format::_ChronoParts; | |
2852 | auto __need = _ChronoParts::_Year | _ChronoParts::_Month | |
2853 | | _ChronoParts::_Day | _ChronoParts::_TimeOfDay; | |
2854 | __detail::_Parser_t<_Duration> __p(__need); | |
2855 | if (__p(__is, __fmt, __abbrev, __offset)) | |
2856 | { | |
2857 | if (__p._M_is_leap_second) | |
2858 | __is.setstate(ios_base::failbit); | |
2859 | else | |
2860 | { | |
2861 | auto __st = __p._M_sys_days + __p._M_time - *__offset; | |
2862 | auto __tt = gps_clock::from_utc(utc_clock::from_sys(__st)); | |
2863 | __tp = chrono::time_point_cast<_Duration>(__tt); | |
2864 | } | |
2865 | } | |
ce6c4d3b JW |
2866 | return __is; |
2867 | } | |
f99b9486 JW |
2868 | |
2869 | template<typename _CharT, typename _Traits, typename _Duration> | |
2870 | inline basic_ostream<_CharT, _Traits>& | |
2871 | operator<<(basic_ostream<_CharT, _Traits>& __os, | |
2872 | const file_time<_Duration>& __t) | |
2873 | { | |
2874 | __os << std::format(__os.getloc(), _GLIBCXX_WIDEN("{:L%F %T}"), __t); | |
2875 | return __os; | |
2876 | } | |
2877 | ||
ce6c4d3b JW |
2878 | template<typename _CharT, typename _Traits, typename _Duration, |
2879 | typename _Alloc = allocator<_CharT>> | |
2880 | inline basic_istream<_CharT, _Traits>& | |
2881 | from_stream(basic_istream<_CharT, _Traits>& __is, const _CharT* __fmt, | |
2882 | file_time<_Duration>& __tp, | |
2883 | basic_string<_CharT, _Traits, _Alloc>* __abbrev = nullptr, | |
2884 | minutes* __offset = nullptr) | |
2885 | { | |
2886 | sys_time<_Duration> __st; | |
2887 | if (chrono::from_stream(__is, __fmt, __st, __abbrev, __offset)) | |
f4a52c18 | 2888 | __tp = chrono::time_point_cast<_Duration>(file_clock::from_sys(__st)); |
ce6c4d3b JW |
2889 | return __is; |
2890 | } | |
f99b9486 JW |
2891 | |
2892 | template<typename _CharT, typename _Traits, typename _Duration> | |
2893 | inline basic_ostream<_CharT, _Traits>& | |
2894 | operator<<(basic_ostream<_CharT, _Traits>& __os, | |
2895 | const local_time<_Duration>& __lt) | |
2896 | { | |
2897 | __os << sys_time<_Duration>{__lt.time_since_epoch()}; | |
2898 | return __os; | |
2899 | } | |
2900 | ||
ce6c4d3b JW |
2901 | template<typename _CharT, typename _Traits, typename _Duration, |
2902 | typename _Alloc = allocator<_CharT>> | |
2903 | basic_istream<_CharT, _Traits>& | |
2904 | from_stream(basic_istream<_CharT, _Traits>& __is, const _CharT* __fmt, | |
2905 | local_time<_Duration>& __tp, | |
2906 | basic_string<_CharT, _Traits, _Alloc>* __abbrev = nullptr, | |
2907 | minutes* __offset = nullptr) | |
2908 | { | |
2909 | using __format::_ChronoParts; | |
2910 | auto __need = _ChronoParts::_Year | _ChronoParts::_Month | |
2911 | | _ChronoParts::_Day | _ChronoParts::_TimeOfDay; | |
2912 | __detail::_Parser_t<_Duration> __p(__need); | |
2913 | if (__p(__is, __fmt, __abbrev, __offset)) | |
2914 | { | |
2915 | days __d = __p._M_sys_days.time_since_epoch(); | |
2916 | auto __t = local_days(__d) + __p._M_time; // ignore offset | |
2917 | __tp = chrono::time_point_cast<_Duration>(__t); | |
2918 | } | |
2919 | return __is; | |
2920 | } | |
2921 | ||
2922 | // [time.parse] parsing | |
2923 | ||
2924 | namespace __detail | |
2925 | { | |
2926 | template<typename _Parsable, typename _CharT, | |
2927 | typename _Traits = std::char_traits<_CharT>, | |
2928 | typename... _OptArgs> | |
2929 | concept __parsable = requires (basic_istream<_CharT, _Traits>& __is, | |
2930 | const _CharT* __fmt, _Parsable& __tp, | |
2931 | _OptArgs*... __args) | |
2932 | { from_stream(__is, __fmt, __tp, __args...); }; | |
2933 | ||
2934 | template<typename _Parsable, typename _CharT, | |
2935 | typename _Traits = char_traits<_CharT>, | |
2936 | typename _Alloc = allocator<_CharT>> | |
2937 | struct _Parse | |
2938 | { | |
2939 | private: | |
2940 | using __string_type = basic_string<_CharT, _Traits, _Alloc>; | |
2941 | ||
2942 | public: | |
2943 | _Parse(const _CharT* __fmt, _Parsable& __tp, | |
2944 | basic_string<_CharT, _Traits, _Alloc>* __abbrev = nullptr, | |
2945 | minutes* __offset = nullptr) | |
2946 | : _M_fmt(__fmt), _M_tp(std::__addressof(__tp)), | |
2947 | _M_abbrev(__abbrev), _M_offset(__offset) | |
2948 | { } | |
2949 | ||
2950 | _Parse(_Parse&&) = delete; | |
2951 | _Parse& operator=(_Parse&&) = delete; | |
2952 | ||
2953 | private: | |
2954 | using __stream_type = basic_istream<_CharT, _Traits>; | |
2955 | ||
2956 | const _CharT* const _M_fmt; | |
2957 | _Parsable* const _M_tp; | |
2958 | __string_type* const _M_abbrev; | |
2959 | minutes* const _M_offset; | |
2960 | ||
2961 | friend __stream_type& | |
2962 | operator>>(__stream_type& __is, _Parse&& __p) | |
2963 | { | |
2964 | if (__p._M_offset) | |
2965 | from_stream(__is, __p._M_fmt, *__p._M_tp, __p._M_abbrev, | |
2966 | __p._M_offset); | |
2967 | else if (__p._M_abbrev) | |
2968 | from_stream(__is, __p._M_fmt, *__p._M_tp, __p._M_abbrev); | |
2969 | else | |
2970 | from_stream(__is, __p._M_fmt, *__p._M_tp); | |
2971 | return __is; | |
2972 | } | |
2973 | ||
2974 | friend void operator>>(__stream_type&, _Parse&) = delete; | |
2975 | friend void operator>>(__stream_type&, const _Parse&) = delete; | |
2976 | }; | |
2977 | } // namespace __detail | |
2978 | ||
2979 | template<typename _CharT, __detail::__parsable<_CharT> _Parsable> | |
2980 | [[nodiscard, __gnu__::__access__(__read_only__, 1)]] | |
2981 | inline auto | |
2982 | parse(const _CharT* __fmt, _Parsable& __tp) | |
2983 | { return __detail::_Parse<_Parsable, _CharT>(__fmt, __tp); } | |
2984 | ||
2985 | template<typename _CharT, typename _Traits, typename _Alloc, | |
2986 | __detail::__parsable<_CharT, _Traits> _Parsable> | |
2987 | [[nodiscard]] | |
2988 | inline auto | |
2989 | parse(const basic_string<_CharT, _Traits, _Alloc>& __fmt, _Parsable& __tp) | |
2990 | { | |
2991 | return __detail::_Parse<_Parsable, _CharT, _Traits>(__fmt.c_str(), __tp); | |
2992 | } | |
2993 | ||
2994 | template<typename _CharT, typename _Traits, typename _Alloc, | |
2995 | typename _StrT = basic_string<_CharT, _Traits, _Alloc>, | |
2996 | __detail::__parsable<_CharT, _Traits, _StrT> _Parsable> | |
2997 | [[nodiscard, __gnu__::__access__(__read_only__, 1)]] | |
2998 | inline auto | |
2999 | parse(const _CharT* __fmt, _Parsable& __tp, | |
3000 | basic_string<_CharT, _Traits, _Alloc>& __abbrev) | |
3001 | { | |
3002 | auto __pa = std::__addressof(__abbrev); | |
3003 | return __detail::_Parse<_Parsable, _CharT, _Traits, _Alloc>(__fmt, __tp, | |
3004 | __pa); | |
3005 | } | |
3006 | ||
3007 | template<typename _CharT, typename _Traits, typename _Alloc, | |
3008 | typename _StrT = basic_string<_CharT, _Traits, _Alloc>, | |
3009 | __detail::__parsable<_CharT, _Traits, _StrT> _Parsable> | |
3010 | [[nodiscard]] | |
3011 | inline auto | |
3012 | parse(const basic_string<_CharT, _Traits, _Alloc>& __fmt, _Parsable& __tp, | |
3013 | basic_string<_CharT, _Traits, _Alloc>& __abbrev) | |
3014 | { | |
3015 | auto __pa = std::__addressof(__abbrev); | |
3016 | return __detail::_Parse<_Parsable, _CharT, _Traits, _Alloc>(__fmt.c_str(), | |
3017 | __tp, __pa); | |
3018 | } | |
3019 | ||
3020 | template<typename _CharT, typename _Traits = char_traits<_CharT>, | |
3021 | typename _StrT = basic_string<_CharT, _Traits>, | |
3022 | __detail::__parsable<_CharT, _Traits, _StrT, minutes> _Parsable> | |
3023 | [[nodiscard, __gnu__::__access__(__read_only__, 1)]] | |
3024 | inline auto | |
3025 | parse(const _CharT* __fmt, _Parsable& __tp, minutes& __offset) | |
3026 | { | |
3027 | return __detail::_Parse<_Parsable, _CharT>(__fmt, __tp, nullptr, | |
3028 | &__offset); | |
3029 | } | |
3030 | ||
3031 | template<typename _CharT, typename _Traits, typename _Alloc, | |
3032 | typename _StrT = basic_string<_CharT, _Traits>, | |
3033 | __detail::__parsable<_CharT, _Traits, _StrT, minutes> _Parsable> | |
3034 | [[nodiscard]] | |
3035 | inline auto | |
3036 | parse(const basic_string<_CharT, _Traits, _Alloc>& __fmt, _Parsable& __tp, | |
3037 | minutes& __offset) | |
3038 | { | |
3039 | return __detail::_Parse<_Parsable, _CharT, _Traits, _Alloc>(__fmt.c_str(), | |
3040 | __tp, nullptr, | |
3041 | &__offset); | |
3042 | } | |
3043 | ||
3044 | template<typename _CharT, typename _Traits, typename _Alloc, | |
3045 | typename _StrT = basic_string<_CharT, _Traits, _Alloc>, | |
3046 | __detail::__parsable<_CharT, _Traits, _StrT, minutes> _Parsable> | |
3047 | [[nodiscard, __gnu__::__access__(__read_only__, 1)]] | |
3048 | inline auto | |
3049 | parse(const _CharT* __fmt, _Parsable& __tp, | |
3050 | basic_string<_CharT, _Traits, _Alloc>& __abbrev, minutes& __offset) | |
3051 | { | |
3052 | auto __pa = std::__addressof(__abbrev); | |
3053 | return __detail::_Parse<_Parsable, _CharT, _Traits, _Alloc>(__fmt, __tp, | |
3054 | __pa, | |
3055 | &__offset); | |
3056 | } | |
3057 | ||
3058 | template<typename _CharT, typename _Traits, typename _Alloc, | |
3059 | typename _StrT = basic_string<_CharT, _Traits, _Alloc>, | |
3060 | __detail::__parsable<_CharT, _Traits, _StrT, minutes> _Parsable> | |
3061 | [[nodiscard]] | |
3062 | inline auto | |
3063 | parse(const basic_string<_CharT, _Traits, _Alloc>& __fmt, _Parsable& __tp, | |
3064 | basic_string<_CharT, _Traits, _Alloc>& __abbrev, minutes& __offset) | |
3065 | { | |
3066 | auto __pa = std::__addressof(__abbrev); | |
3067 | return __detail::_Parse<_Parsable, _CharT, _Traits, _Alloc>(__fmt.c_str(), | |
3068 | __tp, __pa, | |
3069 | &__offset); | |
3070 | } | |
3071 | ||
3072 | /// @cond undocumented | |
3073 | template<typename _Duration> | |
3074 | template<typename _CharT, typename _Traits, typename _Alloc> | |
3075 | basic_istream<_CharT, _Traits>& | |
3076 | __detail::_Parser<_Duration>:: | |
3077 | operator()(basic_istream<_CharT, _Traits>& __is, const _CharT* __fmt, | |
3078 | basic_string<_CharT, _Traits, _Alloc>* __abbrev, | |
3079 | minutes* __offset) | |
3080 | { | |
3081 | using sentry = typename basic_istream<_CharT, _Traits>::sentry; | |
3082 | ios_base::iostate __err = ios_base::goodbit; | |
3083 | if (sentry __cerb(__is, true); __cerb) | |
3084 | { | |
3085 | locale __loc = __is.getloc(); | |
3086 | auto& __tmget = std::use_facet<std::time_get<_CharT>>(__loc); | |
3087 | auto& __tmpunct = std::use_facet<std::__timepunct<_CharT>>(__loc); | |
3088 | ||
3089 | // RAII type to save and restore stream state. | |
3090 | struct _Stream_state | |
3091 | { | |
3092 | explicit | |
3093 | _Stream_state(basic_istream<_CharT, _Traits>& __i) | |
3094 | : _M_is(__i), | |
3095 | _M_flags(__i.flags(ios_base::skipws | ios_base::dec)), | |
3096 | _M_w(__i.width(0)) | |
3097 | { } | |
3098 | ||
3099 | ~_Stream_state() | |
3100 | { | |
3101 | _M_is.flags(_M_flags); | |
3102 | _M_is.width(_M_w); | |
3103 | } | |
3104 | ||
3105 | _Stream_state(_Stream_state&&) = delete; | |
3106 | ||
3107 | basic_istream<_CharT, _Traits>& _M_is; | |
3108 | ios_base::fmtflags _M_flags; | |
3109 | streamsize _M_w; | |
3110 | }; | |
3111 | ||
3112 | auto __is_failed = [](ios_base::iostate __e) { | |
3113 | return static_cast<bool>(__e & ios_base::failbit); | |
3114 | }; | |
3115 | ||
3116 | // Read an unsigned integer from the stream and return it. | |
3117 | // Extract no more than __n digits. Set __err on error. | |
3118 | auto __read_unsigned = [&] (int __n) { | |
3119 | return _S_read_unsigned(__is, __err, __n); | |
3120 | }; | |
3121 | ||
3122 | // Read a signed integer from the stream and return it. | |
3123 | // Extract no more than __n digits. Set __err on error. | |
3124 | auto __read_signed = [&] (int __n) { | |
3125 | return _S_read_signed(__is, __err, __n); | |
3126 | }; | |
3127 | ||
3128 | // Read an expected character from the stream. | |
3129 | auto __read_chr = [&__is, &__err] (_CharT __c) { | |
3130 | return _S_read_chr(__is, __err, __c); | |
3131 | }; | |
3132 | ||
3133 | using __format::_ChronoParts; | |
3134 | _ChronoParts __parts{}; | |
3135 | ||
3136 | const year __bad_y = --year::min(); // SHRT_MIN | |
3137 | const month __bad_mon(255); | |
3138 | const day __bad_day(255); | |
3139 | const weekday __bad_wday(255); | |
3140 | const hours __bad_h(-1); | |
3141 | const minutes __bad_min(-9999); | |
3142 | const seconds __bad_sec(-1); | |
3143 | ||
3144 | year __y = __bad_y, __yy = __bad_y; // %Y, %yy | |
3145 | year __iso_y = __bad_y, __iso_yy = __bad_y; // %G, %g | |
3146 | month __m = __bad_mon; // %m | |
3147 | day __d = __bad_day; // %d | |
3148 | weekday __wday = __bad_wday; // %a %A %u %w | |
3149 | hours __h = __bad_h, __h12 = __bad_h; // %H, %I | |
3150 | minutes __min = __bad_min; // %M | |
3151 | _Duration __s = __bad_sec; // %S | |
3152 | int __ampm = 0; // %p | |
3153 | int __iso_wk = -1, __sunday_wk = -1, __monday_wk = -1; // %V, %U, %W | |
3154 | int __century = -1; // %C | |
3155 | int __dayofyear = -1; // %j (for non-duration) | |
3156 | ||
3157 | minutes __tz_offset = __bad_min; | |
3158 | basic_string<_CharT, _Traits> __tz_abbr; | |
3159 | ||
3e8ee03e JW |
3160 | if ((_M_need & _ChronoParts::_TimeOfDay) |
3161 | && (_M_need & _ChronoParts::_Year)) | |
3162 | { | |
3163 | // For time_points assume "00:00:00" is implicitly present, | |
3164 | // so we don't fail to parse if it's not (PR libstdc++/114240). | |
3165 | // We will still fail to parse if there's no year+month+day. | |
3166 | __h = hours(0); | |
3167 | __parts = _ChronoParts::_TimeOfDay; | |
3168 | } | |
3169 | ||
ce6c4d3b JW |
3170 | // bool __is_neg = false; // TODO: how is this handled for parsing? |
3171 | ||
3172 | _CharT __mod{}; // One of 'E' or 'O' or nul. | |
3173 | unsigned __num = 0; // Non-zero for N modifier. | |
3174 | bool __is_flag = false; // True if we're processing a % flag. | |
3175 | ||
5f9d7a5b JW |
3176 | constexpr bool __is_floating |
3177 | = treat_as_floating_point_v<typename _Duration::rep>; | |
3178 | ||
ce6c4d3b JW |
3179 | // If an out-of-range value is extracted (e.g. 61min for %M), |
3180 | // do not set failbit immediately because we might not need it | |
3181 | // (e.g. parsing chrono::year doesn't care about invalid %M values). | |
3182 | // Instead set the variable back to its initial 'bad' state, | |
3183 | // and also set related variables corresponding to the same field | |
3184 | // (e.g. a bad %M value for __min should also reset __h and __s). | |
3185 | // If a valid value is needed later the bad value will cause failure. | |
3186 | ||
3187 | // For some fields we don't know the correct range when parsing and | |
3188 | // we have to be liberal in what we accept, e.g. we allow 366 for | |
3189 | // day-of-year because that's valid in leap years, and we allow 31 | |
3190 | // for day-of-month. If those values are needed to determine the | |
3191 | // result then we can do a correct range check at the end when we | |
3192 | // know the how many days the relevant year or month actually has. | |
3193 | ||
3194 | while (*__fmt) | |
3195 | { | |
3196 | _CharT __c = *__fmt++; | |
3197 | if (!__is_flag) | |
3198 | { | |
3199 | if (__c == '%') | |
3200 | __is_flag = true; // This is the start of a flag. | |
3201 | else if (std::isspace(__c, __loc)) | |
3202 | std::ws(__is); // Match zero or more whitespace characters. | |
3203 | else if (!__read_chr(__c)) [[unlikely]] | |
3204 | break; // Failed to match the expected character. | |
3205 | ||
3206 | continue; // Process next character in the format string. | |
3207 | } | |
3208 | ||
3209 | // Now processing a flag. | |
3210 | switch (__c) | |
3211 | { | |
3212 | case 'a': // Locale's weekday name | |
3213 | case 'A': // (full or abbreviated, matched case-insensitively). | |
3214 | if (__mod || __num) [[unlikely]] | |
3215 | __err = ios_base::failbit; | |
3216 | else | |
3217 | { | |
3218 | struct tm __tm{}; | |
3219 | __tmget.get(__is, {}, __is, __err, &__tm, | |
3220 | __fmt - 2, __fmt); | |
3221 | if (!__is_failed(__err)) | |
3222 | __wday = weekday(__tm.tm_wday); | |
3223 | } | |
3224 | __parts |= _ChronoParts::_Weekday; | |
3225 | break; | |
3226 | ||
3227 | case 'b': // Locale's month name | |
3228 | case 'h': // (full or abbreviated, matched case-insensitively). | |
3229 | case 'B': | |
3230 | if (__mod || __num) [[unlikely]] | |
3231 | __err = ios_base::failbit; | |
3232 | else | |
3233 | { | |
3234 | // strptime behaves differently for %b and %B, | |
3235 | // but chrono::parse says they're equivalent. | |
3236 | // Luckily libstdc++ std::time_get works as needed. | |
3237 | struct tm __tm{}; | |
3238 | __tmget.get(__is, {}, __is, __err, &__tm, | |
3239 | __fmt - 2, __fmt); | |
3240 | if (!__is_failed(__err)) | |
3241 | __m = month(__tm.tm_mon + 1); | |
3242 | } | |
3243 | __parts |= _ChronoParts::_Month; | |
3244 | break; | |
3245 | ||
3246 | case 'c': // Locale's date and time representation. | |
3247 | if (__mod == 'O' || __num) [[unlikely]] | |
3248 | __err |= ios_base::failbit; | |
3249 | else | |
3250 | { | |
3251 | struct tm __tm{}; | |
3252 | __tmget.get(__is, {}, __is, __err, &__tm, | |
3253 | __fmt - 2 - (__mod == 'E'), __fmt); | |
3254 | if (!__is_failed(__err)) | |
3255 | { | |
3256 | __y = year(__tm.tm_year + 1900); | |
3257 | __m = month(__tm.tm_mon + 1); | |
3258 | __d = day(__tm.tm_mday); | |
3259 | __h = hours(__tm.tm_hour); | |
3260 | __min = minutes(__tm.tm_min); | |
5f9d7a5b | 3261 | __s = seconds(__tm.tm_sec); |
ce6c4d3b JW |
3262 | } |
3263 | } | |
3264 | __parts |= _ChronoParts::_DateTime; | |
3265 | break; | |
3266 | ||
3267 | case 'C': // Century | |
3268 | if (!__mod) [[likely]] | |
3269 | { | |
3270 | auto __v = __read_signed(__num ? __num : 2); | |
3271 | if (!__is_failed(__err)) | |
207c5074 JW |
3272 | { |
3273 | int __cmin = (int)year::min() / 100; | |
3274 | int __cmax = (int)year::max() / 100; | |
3275 | if (__cmin <= __v && __v <= __cmax) | |
3276 | __century = __v * 100; | |
3277 | else | |
3278 | __century = -2; // This prevents guessing century. | |
3279 | } | |
ce6c4d3b JW |
3280 | } |
3281 | else if (__mod == 'E') | |
3282 | { | |
3283 | struct tm __tm{}; | |
3284 | __tmget.get(__is, {}, __is, __err, &__tm, | |
3285 | __fmt - 3, __fmt); | |
3286 | if (!__is_failed(__err)) | |
3287 | __century = __tm.tm_year; | |
3288 | } | |
3289 | else [[unlikely]] | |
3290 | __err |= ios_base::failbit; | |
3291 | // N.B. don't set this here: __parts |= _ChronoParts::_Year; | |
3292 | break; | |
3293 | ||
3294 | case 'd': // Day of month (1-31) | |
3295 | case 'e': | |
3296 | if (!__mod) [[likely]] | |
3297 | { | |
3298 | auto __v = __read_unsigned(__num ? __num : 2); | |
3299 | if (!__is_failed(__err)) | |
3300 | __d = day(__v); | |
3301 | } | |
3302 | else if (__mod == 'O') | |
3303 | { | |
3304 | struct tm __tm{}; | |
3305 | __tmget.get(__is, {}, __is, __err, &__tm, | |
3306 | __fmt - 3, __fmt); | |
3307 | if (!__is_failed(__err)) | |
3308 | __d = day(__tm.tm_mday); | |
3309 | } | |
3310 | else [[unlikely]] | |
3311 | __err |= ios_base::failbit; | |
3312 | __parts |= _ChronoParts::_Day; | |
3313 | break; | |
3314 | ||
3315 | case 'D': // %m/%d/%y | |
3316 | if (__mod || __num) [[unlikely]] | |
3317 | __err |= ios_base::failbit; | |
3318 | else | |
3319 | { | |
3320 | auto __month = __read_unsigned(2); // %m | |
3321 | __read_chr('/'); | |
3322 | auto __day = __read_unsigned(2); // %d | |
3323 | __read_chr('/'); | |
3324 | auto __year = __read_unsigned(2); // %y | |
3325 | if (__is_failed(__err)) | |
3326 | break; | |
3327 | __y = year(__year + 1900 + 100 * int(__year < 69)); | |
3328 | __m = month(__month); | |
3329 | __d = day(__day); | |
3330 | if (!year_month_day(__y, __m, __d).ok()) | |
3331 | { | |
3332 | __y = __yy = __iso_y = __iso_yy = __bad_y; | |
3333 | __m = __bad_mon; | |
3334 | __d = __bad_day; | |
3335 | break; | |
3336 | } | |
3337 | } | |
3338 | __parts |= _ChronoParts::_Date; | |
3339 | break; | |
3340 | ||
3341 | case 'F': // %Y-%m-%d - any N modifier only applies to %Y. | |
3342 | if (__mod) [[unlikely]] | |
3343 | __err |= ios_base::failbit; | |
3344 | else | |
3345 | { | |
3346 | auto __year = __read_signed(__num ? __num : 4); // %Y | |
3347 | __read_chr('-'); | |
3348 | auto __month = __read_unsigned(2); // %m | |
3349 | __read_chr('-'); | |
3350 | auto __day = __read_unsigned(2); // %d | |
3351 | if (__is_failed(__err)) | |
3352 | break; | |
3353 | __y = year(__year); | |
3354 | __m = month(__month); | |
3355 | __d = day(__day); | |
3356 | if (!year_month_day(__y, __m, __d).ok()) | |
3357 | { | |
3358 | __y = __yy = __iso_y = __iso_yy = __bad_y; | |
3359 | __m = __bad_mon; | |
3360 | __d = __bad_day; | |
3361 | break; | |
3362 | } | |
3363 | } | |
3364 | __parts |= _ChronoParts::_Date; | |
3365 | break; | |
3366 | ||
3367 | case 'g': // Last two digits of ISO week-based year. | |
3368 | if (__mod) [[unlikely]] | |
3369 | __err |= ios_base::failbit; | |
3370 | else | |
3371 | { | |
3372 | auto __val = __read_unsigned(__num ? __num : 2); | |
3373 | if (__val >= 0 && __val <= 99) | |
3374 | { | |
3375 | __iso_yy = year(__val); | |
3376 | if (__century == -1) // No %C has been parsed yet. | |
3377 | __century = 2000; | |
3378 | } | |
3379 | else | |
3380 | __iso_yy = __iso_y = __y = __yy = __bad_y; | |
3381 | } | |
3382 | __parts |= _ChronoParts::_Year; | |
3383 | break; | |
3384 | ||
3385 | case 'G': // ISO week-based year. | |
3386 | if (__mod) [[unlikely]] | |
3387 | __err |= ios_base::failbit; | |
3388 | else | |
3389 | __iso_y = year(__read_unsigned(__num ? __num : 4)); | |
3390 | __parts |= _ChronoParts::_Year; | |
3391 | break; | |
3392 | ||
3393 | case 'H': // 24-hour (00-23) | |
3394 | case 'I': // 12-hour (1-12) | |
3395 | if (__mod == 'E') [[unlikely]] | |
3396 | __err |= ios_base::failbit; | |
3397 | else if (__mod == 'O') | |
3398 | { | |
3399 | #if 0 | |
3400 | struct tm __tm{}; | |
3401 | __tm.tm_ampm = 1; | |
3402 | __tmget.get(__is, {}, __is, __err, &__tm, | |
3403 | __fmt - 3, __fmt); | |
3404 | if (!__is_failed(__err)) | |
3405 | { | |
3406 | if (__c == 'I') | |
3407 | { | |
3408 | __h12 = hours(__tm.tm_hour); | |
3409 | __h = __bad_h; | |
3410 | } | |
3411 | else | |
3412 | __h = hours(__tm.tm_hour); | |
3413 | } | |
3414 | #else | |
3415 | // XXX %OI seems to be unimplementable. | |
3416 | __err |= ios_base::failbit; | |
3417 | #endif | |
3418 | } | |
3419 | else | |
3420 | { | |
3421 | auto __val = __read_unsigned(__num ? __num : 2); | |
3422 | if (__c == 'I' && __val >= 1 && __val <= 12) | |
3423 | { | |
3424 | __h12 = hours(__val); | |
3425 | __h = __bad_h; | |
3426 | } | |
3427 | else if (__c == 'H' && __val >= 0 && __val <= 23) | |
e5af77ad JW |
3428 | { |
3429 | __h = hours(__val); | |
3430 | __h12 = __bad_h; | |
3431 | } | |
3432 | else | |
3433 | { | |
3434 | if (_M_need & _ChronoParts::_TimeOfDay) | |
3435 | __err |= ios_base::failbit; | |
3436 | break; | |
3437 | } | |
ce6c4d3b JW |
3438 | } |
3439 | __parts |= _ChronoParts::_TimeOfDay; | |
3440 | break; | |
3441 | ||
3442 | case 'j': // For duration, count of days, otherwise day of year | |
3443 | if (__mod) [[unlikely]] | |
3444 | __err |= ios_base::failbit; | |
3445 | else if (_M_need == _ChronoParts::_TimeOfDay) // duration | |
3446 | { | |
3447 | auto __val = __read_signed(__num ? __num : 3); | |
3448 | if (!__is_failed(__err)) | |
3449 | { | |
3450 | __h = days(__val); // __h will get added to _M_time | |
3451 | __parts |= _ChronoParts::_TimeOfDay; | |
3452 | } | |
3453 | } | |
3454 | else | |
3455 | { | |
3456 | __dayofyear = __read_unsigned(__num ? __num : 3); | |
3457 | // N.B. do not alter __parts here, done after loop. | |
3458 | // No need for range checking here either. | |
3459 | } | |
3460 | break; | |
3461 | ||
3462 | case 'm': // Month (1-12) | |
3463 | if (__mod == 'E') [[unlikely]] | |
3464 | __err |= ios_base::failbit; | |
3465 | else if (__mod == 'O') | |
3466 | { | |
3467 | struct tm __tm{}; | |
3468 | __tmget.get(__is, {}, __is, __err, &__tm, | |
3469 | __fmt - 2, __fmt); | |
3470 | if (!__is_failed(__err)) | |
3471 | __m = month(__tm.tm_mon + 1); | |
3472 | } | |
3473 | else | |
3474 | { | |
3475 | auto __val = __read_unsigned(__num ? __num : 2); | |
3476 | if (__val >= 1 && __val <= 12) | |
3477 | __m = month(__val); | |
3478 | else | |
3479 | __m = __bad_mon; | |
3480 | } | |
3481 | __parts |= _ChronoParts::_Month; | |
3482 | break; | |
3483 | ||
3484 | case 'M': // Minutes | |
3485 | if (__mod == 'E') [[unlikely]] | |
3486 | __err |= ios_base::failbit; | |
3487 | else if (__mod == 'O') | |
3488 | { | |
3489 | struct tm __tm{}; | |
3490 | __tmget.get(__is, {}, __is, __err, &__tm, | |
3491 | __fmt - 2, __fmt); | |
3492 | if (!__is_failed(__err)) | |
3493 | __min = minutes(__tm.tm_min); | |
3494 | } | |
3495 | else | |
3496 | { | |
3497 | auto __val = __read_unsigned(__num ? __num : 2); | |
3498 | if (0 <= __val && __val < 60) | |
3499 | __min = minutes(__val); | |
3500 | else | |
3501 | { | |
e5af77ad JW |
3502 | if (_M_need & _ChronoParts::_TimeOfDay) |
3503 | __err |= ios_base::failbit; | |
ce6c4d3b JW |
3504 | break; |
3505 | } | |
3506 | } | |
3507 | __parts |= _ChronoParts::_TimeOfDay; | |
3508 | break; | |
3509 | ||
3510 | case 'p': // Locale's AM/PM designation for 12-hour clock. | |
3511 | if (__mod || __num) | |
3512 | __err |= ios_base::failbit; | |
3513 | else | |
3514 | { | |
3515 | // Can't use std::time_get here as it can't parse %p | |
3516 | // in isolation without %I. This might be faster anyway. | |
3517 | const _CharT* __ampms[2]; | |
3518 | __tmpunct._M_am_pm(__ampms); | |
3519 | int __n = 0, __which = 3; | |
3520 | while (__which != 0) | |
3521 | { | |
3522 | auto __i = __is.peek(); | |
3523 | if (_Traits::eq_int_type(__i, _Traits::eof())) | |
3524 | { | |
3525 | __err |= ios_base::eofbit | ios_base::failbit; | |
3526 | break; | |
3527 | } | |
3528 | __i = std::toupper(_Traits::to_char_type(__i), __loc); | |
3529 | if (__which & 1) | |
3530 | { | |
3531 | if (__i != std::toupper(__ampms[0][__n], __loc)) | |
3532 | __which ^= 1; | |
3533 | else if (__ampms[0][__n + 1] == _CharT()) | |
3534 | { | |
3535 | __which = 1; | |
3536 | (void) __is.get(); | |
3537 | break; | |
3538 | } | |
3539 | } | |
3540 | if (__which & 2) | |
3541 | { | |
3542 | if (__i != std::toupper(__ampms[1][__n], __loc)) | |
3543 | __which ^= 2; | |
3544 | else if (__ampms[1][__n + 1] == _CharT()) | |
3545 | { | |
3546 | __which = 2; | |
3547 | (void) __is.get(); | |
3548 | break; | |
3549 | } | |
3550 | } | |
3551 | if (__which) | |
3552 | (void) __is.get(); | |
3553 | ++__n; | |
3554 | } | |
3555 | if (__which == 0 || __which == 3) | |
3556 | __err |= ios_base::failbit; | |
3557 | else | |
3558 | __ampm = __which; | |
3559 | } | |
3560 | break; | |
3561 | ||
3562 | case 'r': // Locale's 12-hour time. | |
3563 | if (__mod || __num) | |
3564 | __err |= ios_base::failbit; | |
3565 | else | |
3566 | { | |
3567 | struct tm __tm{}; | |
3568 | __tmget.get(__is, {}, __is, __err, &__tm, | |
3569 | __fmt - 2, __fmt); | |
3570 | if (!__is_failed(__err)) | |
3571 | { | |
3572 | __h = hours(__tm.tm_hour); | |
3573 | __min = minutes(__tm.tm_min); | |
3574 | __s = seconds(__tm.tm_sec); | |
3575 | } | |
3576 | } | |
3577 | __parts |= _ChronoParts::_TimeOfDay; | |
3578 | break; | |
3579 | ||
3580 | case 'R': // %H:%M | |
3581 | case 'T': // %H:%M:%S | |
3582 | if (__mod || __num) [[unlikely]] | |
3583 | { | |
3584 | __err |= ios_base::failbit; | |
3585 | break; | |
3586 | } | |
3587 | else | |
3588 | { | |
3589 | auto __val = __read_unsigned(2); | |
e5af77ad | 3590 | if (__val == -1 || __val > 23) [[unlikely]] |
ce6c4d3b | 3591 | { |
e5af77ad JW |
3592 | if (_M_need & _ChronoParts::_TimeOfDay) |
3593 | __err |= ios_base::failbit; | |
ce6c4d3b JW |
3594 | break; |
3595 | } | |
e5af77ad JW |
3596 | if (!__read_chr(':')) [[unlikely]] |
3597 | break; | |
ce6c4d3b JW |
3598 | __h = hours(__val); |
3599 | ||
3600 | __val = __read_unsigned(2); | |
e5af77ad | 3601 | if (__val == -1 || __val > 60) [[unlikely]] |
ce6c4d3b | 3602 | { |
e5af77ad JW |
3603 | if (_M_need & _ChronoParts::_TimeOfDay) |
3604 | __err |= ios_base::failbit; | |
ce6c4d3b JW |
3605 | break; |
3606 | } | |
3607 | __min = minutes(__val); | |
3608 | ||
e5af77ad JW |
3609 | if (__c == 'R') |
3610 | { | |
3611 | __parts |= _ChronoParts::_TimeOfDay; | |
3612 | break; | |
3613 | } | |
3614 | else if (!__read_chr(':')) [[unlikely]] | |
ce6c4d3b JW |
3615 | break; |
3616 | } | |
3617 | [[fallthrough]]; | |
3618 | ||
3619 | case 'S': // Seconds | |
3620 | if (__mod == 'E') [[unlikely]] | |
3621 | __err |= ios_base::failbit; | |
3622 | else if (__mod == 'O') | |
3623 | { | |
3624 | struct tm __tm{}; | |
3625 | __tmget.get(__is, {}, __is, __err, &__tm, | |
3626 | __fmt - 3, __fmt); | |
3627 | if (!__is_failed(__err)) | |
3628 | __s = seconds(__tm.tm_sec); | |
3629 | } | |
5f9d7a5b JW |
3630 | else if constexpr (_Duration::period::den == 1 |
3631 | && !__is_floating) | |
ce6c4d3b JW |
3632 | { |
3633 | auto __val = __read_unsigned(__num ? __num : 2); | |
e5af77ad | 3634 | if (0 <= __val && __val <= 59) [[likely]] |
ce6c4d3b JW |
3635 | __s = seconds(__val); |
3636 | else | |
3637 | { | |
e5af77ad JW |
3638 | if (_M_need & _ChronoParts::_TimeOfDay) |
3639 | __err |= ios_base::failbit; | |
ce6c4d3b JW |
3640 | break; |
3641 | } | |
3642 | } | |
5f9d7a5b | 3643 | else // Read fractional seconds |
ce6c4d3b JW |
3644 | { |
3645 | basic_stringstream<_CharT> __buf; | |
3646 | auto __digit = _S_try_read_digit(__is, __err); | |
3647 | if (__digit != -1) | |
3648 | { | |
3649 | __buf.put(_CharT('0') + __digit); | |
3650 | __digit = _S_try_read_digit(__is, __err); | |
3651 | if (__digit != -1) | |
3652 | __buf.put(_CharT('0') + __digit); | |
3653 | } | |
3654 | ||
3655 | auto __i = __is.peek(); | |
3656 | if (_Traits::eq_int_type(__i, _Traits::eof())) | |
3657 | __err |= ios_base::eofbit; | |
3658 | else | |
3659 | { | |
715127b6 JW |
3660 | _CharT __dp = '.'; |
3661 | if (__loc != locale::classic()) | |
3662 | { | |
3663 | auto& __np = use_facet<numpunct<_CharT>>(__loc); | |
3664 | __dp = __np.decimal_point(); | |
3665 | } | |
ce6c4d3b JW |
3666 | _CharT __c = _Traits::to_char_type(__i); |
3667 | if (__c == __dp) | |
3668 | { | |
3669 | (void) __is.get(); | |
715127b6 | 3670 | __buf.put('.'); |
ce6c4d3b JW |
3671 | int __prec |
3672 | = hh_mm_ss<_Duration>::fractional_width; | |
3673 | do | |
3674 | { | |
3675 | __digit = _S_try_read_digit(__is, __err); | |
3676 | if (__digit != -1) | |
3677 | __buf.put(_CharT('0') + __digit); | |
3678 | else | |
3679 | break; | |
3680 | } | |
3681 | while (--__prec); | |
3682 | } | |
3683 | } | |
3684 | ||
715127b6 | 3685 | if (!__is_failed(__err)) [[likely]] |
ce6c4d3b | 3686 | { |
715127b6 | 3687 | long double __val{}; |
92b38ec8 | 3688 | #if __cpp_lib_to_chars |
715127b6 JW |
3689 | string __str = std::move(__buf).str(); |
3690 | auto __first = __str.data(); | |
3691 | auto __last = __first + __str.size(); | |
3692 | using enum chars_format; | |
3693 | auto [ptr, ec] = std::from_chars(__first, __last, | |
3694 | __val, fixed); | |
3695 | if ((bool)ec || ptr != __last) [[unlikely]] | |
3696 | __err |= ios_base::failbit; | |
ce6c4d3b | 3697 | else |
92b38ec8 JW |
3698 | #else |
3699 | if (__buf >> __val) | |
3700 | #endif | |
ce6c4d3b JW |
3701 | { |
3702 | duration<long double> __fs(__val); | |
5f9d7a5b JW |
3703 | if constexpr (__is_floating) |
3704 | __s = __fs; | |
3705 | else | |
3706 | __s = chrono::round<_Duration>(__fs); | |
ce6c4d3b JW |
3707 | } |
3708 | } | |
3709 | } | |
3710 | __parts |= _ChronoParts::_TimeOfDay; | |
3711 | break; | |
3712 | ||
3713 | case 'u': // ISO weekday (1-7) | |
3714 | case 'w': // Weekday (0-6) | |
3715 | if (__mod == 'E') [[unlikely]] | |
3716 | __err |= ios_base::failbit; | |
3717 | else if (__mod == 'O') | |
3718 | { | |
3719 | if (__c == 'w') | |
3720 | { | |
3721 | struct tm __tm{}; | |
3722 | __tmget.get(__is, {}, __is, __err, &__tm, | |
3723 | __fmt - 3, __fmt); | |
3724 | if (!__is_failed(__err)) | |
3725 | __wday = weekday(__tm.tm_wday); | |
3726 | } | |
3727 | else | |
3728 | __err |= ios_base::failbit; | |
3729 | } | |
3730 | else | |
3731 | { | |
3732 | const int __lo = __c == 'u' ? 1 : 0; | |
3733 | const int __hi = __lo + 6; | |
3734 | auto __val = __read_unsigned(__num ? __num : 1); | |
3735 | if (__lo <= __val && __val <= __hi) | |
3736 | __wday = weekday(__val); | |
3737 | else | |
3738 | { | |
3739 | __wday = __bad_wday; | |
3740 | break; | |
3741 | } | |
3742 | } | |
3743 | __parts |= _ChronoParts::_Weekday; | |
3744 | break; | |
3745 | ||
3746 | case 'U': // Week number of the year (from first Sunday). | |
3747 | case 'V': // ISO week-based week number. | |
3748 | case 'W': // Week number of the year (from first Monday). | |
3749 | if (__mod == 'E') [[unlikely]] | |
3750 | __err |= ios_base::failbit; | |
3751 | else if (__mod == 'O') | |
3752 | { | |
3753 | if (__c == 'V') [[unlikely]] | |
3754 | __err |= ios_base::failbit; | |
3755 | else | |
3756 | { | |
3757 | // TODO nl_langinfo_l(ALT_DIGITS) ? | |
3758 | // Not implementable using std::time_get. | |
3759 | } | |
3760 | } | |
3761 | else | |
3762 | { | |
3763 | const int __lo = __c == 'V' ? 1 : 0; | |
3764 | const int __hi = 53; | |
3765 | auto __val = __read_unsigned(__num ? __num : 2); | |
3766 | if (__lo <= __val && __val <= __hi) | |
3767 | { | |
3768 | switch (__c) | |
3769 | { | |
3770 | case 'U': | |
3771 | __sunday_wk = __val; | |
3772 | break; | |
3773 | case 'V': | |
3774 | __iso_wk = __val; | |
3775 | break; | |
3776 | case 'W': | |
3777 | __monday_wk = __val; | |
3778 | break; | |
3779 | } | |
3780 | } | |
3781 | else | |
3782 | __iso_wk = __sunday_wk = __monday_wk = -1; | |
3783 | } | |
3784 | // N.B. do not alter __parts here, done after loop. | |
3785 | break; | |
3786 | ||
3787 | case 'x': // Locale's date representation. | |
3788 | if (__mod == 'O' || __num) [[unlikely]] | |
3789 | __err |= ios_base::failbit; | |
3790 | else | |
3791 | { | |
3792 | struct tm __tm{}; | |
3793 | __tmget.get(__is, {}, __is, __err, &__tm, | |
3794 | __fmt - 2 - (__mod == 'E'), __fmt); | |
3795 | if (!__is_failed(__err)) | |
3796 | { | |
3797 | __y = year(__tm.tm_year + 1900); | |
3798 | __m = month(__tm.tm_mon + 1); | |
3799 | __d = day(__tm.tm_mday); | |
3800 | } | |
3801 | } | |
3802 | __parts |= _ChronoParts::_Date; | |
3803 | break; | |
3804 | ||
3805 | case 'X': // Locale's time representation. | |
3806 | if (__mod == 'O' || __num) [[unlikely]] | |
3807 | __err |= ios_base::failbit; | |
3808 | else | |
3809 | { | |
3810 | struct tm __tm{}; | |
3811 | __tmget.get(__is, {}, __is, __err, &__tm, | |
3812 | __fmt - 2 - (__mod == 'E'), __fmt); | |
3813 | if (!__is_failed(__err)) | |
3814 | { | |
3815 | __h = hours(__tm.tm_hour); | |
3816 | __min = minutes(__tm.tm_min); | |
5f9d7a5b | 3817 | __s = seconds(__tm.tm_sec); |
ce6c4d3b JW |
3818 | } |
3819 | } | |
3820 | __parts |= _ChronoParts::_TimeOfDay; | |
3821 | break; | |
3822 | ||
3823 | case 'y': // Last two digits of year. | |
3824 | if (__mod) [[unlikely]] | |
3825 | { | |
3826 | struct tm __tm{}; | |
3827 | __tmget.get(__is, {}, __is, __err, &__tm, | |
3828 | __fmt - 3, __fmt); | |
3829 | if (!__is_failed(__err)) | |
3830 | { | |
3831 | int __cent = __tm.tm_year < 2000 ? 1900 : 2000; | |
3832 | __yy = year(__tm.tm_year - __cent); | |
3833 | if (__century == -1) // No %C has been parsed yet. | |
3834 | __century = __cent; | |
3835 | } | |
3836 | } | |
3837 | else | |
3838 | { | |
3839 | auto __val = __read_unsigned(__num ? __num : 2); | |
3840 | if (__val >= 0 && __val <= 99) | |
3841 | { | |
3842 | __yy = year(__val); | |
3843 | if (__century == -1) // No %C has been parsed yet. | |
3844 | __century = __val < 69 ? 2000 : 1900; | |
3845 | } | |
3846 | else | |
3847 | __y = __yy = __iso_yy = __iso_y = __bad_y; | |
3848 | } | |
3849 | __parts |= _ChronoParts::_Year; | |
3850 | break; | |
3851 | ||
3852 | case 'Y': // Year | |
3853 | if (__mod == 'O') [[unlikely]] | |
3854 | __err |= ios_base::failbit; | |
3855 | else if (__mod == 'E') | |
3856 | { | |
3857 | struct tm __tm{}; | |
3858 | __tmget.get(__is, {}, __is, __err, &__tm, | |
3859 | __fmt - 3, __fmt); | |
3860 | if (!__is_failed(__err)) | |
3861 | __y = year(__tm.tm_year); | |
3862 | } | |
3863 | else | |
3864 | { | |
3865 | auto __val = __read_unsigned(__num ? __num : 4); | |
3866 | if (!__is_failed(__err)) | |
3867 | __y = year(__val); | |
3868 | } | |
3869 | __parts |= _ChronoParts::_Year; | |
3870 | break; | |
3871 | ||
3872 | case 'z': | |
3873 | if (__num) [[unlikely]] | |
3874 | __err |= ios_base::failbit; | |
3875 | else | |
3876 | { | |
3877 | // For %Ez and %Oz read [+|-][h]h[:mm]. | |
3878 | // For %z read [+|-]hh[mm]. | |
3879 | ||
3880 | auto __i = __is.peek(); | |
3881 | if (_Traits::eq_int_type(__i, _Traits::eof())) | |
3882 | { | |
3883 | __err |= ios_base::eofbit | ios_base::failbit; | |
3884 | break; | |
3885 | } | |
3886 | _CharT __ic = _Traits::to_char_type(__i); | |
3887 | const bool __neg = __ic == _CharT('-'); | |
3888 | if (__ic == _CharT('-') || __ic == _CharT('+')) | |
3889 | (void) __is.get(); | |
3890 | ||
3891 | int_least32_t __hh; | |
3892 | if (__mod) | |
3893 | { | |
3894 | // Read h[h] | |
3895 | __hh = __read_unsigned(2); | |
3896 | } | |
3897 | else | |
3898 | { | |
3899 | // Read hh | |
3900 | __hh = 10 * _S_try_read_digit(__is, __err); | |
3901 | __hh += _S_try_read_digit(__is, __err); | |
3902 | } | |
3903 | ||
3904 | if (__is_failed(__err)) | |
3905 | break; | |
3906 | ||
3907 | __i = __is.peek(); | |
3908 | if (_Traits::eq_int_type(__i, _Traits::eof())) | |
3909 | { | |
3910 | __err |= ios_base::eofbit; | |
3911 | __tz_offset = minutes(__hh * (__neg ? -60 : 60)); | |
3912 | break; | |
3913 | } | |
3914 | __ic = _Traits::to_char_type(__i); | |
3915 | ||
3916 | bool __read_mm = false; | |
3917 | if (__mod) | |
3918 | { | |
3919 | if (__ic == _GLIBCXX_WIDEN(":")[0]) | |
3920 | { | |
3921 | // Read [:mm] part. | |
3922 | (void) __is.get(); | |
3923 | __read_mm = true; | |
3924 | } | |
3925 | } | |
3926 | else if (_CharT('0') <= __ic && __ic <= _CharT('9')) | |
3927 | { | |
3928 | // Read [mm] part. | |
3929 | __read_mm = true; | |
3930 | } | |
3931 | ||
3932 | int_least32_t __mm = 0; | |
3933 | if (__read_mm) | |
3934 | { | |
3935 | __mm = 10 * _S_try_read_digit(__is, __err); | |
3936 | __mm += _S_try_read_digit(__is, __err); | |
3937 | } | |
3938 | ||
3939 | if (!__is_failed(__err)) | |
3940 | { | |
3941 | auto __z = __hh * 60 + __mm; | |
3942 | __tz_offset = minutes(__neg ? -__z : __z); | |
3943 | } | |
3944 | } | |
3945 | break; | |
3946 | ||
3947 | case 'Z': | |
3948 | if (__mod || __num) [[unlikely]] | |
3949 | __err |= ios_base::failbit; | |
3950 | else | |
3951 | { | |
3952 | basic_string_view<_CharT> __x = _GLIBCXX_WIDEN("_/-+"); | |
3953 | __tz_abbr.clear(); | |
3954 | while (true) | |
3955 | { | |
3956 | auto __i = __is.peek(); | |
3957 | if (!_Traits::eq_int_type(__i, _Traits::eof())) | |
3958 | { | |
3959 | _CharT __a = _Traits::to_char_type(__i); | |
3960 | if (std::isalnum(__a, __loc) | |
3961 | || __x.find(__a) != __x.npos) | |
3962 | { | |
3963 | __tz_abbr.push_back(__a); | |
3964 | (void) __is.get(); | |
3965 | continue; | |
3966 | } | |
3967 | } | |
3968 | else | |
3969 | __err |= ios_base::eofbit; | |
3970 | break; | |
3971 | } | |
3972 | if (__tz_abbr.empty()) | |
3973 | __err |= ios_base::failbit; | |
3974 | } | |
3975 | break; | |
3976 | ||
3977 | case 'n': // Exactly one whitespace character. | |
3978 | if (__mod || __num) [[unlikely]] | |
3979 | __err |= ios_base::failbit; | |
3980 | else | |
3981 | { | |
3982 | _CharT __i = __is.peek(); | |
3983 | if (_Traits::eq_int_type(__i, _Traits::eof())) | |
3984 | __err |= ios_base::eofbit | ios_base::failbit; | |
3985 | else if (std::isspace(_Traits::to_char_type(__i), __loc)) | |
3986 | (void) __is.get(); | |
3987 | else | |
3988 | __err |= ios_base::failbit; | |
3989 | } | |
3990 | break; | |
3991 | ||
3992 | case 't': // Zero or one whitespace characters. | |
3993 | if (__mod || __num) [[unlikely]] | |
3994 | __err |= ios_base::failbit; | |
3995 | else | |
3996 | { | |
3997 | _CharT __i = __is.peek(); | |
3998 | if (_Traits::eq_int_type(__i, _Traits::eof())) | |
3999 | __err |= ios_base::eofbit; | |
4000 | else if (std::isspace(_Traits::to_char_type(__i), __loc)) | |
4001 | (void) __is.get(); | |
4002 | } | |
4003 | break; | |
4004 | ||
4005 | case '%': // A % character. | |
4006 | if (__mod || __num) [[unlikely]] | |
4007 | __err |= ios_base::failbit; | |
4008 | else | |
4009 | __read_chr('%'); | |
4010 | break; | |
4011 | ||
4012 | case 'O': // Modifiers | |
4013 | case 'E': | |
4014 | if (__mod || __num) [[unlikely]] | |
4015 | { | |
4016 | __err |= ios_base::failbit; | |
4017 | break; | |
4018 | } | |
4019 | __mod = __c; | |
4020 | continue; | |
4021 | ||
4022 | default: | |
4023 | if (_CharT('1') <= __c && __c <= _CharT('9')) | |
4024 | { | |
4025 | if (!__mod) [[likely]] | |
4026 | { | |
4027 | // %Nx - extract positive decimal integer N | |
4028 | auto __end = __fmt + _Traits::length(__fmt); | |
4029 | auto [__v, __ptr] | |
4030 | = __format::__parse_integer(__fmt - 1, __end); | |
4031 | if (__ptr) [[likely]] | |
4032 | { | |
4033 | __num = __v; | |
4034 | __fmt = __ptr; | |
4035 | continue; | |
4036 | } | |
4037 | } | |
4038 | } | |
4039 | __err |= ios_base::failbit; | |
4040 | } | |
4041 | ||
4042 | if (__is_failed(__err)) [[unlikely]] | |
4043 | break; | |
4044 | ||
4045 | __is_flag = false; | |
4046 | __num = 0; | |
4047 | __mod = _CharT(); | |
4048 | } | |
4049 | ||
4050 | if (__century >= 0) | |
4051 | { | |
4052 | if (__yy != __bad_y && __y == __bad_y) | |
4053 | __y = years(__century) + __yy; // Use %y instead of %Y | |
4054 | if (__iso_yy != __bad_y && __iso_y == __bad_y) | |
4055 | __iso_y = years(__century) + __iso_yy; // Use %g instead of %G | |
4056 | } | |
4057 | ||
4058 | bool __can_use_doy = false; | |
4059 | bool __can_use_iso_wk = false; | |
4060 | bool __can_use_sun_wk = false; | |
4061 | bool __can_use_mon_wk = false; | |
4062 | ||
4063 | // A year + day-of-year can be converted to a full date. | |
4064 | if (__y != __bad_y && __dayofyear >= 0) | |
4065 | { | |
4066 | __can_use_doy = true; | |
4067 | __parts |= _ChronoParts::_Date; | |
4068 | } | |
4069 | else if (__y != __bad_y && __wday != __bad_wday && __sunday_wk >= 0) | |
4070 | { | |
4071 | __can_use_sun_wk = true; | |
4072 | __parts |= _ChronoParts::_Date; | |
4073 | } | |
4074 | else if (__y != __bad_y && __wday != __bad_wday && __monday_wk >= 0) | |
4075 | { | |
4076 | __can_use_mon_wk = true; | |
4077 | __parts |= _ChronoParts::_Date; | |
4078 | } | |
4079 | else if (__iso_y != __bad_y && __wday != __bad_wday && __iso_wk > 0) | |
4080 | { | |
4081 | // An ISO week date can be converted to a full date. | |
4082 | __can_use_iso_wk = true; | |
4083 | __parts |= _ChronoParts::_Date; | |
4084 | } | |
4085 | ||
4086 | if (__is_failed(__err)) [[unlikely]] | |
4087 | ; // Don't bother doing any more work. | |
4088 | else if (__is_flag) [[unlikely]] // incomplete format flag | |
4089 | __err |= ios_base::failbit; | |
4090 | else if ((_M_need & __parts) == _M_need) [[likely]] | |
4091 | { | |
4092 | // We try to avoid calculating _M_sys_days and _M_ymd unless | |
4093 | // necessary, because converting sys_days to year_month_day | |
4094 | // (or vice versa) requires non-trivial calculations. | |
4095 | // If we have y/m/d values then use them to populate _M_ymd | |
4096 | // and only convert it to _M_sys_days if the caller needs that. | |
4097 | // But if we don't have y/m/d and need to calculate the date | |
4098 | // from the day-of-year or a week+weekday then we set _M_sys_days | |
4099 | // and only convert it to _M_ymd if the caller needs that. | |
4100 | ||
4101 | // We do more error checking here, but only for the fields that | |
4102 | // we actually need to use. For example, we will not diagnose | |
4103 | // an invalid dayofyear==366 for non-leap years unless actually | |
4104 | // using __dayofyear. This should mean we never produce invalid | |
4105 | // results, but it means not all invalid inputs are diagnosed, | |
4106 | // e.g. "2023-01-01 366" >> "%F %j" ignores the invalid 366. | |
4107 | // We also do not diagnose inconsistent values for the same | |
4108 | // field, e.g. "2021 2022 2023" >> "%C%y %Y %Y" just uses 2023. | |
4109 | ||
4110 | // Whether the caller wants _M_wd. | |
4111 | // The _Weekday bit is only set for chrono::weekday. | |
4112 | const bool __need_wday = _M_need & _ChronoParts::_Weekday; | |
4113 | ||
4114 | // Whether the caller wants _M_sys_days and _M_time. | |
3e8ee03e | 4115 | // Only true for durations and time_points. |
ce6c4d3b JW |
4116 | const bool __need_time = _M_need & _ChronoParts::_TimeOfDay; |
4117 | ||
4118 | if (__need_wday && __wday != __bad_wday) | |
4119 | _M_wd = __wday; // Caller only wants a weekday and we have one. | |
4120 | else if (_M_need & _ChronoParts::_Date) // subsumes __need_wday | |
4121 | { | |
4122 | // Whether the caller wants _M_ymd. | |
4123 | // True for chrono::year etc., false for time_points. | |
4124 | const bool __need_ymd = !__need_wday && !__need_time; | |
4125 | ||
4126 | if ((_M_need & _ChronoParts::_Year && __y == __bad_y) | |
4127 | || (_M_need & _ChronoParts::_Month && __m == __bad_mon) | |
4128 | || (_M_need & _ChronoParts::_Day && __d == __bad_day)) | |
4129 | { | |
4130 | // Missing at least one of y/m/d so calculate sys_days | |
4131 | // from the other data we have available. | |
4132 | ||
4133 | if (__can_use_doy) | |
4134 | { | |
4135 | if ((0 < __dayofyear && __dayofyear <= 365) | |
4136 | || (__dayofyear == 366 && __y.is_leap())) | |
4137 | [[likely]] | |
4138 | { | |
4139 | _M_sys_days = sys_days(__y/January/1) | |
4140 | + days(__dayofyear - 1); | |
4141 | if (__need_ymd) | |
4142 | _M_ymd = year_month_day(_M_sys_days); | |
4143 | } | |
4144 | else | |
4145 | __err |= ios_base::failbit; | |
4146 | } | |
4147 | else if (__can_use_iso_wk) | |
4148 | { | |
4149 | // Calculate y/m/d from ISO week date. | |
4150 | ||
4151 | if (__iso_wk == 53) | |
4152 | { | |
4153 | // A year has 53 weeks iff Jan 1st is a Thursday | |
4154 | // or Jan 1 is a Wednesday and it's a leap year. | |
4155 | const sys_days __jan4(__iso_y/January/4); | |
4156 | weekday __wd1(__jan4 - days(3)); | |
4157 | if (__wd1 != Thursday) | |
4158 | if (__wd1 != Wednesday || !__iso_y.is_leap()) | |
4159 | __err |= ios_base::failbit; | |
4160 | } | |
4161 | ||
4162 | if (!__is_failed(__err)) [[likely]] | |
4163 | { | |
4164 | // First Thursday is always in week one: | |
4165 | sys_days __w(Thursday[1]/January/__iso_y); | |
4166 | // First day of week-based year: | |
4167 | __w -= Thursday - Monday; | |
4168 | __w += days(weeks(__iso_wk - 1)); | |
4169 | __w += __wday - Monday; | |
4170 | _M_sys_days = __w; | |
4171 | ||
4172 | if (__need_ymd) | |
4173 | _M_ymd = year_month_day(_M_sys_days); | |
4174 | } | |
4175 | } | |
4176 | else if (__can_use_sun_wk) | |
4177 | { | |
4178 | // Calculate y/m/d from week number + weekday. | |
4179 | sys_days __wk1(__y/January/Sunday[1]); | |
4180 | _M_sys_days = __wk1 + weeks(__sunday_wk - 1) | |
4181 | + days(__wday.c_encoding()); | |
4182 | _M_ymd = year_month_day(_M_sys_days); | |
4183 | if (_M_ymd.year() != __y) [[unlikely]] | |
4184 | __err |= ios_base::failbit; | |
4185 | } | |
4186 | else if (__can_use_mon_wk) | |
4187 | { | |
4188 | // Calculate y/m/d from week number + weekday. | |
4189 | sys_days __wk1(__y/January/Monday[1]); | |
4190 | _M_sys_days = __wk1 + weeks(__monday_wk - 1) | |
4191 | + days(__wday.c_encoding() - 1); | |
4192 | _M_ymd = year_month_day(_M_sys_days); | |
4193 | if (_M_ymd.year() != __y) [[unlikely]] | |
4194 | __err |= ios_base::failbit; | |
4195 | } | |
4196 | else // Should not be able to get here. | |
4197 | __err |= ios_base::failbit; | |
4198 | } | |
4199 | else | |
4200 | { | |
4201 | // We know that all fields the caller needs are present, | |
4202 | // but check that their values are in range. | |
4203 | // Make unwanted fields valid so that _M_ymd.ok() is true. | |
4204 | ||
4205 | if (_M_need & _ChronoParts::_Year) | |
4206 | { | |
4207 | if (!__y.ok()) [[unlikely]] | |
4208 | __err |= ios_base::failbit; | |
4209 | } | |
4210 | else if (__y == __bad_y) | |
4211 | __y = 1972y; // Leap year so that Feb 29 is valid. | |
4212 | ||
4213 | if (_M_need & _ChronoParts::_Month) | |
4214 | { | |
4215 | if (!__m.ok()) [[unlikely]] | |
4216 | __err |= ios_base::failbit; | |
4217 | } | |
4218 | else if (__m == __bad_mon) | |
4219 | __m = January; | |
4220 | ||
4221 | if (_M_need & _ChronoParts::_Day) | |
4222 | { | |
4223 | if (__d < day(1) || __d > (__y/__m/last).day()) | |
4224 | __err |= ios_base::failbit; | |
4225 | } | |
4226 | else if (__d == __bad_day) | |
4227 | __d = 1d; | |
4228 | ||
4229 | if (year_month_day __ymd(__y, __m, __d); __ymd.ok()) | |
4230 | { | |
4231 | _M_ymd = __ymd; | |
4232 | if (__need_wday || __need_time) | |
4233 | _M_sys_days = sys_days(_M_ymd); | |
4234 | } | |
4235 | else [[unlikely]] | |
4236 | __err |= ios_base::failbit; | |
4237 | } | |
4238 | ||
4239 | if (__need_wday) | |
4240 | _M_wd = weekday(_M_sys_days); | |
4241 | } | |
4242 | ||
4243 | // Need to set _M_time for both durations and time_points. | |
4244 | if (__need_time) | |
4245 | { | |
4246 | if (__h == __bad_h && __h12 != __bad_h) | |
4247 | { | |
4248 | if (__ampm == 1) | |
4249 | __h = __h12 == hours(12) ? hours(0) : __h12; | |
4250 | else if (__ampm == 2) | |
4251 | __h = __h12 == hours(12) ? __h12 : __h12 + hours(12); | |
4252 | else [[unlikely]] | |
4253 | __err |= ios_base::failbit; | |
4254 | } | |
4255 | ||
4256 | auto __t = _M_time.zero(); | |
4257 | bool __ok = false; | |
4258 | ||
4259 | if (__h != __bad_h) | |
4260 | { | |
4261 | __ok = true; | |
4262 | __t += __h; | |
4263 | } | |
4264 | ||
4265 | if (__min != __bad_min) | |
4266 | { | |
4267 | __ok = true; | |
4268 | __t += __min; | |
4269 | } | |
4270 | ||
4271 | if (__s != __bad_sec) | |
4272 | { | |
4273 | __ok = true; | |
4274 | __t += __s; | |
f4a52c18 | 4275 | _M_is_leap_second = __s >= seconds(60); |
ce6c4d3b JW |
4276 | } |
4277 | ||
4278 | if (__ok) | |
4279 | _M_time = __t; | |
4280 | else | |
4281 | __err |= ios_base::failbit; | |
4282 | } | |
4283 | ||
4284 | if (!__is_failed(__err)) [[likely]] | |
4285 | { | |
4286 | if (__offset && __tz_offset != __bad_min) | |
4287 | *__offset = __tz_offset; | |
4288 | if (__abbrev && !__tz_abbr.empty()) | |
4289 | *__abbrev = std::move(__tz_abbr); | |
4290 | } | |
4291 | } | |
4292 | else | |
4293 | __err |= ios_base::failbit; | |
4294 | } | |
4295 | if (__err) | |
4296 | __is.setstate(__err); | |
4297 | return __is; | |
4298 | } | |
4299 | /// @endcond | |
f99b9486 JW |
4300 | #undef _GLIBCXX_WIDEN |
4301 | ||
4302 | /// @} group chrono | |
4303 | } // namespace chrono | |
4304 | ||
4305 | _GLIBCXX_END_NAMESPACE_VERSION | |
4306 | } // namespace std | |
4307 | ||
4308 | #endif // C++20 | |
4309 | ||
4310 | #endif //_GLIBCXX_CHRONO_IO_H |