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
41#include <bits/charconv.h>
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
73 // Write an arbitrary duration suffix into the buffer.
74 template<typename _Period>
75 constexpr const char*
76 __units_suffix_misc(char* __buf, size_t /* TODO check length? */) noexcept
77 {
78 namespace __tc = std::__detail;
79 char* __p = __buf;
80 __p[0] = '[';
81 unsigned __nlen = __tc::__to_chars_len((uintmax_t)_Period::num);
82 __tc::__to_chars_10_impl(__p + 1, __nlen, (uintmax_t)_Period::num);
83 __p += 1 + __nlen;
84 if constexpr (_Period::den != 1)
85 {
86 __p[0] = '/';
87 unsigned __dlen = __tc::__to_chars_len((uintmax_t)_Period::den);
88 __tc::__to_chars_10_impl(__p + 1, __dlen, (uintmax_t)_Period::den);
89 __p += 1 + __dlen;
90 }
91 __p[0] = ']';
92 __p[1] = 's';
93 __p[2] = '\0';
94 return __buf;
95 }
96
97 template<typename _Period, typename _CharT>
98 constexpr auto
99 __units_suffix(char* __buf, size_t __n) noexcept
100 {
101 // The standard say these are all narrow strings, which would need to
102 // be widened at run-time when inserted into a wide stream. We use
103 // STATICALLY-WIDEN to widen at compile-time.
104#define _GLIBCXX_UNITS_SUFFIX(period, suffix) \
105 if constexpr (is_same_v<_Period, period>) \
106 return _GLIBCXX_WIDEN(suffix); \
107 else
108
109 _GLIBCXX_UNITS_SUFFIX(atto, "as")
110 _GLIBCXX_UNITS_SUFFIX(femto, "fs")
111 _GLIBCXX_UNITS_SUFFIX(pico, "ps")
112 _GLIBCXX_UNITS_SUFFIX(nano, "ns")
113 _GLIBCXX_UNITS_SUFFIX(milli, "ms")
114#if _GLIBCXX_USE_ALT_MICROSECONDS_SUFFIX
115 // Deciding this at compile-time is wrong, maybe use nl_langinfo(CODESET)
116 // to check runtime environment and return u8"\u00b5s", "\xb5s", or "us".
117 _GLIBCXX_UNITS_SUFFIX(micro, "\u00b5s")
118#else
119 _GLIBCXX_UNITS_SUFFIX(micro, "us")
120#endif
121 _GLIBCXX_UNITS_SUFFIX(centi, "cs")
122 _GLIBCXX_UNITS_SUFFIX(deci, "ds")
123 _GLIBCXX_UNITS_SUFFIX(ratio<1>, "s")
124 _GLIBCXX_UNITS_SUFFIX(deca, "das")
125 _GLIBCXX_UNITS_SUFFIX(hecto, "hs")
126 _GLIBCXX_UNITS_SUFFIX(kilo, "ks")
127 _GLIBCXX_UNITS_SUFFIX(mega, "Ms")
128 _GLIBCXX_UNITS_SUFFIX(giga, "Gs")
129 _GLIBCXX_UNITS_SUFFIX(tera, "Ts")
130 _GLIBCXX_UNITS_SUFFIX(tera, "Ts")
131 _GLIBCXX_UNITS_SUFFIX(peta, "Ps")
132 _GLIBCXX_UNITS_SUFFIX(exa, "Es")
133 _GLIBCXX_UNITS_SUFFIX(ratio<60>, "min")
134 _GLIBCXX_UNITS_SUFFIX(ratio<3600>, "h")
135 _GLIBCXX_UNITS_SUFFIX(ratio<86400>, "d")
136#undef _GLIBCXX_UNITS_SUFFIX
137 return __detail::__units_suffix_misc<_Period>(__buf, __n);
138 }
139} // namespace __detail
140/// @endcond
141
142 /** Write a `chrono::duration` to an ostream.
143 *
144 * @since C++20
145 */
146 template<typename _CharT, typename _Traits,
147 typename _Rep, typename _Period>
150 const duration<_Rep, _Period>& __d)
151 {
152 using period = typename _Period::type;
153 char __buf[sizeof("[/]s") + 2 * numeric_limits<intmax_t>::digits10];
155 __s.flags(__os.flags());
156 __s.imbue(__os.getloc());
157 __s.precision(__os.precision());
158 __s << __d.count();
159 __s << __detail::__units_suffix<period, _CharT>(__buf, sizeof(__buf));
160 __os << std::move(__s).str();
161 return __os;
162 }
163
164/// @cond undocumented
165namespace __detail
166{
167 // An unspecified type returned by `chrono::local_time_format`.
168 template<typename _Duration>
169 struct __local_time_fmt
170 {
171 local_time<_Duration> _M_time;
172 const string* _M_abbrev;
173 const seconds* _M_offset_sec;
174 };
175
176 struct __local_fmt_t;
177}
178/// @endcond
179
180 /** Return an object that asssociates timezone info with a local time.
181 *
182 * A `chrono::local_time` object has no timezone associated with it. This
183 * function creates an object that allows formatting a `local_time` as
184 * though it refers to a timezone with the given abbreviated name and
185 * offset from UTC.
186 *
187 * @since C++20
188 */
189 template<typename _Duration>
190 inline __detail::__local_time_fmt<_Duration>
192 const string* __abbrev = nullptr,
193 const seconds* __offset_sec = nullptr)
194 { return {__time, __abbrev, __offset_sec}; }
195
196 /// @}
197} // namespace chrono
198
199/// @cond undocumented
200namespace __format
201{
202 [[noreturn,__gnu__::__always_inline__]]
203 inline void
204 __no_timezone_available()
205 { __throw_format_error("format error: no timezone available for %Z or %z"); }
206
207 [[noreturn,__gnu__::__always_inline__]]
208 inline void
209 __not_valid_for_duration()
210 { __throw_format_error("format error: chrono-format-spec not valid for "
211 "chrono::duration"); }
212
213 [[noreturn,__gnu__::__always_inline__]]
214 inline void
215 __invalid_chrono_spec()
216 { __throw_format_error("format error: chrono-format-spec not valid for "
217 "argument type"); }
218
219 template<typename _CharT>
220 struct _ChronoSpec : _Spec<_CharT>
221 {
222 basic_string_view<_CharT> _M_chrono_specs;
223 };
224
225 // Represents the information provided by a chrono type.
226 // e.g. month_weekday has month and weekday but no year or time of day,
227 // hh_mm_ss has time of day but no date, sys_time is time_point+timezone.
228 enum _ChronoParts {
229 _Year = 1, _Month = 2, _Day = 4, _Weekday = 8, _TimeOfDay = 16,
230 _TimeZone = 32,
231 _Date = _Year | _Month | _Day | _Weekday,
232 _DateTime = _Date | _TimeOfDay,
233 _ZonedDateTime = _DateTime | _TimeZone,
234 _Duration = 128 // special case
235 };
236
237 constexpr _ChronoParts
238 operator|(_ChronoParts __x, _ChronoParts __y)
239 { return static_cast<_ChronoParts>((int)__x | (int)__y); }
240
241 // TODO rename this to chrono::__formatter? or chrono::__detail::__formatter?
242 template<typename _CharT>
243 struct __formatter_chrono
244 {
245 using __string_view = basic_string_view<_CharT>;
246 using __string = basic_string<_CharT>;
247
248 template<typename _ParseContext>
249 constexpr typename _ParseContext::iterator
250 _M_parse(_ParseContext& __pc, _ChronoParts __parts)
251 {
252 auto __first = __pc.begin();
253 auto __last = __pc.end();
254
255 _ChronoSpec<_CharT> __spec{};
256
257 auto __finalize = [this, &__spec] {
258 _M_spec = __spec;
259 };
260
261 auto __finished = [&] {
262 if (__first == __last || *__first == '}')
263 {
264 __finalize();
265 return true;
266 }
267 return false;
268 };
269
270 if (__finished())
271 return __first;
272
273 __first = __spec._M_parse_fill_and_align(__first, __last);
274 if (__finished())
275 return __first;
276
277 __first = __spec._M_parse_width(__first, __last, __pc);
278 if (__finished())
279 return __first;
280
281 if (__parts & _ChronoParts::_Duration)
282 {
283 __first = __spec._M_parse_precision(__first, __last, __pc);
284 if (__finished())
285 return __first;
286 }
287
288 __first = __spec._M_parse_locale(__first, __last);
289 if (__finished())
290 return __first;
291
292 // Everything up to the end of the string or the first '}' is a
293 // chrono-specs string. Check it is valid.
294 {
295 __string_view __str(__first, __last - __first);
296 auto __end = __str.find('}');
297 if (__end != __str.npos)
298 {
299 __str.remove_suffix(__str.length() - __end);
300 __last = __first + __end;
301 }
302 if (__str.find('{') != __str.npos)
303 __throw_format_error("chrono format error: '{' in chrono-specs");
304 }
305
306 // Parse chrono-specs in [first,last), checking each conversion-spec
307 // against __parts (so fail for %Y if no year in parts).
308 // Save range in __spec._M_chrono_specs.
309
310 const auto __chrono_specs = __first++; // Skip leading '%'
311 if (*__chrono_specs != '%')
312 __throw_format_error("chrono format error: no '%' at start of "
313 "chrono-specs");
314
315 _CharT __mod{};
316 bool __conv = true;
317 int __needed = 0;
318
319 while (__first != __last)
320 {
321 enum _Mods { _Mod_none, _Mod_E, _Mod_O, _Mod_E_O };
322 _Mods __allowed_mods = _Mod_none;
323
324 _CharT __c = *__first++;
325 switch (__c)
326 {
327 case 'a':
328 case 'A':
329 __needed = _Weekday;
330 break;
331 case 'b':
332 case 'h':
333 case 'B':
334 __needed = _Month;
335 break;
336 case 'c':
337 __needed = _DateTime;
338 __allowed_mods = _Mod_E;
339 break;
340 case 'C':
341 __needed = _Year;
342 __allowed_mods = _Mod_E;
343 break;
344 case 'd':
345 case 'e':
346 __needed = _Day;
347 __allowed_mods = _Mod_O;
348 break;
349 case 'D':
350 case 'F':
351 __needed = _Date;
352 break;
353 case 'g':
354 case 'G':
355 __needed = _Date;
356 break;
357 case 'H':
358 case 'I':
359 __needed = _TimeOfDay;
360 __allowed_mods = _Mod_O;
361 break;
362 case 'j':
363 if (!(__parts & _Duration))
364 __needed = _Date;
365 break;
366 case 'm':
367 __needed = _Month;
368 __allowed_mods = _Mod_O;
369 break;
370 case 'M':
371 __needed = _TimeOfDay;
372 __allowed_mods = _Mod_O;
373 break;
374 case 'p':
375 case 'r':
376 case 'R':
377 case 'T':
378 __needed = _TimeOfDay;
379 break;
380 case 'q':
381 case 'Q':
382 __needed = _Duration;
383 break;
384 case 'S':
385 __needed = _TimeOfDay;
386 __allowed_mods = _Mod_O;
387 break;
388 case 'u':
389 case 'w':
390 __needed = _Weekday;
391 __allowed_mods = _Mod_O;
392 break;
393 case 'U':
394 case 'V':
395 case 'W':
396 __needed = _Date;
397 __allowed_mods = _Mod_O;
398 break;
399 case 'x':
400 __needed = _Date;
401 __allowed_mods = _Mod_E;
402 break;
403 case 'X':
404 __needed = _TimeOfDay;
405 __allowed_mods = _Mod_E;
406 break;
407 case 'y':
408 __needed = _Year;
409 __allowed_mods = _Mod_E_O;
410 break;
411 case 'Y':
412 __needed = _Year;
413 __allowed_mods = _Mod_E;
414 break;
415 case 'z':
416 __needed = _TimeZone;
417 __allowed_mods = _Mod_E_O;
418 break;
419 case 'Z':
420 __needed = _TimeZone;
421 break;
422 case 'n':
423 case 't':
424 case '%':
425 break;
426 case 'O':
427 case 'E':
428 if (__mod) [[unlikely]]
429 {
430 __allowed_mods = _Mod_none;
431 break;
432 }
433 __mod = __c;
434 continue;
435 default:
436 __throw_format_error("chrono format error: invalid "
437 " specifier in chrono-specs");
438 }
439
440 if ((__mod == 'E' && !(__allowed_mods & _Mod_E))
441 || (__mod == 'O' && !(__allowed_mods & _Mod_O)))
442 __throw_format_error("chrono format error: invalid "
443 " modifier in chrono-specs");
444 __mod = _CharT();
445
446 if ((__parts & __needed) != __needed)
447 __throw_format_error("chrono format error: format argument "
448 "does not contain the information "
449 "required by the chrono-specs");
450
451 // Scan for next '%', ignoring literal-chars before it.
452 size_t __pos = __string_view(__first, __last - __first).find('%');
453 if (__pos == 0)
454 ++__first;
455 else
456 {
457 if (__pos == __string_view::npos)
458 {
459 __first = __last;
460 __conv = false;
461 }
462 else
463 __first += __pos + 1;
464 }
465 }
466
467 // Check for a '%' conversion-spec without a type.
468 if (__conv || __mod != _CharT())
469 __throw_format_error("chrono format error: unescaped '%' in "
470 "chrono-specs");
471
472 _M_spec = __spec;
473 _M_spec._M_chrono_specs
474 = __string_view(__chrono_specs, __first - __chrono_specs);
475
476 return __first;
477 }
478
479 // TODO this function template is instantiated for every different _Tp.
480 // Consider creating a polymorphic interface for calendar types so
481 // that we instantiate fewer different specializations. Similar to
482 // _Sink_iter for std::format. Replace each _S_year, _S_day etc. with
483 // member functions of that type.
484 template<typename _Tp, typename _FormatContext>
485 typename _FormatContext::iterator
486 _M_format(const _Tp& __t, _FormatContext& __fc,
487 bool __is_neg = false) const
488 {
489 auto __first = _M_spec._M_chrono_specs.begin();
490 const auto __last = _M_spec._M_chrono_specs.end();
491 if (__first == __last)
492 return _M_format_to_ostream(__t, __fc, __is_neg);
493
494 _Sink_iter<_CharT> __out;
495 __format::_Str_sink<_CharT> __sink;
496 bool __write_direct = false;
497 if constexpr (is_same_v<typename _FormatContext::iterator,
498 _Sink_iter<_CharT>>)
499 {
500 if (_M_spec._M_width_kind == __format::_WP_none)
501 {
502 __out = __fc.out();
503 __write_direct = true;
504 }
505 else
506 __out = __sink.out();
507 }
508 else
509 __out = __sink.out();
510
511 // formatter<duration> passes the correct value of __is_neg
512 // for durations but for hh_mm_ss we decide it here.
513 if constexpr (__is_specialization_of<_Tp, chrono::hh_mm_ss>)
514 __is_neg = __t.is_negative();
515
516 auto __print_sign = [&__is_neg, &__out] {
517 if constexpr (chrono::__is_duration_v<_Tp>
518 || __is_specialization_of<_Tp, chrono::hh_mm_ss>)
519 if (__is_neg)
520 {
521 *__out++ = _S_plus_minus[1];
522 __is_neg = false;
523 }
524 return std::move(__out);
525 };
526
527 // Characters to output for "%n", "%t" and "%%" specifiers.
528 constexpr const _CharT* __literals = _GLIBCXX_WIDEN("\n\t%");
529
530 ++__first; // Skip leading '%' at start of chrono-specs.
531
532 _CharT __mod{};
533 do
534 {
535 _CharT __c = *__first++;
536 switch (__c)
537 {
538 case 'a':
539 case 'A':
540 __out = _M_a_A(__t, std::move(__out), __fc, __c == 'A');
541 break;
542 case 'b':
543 case 'h':
544 case 'B':
545 __out = _M_b_B(__t, std::move(__out), __fc, __c == 'B');
546 break;
547 case 'c':
548 __out = _M_c(__t, std::move(__out), __fc, __mod == 'E');
549 break;
550 case 'C':
551 case 'y':
552 case 'Y':
553 __out = _M_C_y_Y(__t, std::move(__out), __fc, __c, __mod);
554 break;
555 case 'd':
556 case 'e':
557 __out = _M_d_e(__t, std::move(__out), __fc, __c, __mod == 'O');
558 break;
559 case 'D':
560 __out = _M_D(__t, std::move(__out), __fc);
561 break;
562 case 'F':
563 __out = _M_F(__t, std::move(__out), __fc);
564 break;
565 case 'g':
566 case 'G':
567 __out = _M_g_G(__t, std::move(__out), __fc, __c == 'G');
568 break;
569 case 'H':
570 case 'I':
571 __out = _M_H_I(__t, __print_sign(), __fc, __c, __mod == 'O');
572 break;
573 case 'j':
574 __out = _M_j(__t, __print_sign(), __fc);
575 break;
576 case 'm':
577 __out = _M_m(__t, std::move(__out), __fc, __mod == 'O');
578 break;
579 case 'M':
580 __out = _M_M(__t, __print_sign(), __fc, __mod == 'O');
581 break;
582 case 'p':
583 __out = _M_p(__t, std::move(__out), __fc);
584 break;
585 case 'q':
586 __out = _M_q(__t, std::move(__out), __fc);
587 break;
588 case 'Q':
589 // %Q The duration's numeric value.
590 if constexpr (chrono::__is_duration_v<_Tp>)
591 __out = std::format_to(__print_sign(), _S_empty_spec,
592 __t.count());
593 else
594 __throw_format_error("chrono format error: argument is "
595 "not a duration");
596 break;
597 case 'r':
598 __out = _M_r(__t, __print_sign(), __fc);
599 break;
600 case 'R':
601 case 'T':
602 __out = _M_R_T(__t, __print_sign(), __fc, __c == 'T');
603 break;
604 case 'S':
605 __out = _M_S(__t, __print_sign(), __fc, __mod == 'O');
606 break;
607 case 'u':
608 case 'w':
609 __out = _M_u_w(__t, std::move(__out), __fc, __c, __mod == 'O');
610 break;
611 case 'U':
612 case 'V':
613 case 'W':
614 __out = _M_U_V_W(__t, std::move(__out), __fc, __c,
615 __mod == 'O');
616 break;
617 case 'x':
618 __out = _M_x(__t, std::move(__out), __fc, __mod == 'E');
619 break;
620 case 'X':
621 __out = _M_X(__t, __print_sign(), __fc, __mod == 'E');
622 break;
623 case 'z':
624 __out = _M_z(__t, std::move(__out), __fc, (bool)__mod);
625 break;
626 case 'Z':
627 __out = _M_Z(__t, std::move(__out), __fc);
628 break;
629 case 'n':
630 *__out++ = __literals[0];
631 break;
632 case 't':
633 *__out++ = __literals[1];
634 break;
635 case '%':
636 *__out++ = __literals[2];
637 break;
638 case 'O':
639 case 'E':
640 __mod = __c;
641 continue;
642 case '}':
643 __first = __last;
644 break;
645 }
646 __mod = _CharT();
647 // Scan for next '%' and write out everything before it.
648 __string_view __str(__first, __last - __first);
649 size_t __pos = __str.find('%');
650 if (__pos == 0)
651 ++__first;
652 else
653 {
654 if (__pos == __str.npos)
655 __first = __last;
656 else
657 {
658 __str.remove_suffix(__str.length() - __pos);
659 __first += __pos + 1;
660 }
661 __out = __format::__write(std::move(__out), __str);
662 }
663 }
664 while (__first != __last);
665
666 if constexpr (is_same_v<typename _FormatContext::iterator,
667 _Sink_iter<_CharT>>)
668 if (__write_direct)
669 return __out;
670
671 auto __str = std::move(__sink).get();
672 return __format::__write_padded_as_spec(__str, __str.size(),
673 __fc, _M_spec);
674 }
675
676 _ChronoSpec<_CharT> _M_spec;
677
678 private:
679 // Return the formatting locale.
680 template<typename _FormatContext>
682 _M_locale(_FormatContext& __fc) const
683 {
684 if (!_M_spec._M_localized)
685 return std::locale::classic();
686 else
687 return __fc.locale();
688 }
689
690 // Format for empty chrono-specs, e.g. "{}" (C++20 [time.format] p6).
691 // TODO: consider moving body of every operator<< into this function
692 // and use std::format("{}", t) to implement those operators. That
693 // would avoid std::format("{}", t) calling operator<< which calls
694 // std::format again.
695 template<typename _Tp, typename _FormatContext>
696 typename _FormatContext::iterator
697 _M_format_to_ostream(const _Tp& __t, _FormatContext& __fc,
698 bool __is_neg) const
699 {
700 using ::std::chrono::__detail::__utc_leap_second;
701 using ::std::chrono::__detail::__local_time_fmt;
702
703 if constexpr (__is_specialization_of<_Tp, __local_time_fmt>)
704 return _M_format_to_ostream(__t._M_time, __fc, false);
705 else
706 {
707 basic_ostringstream<_CharT> __os;
708 __os.imbue(_M_locale(__fc));
709
710 if constexpr (__is_specialization_of<_Tp, __utc_leap_second>)
711 __os << __t._M_date << ' ' << __t._M_time;
712 else if constexpr (chrono::__is_time_point_v<_Tp>)
713 {
714 // Need to be careful here because not all specializations
715 // of chrono::sys_time can be written to an ostream.
716 // For the specializations of time_point that can be
717 // formatted with an empty chrono-specs, either it's a
718 // sys_time with period greater or equal to days:
719 if constexpr (is_convertible_v<_Tp, chrono::sys_days>)
720 __os << _S_date(__t);
721 else // Or it's formatted as "{:L%F %T}":
722 {
723 auto __days = chrono::floor<chrono::days>(__t);
724 __os << chrono::year_month_day(__days) << ' '
725 << chrono::hh_mm_ss(__t - __days);
726 }
727 }
728 else
729 {
730 if constexpr (chrono::__is_duration_v<_Tp>)
731 if (__is_neg) [[unlikely]]
732 __os << _S_plus_minus[1];
733 __os << __t;
734 }
735
736 auto __str = std::move(__os).str();
737 return __format::__write_padded_as_spec(__str, __str.size(),
738 __fc, _M_spec);
739 }
740 }
741
742 static constexpr const _CharT* _S_chars
743 = _GLIBCXX_WIDEN("0123456789+-:/ {}");
744 static constexpr const _CharT* _S_plus_minus = _S_chars + 10;
745 static constexpr _CharT _S_colon = _S_chars[12];
746 static constexpr _CharT _S_slash = _S_chars[13];
747 static constexpr _CharT _S_space = _S_chars[14];
748 static constexpr const _CharT* _S_empty_spec = _S_chars + 15;
749
750 template<typename _Tp, typename _FormatContext>
751 typename _FormatContext::iterator
752 _M_a_A(const _Tp& __t, typename _FormatContext::iterator __out,
753 _FormatContext& __ctx, bool __full) const
754 {
755 // %a Locale's abbreviated weekday name.
756 // %A Locale's full weekday name.
757 chrono::weekday __wd = _S_weekday(__t);
758 if (!__wd.ok())
759 __throw_format_error("format error: invalid weekday");
760
761 locale __loc = _M_locale(__ctx);
762 const auto& __tp = use_facet<__timepunct<_CharT>>(__loc);
763 const _CharT* __days[7];
764 if (__full)
765 __tp._M_days(__days);
766 else
767 __tp._M_days_abbreviated(__days);
768 __string_view __str(__days[__wd.c_encoding()]);
769 return __format::__write(std::move(__out), __str);
770 }
771
772 template<typename _Tp, typename _FormatContext>
773 typename _FormatContext::iterator
774 _M_b_B(const _Tp& __t, typename _FormatContext::iterator __out,
775 _FormatContext& __ctx, bool __full) const
776 {
777 // %b Locale's abbreviated month name.
778 // %B Locale's full month name.
779 chrono::month __m = _S_month(__t);
780 if (!__m.ok())
781 __throw_format_error("format error: invalid month");
782 locale __loc = _M_locale(__ctx);
783 const auto& __tp = use_facet<__timepunct<_CharT>>(__loc);
784 const _CharT* __months[12];
785 if (__full)
786 __tp._M_months(__months);
787 else
788 __tp._M_months_abbreviated(__months);
789 __string_view __str(__months[(unsigned)__m - 1]);
790 return __format::__write(std::move(__out), __str);
791 }
792
793 template<typename _Tp, typename _FormatContext>
794 typename _FormatContext::iterator
795 _M_c(const _Tp& __tt, typename _FormatContext::iterator __out,
796 _FormatContext& __ctx, bool __mod = false) const
797 {
798 // %c Locale's date and time representation.
799 // %Ec Locale's alternate date and time representation.
800
801 auto __t = _S_floor_seconds(__tt);
802 locale __loc = _M_locale(__ctx);
803 const auto& __tp = use_facet<__timepunct<_CharT>>(__loc);
804 const _CharT* __formats[2];
805 __tp._M_date_time_formats(__formats);
806 const _CharT* __rep = __formats[__mod];
807 if (!*__rep)
808 __rep = _GLIBCXX_WIDEN("%a %b %e %H:%M:%S %Y");
809 basic_string<_CharT> __fmt(_S_empty_spec);
810 __fmt.insert(1u, 1u, _S_colon);
811 __fmt.insert(2u, __rep);
812 return std::vformat_to(std::move(__out), __loc, __fmt,
813 std::make_format_args<_FormatContext>(__t));
814 }
815
816 template<typename _Tp, typename _FormatContext>
817 typename _FormatContext::iterator
818 _M_C_y_Y(const _Tp& __t, typename _FormatContext::iterator __out,
819 _FormatContext& __ctx, _CharT __conv, _CharT __mod = 0) const
820 {
821 // %C Year divided by 100 using floored division.
822 // %EC Locale's alternative preresentation of the century (era name).
823 // %y Last two decimal digits of the year.
824 // %Oy Locale's alternative representation.
825 // %Ey Locale's alternative representation of offset from %EC.
826 // %Y Year as a decimal number.
827 // %EY Locale's alternative full year representation.
828
829 chrono::year __y = _S_year(__t);
830
831 if (__mod) [[unlikely]]
832 {
833 struct tm __tm{};
834 __tm.tm_year = (int)__y - 1900;
835 return _M_locale_fmt(std::move(__out), _M_locale(__ctx), __tm,
836 __conv, __mod);
837 }
838
839 basic_string<_CharT> __s;
840 int __yi = (int)__y;
841 const bool __is_neg = __yi < 0;
842 __yi = __builtin_abs(__yi);
843
844 if (__conv == 'Y' || __conv == 'C')
845 {
846 int __ci = __yi / 100;
847 if (__is_neg) [[unlikely]]
848 {
849 __s.assign(1, _S_plus_minus[1]);
850 // For floored division -123//100 is -2 and -100//100 is -1
851 if (__conv == 'C' && (__ci * 100) != __yi)
852 ++__ci;
853 }
854 if (__ci >= 100) [[unlikely]]
855 {
856 __s += std::format(_S_empty_spec, __ci / 100);
857 __ci %= 100;
858 }
859 __s += _S_two_digits(__ci);
860 }
861
862 if (__conv == 'Y' || __conv == 'y')
863 __s += _S_two_digits(__yi % 100);
864
865 return __format::__write(std::move(__out), __string_view(__s));
866 }
867
868 template<typename _Tp, typename _FormatContext>
869 typename _FormatContext::iterator
870 _M_D(const _Tp& __t, typename _FormatContext::iterator __out,
871 _FormatContext&) const
872 {
873 auto __ymd = _S_date(__t);
874 basic_string<_CharT> __s;
875#if ! _GLIBCXX_USE_CXX11_ABI
876 __s.reserve(8);
877#endif
878 __s = _S_two_digits((unsigned)__ymd.month());
879 __s += _S_slash;
880 __s += _S_two_digits((unsigned)__ymd.day());
881 __s += _S_slash;
882 __s += _S_two_digits(__builtin_abs((int)__ymd.year()) % 100);
883 return __format::__write(std::move(__out), __string_view(__s));
884 }
885
886 template<typename _Tp, typename _FormatContext>
887 typename _FormatContext::iterator
888 _M_d_e(const _Tp& __t, typename _FormatContext::iterator __out,
889 _FormatContext& __ctx, _CharT __conv, bool __mod = false) const
890 {
891 // %d The day of month as a decimal number.
892 // %Od Locale's alternative representation.
893 // %e Day of month as decimal number, padded with space.
894 // %Oe Locale's alternative digits.
895
896 chrono::day __d = _S_day(__t);
897 unsigned __i = (unsigned)__d;
898
899 if (__mod) [[unlikely]]
900 {
901 struct tm __tm{};
902 __tm.tm_mday = __i;
903 return _M_locale_fmt(std::move(__out), _M_locale(__ctx), __tm,
904 (char)__conv, 'O');
905 }
906
907 auto __sv = _S_two_digits(__i);
908 _CharT __buf[2];
909 if (__conv == _CharT('e') && __i < 10)
910 {
911 __buf[0] = _S_space;
912 __buf[1] = __sv[1];
913 __sv = {__buf, 2};
914 }
915 return __format::__write(std::move(__out), __sv);
916 }
917
918 template<typename _Tp, typename _FormatContext>
919 typename _FormatContext::iterator
920 _M_F(const _Tp& __t, typename _FormatContext::iterator __out,
921 _FormatContext&) const
922 {
923 auto __ymd = _S_date(__t);
924 basic_string<_CharT> __s;
925#if ! _GLIBCXX_USE_CXX11_ABI
926 __s.reserve(11);
927#endif
928 __s += std::format(_GLIBCXX_WIDEN("{:04d}- - "), (int)__ymd.year());
929 auto __sv = _S_two_digits((unsigned)__ymd.month());
930 __s[__s.size() - 5] = __sv[0];
931 __s[__s.size() - 4] = __sv[1];
932 __sv = _S_two_digits((unsigned)__ymd.day());
933 __s[__s.size() - 2] = __sv[0];
934 __s[__s.size() - 1] = __sv[1];
935 __sv = __s;
936 return __format::__write(std::move(__out), __sv);
937 }
938
939 template<typename _Tp, typename _FormatContext>
940 typename _FormatContext::iterator
941 _M_g_G(const _Tp& __t, typename _FormatContext::iterator __out,
942 _FormatContext& __ctx, bool __full) const
943 {
944 // %g last two decimal digits of the ISO week-based year.
945 // %G ISO week-based year.
946 using namespace chrono;
947 auto __d = _S_days(__t);
948 // Move to nearest Thursday:
949 __d -= (weekday(__d) - Monday) - days(3);
950 // ISO week-based year is the year that contains that Thursday:
951 year __y = year_month_day(__d).year();
952 return _M_C_y_Y(__y, std::move(__out), __ctx, "yY"[__full]);
953 }
954
955 template<typename _Tp, typename _FormatContext>
956 typename _FormatContext::iterator
957 _M_H_I(const _Tp& __t, typename _FormatContext::iterator __out,
958 _FormatContext& __ctx, _CharT __conv, bool __mod = false) const
959 {
960 // %H The hour (24-hour clock) as a decimal number.
961 // %OH Locale's alternative representation.
962 // %I The hour (12-hour clock) as a decimal number.
963 // %OI Locale's alternative representation.
964
965 const auto __hms = _S_hms(__t);
966 int __i = __hms.hours().count();
967
968 if (__mod) [[unlikely]]
969 {
970 struct tm __tm{};
971 __tm.tm_hour = __i;
972 return _M_locale_fmt(std::move(__out), _M_locale(__ctx), __tm,
973 (char)__conv, 'O');
974 }
975
976 if (__conv == _CharT('I'))
977 {
978 if (__i == 0)
979 __i = 12;
980 else if (__i > 12)
981 __i -= 12;
982 }
983 return __format::__write(std::move(__out), _S_two_digits(__i));
984 }
985
986 template<typename _Tp, typename _FormatContext>
987 typename _FormatContext::iterator
988 _M_j(const _Tp& __t, typename _FormatContext::iterator __out,
989 _FormatContext&) const
990 {
991 if constexpr (chrono::__is_duration_v<_Tp>)
992 {
993 // Decimal number of days, without padding.
994 unsigned __d = chrono::duration_cast<chrono::days>(__t).count();
995 return std::format_to(std::move(__out), _S_empty_spec, __d);
996 }
997 else
998 {
999 // Day of the year as a decimal number, padding with zero.
1000 using namespace chrono;
1001 auto __day = _S_days(__t);
1002 auto __ymd = _S_date(__t);
1003 days __d;
1004 // See "Calculating Ordinal Dates" at
1005 // https://github.com/HowardHinnant/date/wiki/Examples-and-Recipes
1006 if constexpr (is_same_v<typename decltype(__day)::clock, local_t>)
1007 __d = __day - local_days(__ymd.year()/January/0);
1008 else
1009 __d = __day - sys_days(__ymd.year()/January/0);
1010 return std::format_to(std::move(__out), _GLIBCXX_WIDEN("{:03d}"),
1011 __d.count());
1012 }
1013 }
1014
1015 template<typename _Tp, typename _FormatContext>
1016 typename _FormatContext::iterator
1017 _M_m(const _Tp& __t, typename _FormatContext::iterator __out,
1018 _FormatContext& __ctx, bool __mod) const
1019 {
1020 // %m month as a decimal number.
1021 // %Om Locale's alternative representation.
1022
1023 auto __m = _S_month(__t);
1024 auto __i = (unsigned)__m;
1025
1026 if (__mod) [[unlikely]] // %Om
1027 {
1028 struct tm __tm{};
1029 __tm.tm_mon = __i - 1;
1030 return _M_locale_fmt(std::move(__out), _M_locale(__ctx), __tm,
1031 'm', 'O');
1032 }
1033
1034 return __format::__write(std::move(__out), _S_two_digits(__i));
1035 }
1036
1037 template<typename _Tp, typename _FormatContext>
1038 typename _FormatContext::iterator
1039 _M_M(const _Tp& __t, typename _FormatContext::iterator __out,
1040 _FormatContext& __ctx, bool __mod) const
1041 {
1042 // %M The minute as a decimal number.
1043 // %OM Locale's alternative representation.
1044
1045 auto __m = _S_hms(__t).minutes();
1046 auto __i = __m.count();
1047
1048 if (__mod) [[unlikely]] // %OM
1049 {
1050 struct tm __tm{};
1051 __tm.tm_min = __i;
1052 return _M_locale_fmt(std::move(__out), _M_locale(__ctx), __tm,
1053 'M', 'O');
1054 }
1055
1056 return __format::__write(std::move(__out), _S_two_digits(__i));
1057 }
1058
1059 template<typename _Tp, typename _FormatContext>
1060 typename _FormatContext::iterator
1061 _M_p(const _Tp& __t, typename _FormatContext::iterator __out,
1062 _FormatContext& __ctx) const
1063 {
1064 // %p The locale's equivalent of the AM/PM designations.
1065 auto __hms = _S_hms(__t);
1066 locale __loc = _M_locale(__ctx);
1067 const auto& __tp = use_facet<__timepunct<_CharT>>(__loc);
1068 const _CharT* __ampm[2];
1069 __tp._M_am_pm(__ampm);
1070 return std::format_to(std::move(__out), _S_empty_spec,
1071 __ampm[__hms.hours().count() >= 12]);
1072 }
1073
1074 template<typename _Tp, typename _FormatContext>
1075 typename _FormatContext::iterator
1076 _M_q(const _Tp&, typename _FormatContext::iterator __out,
1077 _FormatContext& __ctx) const
1078 {
1079 // %q The duration's unit suffix
1080 if constexpr (!chrono::__is_duration_v<_Tp>)
1081 __throw_format_error("format error: argument is not a duration");
1082 else
1083 {
1084 using period = typename _Tp::period;
1085 char __buf[sizeof("[/]s") + 2 * numeric_limits<intmax_t>::digits10];
1086 constexpr size_t __n = sizeof(__buf);
1087 auto __s = chrono::__detail::__units_suffix<period, _CharT>(__buf,
1088 __n);
1089 if constexpr (is_same_v<decltype(__s), const _CharT*>)
1090 return std::format_to(std::move(__out), _S_empty_spec, __s);
1091 else
1092 {
1093 // Suffix was written to __buf as narrow string.
1094 _CharT __wbuf[__n];
1095 size_t __len = __builtin_strlen(__buf);
1096 locale __loc = _M_locale(__ctx);
1097 auto& __ct = use_facet<ctype<_CharT>>(__loc);
1098 __ct.widen(__buf, __len, __wbuf);
1099 __wbuf[__len] = 0;
1100 return std::format_to(std::move(__out), _S_empty_spec,
1101 __wbuf);
1102 }
1103 }
1104 }
1105
1106 // %Q handled in _M_format
1107
1108 template<typename _Tp, typename _FormatContext>
1109 typename _FormatContext::iterator
1110 _M_r(const _Tp& __tt, typename _FormatContext::iterator __out,
1111 _FormatContext& __ctx) const
1112 {
1113 // %r locale's 12-hour clock time.
1114 auto __t = _S_floor_seconds(__tt);
1115 locale __loc = _M_locale(__ctx);
1116 const auto& __tp = use_facet<__timepunct<_CharT>>(__loc);
1117 const _CharT* __ampm_fmt;
1118 __tp._M_am_pm_format(&__ampm_fmt);
1119 basic_string<_CharT> __fmt(_S_empty_spec);
1120 __fmt.insert(1u, 1u, _S_colon);
1121 __fmt.insert(2u, __ampm_fmt);
1122 return std::vformat_to(std::move(__out), __fmt,
1123 std::make_format_args<_FormatContext>(__t));
1124 }
1125
1126 template<typename _Tp, typename _FormatContext>
1127 typename _FormatContext::iterator
1128 _M_R_T(const _Tp& __t, typename _FormatContext::iterator __out,
1129 _FormatContext& __ctx, bool __secs) const
1130 {
1131 // %R Equivalent to %H:%M
1132 // %T Equivalent to %H:%M:%S
1133 auto __hms = _S_hms(__t);
1134
1135 basic_string<_CharT> __s;
1136#if ! _GLIBCXX_USE_CXX11_ABI
1137 __s.reserve(11);
1138#endif
1139 __s = std::format(_GLIBCXX_WIDEN("{:02d}:00"), __hms.hours().count());
1140 auto __sv = _S_two_digits(__hms.minutes().count());
1141 __s[__s.size() - 2] = __sv[0];
1142 __s[__s.size() - 1] = __sv[1];
1143 __sv = __s;
1144 __out = __format::__write(std::move(__out), __sv);
1145 if (__secs)
1146 {
1147 *__out++ = _S_colon;
1148 __out = _M_S(__hms, std::move(__out), __ctx);
1149 }
1150 return __out;
1151 }
1152
1153 template<typename _Tp, typename _FormatContext>
1154 typename _FormatContext::iterator
1155 _M_S(const _Tp& __t, typename _FormatContext::iterator __out,
1156 _FormatContext& __ctx, bool __mod = false) const
1157 {
1158 // %S Seconds as a decimal number.
1159 // %OS The locale's alternative representation.
1160 auto __hms = _S_hms(__t);
1161
1162 if (__mod) [[unlikely]] // %OS
1163 {
1164 struct tm __tm{};
1165 __tm.tm_sec = (int)__hms.seconds().count();
1166 return _M_locale_fmt(std::move(__out), _M_locale(__ctx), __tm,
1167 'S', 'O');
1168 }
1169
1170 if constexpr (__hms.fractional_width == 0)
1171 __out = __format::__write(std::move(__out),
1172 _S_two_digits(__hms.seconds().count()));
1173 else
1174 {
1175 locale __loc = _M_locale(__ctx);
1176 auto __s = __hms.seconds();
1177 auto __ss = __hms.subseconds();
1178 using rep = typename decltype(__ss)::rep;
1179 if constexpr (is_floating_point_v<rep>)
1180 {
1181 chrono::duration<rep> __fs = __s + __ss;
1182 __out = std::format_to(std::move(__out), __loc,
1183 _GLIBCXX_WIDEN("{:#0{}.{}Lf}"),
1184 __fs.count(),
1185 3 + __hms.fractional_width,
1186 __hms.fractional_width);
1187 }
1188 else
1189 {
1190 const auto& __np
1191 = use_facet<numpunct<_CharT>>(__loc);
1192 __out = __format::__write(std::move(__out),
1193 _S_two_digits(__s.count()));
1194 *__out++ = __np.decimal_point();
1195 if constexpr (is_integral_v<rep>)
1196 __out = std::format_to(std::move(__out),
1197 _GLIBCXX_WIDEN("{:0{}}"),
1198 __ss.count(),
1199 __hms.fractional_width);
1200 else
1201 {
1202 auto __str = std::format(_S_empty_spec, __ss.count());
1203 __out = std::format_to(_GLIBCXX_WIDEN("{:0>{}s}"),
1204 __str,
1205 __hms.fractional_width);
1206 }
1207 }
1208 }
1209 return __out;
1210 }
1211
1212 // %t handled in _M_format
1213
1214 template<typename _Tp, typename _FormatContext>
1215 typename _FormatContext::iterator
1216 _M_u_w(const _Tp& __t, typename _FormatContext::iterator __out,
1217 _FormatContext& __ctx, _CharT __conv, bool __mod = false) const
1218 {
1219 // %u ISO weekday as a decimal number (1-7), where Monday is 1.
1220 // %Ou Locale's alternative numeric rep.
1221 // %w Weekday as a decimal number (0-6), where Sunday is 0.
1222 // %Ow Locale's alternative numeric rep.
1223
1224 chrono::weekday __wd = _S_weekday(__t);
1225
1226 if (__mod) [[unlikely]]
1227 {
1228 struct tm __tm{};
1229 __tm.tm_wday = __wd.c_encoding();
1230 return _M_locale_fmt(std::move(__out), _M_locale(__ctx), __tm,
1231 (char)__conv, 'O');
1232 }
1233
1234 unsigned __wdi = __conv == 'u' ? __wd.iso_encoding()
1235 : __wd.c_encoding();
1236 const _CharT __d = _S_digit(__wdi);
1237 return __format::__write(std::move(__out), __string_view(&__d, 1));
1238 }
1239
1240 template<typename _Tp, typename _FormatContext>
1241 typename _FormatContext::iterator
1242 _M_U_V_W(const _Tp& __t, typename _FormatContext::iterator __out,
1243 _FormatContext& __ctx, _CharT __conv, bool __mod = false) const
1244 {
1245 // %U Week number of the year as a decimal number, from first Sunday.
1246 // %OU Locale's alternative numeric rep.
1247 // %V ISO week-based week number as a decimal number.
1248 // %OV Locale's alternative numeric rep.
1249 // %W Week number of the year as a decimal number, from first Monday.
1250 // %OW Locale's alternative numeric rep.
1251 using namespace chrono;
1252 auto __d = _S_days(__t);
1253 using _TDays = decltype(__d); // Either sys_days or local_days.
1254
1255 if (__mod) [[unlikely]]
1256 {
1257 const year_month_day __ymd(__d);
1258 const year __y = __ymd.year();
1259 struct tm __tm{};
1260 __tm.tm_year = (int)__y - 1900;
1261 __tm.tm_yday = (__d - _TDays(__y/January/1)).count();
1262 __tm.tm_wday = weekday(__d).c_encoding();
1263 return _M_locale_fmt(std::move(__out), _M_locale(__ctx), __tm,
1264 (char)__conv, 'O');
1265 }
1266
1267 _TDays __first; // First day of week 1.
1268 if (__conv == 'V') // W01 begins on Monday before first Thursday.
1269 {
1270 // Move to nearest Thursday:
1271 __d -= (weekday(__d) - Monday) - days(3);
1272 // ISO week of __t is number of weeks since January 1 of the
1273 // same year as that nearest Thursday.
1274 __first = _TDays(year_month_day(__d).year()/January/1);
1275 }
1276 else
1277 {
1278 year __y;
1279 if constexpr (requires { __t.year(); })
1280 __y = __t.year();
1281 else
1282 __y = year_month_day(__d).year();
1283 const weekday __weekstart = __conv == 'U' ? Sunday : Monday;
1284 __first = _TDays(__y/January/__weekstart[1]);
1285 }
1286 auto __weeks = chrono::floor<weeks>(__d - __first);
1287 __string_view __sv = _S_two_digits(__weeks.count() + 1);
1288 return __format::__write(std::move(__out), __sv);
1289 }
1290
1291 template<typename _Tp, typename _FormatContext>
1292 typename _FormatContext::iterator
1293 _M_x(const _Tp& __t, typename _FormatContext::iterator __out,
1294 _FormatContext& __ctx, bool __mod = false) const
1295 {
1296 // %x Locale's date rep
1297 // %Ex Locale's alternative date representation.
1298 locale __loc = _M_locale(__ctx);
1299 const auto& __tp = use_facet<__timepunct<_CharT>>(__loc);
1300 const _CharT* __date_reps[2];
1301 __tp._M_date_formats(__date_reps);
1302 const _CharT* __rep = __date_reps[__mod];
1303 if (!*__rep)
1304 return _M_D(__t, std::move(__out), __ctx);
1305
1306 basic_string<_CharT> __fmt(_S_empty_spec);
1307 __fmt.insert(1u, 1u, _S_colon);
1308 __fmt.insert(2u, __rep);
1309 return std::vformat_to(std::move(__out), __fmt,
1310 std::make_format_args<_FormatContext>(__t));
1311 }
1312
1313 template<typename _Tp, typename _FormatContext>
1314 typename _FormatContext::iterator
1315 _M_X(const _Tp& __tt, typename _FormatContext::iterator __out,
1316 _FormatContext& __ctx, bool __mod = false) const
1317 {
1318 // %X Locale's time rep
1319 // %EX Locale's alternative time representation.
1320 auto __t = _S_floor_seconds(__tt);
1321 locale __loc = _M_locale(__ctx);
1322 const auto& __tp = use_facet<__timepunct<_CharT>>(__loc);
1323 const _CharT* __time_reps[2];
1324 __tp._M_time_formats(__time_reps);
1325 const _CharT* __rep = __time_reps[__mod];
1326 if (!*__rep)
1327 return _M_R_T(__t, std::move(__out), __ctx, true);
1328
1329 basic_string<_CharT> __fmt(_S_empty_spec);
1330 __fmt.insert(1u, 1u, _S_colon);
1331 __fmt.insert(2u, __rep);
1332 return std::vformat_to(std::move(__out), __fmt,
1333 std::make_format_args<_FormatContext>(__t));
1334 }
1335
1336 template<typename _Tp, typename _FormatContext>
1337 typename _FormatContext::iterator
1338 _M_z(const _Tp& __t, typename _FormatContext::iterator __out,
1339 _FormatContext&, bool __mod = false) const
1340 {
1341 using ::std::chrono::__detail::__utc_leap_second;
1342 using ::std::chrono::__detail::__local_time_fmt;
1343
1344 auto __utc = __mod ? __string_view(_GLIBCXX_WIDEN("+00:00"), 6)
1345 : __string_view(_GLIBCXX_WIDEN("+0000"), 5);
1346
1347 if constexpr (chrono::__is_time_point_v<_Tp>)
1348 {
1349 if constexpr (is_same_v<typename _Tp::clock,
1350 chrono::system_clock>)
1351 return __format::__write(std::move(__out), __utc);
1352 }
1353 else if constexpr (__is_specialization_of<_Tp, __local_time_fmt>)
1354 {
1355 if (__t._M_offset_sec)
1356 {
1357 auto __sv = __utc;
1358 basic_string<_CharT> __s;
1359 if (*__t._M_offset_sec != 0s)
1360 {
1361 chrono:: hh_mm_ss __hms(*__t._M_offset_sec);
1362 __s = _S_plus_minus[__hms.is_negative()];
1363 __s += _S_two_digits(__hms.hours().count());
1364 if (__mod)
1365 __s += _S_colon;
1366 __s += _S_two_digits(__hms.minutes().count());
1367 __sv = __s;
1368 }
1369 return __format::__write(std::move(__out), __sv);
1370 }
1371 }
1372 else if constexpr (__is_specialization_of<_Tp, __utc_leap_second>)
1373 return __format::__write(std::move(__out), __utc);
1374
1375 __no_timezone_available();
1376 }
1377
1378 template<typename _Tp, typename _FormatContext>
1379 typename _FormatContext::iterator
1380 _M_Z(const _Tp& __t, typename _FormatContext::iterator __out,
1381 _FormatContext& __ctx) const
1382 {
1383 using ::std::chrono::__detail::__utc_leap_second;
1384 using ::std::chrono::__detail::__local_time_fmt;
1385
1386 __string_view __utc(_GLIBCXX_WIDEN("UTC"), 3);
1387 if constexpr (chrono::__is_time_point_v<_Tp>)
1388 {
1389 if constexpr (is_same_v<typename _Tp::clock,
1390 chrono::system_clock>)
1391 return __format::__write(std::move(__out), __utc);
1392 }
1393 else if constexpr (__is_specialization_of<_Tp, __local_time_fmt>)
1394 {
1395 if (__t._M_abbrev)
1396 {
1397 __string_view __wsv;
1398 if constexpr (is_same_v<_CharT, char>)
1399 __wsv = *__t._M_abbrev;
1400 else
1401 {
1402 string_view __sv = *__t._M_abbrev;
1403 basic_string<_CharT> __ws(__sv.size(), _CharT());
1404 auto& __ct = use_facet<ctype<_CharT>>(_M_locale(__ctx));
1405 __ct.widen(__sv.begin(), __sv.end(), __ws.data());
1406 __wsv = __ws;
1407 }
1408 return __format::__write(std::move(__out), __wsv);
1409 }
1410 }
1411 else if constexpr (__is_specialization_of<_Tp, __utc_leap_second>)
1412 return __format::__write(std::move(__out), __utc);
1413
1414 __no_timezone_available();
1415 }
1416
1417 // %% handled in _M_format
1418
1419 // A single digit character in the range '0'..'9'.
1420 static _CharT
1421 _S_digit(int __n) noexcept
1422 {
1423 // Extra 9s avoid past-the-end read on bad input.
1424 return _GLIBCXX_WIDEN("0123456789999999")[__n & 0xf];
1425 }
1426
1427 // A string view of two digit characters, "00".."99".
1428 static basic_string_view<_CharT>
1429 _S_two_digits(int __n) noexcept
1430 {
1431 return {
1432 _GLIBCXX_WIDEN("0001020304050607080910111213141516171819"
1433 "2021222324252627282930313233343536373839"
1434 "4041424344454647484950515253545556575859"
1435 "6061626364656667686970717273747576777879"
1436 "8081828384858687888990919293949596979899"
1437 "9999999999999999999999999999999999999999"
1438 "9999999999999999") + 2 * (__n & 0x7f),
1439 2
1440 };
1441 }
1442
1443 // Accessors for the components of chrono types:
1444
1445 // Returns a hh_mm_ss.
1446 template<typename _Tp>
1447 static decltype(auto)
1448 _S_hms(const _Tp& __t)
1449 {
1450 using ::std::chrono::__detail::__utc_leap_second;
1451 using ::std::chrono::__detail::__local_time_fmt;
1452
1453 if constexpr (__is_specialization_of<_Tp, chrono::hh_mm_ss>)
1454 return __t;
1455 else if constexpr (__is_specialization_of<_Tp, __utc_leap_second>)
1456 return __t._M_time;
1457 else if constexpr (chrono::__is_duration_v<_Tp>)
1458 return chrono::hh_mm_ss<_Tp>(__t);
1459 else if constexpr (chrono::__is_time_point_v<_Tp>)
1460 return chrono::hh_mm_ss(__t - chrono::floor<chrono::days>(__t));
1461 else if constexpr (__is_specialization_of<_Tp, __local_time_fmt>)
1462 return _S_hms(__t._M_time);
1463 else
1464 {
1465 __invalid_chrono_spec();
1466 return chrono::hh_mm_ss<chrono::seconds>();
1467 }
1468 }
1469
1470 // Returns a sys_days or local_days.
1471 template<typename _Tp>
1472 static auto
1473 _S_days(const _Tp& __t)
1474 {
1475 using namespace chrono;
1476 using ::std::chrono::__detail::__utc_leap_second;
1477 using ::std::chrono::__detail::__local_time_fmt;
1478
1479 if constexpr (__is_time_point_v<_Tp>)
1480 return chrono::floor<days>(__t);
1481 else if constexpr (__is_specialization_of<_Tp, __utc_leap_second>)
1482 return __t._M_date;
1483 else if constexpr (__is_specialization_of<_Tp, __local_time_fmt>)
1484 return chrono::floor<days>(__t._M_time);
1485 else if constexpr (is_same_v<_Tp, year_month_day>
1486 || is_same_v<_Tp, year_month_day_last>
1487 || is_same_v<_Tp, year_month_weekday>
1488 || is_same_v<_Tp, year_month_weekday_last>)
1489 return sys_days(__t);
1490 else
1491 {
1492 if constexpr (__is_duration_v<_Tp>)
1493 __not_valid_for_duration();
1494 else
1495 __invalid_chrono_spec();
1496 return chrono::sys_days();
1497 }
1498 }
1499
1500 // Returns a year_month_day.
1501 template<typename _Tp>
1502 static chrono::year_month_day
1503 _S_date(const _Tp& __t)
1504 {
1505 if constexpr (is_same_v<_Tp, chrono::year_month_day>)
1506 return __t;
1507 else
1508 return chrono::year_month_day(_S_days(__t));
1509 }
1510
1511 template<typename _Tp>
1512 static chrono::day
1513 _S_day(const _Tp& __t)
1514 {
1515 using namespace chrono;
1516
1517 if constexpr (is_same_v<_Tp, day>)
1518 return __t;
1519 else if constexpr (requires { __t.day(); })
1520 return __t.day();
1521 else
1522 return _S_date(__t).day();
1523 }
1524
1525 template<typename _Tp>
1526 static chrono::month
1527 _S_month(const _Tp& __t)
1528 {
1529 using namespace chrono;
1530
1531 if constexpr (is_same_v<_Tp, month>)
1532 return __t;
1533 else if constexpr (requires { __t.month(); })
1534 return __t.month();
1535 else
1536 return _S_date(__t).month();
1537 }
1538
1539 template<typename _Tp>
1540 static chrono::year
1541 _S_year(const _Tp& __t)
1542 {
1543 using namespace chrono;
1544
1545 if constexpr (is_same_v<_Tp, year>)
1546 return __t;
1547 else if constexpr (requires { __t.year(); })
1548 return __t.year();
1549 else
1550 return _S_date(__t).year();
1551 }
1552
1553 template<typename _Tp>
1554 static chrono::weekday
1555 _S_weekday(const _Tp& __t)
1556 {
1557 using namespace ::std::chrono;
1558 using ::std::chrono::__detail::__local_time_fmt;
1559
1560 if constexpr (is_same_v<_Tp, weekday>)
1561 return __t;
1562 else if constexpr (requires { __t.weekday(); })
1563 return __t.weekday();
1564 else if constexpr (is_same_v<_Tp, month_weekday>)
1565 return __t.weekday_indexed().weekday();
1566 else if constexpr (is_same_v<_Tp, month_weekday_last>)
1567 return __t.weekday_last().weekday();
1568 else
1569 return weekday(_S_days(__t));
1570 }
1571
1572 // Remove subsecond precision from a time_point.
1573 template<typename _Tp>
1574 static auto
1575 _S_floor_seconds(const _Tp& __t)
1576 {
1577 using chrono::__detail::__local_time_fmt;
1578 if constexpr (chrono::__is_time_point_v<_Tp>
1579 || chrono::__is_duration_v<_Tp>)
1580 {
1581 if constexpr (_Tp::period::den != 1)
1582 return chrono::floor<chrono::seconds>(__t);
1583 else
1584 return __t;
1585 }
1586 else if constexpr (__is_specialization_of<_Tp, chrono::hh_mm_ss>)
1587 {
1588 if constexpr (_Tp::fractional_width != 0)
1589 return chrono::floor<chrono::seconds>(__t.to_duration());
1590 else
1591 return __t;
1592 }
1593 else if constexpr (__is_specialization_of<_Tp, __local_time_fmt>)
1594 return _S_floor_seconds(__t._M_time);
1595 else
1596 return __t;
1597 }
1598
1599 // Use the formatting locale's std::time_put facet to produce
1600 // a locale-specific representation.
1601 template<typename _Iter>
1602 _Iter
1603 _M_locale_fmt(_Iter __out, const locale& __loc, const struct tm& __tm,
1604 char __fmt, char __mod) const
1605 {
1606 basic_ostringstream<_CharT> __os;
1607 const auto& __tp = use_facet<time_put<_CharT>>(__loc);
1608 __tp.put(__os, __os, _S_space, &__tm, __fmt, __mod);
1609 if (__os)
1610 __out = __format::__write(std::move(__out), __os.view());
1611 return __out;
1612 }
1613 };
1614
1615} // namespace __format
1616/// @endcond
1617
1618 template<typename _Rep, typename _Period, typename _CharT>
1619 struct formatter<chrono::duration<_Rep, _Period>, _CharT>
1620 {
1621 constexpr typename basic_format_parse_context<_CharT>::iterator
1622 parse(basic_format_parse_context<_CharT>& __pc)
1623 {
1624 using namespace __format;
1625 auto __it = _M_f._M_parse(__pc, _Duration|_TimeOfDay);
1626 if constexpr (!is_floating_point_v<_Rep>)
1627 if (_M_f._M_spec._M_prec_kind != __format::_WP_none)
1628 __throw_format_error("format error: invalid precision for duration");
1629 return __it;
1630 }
1631
1632 template<typename _Out>
1633 typename basic_format_context<_Out, _CharT>::iterator
1634 format(const chrono::duration<_Rep, _Period>& __d,
1635 basic_format_context<_Out, _CharT>& __fc) const
1636 {
1637 return _M_f._M_format(chrono::abs(__d), __fc, __d < __d.zero());
1638 }
1639
1640 private:
1641 __format::__formatter_chrono<_CharT> _M_f;
1642 };
1643
1644 template<typename _CharT>
1645 struct formatter<chrono::day, _CharT>
1646 {
1647 template<typename _ParseContext>
1648 constexpr typename _ParseContext::iterator
1649 parse(_ParseContext& __pc)
1650 { return _M_f._M_parse(__pc, __format::_Day); }
1651
1652 template<typename _FormatContext>
1653 typename _FormatContext::iterator
1654 format(const chrono::day& __t, _FormatContext& __fc) const
1655 { return _M_f._M_format(__t, __fc); }
1656
1657 private:
1658 __format::__formatter_chrono<_CharT> _M_f;
1659 };
1660
1661 template<typename _CharT>
1662 struct formatter<chrono::month, _CharT>
1663 {
1664 template<typename _ParseContext>
1665 constexpr typename _ParseContext::iterator
1666 parse(_ParseContext& __pc)
1667 { return _M_f._M_parse(__pc, __format::_Month); }
1668
1669 template<typename _FormatContext>
1670 typename _FormatContext::iterator
1671 format(const chrono::month& __t, _FormatContext& __fc) const
1672 { return _M_f._M_format(__t, __fc); }
1673
1674 private:
1675 __format::__formatter_chrono<_CharT> _M_f;
1676 };
1677
1678 template<typename _CharT>
1679 struct formatter<chrono::year, _CharT>
1680 {
1681 template<typename _ParseContext>
1682 constexpr typename _ParseContext::iterator
1683 parse(_ParseContext& __pc)
1684 { return _M_f._M_parse(__pc, __format::_Year); }
1685
1686 template<typename _FormatContext>
1687 typename _FormatContext::iterator
1688 format(const chrono::year& __t, _FormatContext& __fc) const
1689 { return _M_f._M_format(__t, __fc); }
1690
1691 private:
1692 __format::__formatter_chrono<_CharT> _M_f;
1693 };
1694
1695 template<typename _CharT>
1696 struct formatter<chrono::weekday, _CharT>
1697 {
1698 template<typename _ParseContext>
1699 constexpr typename _ParseContext::iterator
1700 parse(_ParseContext& __pc)
1701 { return _M_f._M_parse(__pc, __format::_Weekday); }
1702
1703 template<typename _FormatContext>
1704 typename _FormatContext::iterator
1705 format(const chrono::weekday& __t, _FormatContext& __fc) const
1706 { return _M_f._M_format(__t, __fc); }
1707
1708 private:
1709 __format::__formatter_chrono<_CharT> _M_f;
1710 };
1711
1712 template<typename _CharT>
1713 struct formatter<chrono::weekday_indexed, _CharT>
1714 {
1715 template<typename _ParseContext>
1716 constexpr typename _ParseContext::iterator
1717 parse(_ParseContext& __pc)
1718 { return _M_f._M_parse(__pc, __format::_Weekday); }
1719
1720 template<typename _FormatContext>
1721 typename _FormatContext::iterator
1722 format(const chrono::weekday_indexed& __t, _FormatContext& __fc) const
1723 { return _M_f._M_format(__t, __fc); }
1724
1725 private:
1726 __format::__formatter_chrono<_CharT> _M_f;
1727 };
1728
1729 template<typename _CharT>
1730 struct formatter<chrono::weekday_last, _CharT>
1731 {
1732 template<typename _ParseContext>
1733 constexpr typename _ParseContext::iterator
1734 parse(_ParseContext& __pc)
1735 { return _M_f._M_parse(__pc, __format::_Weekday); }
1736
1737 template<typename _FormatContext>
1738 typename _FormatContext::iterator
1739 format(const chrono::weekday_last& __t, _FormatContext& __fc) const
1740 { return _M_f._M_format(__t, __fc); }
1741
1742 private:
1743 __format::__formatter_chrono<_CharT> _M_f;
1744 };
1745
1746 template<typename _CharT>
1747 struct formatter<chrono::month_day, _CharT>
1748 {
1749 template<typename _ParseContext>
1750 constexpr typename _ParseContext::iterator
1751 parse(_ParseContext& __pc)
1752 { return _M_f._M_parse(__pc, __format::_Month|__format::_Day); }
1753
1754 template<typename _FormatContext>
1755 typename _FormatContext::iterator
1756 format(const chrono::month_day& __t, _FormatContext& __fc) const
1757 { return _M_f._M_format(__t, __fc); }
1758
1759 private:
1760 __format::__formatter_chrono<_CharT> _M_f;
1761 };
1762
1763 template<typename _CharT>
1764 struct formatter<chrono::month_day_last, _CharT>
1765 {
1766 template<typename _ParseContext>
1767 constexpr typename _ParseContext::iterator
1768 parse(_ParseContext& __pc)
1769 { return _M_f._M_parse(__pc, __format::_Month|__format::_Day); }
1770
1771 template<typename _FormatContext>
1772 typename _FormatContext::iterator
1773 format(const chrono::month_day_last& __t, _FormatContext& __fc) const
1774 { return _M_f._M_format(__t, __fc); }
1775
1776 private:
1777 __format::__formatter_chrono<_CharT> _M_f;
1778 };
1779
1780 template<typename _CharT>
1781 struct formatter<chrono::month_weekday, _CharT>
1782 {
1783 template<typename _ParseContext>
1784 constexpr typename _ParseContext::iterator
1785 parse(_ParseContext& __pc)
1786 { return _M_f._M_parse(__pc, __format::_Month|__format::_Weekday); }
1787
1788 template<typename _FormatContext>
1789 typename _FormatContext::iterator
1790 format(const chrono::month_weekday& __t, _FormatContext& __fc) const
1791 { return _M_f._M_format(__t, __fc); }
1792
1793 private:
1794 __format::__formatter_chrono<_CharT> _M_f;
1795 };
1796
1797 template<typename _CharT>
1798 struct formatter<chrono::month_weekday_last, _CharT>
1799 {
1800 template<typename _ParseContext>
1801 constexpr typename _ParseContext::iterator
1802 parse(_ParseContext& __pc)
1803 { return _M_f._M_parse(__pc, __format::_Month|__format::_Weekday); }
1804
1805 template<typename _FormatContext>
1806 typename _FormatContext::iterator
1807 format(const chrono::month_weekday_last& __t,
1808 _FormatContext& __fc) const
1809 { return _M_f._M_format(__t, __fc); }
1810
1811 private:
1812 __format::__formatter_chrono<_CharT> _M_f;
1813 };
1814
1815 template<typename _CharT>
1816 struct formatter<chrono::year_month, _CharT>
1817 {
1818 template<typename _ParseContext>
1819 constexpr typename _ParseContext::iterator
1820 parse(_ParseContext& __pc)
1821 { return _M_f._M_parse(__pc, __format::_Year|__format::_Month); }
1822
1823 template<typename _FormatContext>
1824 typename _FormatContext::iterator
1825 format(const chrono::year_month& __t, _FormatContext& __fc) const
1826 { return _M_f._M_format(__t, __fc); }
1827
1828 private:
1829 __format::__formatter_chrono<_CharT> _M_f;
1830 };
1831
1832 template<typename _CharT>
1833 struct formatter<chrono::year_month_day, _CharT>
1834 {
1835 template<typename _ParseContext>
1836 constexpr typename _ParseContext::iterator
1837 parse(_ParseContext& __pc)
1838 { return _M_f._M_parse(__pc, __format::_Date); }
1839
1840 template<typename _FormatContext>
1841 typename _FormatContext::iterator
1842 format(const chrono::year_month_day& __t, _FormatContext& __fc) const
1843 { return _M_f._M_format(__t, __fc); }
1844
1845 private:
1846 __format::__formatter_chrono<_CharT> _M_f;
1847 };
1848
1849 template<typename _CharT>
1850 struct formatter<chrono::year_month_day_last, _CharT>
1851 {
1852 template<typename _ParseContext>
1853 constexpr typename _ParseContext::iterator
1854 parse(_ParseContext& __pc)
1855 { return _M_f._M_parse(__pc, __format::_Date); }
1856
1857 template<typename _FormatContext>
1858 typename _FormatContext::iterator
1859 format(const chrono::year_month_day_last& __t,
1860 _FormatContext& __fc) const
1861 { return _M_f._M_format(__t, __fc); }
1862
1863 private:
1864 __format::__formatter_chrono<_CharT> _M_f;
1865 };
1866
1867 template<typename _CharT>
1868 struct formatter<chrono::year_month_weekday, _CharT>
1869 {
1870 template<typename _ParseContext>
1871 constexpr typename _ParseContext::iterator
1872 parse(_ParseContext& __pc)
1873 { return _M_f._M_parse(__pc, __format::_Date); }
1874
1875 template<typename _FormatContext>
1876 typename _FormatContext::iterator
1877 format(const chrono::year_month_weekday& __t,
1878 _FormatContext& __fc) const
1879 { return _M_f._M_format(__t, __fc); }
1880
1881 private:
1882 __format::__formatter_chrono<_CharT> _M_f;
1883 };
1884
1885 template<typename _CharT>
1886 struct formatter<chrono::year_month_weekday_last, _CharT>
1887 {
1888 template<typename _ParseContext>
1889 constexpr typename _ParseContext::iterator
1890 parse(_ParseContext& __pc)
1891 { return _M_f._M_parse(__pc, __format::_Date); }
1892
1893 template<typename _FormatContext>
1894 typename _FormatContext::iterator
1895 format(const chrono::year_month_weekday_last& __t,
1896 _FormatContext& __fc) const
1897 { return _M_f._M_format(__t, __fc); }
1898
1899 private:
1900 __format::__formatter_chrono<_CharT> _M_f;
1901 };
1902
1903 template<typename _Rep, typename _Period, typename _CharT>
1904 struct formatter<chrono::hh_mm_ss<chrono::duration<_Rep, _Period>>, _CharT>
1905 {
1906 template<typename _ParseContext>
1907 constexpr typename _ParseContext::iterator
1908 parse(_ParseContext& __pc)
1909 { return _M_f._M_parse(__pc, __format::_TimeOfDay); }
1910
1911 template<typename _FormatContext>
1912 typename _FormatContext::iterator
1913 format(const chrono::hh_mm_ss<chrono::duration<_Rep, _Period>>& __t,
1914 _FormatContext& __fc) const
1915 { return _M_f._M_format(__t, __fc); }
1916
1917 private:
1918 __format::__formatter_chrono<_CharT> _M_f;
1919 };
1920
1921#if _GLIBCXX_USE_CXX11_ABI || ! _GLIBCXX_USE_DUAL_ABI
1922 template<typename _CharT>
1923 struct formatter<chrono::sys_info, _CharT>
1924 {
1925 template<typename _ParseContext>
1926 constexpr typename _ParseContext::iterator
1927 parse(_ParseContext& __pc)
1928 { return _M_f._M_parse(__pc, __format::_ChronoParts{}); }
1929
1930 template<typename _FormatContext>
1931 typename _FormatContext::iterator
1932 format(const chrono::sys_info& __i, _FormatContext& __fc) const
1933 { return _M_f._M_format(__i, __fc); }
1934
1935 private:
1936 __format::__formatter_chrono<_CharT> _M_f;
1937 };
1938
1939 template<typename _CharT>
1940 struct formatter<chrono::local_info, _CharT>
1941 {
1942 template<typename _ParseContext>
1943 constexpr typename _ParseContext::iterator
1944 parse(_ParseContext& __pc)
1945 { return _M_f._M_parse(__pc, __format::_ChronoParts{}); }
1946
1947 template<typename _FormatContext>
1948 typename _FormatContext::iterator
1949 format(const chrono::local_info& __i, _FormatContext& __fc) const
1950 { return _M_f._M_format(__i, __fc); }
1951
1952 private:
1953 __format::__formatter_chrono<_CharT> _M_f;
1954 };
1955#endif
1956
1957 template<typename _Duration, typename _CharT>
1958 struct formatter<chrono::sys_time<_Duration>, _CharT>
1959 {
1960 template<typename _ParseContext>
1961 constexpr typename _ParseContext::iterator
1962 parse(_ParseContext& __pc)
1963 {
1964 auto __next = _M_f._M_parse(__pc, __format::_ZonedDateTime);
1965 if constexpr (!__stream_insertable)
1966 if (_M_f._M_spec._M_chrono_specs.empty())
1967 __format::__invalid_chrono_spec(); // chrono-specs can't be empty
1968 return __next;
1969 }
1970
1971 template<typename _FormatContext>
1972 typename _FormatContext::iterator
1973 format(const chrono::sys_time<_Duration>& __t,
1974 _FormatContext& __fc) const
1975 { return _M_f._M_format(__t, __fc); }
1976
1977 private:
1978 static constexpr bool __stream_insertable
1979 = requires (basic_ostream<_CharT>& __os,
1980 chrono::sys_time<_Duration> __t) { __os << __t; };
1981
1982 __format::__formatter_chrono<_CharT> _M_f;
1983 };
1984
1985 template<typename _Duration, typename _CharT>
1986 struct formatter<chrono::utc_time<_Duration>, _CharT>
1987 : __format::__formatter_chrono<_CharT>
1988 {
1989 template<typename _ParseContext>
1990 constexpr typename _ParseContext::iterator
1991 parse(_ParseContext& __pc)
1992 { return _M_f._M_parse(__pc, __format::_ZonedDateTime); }
1993
1994 template<typename _FormatContext>
1995 typename _FormatContext::iterator
1996 format(const chrono::utc_time<_Duration>& __t,
1997 _FormatContext& __fc) const
1998 {
1999 // Adjust by removing leap seconds to get equivalent sys_time.
2000 // We can't just use clock_cast because we want to know if the time
2001 // falls within a leap second insertion, and format seconds as "60".
2002 using chrono::__detail::__utc_leap_second;
2003 using chrono::seconds;
2004 using chrono::sys_time;
2005 using _CDur = common_type_t<_Duration, seconds>;
2006 const auto __li = chrono::get_leap_second_info(__t);
2007 sys_time<_CDur> __s{__t.time_since_epoch() - __li.elapsed};
2008 if (!__li.is_leap_second) [[likely]]
2009 return _M_f._M_format(__s, __fc);
2010 else
2011 return _M_f._M_format(__utc_leap_second(__s), __fc);
2012 }
2013
2014 private:
2015 friend formatter<chrono::__detail::__utc_leap_second<_Duration>, _CharT>;
2016
2017 __format::__formatter_chrono<_CharT> _M_f;
2018 };
2019
2020 template<typename _Duration, typename _CharT>
2021 struct formatter<chrono::tai_time<_Duration>, _CharT>
2022 : __format::__formatter_chrono<_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::tai_time<_Duration>& __t,
2032 _FormatContext& __fc) const
2033 {
2034 // Convert to __local_time_fmt with abbrev "TAI" and offset 0s.
2035
2036 // Offset is 1970y/January/1 - 1958y/January/1
2037 constexpr chrono::days __tai_offset = chrono::days(4383);
2038 using _CDur = common_type_t<_Duration, chrono::days>;
2039 chrono::local_time<_CDur> __lt(__t.time_since_epoch() - __tai_offset);
2040 const string __abbrev("TAI", 3);
2041 const chrono::seconds __off = 0s;
2042 const auto __lf = chrono::local_time_format(__lt, &__abbrev, &__off);
2043 return _M_f._M_format(__lf, __fc);
2044 }
2045
2046 private:
2047 __format::__formatter_chrono<_CharT> _M_f;
2048 };
2049
2050 template<typename _Duration, typename _CharT>
2051 struct formatter<chrono::gps_time<_Duration>, _CharT>
2052 : __format::__formatter_chrono<_CharT>
2053 {
2054 template<typename _ParseContext>
2055 constexpr typename _ParseContext::iterator
2056 parse(_ParseContext& __pc)
2057 { return _M_f._M_parse(__pc, __format::_ZonedDateTime); }
2058
2059 template<typename _FormatContext>
2060 typename _FormatContext::iterator
2061 format(const chrono::gps_time<_Duration>& __t,
2062 _FormatContext& __fc) const
2063 {
2064 // Convert to __local_time_fmt with abbrev "GPS" and offset 0s.
2065
2066 // Offset is 1980y/January/Sunday[1] - 1970y/January/1
2067 constexpr chrono::days __gps_offset = chrono::days(3657);
2068 using _CDur = common_type_t<_Duration, chrono::days>;
2069 chrono::local_time<_CDur> __lt(__t.time_since_epoch() + __gps_offset);
2070 const string __abbrev("GPS", 3);
2071 const chrono::seconds __off = 0s;
2072 const auto __lf = chrono::local_time_format(__lt, &__abbrev, &__off);
2073 return _M_f._M_format(__lf, __fc);
2074 }
2075
2076 private:
2077 __format::__formatter_chrono<_CharT> _M_f;
2078 };
2079
2080 template<typename _Duration, typename _CharT>
2081 struct formatter<chrono::file_time<_Duration>, _CharT>
2082 {
2083 template<typename _ParseContext>
2084 constexpr typename _ParseContext::iterator
2085 parse(_ParseContext& __pc)
2086 { return _M_f._M_parse(__pc, __format::_ZonedDateTime); }
2087
2088 template<typename _FormatContext>
2089 typename _FormatContext::iterator
2090 format(const chrono::file_time<_Duration>& __t,
2091 _FormatContext& __ctx) const
2092 {
2093 using namespace chrono;
2094 return _M_f._M_format(chrono::clock_cast<system_clock>(__t), __ctx);
2095 }
2096
2097 private:
2098 __format::__formatter_chrono<_CharT> _M_f;
2099 };
2100
2101 template<typename _Duration, typename _CharT>
2102 struct formatter<chrono::local_time<_Duration>, _CharT>
2103 {
2104 template<typename _ParseContext>
2105 constexpr typename _ParseContext::iterator
2106 parse(_ParseContext& __pc)
2107 { return _M_f._M_parse(__pc, __format::_DateTime); }
2108
2109 template<typename _FormatContext>
2110 typename _FormatContext::iterator
2111 format(const chrono::local_time<_Duration>& __t,
2112 _FormatContext& __ctx) const
2113 { return _M_f._M_format(__t, __ctx); }
2114
2115 private:
2116 __format::__formatter_chrono<_CharT> _M_f;
2117 };
2118
2119 template<typename _Duration, typename _CharT>
2120 struct formatter<chrono::__detail::__local_time_fmt<_Duration>, _CharT>
2121 {
2122 template<typename _ParseContext>
2123 constexpr typename _ParseContext::iterator
2124 parse(_ParseContext& __pc)
2125 { return _M_f._M_parse(__pc, __format::_ZonedDateTime); }
2126
2127 template<typename _FormatContext>
2128 typename _FormatContext::iterator
2129 format(const chrono::__detail::__local_time_fmt<_Duration>& __t,
2130 _FormatContext& __ctx) const
2131 { return _M_f._M_format(__t, __ctx); }
2132
2133 private:
2134 __format::__formatter_chrono<_CharT> _M_f;
2135 };
2136
2137#if _GLIBCXX_USE_CXX11_ABI || ! _GLIBCXX_USE_DUAL_ABI
2138 template<typename _Duration, typename _TimeZonePtr, typename _CharT>
2139 struct formatter<chrono::zoned_time<_Duration, _TimeZonePtr>, _CharT>
2140 : formatter<chrono::__detail::__local_time_fmt<_Duration>, _CharT>
2141 {
2142 template<typename _FormatContext>
2143 typename _FormatContext::iterator
2144 format(const chrono::zoned_time<_Duration, _TimeZonePtr>& __tp,
2145 _FormatContext& __ctx) const
2146 {
2147 using chrono::__detail::__local_time_fmt;
2148 using _Base = formatter<__local_time_fmt<_Duration>, _CharT>;
2149 const chrono::sys_info __info = __tp.get_info();
2150 const auto __lf = chrono::local_time_format(__tp.get_local_time(),
2151 &__info.abbrev,
2152 &__info.offset);
2153 return _Base::format(__lf, __ctx);
2154 }
2155 };
2156#endif
2157
2158 // Partial specialization needed for %c formatting of __utc_leap_second.
2159 template<typename _Duration, typename _CharT>
2160 struct formatter<chrono::__detail::__utc_leap_second<_Duration>, _CharT>
2161 : formatter<chrono::utc_time<_Duration>, _CharT>
2162 {
2163 template<typename _FormatContext>
2164 typename _FormatContext::iterator
2165 format(const chrono::__detail::__utc_leap_second<_Duration>& __t,
2166 _FormatContext& __fc) const
2167 { return this->_M_f._M_format(__t, __fc); }
2168 };
2169
2170namespace chrono
2171{
2172/// @addtogroup chrono
2173/// @{
2174
2175 // TODO: from_stream for duration
2176#if 0
2177 template<typename _CharT, typename _Traits, typename _Rep, typename _Period,
2178 typename _Alloc = allocator<_CharT>>
2179 basic_istream<_CharT, _Traits>&
2180 from_stream(basic_istream<_CharT, _Traits>& __is, const _CharT* __fmt,
2181 duration<_Rep, _Period>& __d,
2182 basic_string<_CharT, _Traits, _Alloc>* __abbrev = nullptr,
2183 minutes* __offset = nullptr)
2184 {
2185 }
2186#endif
2187
2188 template<typename _CharT, typename _Traits>
2189 inline basic_ostream<_CharT, _Traits>&
2190 operator<<(basic_ostream<_CharT, _Traits>& __os, const day& __d)
2191 {
2192 using _Ctx = __conditional_t<is_same_v<_CharT, char>,
2193 format_context, wformat_context>;
2194 using _Str = basic_string_view<_CharT>;
2195 _Str __s = _GLIBCXX_WIDEN("{:02d} is not a valid day");
2196 if (__d.ok())
2197 __s = __s.substr(0, 6);
2198 auto __u = (unsigned)__d;
2199 __os << std::vformat(__s, make_format_args<_Ctx>(__u));
2200 return __os;
2201 }
2202
2203 // TODO from_stream for day
2204
2205 template<typename _CharT, typename _Traits>
2206 inline basic_ostream<_CharT, _Traits>&
2207 operator<<(basic_ostream<_CharT, _Traits>& __os, const month& __m)
2208 {
2209 using _Ctx = __conditional_t<is_same_v<_CharT, char>,
2210 format_context, wformat_context>;
2211 using _Str = basic_string_view<_CharT>;
2212 _Str __s = _GLIBCXX_WIDEN("{:L%b}{} is not a valid month");
2213 if (__m.ok())
2214 __os << std::vformat(__os.getloc(), __s.substr(0, 6),
2215 make_format_args<_Ctx>(__m));
2216 else
2217 {
2218 auto __u = (unsigned)__m;
2219 __os << std::vformat(__s.substr(6), make_format_args<_Ctx>(__u));
2220 }
2221 return __os;
2222 }
2223
2224 // TODO from_stream for month
2225
2226 template<typename _CharT, typename _Traits>
2227 inline basic_ostream<_CharT, _Traits>&
2228 operator<<(basic_ostream<_CharT, _Traits>& __os, const year& __y)
2229 {
2230 using _Ctx = __conditional_t<is_same_v<_CharT, char>,
2231 format_context, wformat_context>;
2232 using _Str = basic_string_view<_CharT>;
2233 _Str __s = _GLIBCXX_WIDEN("-{:04d} is not a valid year");
2234 if (__y.ok())
2235 __s = __s.substr(0, 7);
2236 int __i = (int)__y;
2237 if (__i >= 0) [[likely]]
2238 __s.remove_prefix(1);
2239 else
2240 __i = -__i;
2241 __os << std::vformat(__s, make_format_args<_Ctx>(__i));
2242 return __os;
2243 }
2244
2245 // TODO from_stream for year
2246
2247 template<typename _CharT, typename _Traits>
2248 inline basic_ostream<_CharT, _Traits>&
2249 operator<<(basic_ostream<_CharT, _Traits>& __os, const weekday& __wd)
2250 {
2251 using _Ctx = __conditional_t<is_same_v<_CharT, char>,
2252 format_context, wformat_context>;
2253 using _Str = basic_string_view<_CharT>;
2254 _Str __s = _GLIBCXX_WIDEN("{:L%a}{} is not a valid weekday");
2255 if (__wd.ok())
2256 __os << std::vformat(__os.getloc(), __s.substr(0, 6),
2257 make_format_args<_Ctx>(__wd));
2258 else
2259 {
2260 auto __c = __wd.c_encoding();
2261 __os << std::vformat(__s.substr(6), make_format_args<_Ctx>(__c));
2262 }
2263 return __os;
2264 }
2265
2266 // TODO from_stream for weekday
2267
2268 template<typename _CharT, typename _Traits>
2269 inline basic_ostream<_CharT, _Traits>&
2270 operator<<(basic_ostream<_CharT, _Traits>& __os,
2271 const weekday_indexed& __wdi)
2272 {
2273 // The standard says to format wdi.weekday() and wdi.index() using
2274 // either "{:L}[{}]" or "{:L}[{} is not a valid index]". The {:L} spec
2275 // means to format the weekday using ostringstream, so just do that.
2276 basic_stringstream<_CharT> __os2;
2277 __os2.imbue(__os.getloc());
2278 __os2 << __wdi.weekday();
2279 const auto __i = __wdi.index();
2280 if constexpr (is_same_v<_CharT, char>)
2281 __os2 << std::format("[{}", __i);
2282 else
2283 __os2 << std::format(L"[{}", __i);
2284 basic_string_view<_CharT> __s = _GLIBCXX_WIDEN(" is not a valid index]");
2285 if (__i >= 1 && __i <= 5)
2286 __os2 << __s.back();
2287 else
2288 __os2 << __s;
2289 __os << __os2.view();
2290 return __os;
2291 }
2292
2293 template<typename _CharT, typename _Traits>
2294 inline basic_ostream<_CharT, _Traits>&
2295 operator<<(basic_ostream<_CharT, _Traits>& __os,
2296 const weekday_last& __wdl)
2297 {
2298 // As above, just write straight to a stringstream, as if by "{:L}[last]"
2299 basic_stringstream<_CharT> __os2;
2300 __os2.imbue(__os.getloc());
2301 __os2 << __wdl.weekday() << _GLIBCXX_WIDEN("[last]");
2302 __os << __os2.view();
2303 return __os;
2304 }
2305
2306 template<typename _CharT, typename _Traits>
2307 inline basic_ostream<_CharT, _Traits>&
2308 operator<<(basic_ostream<_CharT, _Traits>& __os, const month_day& __md)
2309 {
2310 // As above, just write straight to a stringstream, as if by "{:L}/{}"
2311 basic_stringstream<_CharT> __os2;
2312 __os2.imbue(__os.getloc());
2313 __os2 << __md.month();
2314 if constexpr (is_same_v<_CharT, char>)
2315 __os2 << '/';
2316 else
2317 __os2 << L'/';
2318 __os2 << __md.day();
2319 __os << __os2.view();
2320 return __os;
2321 }
2322
2323 // TODO from_stream for month_day
2324
2325 template<typename _CharT, typename _Traits>
2326 inline basic_ostream<_CharT, _Traits>&
2327 operator<<(basic_ostream<_CharT, _Traits>& __os,
2328 const month_day_last& __mdl)
2329 {
2330 // As above, just write straight to a stringstream, as if by "{:L}/last"
2331 basic_stringstream<_CharT> __os2;
2332 __os2.imbue(__os.getloc());
2333 __os2 << __mdl.month();
2334 if constexpr (is_same_v<_CharT, char>)
2335 __os2 << "/last";
2336 else
2337 __os2 << L"/last";
2338 __os << __os2.view();
2339 return __os;
2340 }
2341
2342 template<typename _CharT, typename _Traits>
2343 inline basic_ostream<_CharT, _Traits>&
2344 operator<<(basic_ostream<_CharT, _Traits>& __os,
2345 const month_weekday& __mwd)
2346 {
2347 // As above, just write straight to a stringstream, as if by "{:L}/{:L}"
2348 basic_stringstream<_CharT> __os2;
2349 __os2.imbue(__os.getloc());
2350 __os2 << __mwd.month();
2351 if constexpr (is_same_v<_CharT, char>)
2352 __os2 << '/';
2353 else
2354 __os2 << L'/';
2355 __os2 << __mwd.weekday_indexed();
2356 __os << __os2.view();
2357 return __os;
2358 }
2359
2360 template<typename _CharT, typename _Traits>
2361 inline basic_ostream<_CharT, _Traits>&
2362 operator<<(basic_ostream<_CharT, _Traits>& __os,
2363 const month_weekday_last& __mwdl)
2364 {
2365 // As above, just write straight to a stringstream, as if by "{:L}/{:L}"
2366 basic_stringstream<_CharT> __os2;
2367 __os2.imbue(__os.getloc());
2368 __os2 << __mwdl.month();
2369 if constexpr (is_same_v<_CharT, char>)
2370 __os2 << '/';
2371 else
2372 __os2 << L'/';
2373 __os2 << __mwdl.weekday_last();
2374 __os << __os2.view();
2375 return __os;
2376 }
2377
2378 template<typename _CharT, typename _Traits>
2379 inline basic_ostream<_CharT, _Traits>&
2380 operator<<(basic_ostream<_CharT, _Traits>& __os, const year_month& __ym)
2381 {
2382 // As above, just write straight to a stringstream, as if by "{}/{:L}"
2383 basic_stringstream<_CharT> __os2;
2384 __os2.imbue(__os.getloc());
2385 __os2 << __ym.year();
2386 if constexpr (is_same_v<_CharT, char>)
2387 __os2 << '/';
2388 else
2389 __os2 << L'/';
2390 __os2 << __ym.month();
2391 __os << __os2.view();
2392 return __os;
2393 }
2394
2395 // TODO from_stream for year_month
2396
2397 template<typename _CharT, typename _Traits>
2398 inline basic_ostream<_CharT, _Traits>&
2399 operator<<(basic_ostream<_CharT, _Traits>& __os,
2400 const year_month_day& __ymd)
2401 {
2402 using _Ctx = __conditional_t<is_same_v<_CharT, char>,
2403 format_context, wformat_context>;
2404 using _Str = basic_string_view<_CharT>;
2405 _Str __s = _GLIBCXX_WIDEN("{:%F} is not a valid date");
2406 __os << std::vformat(__ymd.ok() ? __s.substr(0, 5) : __s,
2407 make_format_args<_Ctx>(__ymd));
2408 return __os;
2409 }
2410
2411 // TODO from_stream for year_month_day
2412
2413 template<typename _CharT, typename _Traits>
2414 inline basic_ostream<_CharT, _Traits>&
2415 operator<<(basic_ostream<_CharT, _Traits>& __os,
2416 const year_month_day_last& __ymdl)
2417 {
2418 // As above, just write straight to a stringstream, as if by "{}/{:L}"
2419 basic_stringstream<_CharT> __os2;
2420 __os2.imbue(__os.getloc());
2421 __os2 << __ymdl.year();
2422 if constexpr (is_same_v<_CharT, char>)
2423 __os2 << '/';
2424 else
2425 __os2 << L'/';
2426 __os2 << __ymdl.month_day_last();
2427 __os << __os2.view();
2428 return __os;
2429 }
2430
2431 template<typename _CharT, typename _Traits>
2432 inline basic_ostream<_CharT, _Traits>&
2433 operator<<(basic_ostream<_CharT, _Traits>& __os,
2434 const year_month_weekday& __ymwd)
2435 {
2436 // As above, just write straight to a stringstream, as if by
2437 // "{}/{:L}/{:L}"
2438 basic_stringstream<_CharT> __os2;
2439 __os2.imbue(__os.getloc());
2440 _CharT __slash;
2441 if constexpr (is_same_v<_CharT, char>)
2442 __slash = '/';
2443 else
2444 __slash = L'/';
2445 __os2 << __ymwd.year() << __slash << __ymwd.month() << __slash
2446 << __ymwd.weekday_indexed();
2447 __os << __os2.view();
2448 return __os;
2449 }
2450
2451 template<typename _CharT, typename _Traits>
2452 inline basic_ostream<_CharT, _Traits>&
2453 operator<<(basic_ostream<_CharT, _Traits>& __os,
2454 const year_month_weekday_last& __ymwdl)
2455 {
2456 // As above, just write straight to a stringstream, as if by
2457 // "{}/{:L}/{:L}"
2458 basic_stringstream<_CharT> __os2;
2459 __os2.imbue(__os.getloc());
2460 _CharT __slash;
2461 if constexpr (is_same_v<_CharT, char>)
2462 __slash = '/';
2463 else
2464 __slash = L'/';
2465 __os2 << __ymwdl.year() << __slash << __ymwdl.month() << __slash
2466 << __ymwdl.weekday_last();
2467 __os << __os2.view();
2468 return __os;
2469 }
2470
2471 template<typename _CharT, typename _Traits, typename _Duration>
2472 inline basic_ostream<_CharT, _Traits>&
2473 operator<<(basic_ostream<_CharT, _Traits>& __os,
2474 const hh_mm_ss<_Duration>& __hms)
2475 {
2476 return __os << format(__os.getloc(), _GLIBCXX_WIDEN("{:L%T}"), __hms);
2477 }
2478
2479#if _GLIBCXX_USE_CXX11_ABI || ! _GLIBCXX_USE_DUAL_ABI
2480 /// Writes a sys_info object to an ostream in an unspecified format.
2481 template<typename _CharT, typename _Traits>
2482 basic_ostream<_CharT, _Traits>&
2483 operator<<(basic_ostream<_CharT, _Traits>& __os, const sys_info& __i)
2484 {
2485 __os << '[' << __i.begin << ',' << __i.end
2486 << ',' << hh_mm_ss(__i.offset) << ',' << __i.save
2487 << ',' << __i.abbrev << ']';
2488 return __os;
2489 }
2490
2491 /// Writes a local_info object to an ostream in an unspecified format.
2492 template<typename _CharT, typename _Traits>
2493 basic_ostream<_CharT, _Traits>&
2494 operator<<(basic_ostream<_CharT, _Traits>& __os, const local_info& __li)
2495 {
2496 __os << '[';
2497 if (__li.result == local_info::unique)
2498 __os << __li.first;
2499 else
2500 {
2501 if (__li.result == local_info::nonexistent)
2502 __os << "nonexistent";
2503 else
2504 __os << "ambiguous";
2505 __os << " local time between " << __li.first;
2506 __os << " and " << __li.second;
2507 }
2508 __os << ']';
2509 return __os;
2510 }
2511
2512 template<typename _CharT, typename _Traits, typename _Duration,
2513 typename _TimeZonePtr>
2514 inline basic_ostream<_CharT, _Traits>&
2515 operator<<(basic_ostream<_CharT, _Traits>& __os,
2516 const zoned_time<_Duration, _TimeZonePtr>& __t)
2517 {
2518 __os << format(__os.getloc(), _GLIBCXX_WIDEN("{:L%F %T %Z}"), __t);
2519 return __os;
2520 }
2521#endif
2522
2523 template<typename _CharT, typename _Traits, typename _Duration>
2524 requires (!treat_as_floating_point_v<typename _Duration::rep>)
2525 && ratio_less_v<typename _Duration::period, days::period>
2526 inline basic_ostream<_CharT, _Traits>&
2527 operator<<(basic_ostream<_CharT, _Traits>& __os,
2528 const sys_time<_Duration>& __tp)
2529 {
2530 __os << std::format(__os.getloc(), _GLIBCXX_WIDEN("{:L%F %T}"), __tp);
2531 return __os;
2532 }
2533
2534 template<typename _CharT, typename _Traits>
2535 inline basic_ostream<_CharT, _Traits>&
2536 operator<<(basic_ostream<_CharT, _Traits>& __os, const sys_days& __dp)
2537 {
2538 __os << year_month_day{__dp};
2539 return __os;
2540 }
2541
2542 // TODO: from_stream for sys_time
2543
2544 template<typename _CharT, typename _Traits, typename _Duration>
2545 inline basic_ostream<_CharT, _Traits>&
2546 operator<<(basic_ostream<_CharT, _Traits>& __os,
2547 const utc_time<_Duration>& __t)
2548 {
2549 __os << std::format(__os.getloc(), _GLIBCXX_WIDEN("{:L%F %T}"), __t);
2550 return __os;
2551 }
2552
2553 // TODO: from_stream for utc_time
2554
2555 template<typename _CharT, typename _Traits, typename _Duration>
2556 inline basic_ostream<_CharT, _Traits>&
2557 operator<<(basic_ostream<_CharT, _Traits>& __os,
2558 const tai_time<_Duration>& __t)
2559 {
2560 __os << std::format(__os.getloc(), _GLIBCXX_WIDEN("{:L%F %T}"), __t);
2561 return __os;
2562 }
2563
2564 // TODO: from_stream for tai_time
2565
2566 template<typename _CharT, typename _Traits, typename _Duration>
2567 inline basic_ostream<_CharT, _Traits>&
2568 operator<<(basic_ostream<_CharT, _Traits>& __os,
2569 const gps_time<_Duration>& __t)
2570 {
2571 __os << std::format(__os.getloc(), _GLIBCXX_WIDEN("{:L%F %T}"), __t);
2572 return __os;
2573 }
2574
2575 // TODO: from_stream for gps_time
2576
2577
2578 template<typename _CharT, typename _Traits, typename _Duration>
2579 inline basic_ostream<_CharT, _Traits>&
2580 operator<<(basic_ostream<_CharT, _Traits>& __os,
2581 const file_time<_Duration>& __t)
2582 {
2583 __os << std::format(__os.getloc(), _GLIBCXX_WIDEN("{:L%F %T}"), __t);
2584 return __os;
2585 }
2586
2587 // TODO: from_stream for file_time
2588
2589 template<typename _CharT, typename _Traits, typename _Duration>
2590 inline basic_ostream<_CharT, _Traits>&
2591 operator<<(basic_ostream<_CharT, _Traits>& __os,
2592 const local_time<_Duration>& __lt)
2593 {
2594 __os << sys_time<_Duration>{__lt.time_since_epoch()};
2595 return __os;
2596 }
2597
2598 // TODO: from_stream for local_time
2599#undef _GLIBCXX_WIDEN
2600
2601 /// @} group chrono
2602} // namespace chrono
2603
2604_GLIBCXX_END_NAMESPACE_VERSION
2605} // namespace std
2606
2607#endif // C++20
2608
2609#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:191
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:149
constexpr std::remove_reference< _Tp >::type && move(_Tp &&__t) noexcept
Convert a value to an rvalue.
Definition: move.h:97
ISO C++ entities toplevel namespace is std.
std::basic_ostream< _CharT, _Traits > & operator<<(std::basic_ostream< _CharT, _Traits > &__os, const bitset< _Nb > &__x)
Global I/O operators for bitsets.
Definition: bitset:1683
constexpr bitset< _Nb > operator|(const bitset< _Nb > &__x, const bitset< _Nb > &__y) noexcept
Global bitwise operations on bitsets.
Definition: bitset:1563
Implementation details not part of the namespace std interface.
ISO C++ 2011 namespace for date and time utilities.
Template class basic_ostream.
Definition: ostream:61
Controlling output for std::string.
Definition: sstream:772
Properties of fundamental types.
Definition: limits:313
Provides compile-time rational arithmetic.
Definition: ratio:267
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
iterator begin()
Definition: cow_string.h:805
streamsize precision() const
Flags access.
Definition: ios_base.h:732
fmtflags flags() const
Access to format flags.
Definition: ios_base.h:662
locale getloc() const
Locale access.
Definition: ios_base.h:806
Container class for localization functionality.
static const locale & classic()
Return reference to the C locale.