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