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