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