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;
418 break;
419 case 'Z':
420 __needed = _TimeZone;
421 __allowed_mods = _Mod_E_O;
422 break;
423 case 'n':
424 case 't':
425 case '%':
426 break;
427 case 'O':
428 case 'E':
429 __mod = __c;
430 continue;
431 default:
432 __throw_format_error("chrono format error: invalid "
433 " specifier in chrono-specs");
434 }
435
436 if ((__mod == 'E' && !(__allowed_mods & _Mod_E))
437 || __mod == 'O' && !(__allowed_mods & _Mod_O))
438 __throw_format_error("chrono format error: invalid "
439 " modifier in chrono-specs");
440 __mod = _CharT();
441
442 if ((__parts & __needed) != __needed)
443 __throw_format_error("chrono format error: format argument "
444 "does not contain the information "
445 "required by the chrono-specs");
446
447 // Scan for next '%', ignoring literal-chars before it.
448 size_t __pos = __string_view(__first, __last - __first).find('%');
449 if (__pos == 0)
450 ++__first;
451 else
452 {
453 if (__pos == __string_view::npos)
454 {
455 __first = __last;
456 __conv = false;
457 }
458 else
459 __first += __pos + 1;
460 }
461 }
462
463 // Check for a '%' conversion-spec without a type.
464 if (__conv || __mod != _CharT())
465 __throw_format_error("chrono format error: unescaped '%' in "
466 "chrono-specs");
467
468 _M_spec = __spec;
469 _M_spec._M_chrono_specs = {__chrono_specs, __first - __chrono_specs};
470
471 return __first;
472 }
473
474 // TODO this function template is instantiated for every different _Tp.
475 // Consider creating a polymorphic interface for calendar types so
476 // that we instantiate fewer different specializations. Similar to
477 // _Sink_iter for std::format. Replace each _S_year, _S_day etc. with
478 // member functions of that type.
479 template<typename _Tp, typename _FormatContext>
480 typename _FormatContext::iterator
481 _M_format(const _Tp& __t, _FormatContext& __fc,
482 bool __is_neg = false) const
483 {
484 if constexpr (__is_specialization_of<_Tp, chrono::hh_mm_ss>)
485 __is_neg = __t.is_negative();
486 else if constexpr (!chrono::__is_duration_v<_Tp>)
487 __is_neg = false;
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 auto __print_sign = [&__is_neg, &__out] {
512 if (__is_neg)
513 {
514 *__out++ = _S_plus_minus[1];
515 __is_neg = false;
516 }
517 return std::move(__out);
518 };
519
520 // Characters to output for "%n", "%t" and "%%" specifiers.
521 constexpr const _CharT* __literals = _GLIBCXX_WIDEN("\n\t%");
522
523 ++__first; // Skip leading '%' at start of chrono-specs.
524
525 _CharT __mod{};
526 do
527 {
528 _CharT __c = *__first++;
529 switch (__c)
530 {
531 case 'a':
532 case 'A':
533 __out = _M_a_A(__t, std::move(__out), __fc, __c == 'A');
534 break;
535 case 'b':
536 case 'h':
537 case 'B':
538 __out = _M_b_B(__t, std::move(__out), __fc, __c == 'B');
539 break;
540 case 'c':
541 __out = _M_c(__t, std::move(__out), __fc, __mod == 'E');
542 break;
543 case 'C':
544 case 'y':
545 case 'Y':
546 __out = _M_C_y_Y(__t, std::move(__out), __fc, __c, __mod);
547 break;
548 case 'd':
549 // %d The day of month as a decimal number.
550 // %Od Locale's alternative representation.
551 __out = _S_dd_zero_fill((unsigned)_S_day(__t),
552 std::move(__out),
553 __fc, __mod == 'O');
554 break;
555 case 'D':
556 __out = _M_D(__t, std::move(__out), __fc);
557 break;
558 case 'e':
559 __out = _M_e(__t, std::move(__out), __fc, __mod == 'O');
560 break;
561 case 'F':
562 __out = _M_F(__t, std::move(__out), __fc);
563 break;
564 case 'g':
565 case 'G':
566 __out = _M_g_G(__t, std::move(__out), __fc, __c == 'G');
567 break;
568 case 'H':
569 // %H The hour (24-hour clock) as a decimal number.
570 // %OH Locale's alternative representation.
571 __out = _S_dd_zero_fill(_S_hms(__t).hours().count(),
572 __print_sign(), __fc, __mod == 'O');
573 break;
574 case 'I':
575 __out = _M_I(__t, __print_sign(), __fc, __mod == 'O');
576 break;
577 case 'j':
578 __out = _M_j(__t, __print_sign(), __fc);
579 break;
580 case 'm':
581 // %m month as a decimal number.
582 // %Om Locale's alternative representation.
583 __out = _S_dd_zero_fill((unsigned)_S_month(__t),
584 std::move(__out), __fc,
585 __mod == 'O');
586 break;
587 case 'M':
588 // %M The minute as a decimal number.
589 // %OM Locale's alternative representation.
590 __out = _S_dd_zero_fill(_S_hms(__t).minutes().count(),
591 __print_sign(), __fc, __mod == 'O');
592 break;
593 case 'p':
594 __out = _M_p(__t, std::move(__out), __fc);
595 break;
596 case 'q':
597 __out = _M_q(__t, std::move(__out), __fc);
598 break;
599 case 'Q':
600 // %Q The duration's numeric value.
601 if constexpr (chrono::__is_duration_v<_Tp>)
602 __out = std::format_to(__print_sign(), _S_empty_spec,
603 __t.count());
604 else
605 __throw_format_error("chrono format error: argument is "
606 "not a duration");
607 break;
608 case 'r':
609 __out = _M_r(__t, __print_sign(), __fc);
610 break;
611 case 'R':
612 case 'T':
613 __out = _M_R_T(__t, __print_sign(), __fc, __c == 'T');
614 break;
615 case 'S':
616 __out = _M_S(__t, __print_sign(), __fc, __mod == 'O');
617 break;
618 case 'u':
619 case 'w':
620 __out = _M_u_w(__t, std::move(__out), __fc, __c, __mod == 'O');
621 break;
622 case 'U':
623 case 'V':
624 case 'W':
625 __out = _M_U_V_W(__t, std::move(__out), __fc, __c,
626 __mod == 'O');
627 break;
628 case 'x':
629 __out = _M_x(__t, std::move(__out), __fc, __mod == 'E');
630 break;
631 case 'X':
632 __out = _M_X(__t, __print_sign(), __fc, __mod == 'E');
633 break;
634 case 'z':
635 __out = _M_z(__t, std::move(__out), __fc, (bool)__mod);
636 break;
637 case 'Z':
638 __out = _M_Z(__t, std::move(__out), __fc);
639 break;
640 case 'n':
641 *__out++ = __literals[0];
642 break;
643 case 't':
644 *__out++ = __literals[1];
645 break;
646 case '%':
647 *__out++ = __literals[2];
648 break;
649 case 'O':
650 case 'E':
651 __mod = __c;
652 continue;
653 case '}':
654 __first = __last;
655 break;
656 }
657 __mod = _CharT();
658 // Scan for next '%' and write out everything before it.
659 __string_view __str(__first, __last - __first);
660 size_t __pos = __str.find('%');
661 if (__pos == 0)
662 ++__first;
663 else
664 {
665 if (__pos == __str.npos)
666 __first = __last;
667 else
668 {
669 __str.remove_suffix(__str.length() - __pos);
670 __first += __pos + 1;
671 }
672 __out = __format::__write(std::move(__out), __str);
673 }
674 }
675 while (__first != __last);
676
677 if constexpr (is_same_v<typename _FormatContext::iterator,
678 _Sink_iter<_CharT>>)
679 if (__write_direct)
680 return __out;
681
682 auto __str = std::move(__sink).get();
683 return __format::__write_padded_as_spec(__str, __str.size(),
684 __fc, _M_spec);
685 }
686
687 _ChronoSpec<_CharT> _M_spec;
688
689 private:
690 // Return the formatting locale.
691 template<typename _FormatContext>
693 _M_locale(_FormatContext& __fc) const
694 {
695 if (!_M_spec._M_localized)
696 return std::locale::classic();
697 else
698 return __fc.locale();
699 }
700
701 // TODO: consider moving body of every operator<< into this function
702 // and use std::format("{}", t) to implement those operators. That
703 // would avoid std::format("{}", t) calling operator<< which calls
704 // std::format again.
705 template<typename _Tp, typename _FormatContext>
706 typename _FormatContext::iterator
707 _M_format_to_ostream(const _Tp& __t, _FormatContext& __fc,
708 bool __is_neg) const
709 {
710 using ::std::chrono::__detail::__utc_leap_second;
711 using ::std::chrono::__detail::__local_time_fmt;
712
713 if constexpr (__is_specialization_of<_Tp, __local_time_fmt>)
714 return _M_format_to_ostream(__t._M_time, __fc, false);
715 else
716 {
717 basic_ostringstream<_CharT> __os;
718 __os.imbue(_M_locale(__fc));
719
720 if constexpr (__is_specialization_of<_Tp, __utc_leap_second>)
721 __os << __t._M_date << ' ' << __t._M_time;
722 else
723 {
724 if (__is_neg) [[unlikely]]
725 __os << _S_plus_minus[1];
726 __os << __t;
727 }
728
729 auto __str = std::move(__os).str();
730 return __format::__write_padded_as_spec(__str, __str.size(),
731 __fc, _M_spec);
732 }
733 }
734
735 static constexpr const _CharT* _S_chars
736 = _GLIBCXX_WIDEN("0123456789+-:/ {}");
737 static constexpr const _CharT* _S_plus_minus = _S_chars + 10;
738 static constexpr _CharT _S_colon = _S_chars[12];
739 static constexpr _CharT _S_slash = _S_chars[13];
740 static constexpr _CharT _S_space = _S_chars[14];
741 static constexpr const _CharT* _S_empty_spec = _S_chars + 15;
742
743 template<typename _Tp, typename _FormatContext>
744 typename _FormatContext::iterator
745 _M_a_A(const _Tp& __t, typename _FormatContext::iterator __out,
746 _FormatContext& __ctx, bool __full) const
747 {
748 // %a Locale's abbreviated weekday name.
749 // %A Locale's full weekday name.
750 chrono::weekday __wd = _S_weekday(__t);
751 if (!__wd.ok())
752 __throw_format_error("format error: invalid weekday");
753
754 locale __loc = _M_locale(__ctx);
755 const auto& __tp = use_facet<__timepunct<_CharT>>(__loc);
756 const _CharT* __days[7];
757 if (__full)
758 __tp._M_days(__days);
759 else
760 __tp._M_days_abbreviated(__days);
761 __string_view __str(__days[__wd.c_encoding()]);
762 return __format::__write(std::move(__out), __str);
763 }
764
765 template<typename _Tp, typename _FormatContext>
766 typename _FormatContext::iterator
767 _M_b_B(const _Tp& __t, typename _FormatContext::iterator __out,
768 _FormatContext& __ctx, bool __full) const
769 {
770 // %b Locale's abbreviated month name.
771 // %B Locale's full month name.
772 chrono::month __m = _S_month(__t);
773 if (!__m.ok())
774 __throw_format_error("format error: invalid month");
775 locale __loc = _M_locale(__ctx);
776 const auto& __tp = use_facet<__timepunct<_CharT>>(__loc);
777 const _CharT* __months[12];
778 if (__full)
779 __tp._M_months(__months);
780 else
781 __tp._M_months_abbreviated(__months);
782 __string_view __str(__months[(unsigned)__m - 1]);
783 return __format::__write(std::move(__out), __str);
784 }
785
786 template<typename _Tp, typename _FormatContext>
787 typename _FormatContext::iterator
788 _M_c(const _Tp& __t, typename _FormatContext::iterator __out,
789 _FormatContext& __ctx, bool __mod = false) const
790 {
791 // %c Locale's date and time representation.
792 // %Ec Locale's alternate date and time representation.
793
794 locale __loc = _M_locale(__ctx);
795 const auto& __tp = use_facet<__timepunct<_CharT>>(__loc);
796 const _CharT* __formats[2];
797 __tp._M_date_time_formats(__formats);
798 const _CharT* __rep = __formats[__mod];
799 if (!*__rep)
800 __rep = _GLIBCXX_WIDEN("%a %b %e %H:%M:%S %Y");
801 basic_string<_CharT> __fmt(_S_empty_spec);
802 __fmt.insert(1u, 1u, _S_colon);
803 __fmt.insert(2u, __rep);
804 return std::vformat_to(std::move(__out), __loc, __fmt,
805 std::make_format_args<_FormatContext>(__t));
806 }
807
808 template<typename _Tp, typename _FormatContext>
809 typename _FormatContext::iterator
810 _M_C_y_Y(const _Tp& __t, typename _FormatContext::iterator __out,
811 _FormatContext& __ctx, char __conv, char __mod = 0) const
812 {
813 // %C Year divided by 100 using floored division.
814 // %EC Locale's alternative preresentation of the century (era name).
815 // %y Last two decimal digits of the year.
816 // %OY Locale's alternative represenation.
817 // %Ey Locale's alternative representation of offset from %EC.
818 // %Y Year as a decimal number.
819 // %EY Locale's alternative full year represenation.
820
821 chrono::year __y = _S_year(__t);
822
823 if (__mod == 'E')
824 {
825 // TODO: %EC, %Ey or %EY
826 // return __out;
827 }
828
829 basic_string<_CharT> __s;
830 int __yi = (int)__y;
831 const bool __is_neg = __yi < 0;
832 __yi = __builtin_abs(__yi);
833
834 if (__conv == 'Y' || __conv == 'C')
835 {
836 if (__is_neg)
837 __s.assign(1, _S_plus_minus[1]);
838 int __ci = __yi / 100;
839 if (__ci >= 100) [[unlikely]]
840 {
841 __s += std::format(_S_empty_spec, __ci / 100);
842 __ci %= 100;
843 }
844 __s += _S_two_digits(__ci);
845 }
846
847 if (__conv == 'Y' || __conv == 'y')
848 __s += _S_two_digits(__yi % 100);
849
850 if (__mod == 'O') // %OY
851 _S_altnum(_M_locale(__ctx), __s, __is_neg);
852
853 return __format::__write(std::move(__out), __string_view(__s));
854 }
855
856 template<typename _Tp, typename _FormatContext>
857 typename _FormatContext::iterator
858 _M_D(const _Tp& __t, typename _FormatContext::iterator __out,
859 _FormatContext&) const
860 {
861 auto __ymd = _S_date(__t);
862 basic_string<_CharT> __s;
863#if ! _GLIBCXX_USE_CXX11_ABI
864 __s.reserve(8);
865#endif
866 __s = _S_two_digits((unsigned)__ymd.month());
867 __s += _S_slash;
868 __s += _S_two_digits((unsigned)__ymd.day());
869 __s += _S_slash;
870 __s += _S_two_digits(__builtin_abs((int)__ymd.year()) % 100);
871 return __format::__write(std::move(__out), __string_view(__s));
872 }
873
874 template<typename _Tp, typename _FormatContext>
875 typename _FormatContext::iterator
876 _M_e(const _Tp& __t, typename _FormatContext::iterator __out,
877 _FormatContext& __ctx, bool __mod = false) const
878 {
879 // %e Day of month as decimal number, padded with space.
880 // %Oe Locale's alternative digits.
881 chrono::day __d = _S_day(__t);
882 unsigned __i = (unsigned)__d;
883 auto __sv = _S_two_digits(__i);
884 basic_string<_CharT> __s;
885 if (__mod)
886 __sv = _S_altnum(_M_locale(__ctx), __s.assign(__sv));
887 if (__i < 10)
888 __sv = __s = {_S_space, __sv[1]};
889 return __format::__write(std::move(__out), __sv);
890 }
891
892 template<typename _Tp, typename _FormatContext>
893 typename _FormatContext::iterator
894 _M_F(const _Tp& __t, typename _FormatContext::iterator __out,
895 _FormatContext&) const
896 {
897 auto __ymd = _S_date(__t);
898 basic_string<_CharT> __s;
899#if ! _GLIBCXX_USE_CXX11_ABI
900 __s.reserve(11);
901#endif
902 __s += std::format(_GLIBCXX_WIDEN("{:04d}- - "), (int)__ymd.year());
903 auto __sv = _S_two_digits((unsigned)__ymd.month());
904 __s[__s.size() - 5] = __sv[0];
905 __s[__s.size() - 4] = __sv[1];
906 __sv = _S_two_digits((unsigned)__ymd.day());
907 __s[__s.size() - 2] = __sv[0];
908 __s[__s.size() - 1] = __sv[1];
909 __sv = __s;
910 return __format::__write(std::move(__out), __sv);
911 }
912
913 template<typename _Tp, typename _FormatContext>
914 typename _FormatContext::iterator
915 _M_g_G(const _Tp& __t, typename _FormatContext::iterator __out,
916 _FormatContext& __ctx, bool __full) const
917 {
918 // %g last two decimal digits of the ISO week-based year.
919 // %G ISO week-based year.
920 using namespace chrono;
921 auto __d = _S_days(__t);
922 // Move to nearest Thursday:
923 __d -= (weekday(__d) - Monday) - days(3);
924 // ISO week-based year is the year that contains that Thursday:
925 year __y = year_month_day(__d).year();
926 return _M_C_y_Y(__y, std::move(__out), __ctx, "yY"[__full]);
927 }
928
929 template<typename _Tp, typename _FormatContext>
930 typename _FormatContext::iterator
931 _M_I(const _Tp& __t, typename _FormatContext::iterator __out,
932 _FormatContext& __ctx, bool __mod = false) const
933 {
934 auto __hms = _S_hms(__t);
935 int __i = __hms.hours().count();
936 if (__i == 0)
937 __i = 12;
938 else if (__i > 12)
939 __i -= 12;
940 auto __sv = _S_two_digits(__i);
941 basic_string<_CharT> __s;
942 if (__mod)
943 __sv = _S_altnum(_M_locale(__ctx), __s.assign(__sv));
944 return __format::__write(std::move(__out), __sv);
945 }
946
947 template<typename _Tp, typename _FormatContext>
948 typename _FormatContext::iterator
949 _M_j(const _Tp& __t, typename _FormatContext::iterator __out,
950 _FormatContext& __ctx) const
951 {
952 if constexpr (chrono::__is_duration_v<_Tp>)
953 {
954 // Decimal number of days, without padding.
955 unsigned __d = chrono::duration_cast<chrono::days>(__t).count();
956 return std::format_to(std::move(__out), _S_empty_spec, __d);
957 }
958 else
959 {
960 // Day of the year as a decimal number, padding with zero.
961 using namespace chrono;
962 auto __day = _S_days(__t);
963 auto __ymd = _S_date(__t);
964 days __d;
965 // See "Calculating Ordinal Dates" at
966 // https://github.com/HowardHinnant/date/wiki/Examples-and-Recipes
967 if constexpr (is_same_v<typename decltype(__day)::clock, local_t>)
968 __d = __day - local_days(__ymd.year()/January/0);
969 else
970 __d = __day - sys_days(__ymd.year()/January/0);
971 return std::format_to(std::move(__out), _GLIBCXX_WIDEN("{:03d}"),
972 __d.count());
973 }
974 }
975
976 template<typename _Tp, typename _FormatContext>
977 typename _FormatContext::iterator
978 _M_p(const _Tp& __t, typename _FormatContext::iterator __out,
979 _FormatContext& __ctx) const
980 {
981 // %p The locale's equivalent of the AM/PM designations.
982 auto __hms = _S_hms(__t);
983 locale __loc = _M_locale(__ctx);
984 const auto& __tp = use_facet<__timepunct<_CharT>>(__loc);
985 const _CharT* __ampm[2];
986 __tp._M_am_pm(__ampm);
987 return std::format_to(std::move(__out), _S_empty_spec,
988 __ampm[__hms.hours().count() >= 12]);
989 }
990
991 template<typename _Tp, typename _FormatContext>
992 typename _FormatContext::iterator
993 _M_q(const _Tp& __t, typename _FormatContext::iterator __out,
994 _FormatContext& __ctx) const
995 {
996 // %q The duration's unit suffix
997 if constexpr (!chrono::__is_duration_v<_Tp>)
998 __throw_format_error("format error: argument is not a duration");
999 else
1000 {
1001 using period = typename _Tp::period;
1002 char __buf[sizeof("[/]s") + 2 * numeric_limits<intmax_t>::digits10];
1003 constexpr size_t __n = sizeof(__buf);
1004 auto __s = chrono::__detail::__units_suffix<period, _CharT>(__buf,
1005 __n);
1006 if constexpr (is_same_v<decltype(__s), const _CharT*>)
1007 return std::format_to(std::move(__out), _S_empty_spec, __s);
1008 else
1009 {
1010 // Suffix was written to __buf as narrow string.
1011 _CharT __wbuf[__n];
1012 size_t __len = __builtin_strlen(__buf);
1013 locale __loc = _M_locale(__ctx);
1014 auto& __ct = use_facet<ctype<_CharT>>(__loc);
1015 __ct.widen(__buf, __len, __wbuf);
1016 __wbuf[__len] = 0;
1017 return std::format_to(std::move(__out), _S_empty_spec,
1018 __wbuf);
1019 }
1020 }
1021 }
1022
1023 template<typename _Tp, typename _FormatContext>
1024 typename _FormatContext::iterator
1025 _M_r(const _Tp& __t, typename _FormatContext::iterator __out,
1026 _FormatContext& __ctx) const
1027 {
1028 // %r locale's 12-hour clock time.
1029 locale __loc = _M_locale(__ctx);
1030 const auto& __tp = use_facet<__timepunct<_CharT>>(__loc);
1031 const _CharT* __ampm_fmt;
1032 __tp._M_am_pm_format(&__ampm_fmt);
1033 basic_string<_CharT> __fmt(_S_empty_spec);
1034 __fmt.insert(1u, 1u, _S_colon);
1035 __fmt.insert(2u, __ampm_fmt);
1036 return std::vformat_to(std::move(__out), __fmt,
1037 std::make_format_args<_FormatContext>(__t));
1038 }
1039
1040 template<typename _Tp, typename _FormatContext>
1041 typename _FormatContext::iterator
1042 _M_R_T(const _Tp& __t, typename _FormatContext::iterator __out,
1043 _FormatContext& __ctx, bool __secs) const
1044 {
1045 // %R Equivalent to %H:%M
1046 // %T Equivalent to %H:%M:%S
1047 auto __hms = _S_hms(__t);
1048
1049 basic_string<_CharT> __s;
1050#if ! _GLIBCXX_USE_CXX11_ABI
1051 __s.reserve(11);
1052#endif
1053 __s = std::format(_GLIBCXX_WIDEN("{:02d}:00"), __hms.hours().count());
1054 auto __sv = _S_two_digits(__hms.minutes().count());
1055 __s[__s.size() - 2] = __sv[0];
1056 __s[__s.size() - 1] = __sv[1];
1057 __sv = __s;
1058 __out = __format::__write(std::move(__out), __sv);
1059 if (__secs)
1060 {
1061 *__out++ = _S_colon;
1062 __out = _M_S(__hms, std::move(__out), __ctx);
1063 }
1064 return __out;
1065 }
1066
1067 template<typename _Tp, typename _FormatContext>
1068 typename _FormatContext::iterator
1069 _M_S(const _Tp& __t, typename _FormatContext::iterator __out,
1070 _FormatContext& __ctx, bool __mod = false) const
1071 {
1072 // %S Seconds as a decimal number.
1073 // %OS (TODO) The locale's alternative representation.
1074 auto __hms = _S_hms(__t);
1075 __out = _S_dd_zero_fill(__hms.seconds().count(),
1076 std::move(__out), __ctx, __mod);
1077 using rep = typename decltype(__hms)::precision::rep;
1078 if constexpr (__hms.fractional_width != 0)
1079 {
1080 locale __loc = _M_locale(__ctx);
1081 auto __ss = __hms.subseconds();
1082 if constexpr (is_floating_point_v<rep>)
1083 {
1084 __out = std::format_to(__loc, std::move(__out),
1085 _GLIBCXX_WIDEN("{:.{}Lg}"),
1086 __ss.count(),
1087 __hms.fractional_width);
1088 }
1089 else if constexpr (is_integral_v<rep>)
1090 {
1091 const auto& __np
1092 = use_facet<numpunct<_CharT>>(__loc);
1093 __out = std::format_to(std::move(__out),
1094 _GLIBCXX_WIDEN("{}{:0{}}"),
1095 __np.decimal_point(),
1096 __ss.count(),
1097 __hms.fractional_width);
1098 }
1099 else
1100 {
1101 const auto& __np
1102 = use_facet<numpunct<_CharT>>(__loc);
1103 *__out++ = __np.decimal_point();
1104 auto __str = std::format(_S_empty_spec, __ss.count());
1105 __out = std::format_to(_GLIBCXX_WIDEN("{:0>{}s}"),
1106 __str,
1107 __hms.fractional_width);
1108 }
1109 }
1110 return __out;
1111 }
1112
1113 // %t handled in _M_format
1114
1115 template<typename _Tp, typename _FormatContext>
1116 typename _FormatContext::iterator
1117 _M_u_w(const _Tp& __t, typename _FormatContext::iterator __out,
1118 _FormatContext& __ctx, _CharT __conv, bool __mod = false) const
1119 {
1120 // %u ISO weekday as a decimal number (1-7), where Monday is 1.
1121 // %Ou Locale's alternative numeric rep.
1122 // %w Weekday as a decimal number (0-6), where Sunday is 0.
1123 // %Ow Locale's alternative numeric rep.
1124 chrono::weekday __wd = _S_weekday(__t);
1125 unsigned __wdi = __conv == 'u' ? __wd.iso_encoding()
1126 : __wd.c_encoding();
1127 basic_string<_CharT> __s(1, _S_digit(__wdi));
1128 if (__mod)
1129 _S_altnum(_M_locale(__ctx), __s);
1130 return __format::__write(std::move(__out), __string_view(__s));
1131 return __out;
1132 }
1133
1134 template<typename _Tp, typename _FormatContext>
1135 typename _FormatContext::iterator
1136 _M_U_V_W(const _Tp& __t, typename _FormatContext::iterator __out,
1137 _FormatContext& __ctx, _CharT __conv, bool __mod = false) const
1138 {
1139 // %U Week number of the year as a decimal number, from first Sunday.
1140 // %OU Locale's alternative numeric rep.
1141 // %V ISO week-based week number as a decimal number.
1142 // %OV Locale's alternative numeric rep.
1143 // %W Week number of the year as a decimal number, from first Monday.
1144 // %OW Locale's alternative numeric rep.
1145 using namespace chrono;
1146 auto __d = _S_days(__t);
1147 using _TDays = decltype(__d); // Either sys_days or local_days.
1148
1149 _TDays __first; // First day of week 1.
1150 if (__conv == 'V') // W01 begins on Monday before first Thursday.
1151 {
1152 // Move to nearest Thursday:
1153 __d -= (weekday(__d) - Monday) - days(3);
1154 // ISO week of __t is number of weeks since January 1 of the
1155 // same year as that nearest Thursday.
1156 __first = _TDays(year_month_day(__d).year()/January/1);
1157 }
1158 else
1159 {
1160 year __y;
1161 if constexpr (requires { __t.year(); })
1162 __y = __t.year();
1163 else
1164 __y = year_month_day(__d).year();
1165 const weekday __weekstart = __conv == 'U' ? Sunday : Monday;
1166 __first = _TDays(__y/January/__weekstart[1]);
1167 }
1168 auto __weeks = chrono::floor<weeks>(__d - __first);
1169 __string_view __sv = _S_two_digits(__weeks.count() + 1);
1170 basic_string<_CharT> __s;
1171 if (__mod)
1172 __sv = _S_altnum(_M_locale(__ctx), __s.assign(__sv));
1173 return __format::__write(std::move(__out), __sv);
1174 }
1175
1176 template<typename _Tp, typename _FormatContext>
1177 typename _FormatContext::iterator
1178 _M_x(const _Tp& __t, typename _FormatContext::iterator __out,
1179 _FormatContext& __ctx, bool __mod = false) const
1180 {
1181 // %x Locale's date rep
1182 // %Ex Locale's alternative date representation.
1183 locale __loc = _M_locale(__ctx);
1184 const auto& __tp = use_facet<__timepunct<_CharT>>(__loc);
1185 const _CharT* __date_reps[2];
1186 __tp._M_date_formats(__date_reps);
1187 const _CharT* __rep = __date_reps[__mod];
1188 if (!*__rep)
1189 return _M_D(__t, std::move(__out), __ctx);
1190
1191 basic_string<_CharT> __fmt(_S_empty_spec);
1192 __fmt.insert(1u, 1u, _S_colon);
1193 __fmt.insert(2u, __rep);
1194 return std::vformat_to(std::move(__out), __fmt,
1195 std::make_format_args<_FormatContext>(__t));
1196 }
1197
1198 template<typename _Tp, typename _FormatContext>
1199 typename _FormatContext::iterator
1200 _M_X(const _Tp& __t, typename _FormatContext::iterator __out,
1201 _FormatContext& __ctx, bool __mod = false) const
1202 {
1203 // %X Locale's time rep
1204 // %EX Locale's alternative time representation.
1205 locale __loc = _M_locale(__ctx);
1206 const auto& __tp = use_facet<__timepunct<_CharT>>(__loc);
1207 const _CharT* __time_reps[2];
1208 __tp._M_time_formats(__time_reps);
1209 const _CharT* __rep = __time_reps[__mod];
1210 if (!*__rep)
1211 return _M_R_T(__t, std::move(__out), __ctx, true);
1212
1213 basic_string<_CharT> __fmt(_S_empty_spec);
1214 __fmt.insert(1u, 1u, _S_colon);
1215 __fmt.insert(2u, __rep);
1216 return std::vformat_to(std::move(__out), __fmt,
1217 std::make_format_args<_FormatContext>(__t));
1218 }
1219
1220 template<typename _Tp, typename _FormatContext>
1221 typename _FormatContext::iterator
1222 _M_z(const _Tp& __t, typename _FormatContext::iterator __out,
1223 _FormatContext& __ctx, bool __mod = false) const
1224 {
1225 using ::std::chrono::__detail::__utc_leap_second;
1226 using ::std::chrono::__detail::__local_time_fmt;
1227
1228 auto __utc = __mod ? __string_view(_GLIBCXX_WIDEN("+00:00"), 6)
1229 : __string_view(_GLIBCXX_WIDEN("+0000"), 5);
1230
1231 if constexpr (chrono::__is_time_point_v<_Tp>)
1232 {
1233 if constexpr (is_same_v<typename _Tp::clock,
1234 chrono::system_clock>)
1235 return __format::__write(std::move(__out), __utc);
1236 }
1237 else if constexpr (__is_specialization_of<_Tp, __local_time_fmt>)
1238 {
1239 if (__t._M_offset_sec)
1240 {
1241 auto __sv = __utc;
1242 basic_string<_CharT> __s;
1243 if (*__t._M_offset_sec != 0s)
1244 {
1245 chrono:: hh_mm_ss __hms(*__t._M_offset_sec);
1246 __s = _S_plus_minus[__hms.is_negative()];
1247 __s += _S_two_digits(__hms.hours().count());
1248 if (__mod)
1249 __s += _S_colon;
1250 __s += _S_two_digits(__hms.minutes().count());
1251 __sv = __s;
1252 }
1253 return __format::__write(std::move(__out), __sv);
1254 }
1255 }
1256 else if constexpr (__is_specialization_of<_Tp, __utc_leap_second>)
1257 return __format::__write(std::move(__out), __utc);
1258
1259 __no_timezone_available();
1260 }
1261
1262 template<typename _Tp, typename _FormatContext>
1263 typename _FormatContext::iterator
1264 _M_Z(const _Tp& __t, typename _FormatContext::iterator __out,
1265 _FormatContext& __ctx) const
1266 {
1267 using ::std::chrono::__detail::__utc_leap_second;
1268 using ::std::chrono::__detail::__local_time_fmt;
1269
1270 __string_view __utc(_GLIBCXX_WIDEN("UTC"), 3);
1271 if constexpr (chrono::__is_time_point_v<_Tp>)
1272 {
1273 if constexpr (is_same_v<typename _Tp::clock,
1274 chrono::system_clock>)
1275 return __format::__write(std::move(__out), __utc);
1276 }
1277 else if constexpr (__is_specialization_of<_Tp, __local_time_fmt>)
1278 {
1279 if (__t._M_abbrev)
1280 {
1281 __string_view __wsv;
1282 if constexpr (is_same_v<_CharT, char>)
1283 __wsv = *__t._M_abbrev;
1284 else
1285 {
1286 string_view __sv = *__t._M_abbrev;
1287 basic_string<_CharT> __ws(__sv.size());
1288 auto& __ct = use_facet<ctype<_CharT>>(_M_locale(__ctx));
1289 __ct.widen(__sv.data(), __sv.size(), __ws.data());
1290 __wsv = __ws;
1291 }
1292 return __format::__write(std::move(__out), __wsv);
1293 }
1294 }
1295 else if constexpr (__is_specialization_of<_Tp, __utc_leap_second>)
1296 return __format::__write(std::move(__out), __utc);
1297
1298 __no_timezone_available();
1299 }
1300
1301 // %% handled in _M_format
1302
1303 // A single digit character in the range '0'..'9'.
1304 static _CharT
1305 _S_digit(int __n) noexcept
1306 {
1307 // Extra 9s avoid past-the-end read on bad input.
1308 return _GLIBCXX_WIDEN("0123456789999999")[__n & 0xf];
1309 }
1310
1311 // A string view of two digit characters, "00".."99".
1312 static basic_string_view<_CharT>
1313 _S_two_digits(int __n) noexcept
1314 {
1315 return {
1316 _GLIBCXX_WIDEN("0001020304050607080910111213141516171819"
1317 "2021222324252627282930313233343536373839"
1318 "4041424344454647484950515253545556575859"
1319 "6061626364656667686970717273747576777879"
1320 "8081828384858687888990919293949596979899"
1321 "9999999999999999999999999999999999999999"
1322 "9999999999999999") + 2 * (__n & 0x7f),
1323 2
1324 };
1325 }
1326
1327 // Convert a numeric string to the locale's alternative numeric symbols.
1328 static basic_string_view<_CharT>
1329 _S_altnum(const locale& __loc, basic_string<_CharT>& __s,
1330 bool __is_neg = false)
1331 {
1332 if (__loc == locale::classic())
1333 return __s;
1334
1335#if 0 // TODO how can we access numpunct_cache?! Need to go via std::time_put?
1336 auto& __np = use_facet<__numpunct_cache<_CharT>>(__loc);
1337 auto __nums = __np._M_atoms_out; // alts for "-+xX01234..."
1338 if (__is_neg)
1339 __s[0] = __nums[0];
1340 __nums += 4; // now points to alternate digits
1341 for (int __i = __is_neg; __i < __s.size(); ++__i)
1342 __s[__i] = __nums[__s[__i] - '0'];
1343#endif
1344 return __s;
1345 }
1346
1347 // Write two digits, zero-filled.
1348 template<typename _FormatContext>
1349 typename _FormatContext::iterator
1350 _S_dd_zero_fill(int __val, typename _FormatContext::iterator __out,
1351 _FormatContext& __ctx, bool __alt_num) const
1352 {
1353 auto __sv = _S_two_digits(__val);
1354 basic_string<_CharT> __s;
1355 if (__alt_num)
1356 __sv = _S_altnum(_M_locale(__ctx), __s.assign(__sv));
1357 return __format::__write(std::move(__out), __sv);
1358 }
1359
1360 // Accessors for the components of chrono types:
1361
1362 // Returns a hh_mm_ss.
1363 template<typename _Tp>
1364 static decltype(auto)
1365 _S_hms(const _Tp& __t)
1366 {
1367 using ::std::chrono::__detail::__utc_leap_second;
1368 using ::std::chrono::__detail::__local_time_fmt;
1369
1370 if constexpr (__is_specialization_of<_Tp, chrono::hh_mm_ss>)
1371 return __t;
1372 else if constexpr (__is_specialization_of<_Tp, __utc_leap_second>)
1373 return __t._M_time;
1374 else if constexpr (chrono::__is_duration_v<_Tp>)
1375 return chrono::hh_mm_ss<_Tp>(__t);
1376 else if constexpr (chrono::__is_time_point_v<_Tp>)
1377 return chrono::hh_mm_ss(__t - chrono::floor<chrono::days>(__t));
1378 else if constexpr (__is_specialization_of<_Tp, __local_time_fmt>)
1379 return _S_hms(__t._M_time);
1380 else
1381 {
1382 __invalid_chrono_spec();
1383 return chrono::hh_mm_ss<chrono::seconds>();
1384 }
1385 }
1386
1387 // Returns a sys_days or local_days.
1388 template<typename _Tp>
1389 static auto
1390 _S_days(const _Tp& __t)
1391 {
1392 using namespace chrono;
1393 using ::std::chrono::__detail::__utc_leap_second;
1394 using ::std::chrono::__detail::__local_time_fmt;
1395
1396 if constexpr (__is_time_point_v<_Tp>)
1397 return chrono::floor<days>(__t);
1398 else if constexpr (__is_specialization_of<_Tp, __utc_leap_second>)
1399 return __t._M_date;
1400 else if constexpr (__is_specialization_of<_Tp, __local_time_fmt>)
1401 return chrono::floor<days>(__t._M_time);
1402 else if constexpr (is_same_v<_Tp, year_month_day>
1403 || is_same_v<_Tp, year_month_day_last>
1404 || is_same_v<_Tp, year_month_weekday>
1405 || is_same_v<_Tp, year_month_weekday_last>)
1406 return sys_days(__t);
1407 else
1408 {
1409 if constexpr (__is_duration_v<_Tp>)
1410 __not_valid_for_duration();
1411 else
1412 __invalid_chrono_spec();
1413 return chrono::sys_days();
1414 }
1415 }
1416
1417 // Returns a year_month_day.
1418 template<typename _Tp>
1419 static chrono::year_month_day
1420 _S_date(const _Tp& __t)
1421 {
1422 if constexpr (is_same_v<_Tp, chrono::year_month_day>)
1423 return __t;
1424 else
1425 return chrono::year_month_day(_S_days(__t));
1426 }
1427
1428 template<typename _Tp>
1429 static chrono::day
1430 _S_day(const _Tp& __t)
1431 {
1432 using namespace chrono;
1433
1434 if constexpr (is_same_v<_Tp, day>)
1435 return __t;
1436 else if constexpr (requires { __t.day(); })
1437 return __t.day();
1438 else
1439 return _S_date(__t).day();
1440 }
1441
1442 template<typename _Tp>
1443 static chrono::month
1444 _S_month(const _Tp& __t)
1445 {
1446 using namespace chrono;
1447
1448 if constexpr (is_same_v<_Tp, month>)
1449 return __t;
1450 else if constexpr (requires { __t.month(); })
1451 return __t.month();
1452 else
1453 return _S_date(__t).month();
1454 }
1455
1456 template<typename _Tp>
1457 static chrono::year
1458 _S_year(const _Tp& __t)
1459 {
1460 using namespace chrono;
1461
1462 if constexpr (is_same_v<_Tp, year>)
1463 return __t;
1464 else if constexpr (requires { __t.year(); })
1465 return __t.year();
1466 else
1467 return _S_date(__t).year();
1468 }
1469
1470 template<typename _Tp>
1471 static chrono::weekday
1472 _S_weekday(const _Tp& __t)
1473 {
1474 using namespace ::std::chrono;
1475 using ::std::chrono::__detail::__local_time_fmt;
1476
1477 if constexpr (is_same_v<_Tp, weekday>)
1478 return __t;
1479 else if constexpr (requires { __t.weekday(); })
1480 return __t.weekday();
1481 else if constexpr (is_same_v<_Tp, month_weekday>)
1482 return __t.weekday_indexed().weekday();
1483 else if constexpr (is_same_v<_Tp, month_weekday_last>)
1484 return __t.weekday_last().weekday();
1485 else
1486 return weekday(_S_days(__t));
1487 }
1488 };
1489
1490} // namespace __format
1491/// @endcond
1492
1493 template<typename _Rep, typename _Period, typename _CharT>
1494 struct formatter<chrono::duration<_Rep, _Period>, _CharT>
1495 {
1496 constexpr typename basic_format_parse_context<_CharT>::iterator
1497 parse(basic_format_parse_context<_CharT>& __pc)
1498 {
1499 using namespace __format;
1500 auto __it = _M_f._M_parse(__pc, _Duration|_TimeOfDay);
1501 if constexpr (!is_floating_point_v<_Rep>)
1502 if (_M_f._M_spec._M_prec_kind != __format::_WP_none)
1503 __throw_format_error("format error: invalid precision for duration");
1504 return __it;
1505 }
1506
1507 template<typename _Out>
1508 typename basic_format_context<_Out, _CharT>::iterator
1509 format(const chrono::duration<_Rep, _Period>& __d,
1510 basic_format_context<_Out, _CharT>& __fc) const
1511 {
1512 return _M_f._M_format(chrono::abs(__d), __fc, __d < __d.zero());
1513 }
1514
1515 private:
1516 __format::__formatter_chrono<_CharT> _M_f;
1517 };
1518
1519 template<typename _CharT>
1520 struct formatter<chrono::day, _CharT>
1521 {
1522 template<typename _ParseContext>
1523 constexpr typename _ParseContext::iterator
1524 parse(_ParseContext& __pc)
1525 { return _M_f._M_parse(__pc, __format::_Day); }
1526
1527 template<typename _FormatContext>
1528 typename _FormatContext::iterator
1529 format(const chrono::day& __t, _FormatContext& __fc) const
1530 { return _M_f._M_format(__t, __fc); }
1531
1532 private:
1533 __format::__formatter_chrono<_CharT> _M_f;
1534 };
1535
1536 template<typename _CharT>
1537 struct formatter<chrono::month, _CharT>
1538 {
1539 template<typename _ParseContext>
1540 constexpr typename _ParseContext::iterator
1541 parse(_ParseContext& __pc)
1542 { return _M_f._M_parse(__pc, __format::_Month); }
1543
1544 template<typename _FormatContext>
1545 typename _FormatContext::iterator
1546 format(const chrono::month& __t, _FormatContext& __fc) const
1547 { return _M_f._M_format(__t, __fc); }
1548
1549 private:
1550 __format::__formatter_chrono<_CharT> _M_f;
1551 };
1552
1553 template<typename _CharT>
1554 struct formatter<chrono::year, _CharT>
1555 {
1556 template<typename _ParseContext>
1557 constexpr typename _ParseContext::iterator
1558 parse(_ParseContext& __pc)
1559 { return _M_f._M_parse(__pc, __format::_Year); }
1560
1561 template<typename _FormatContext>
1562 typename _FormatContext::iterator
1563 format(const chrono::year& __t, _FormatContext& __fc) const
1564 { return _M_f._M_format(__t, __fc); }
1565
1566 private:
1567 __format::__formatter_chrono<_CharT> _M_f;
1568 };
1569
1570 template<typename _CharT>
1571 struct formatter<chrono::weekday, _CharT>
1572 {
1573 template<typename _ParseContext>
1574 constexpr typename _ParseContext::iterator
1575 parse(_ParseContext& __pc)
1576 { return _M_f._M_parse(__pc, __format::_Weekday); }
1577
1578 template<typename _FormatContext>
1579 typename _FormatContext::iterator
1580 format(const chrono::weekday& __t, _FormatContext& __fc) const
1581 { return _M_f._M_format(__t, __fc); }
1582
1583 private:
1584 __format::__formatter_chrono<_CharT> _M_f;
1585 };
1586
1587 template<typename _CharT>
1588 struct formatter<chrono::weekday_indexed, _CharT>
1589 {
1590 template<typename _ParseContext>
1591 constexpr typename _ParseContext::iterator
1592 parse(_ParseContext& __pc)
1593 { return _M_f._M_parse(__pc, __format::_Weekday); }
1594
1595 template<typename _FormatContext>
1596 typename _FormatContext::iterator
1597 format(const chrono::weekday_indexed& __t, _FormatContext& __fc) const
1598 { return _M_f._M_format(__t, __fc); }
1599
1600 private:
1601 __format::__formatter_chrono<_CharT> _M_f;
1602 };
1603
1604 template<typename _CharT>
1605 struct formatter<chrono::weekday_last, _CharT>
1606 {
1607 template<typename _ParseContext>
1608 constexpr typename _ParseContext::iterator
1609 parse(_ParseContext& __pc)
1610 { return _M_f._M_parse(__pc, __format::_Weekday); }
1611
1612 template<typename _FormatContext>
1613 typename _FormatContext::iterator
1614 format(const chrono::weekday_last& __t, _FormatContext& __fc) const
1615 { return _M_f._M_format(__t, __fc); }
1616
1617 private:
1618 __format::__formatter_chrono<_CharT> _M_f;
1619 };
1620
1621 template<typename _CharT>
1622 struct formatter<chrono::month_day, _CharT>
1623 {
1624 template<typename _ParseContext>
1625 constexpr typename _ParseContext::iterator
1626 parse(_ParseContext& __pc)
1627 { return _M_f._M_parse(__pc, __format::_Month|__format::_Day); }
1628
1629 template<typename _FormatContext>
1630 typename _FormatContext::iterator
1631 format(const chrono::month_day& __t, _FormatContext& __fc) const
1632 { return _M_f._M_format(__t, __fc); }
1633
1634 private:
1635 __format::__formatter_chrono<_CharT> _M_f;
1636 };
1637
1638 template<typename _CharT>
1639 struct formatter<chrono::month_day_last, _CharT>
1640 {
1641 template<typename _ParseContext>
1642 constexpr typename _ParseContext::iterator
1643 parse(_ParseContext& __pc)
1644 { return _M_f._M_parse(__pc, __format::_Month|__format::_Day); }
1645
1646 template<typename _FormatContext>
1647 typename _FormatContext::iterator
1648 format(const chrono::month_day_last& __t, _FormatContext& __fc) const
1649 { return _M_f._M_format(__t, __fc); }
1650
1651 private:
1652 __format::__formatter_chrono<_CharT> _M_f;
1653 };
1654
1655 template<typename _CharT>
1656 struct formatter<chrono::month_weekday, _CharT>
1657 {
1658 template<typename _ParseContext>
1659 constexpr typename _ParseContext::iterator
1660 parse(_ParseContext& __pc)
1661 { return _M_f._M_parse(__pc, __format::_Month|__format::_Weekday); }
1662
1663 template<typename _FormatContext>
1664 typename _FormatContext::iterator
1665 format(const chrono::month_weekday& __t, _FormatContext& __fc) const
1666 { return _M_f._M_format(__t, __fc); }
1667
1668 private:
1669 __format::__formatter_chrono<_CharT> _M_f;
1670 };
1671
1672 template<typename _CharT>
1673 struct formatter<chrono::month_weekday_last, _CharT>
1674 {
1675 template<typename _ParseContext>
1676 constexpr typename _ParseContext::iterator
1677 parse(_ParseContext& __pc)
1678 { return _M_f._M_parse(__pc, __format::_Month|__format::_Weekday); }
1679
1680 template<typename _FormatContext>
1681 typename _FormatContext::iterator
1682 format(const chrono::month_weekday_last& __t,
1683 _FormatContext& __fc) const
1684 { return _M_f._M_format(__t, __fc); }
1685
1686 private:
1687 __format::__formatter_chrono<_CharT> _M_f;
1688 };
1689
1690 template<typename _CharT>
1691 struct formatter<chrono::year_month, _CharT>
1692 {
1693 template<typename _ParseContext>
1694 constexpr typename _ParseContext::iterator
1695 parse(_ParseContext& __pc)
1696 { return _M_f._M_parse(__pc, __format::_Year|__format::_Month); }
1697
1698 template<typename _FormatContext>
1699 typename _FormatContext::iterator
1700 format(const chrono::year_month& __t, _FormatContext& __fc) const
1701 { return _M_f._M_format(__t, __fc); }
1702
1703 private:
1704 __format::__formatter_chrono<_CharT> _M_f;
1705 };
1706
1707 template<typename _CharT>
1708 struct formatter<chrono::year_month_day, _CharT>
1709 {
1710 template<typename _ParseContext>
1711 constexpr typename _ParseContext::iterator
1712 parse(_ParseContext& __pc)
1713 { return _M_f._M_parse(__pc, __format::_Date); }
1714
1715 template<typename _FormatContext>
1716 typename _FormatContext::iterator
1717 format(const chrono::year_month_day& __t, _FormatContext& __fc) const
1718 { return _M_f._M_format(__t, __fc); }
1719
1720 private:
1721 __format::__formatter_chrono<_CharT> _M_f;
1722 };
1723
1724 template<typename _CharT>
1725 struct formatter<chrono::year_month_day_last, _CharT>
1726 {
1727 template<typename _ParseContext>
1728 constexpr typename _ParseContext::iterator
1729 parse(_ParseContext& __pc)
1730 { return _M_f._M_parse(__pc, __format::_Date); }
1731
1732 template<typename _FormatContext>
1733 typename _FormatContext::iterator
1734 format(const chrono::year_month_day_last& __t,
1735 _FormatContext& __fc) const
1736 { return _M_f._M_format(__t, __fc); }
1737
1738 private:
1739 __format::__formatter_chrono<_CharT> _M_f;
1740 };
1741
1742 template<typename _CharT>
1743 struct formatter<chrono::year_month_weekday, _CharT>
1744 {
1745 template<typename _ParseContext>
1746 constexpr typename _ParseContext::iterator
1747 parse(_ParseContext& __pc)
1748 { return _M_f._M_parse(__pc, __format::_Date); }
1749
1750 template<typename _FormatContext>
1751 typename _FormatContext::iterator
1752 format(const chrono::year_month_weekday& __t,
1753 _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::year_month_weekday_last, _CharT>
1762 {
1763 template<typename _ParseContext>
1764 constexpr typename _ParseContext::iterator
1765 parse(_ParseContext& __pc)
1766 { return _M_f._M_parse(__pc, __format::_Date); }
1767
1768 template<typename _FormatContext>
1769 typename _FormatContext::iterator
1770 format(const chrono::year_month_weekday_last& __t,
1771 _FormatContext& __fc) const
1772 { return _M_f._M_format(__t, __fc); }
1773
1774 private:
1775 __format::__formatter_chrono<_CharT> _M_f;
1776 };
1777
1778 template<typename _Rep, typename _Period, typename _CharT>
1779 struct formatter<chrono::hh_mm_ss<chrono::duration<_Rep, _Period>>, _CharT>
1780 {
1781 template<typename _ParseContext>
1782 constexpr typename _ParseContext::iterator
1783 parse(_ParseContext& __pc)
1784 { return _M_f._M_parse(__pc, __format::_TimeOfDay); }
1785
1786 template<typename _FormatContext>
1787 typename _FormatContext::iterator
1788 format(const chrono::hh_mm_ss<chrono::duration<_Rep, _Period>>& __t,
1789 _FormatContext& __fc) const
1790 { return _M_f._M_format(__t, __fc); }
1791
1792 private:
1793 __format::__formatter_chrono<_CharT> _M_f;
1794 };
1795
1796#if _GLIBCXX_USE_CXX11_ABI || ! _GLIBCXX_USE_DUAL_ABI
1797 template<typename _CharT>
1798 struct formatter<chrono::sys_info, _CharT>
1799 {
1800 template<typename _ParseContext>
1801 constexpr typename _ParseContext::iterator
1802 parse(_ParseContext& __pc)
1803 { return _M_f._M_parse(__pc, __format::_ChronoParts{}); }
1804
1805 template<typename _FormatContext>
1806 typename _FormatContext::iterator
1807 format(const chrono::sys_info& __i, _FormatContext& __fc) const
1808 { return _M_f._M_format(__i, __fc); }
1809
1810 private:
1811 __format::__formatter_chrono<_CharT> _M_f;
1812 };
1813
1814 template<typename _CharT>
1815 struct formatter<chrono::local_info, _CharT>
1816 {
1817 template<typename _ParseContext>
1818 constexpr typename _ParseContext::iterator
1819 parse(_ParseContext& __pc)
1820 { return _M_f._M_parse(__pc, __format::_ChronoParts{}); }
1821
1822 template<typename _FormatContext>
1823 typename _FormatContext::iterator
1824 format(const chrono::local_info& __i, _FormatContext& __fc) const
1825 { return _M_f._M_format(__i, __fc); }
1826
1827 private:
1828 __format::__formatter_chrono<_CharT> _M_f;
1829 };
1830#endif
1831
1832 template<typename _Duration, typename _CharT>
1833 struct formatter<chrono::sys_time<_Duration>, _CharT>
1834 {
1835 template<typename _ParseContext>
1836 constexpr typename _ParseContext::iterator
1837 parse(_ParseContext& __pc)
1838 { return _M_f._M_parse(__pc, __format::_ZonedDateTime); }
1839
1840 template<typename _FormatContext>
1841 typename _FormatContext::iterator
1842 format(const chrono::sys_time<_Duration>& __t,
1843 _FormatContext& __fc) const
1844 { return _M_f._M_format(__t, __fc); }
1845
1846 private:
1847 __format::__formatter_chrono<_CharT> _M_f;
1848 };
1849
1850 template<typename _Duration, typename _CharT>
1851 struct formatter<chrono::utc_time<_Duration>, _CharT>
1852 : __format::__formatter_chrono<_CharT>
1853 {
1854 template<typename _ParseContext>
1855 constexpr typename _ParseContext::iterator
1856 parse(_ParseContext& __pc)
1857 { return _M_f._M_parse(__pc, __format::_ZonedDateTime); }
1858
1859 template<typename _FormatContext>
1860 typename _FormatContext::iterator
1861 format(const chrono::utc_time<_Duration>& __t,
1862 _FormatContext& __fc) const
1863 {
1864 // Adjust by removing leap seconds to get equivalent sys_time.
1865 // We can't just use clock_cast because we want to know if the time
1866 // falls within a leap second insertion, and format seconds as "60".
1867 using chrono::__detail::__utc_leap_second;
1868 using chrono::seconds;
1869 using chrono::sys_time;
1870 using _CDur = common_type_t<_Duration, seconds>;
1871 const auto __li = chrono::get_leap_second_info(__t);
1872 sys_time<_CDur> __s{__t.time_since_epoch() - __li.elapsed};
1873 if (!__li.is_leap_second) [[likely]]
1874 return _M_f._M_format(__s, __fc);
1875 else
1876 return _M_f._M_format(__utc_leap_second(__s), __fc);
1877 }
1878
1879 private:
1880 friend formatter<chrono::__detail::__utc_leap_second<_Duration>, _CharT>;
1881
1882 __format::__formatter_chrono<_CharT> _M_f;
1883 };
1884
1885 template<typename _Duration, typename _CharT>
1886 struct formatter<chrono::tai_time<_Duration>, _CharT>
1887 : __format::__formatter_chrono<_CharT>
1888 {
1889 template<typename _ParseContext>
1890 constexpr typename _ParseContext::iterator
1891 parse(_ParseContext& __pc)
1892 { return _M_f._M_parse(__pc, __format::_ZonedDateTime); }
1893
1894 template<typename _FormatContext>
1895 typename _FormatContext::iterator
1896 format(const chrono::tai_time<_Duration>& __t,
1897 _FormatContext& __fc) const
1898 {
1899 // Convert to __local_time_fmt with abbrev "TAI" and offset 0s.
1900
1901 // Offset is 1970y/January/1 - 1958y/January/1
1902 constexpr chrono::days __tai_offset = chrono::days(4383);
1903 using _CDur = common_type_t<_Duration, chrono::days>;
1904 chrono::local_time<_CDur> __lt(__t.time_since_epoch() - __tai_offset);
1905 const string __abbrev("TAI", 3);
1906 const chrono::seconds __off = 0s;
1907 const auto __lf = chrono::local_time_format(__lt, &__abbrev, &__off);
1908 return _M_f._M_format(__lf, __fc);
1909 }
1910
1911 private:
1912 __format::__formatter_chrono<_CharT> _M_f;
1913 };
1914
1915 template<typename _Duration, typename _CharT>
1916 struct formatter<chrono::gps_time<_Duration>, _CharT>
1917 : __format::__formatter_chrono<_CharT>
1918 {
1919 template<typename _ParseContext>
1920 constexpr typename _ParseContext::iterator
1921 parse(_ParseContext& __pc)
1922 { return _M_f._M_parse(__pc, __format::_ZonedDateTime); }
1923
1924 template<typename _FormatContext>
1925 typename _FormatContext::iterator
1926 format(const chrono::gps_time<_Duration>& __t,
1927 _FormatContext& __fc) const
1928 {
1929 // Convert to __local_time_fmt with abbrev "GPS" and offset 0s.
1930
1931 // Offset is 1980y/January/Sunday[1] - 1970y/January/1
1932 constexpr chrono::days __gps_offset = chrono::days(3657);
1933 using _CDur = common_type_t<_Duration, chrono::days>;
1934 chrono::local_time<_CDur> __lt(__t.time_since_epoch() + __gps_offset);
1935 const string __abbrev("GPS", 3);
1936 const chrono::seconds __off = 0s;
1937 const auto __lf = chrono::local_time_format(__lt, &__abbrev, &__off);
1938 return _M_f._M_format(__lf, __fc);
1939 }
1940
1941 private:
1942 __format::__formatter_chrono<_CharT> _M_f;
1943 };
1944
1945 template<typename _Duration, typename _CharT>
1946 struct formatter<chrono::file_time<_Duration>, _CharT>
1947 {
1948 template<typename _ParseContext>
1949 constexpr typename _ParseContext::iterator
1950 parse(_ParseContext& __pc)
1951 { return _M_f._M_parse(__pc, __format::_ZonedDateTime); }
1952
1953 template<typename _FormatContext>
1954 typename _FormatContext::iterator
1955 format(const chrono::file_time<_Duration>& __t,
1956 _FormatContext& __ctx) const
1957 {
1958 using namespace chrono;
1959 return _M_f._M_format(chrono::clock_cast<system_clock>(__t), __ctx);
1960 }
1961
1962 private:
1963 __format::__formatter_chrono<_CharT> _M_f;
1964 };
1965
1966 template<typename _Duration, typename _CharT>
1967 struct formatter<chrono::local_time<_Duration>, _CharT>
1968 {
1969 template<typename _ParseContext>
1970 constexpr typename _ParseContext::iterator
1971 parse(_ParseContext& __pc)
1972 { return _M_f._M_parse(__pc, __format::_DateTime); }
1973
1974 template<typename _FormatContext>
1975 typename _FormatContext::iterator
1976 format(const chrono::local_time<_Duration>& __t,
1977 _FormatContext& __ctx) const
1978 { return _M_f._M_format(__t, __ctx); }
1979
1980 private:
1981 __format::__formatter_chrono<_CharT> _M_f;
1982 };
1983
1984 template<typename _Duration, typename _CharT>
1985 struct formatter<chrono::__detail::__local_time_fmt<_Duration>, _CharT>
1986 {
1987 template<typename _ParseContext>
1988 constexpr typename _ParseContext::iterator
1989 parse(_ParseContext& __pc)
1990 { return _M_f._M_parse(__pc, __format::_ZonedDateTime); }
1991
1992 template<typename _FormatContext>
1993 typename _FormatContext::iterator
1994 format(const chrono::__detail::__local_time_fmt<_Duration>& __t,
1995 _FormatContext& __ctx) const
1996 { return _M_f._M_format(__t, __ctx); }
1997
1998 private:
1999 __format::__formatter_chrono<_CharT> _M_f;
2000 };
2001
2002#if _GLIBCXX_USE_CXX11_ABI || ! _GLIBCXX_USE_DUAL_ABI
2003 template<typename _Duration, typename _TimeZonePtr, typename _CharT>
2004 struct formatter<chrono::zoned_time<_Duration, _TimeZonePtr>, _CharT>
2005 : formatter<chrono::__detail::__local_time_fmt<_Duration>, _CharT>
2006 {
2007 template<typename _FormatContext>
2008 typename _FormatContext::iterator
2009 format(const chrono::zoned_time<_Duration, _TimeZonePtr>& __tp,
2010 _FormatContext& __ctx) const
2011 {
2012 using chrono::__detail::__local_time_fmt;
2013 using _Base = formatter<__local_time_fmt<_Duration>, _CharT>;
2014 const chrono::sys_info __info = __tp.get_info();
2015 const auto __lf = chrono::local_time_format(__tp.get_local_time(),
2016 &__info.abbrev,
2017 &__info.offset);
2018 return _Base::format(__lf, __ctx);
2019 }
2020 };
2021#endif
2022
2023 // Partial specialization needed for %c formatting of __utc_leap_second.
2024 template<typename _Duration, typename _CharT>
2025 struct formatter<chrono::__detail::__utc_leap_second<_Duration>, _CharT>
2026 : formatter<chrono::utc_time<_Duration>, _CharT>
2027 {
2028 template<typename _FormatContext>
2029 typename _FormatContext::iterator
2030 format(const chrono::__detail::__utc_leap_second<_Duration>& __t,
2031 _FormatContext& __fc) const
2032 { return this->_M_f._M_format(__t, __fc); }
2033 };
2034
2035namespace chrono
2036{
2037/// @addtogroup chrono
2038/// @{
2039
2040 // TODO: from_stream for duration
2041#if 0
2042 template<typename _CharT, typename _Traits, typename _Rep, typename _Period,
2043 typename _Alloc = allocator<_CharT>>
2044 basic_istream<_CharT, _Traits>&
2045 from_stream(basic_istream<_CharT, _Traits>& __is, const _CharT* __fmt,
2046 duration<_Rep, _Period>& __d,
2047 basic_string<_CharT, _Traits, _Alloc>* __abbrev = nullptr,
2048 minutes* __offset = nullptr)
2049 {
2050 }
2051#endif
2052
2053 template<typename _CharT, typename _Traits>
2054 inline basic_ostream<_CharT, _Traits>&
2055 operator<<(basic_ostream<_CharT, _Traits>& __os, const day& __d)
2056 {
2057 using _Ctx = __conditional_t<is_same_v<_CharT, char>,
2058 format_context, wformat_context>;
2059 using _Str = basic_string_view<_CharT>;
2060 _Str __s = _GLIBCXX_WIDEN("{:02d} is not a valid day");
2061 if (__d.ok())
2062 __s = __s.substr(0, 6);
2063 __os << std::vformat(__s, make_format_args<_Ctx>((unsigned)__d));
2064 return __os;
2065 }
2066
2067 // TODO from_stream for day
2068
2069 template<typename _CharT, typename _Traits>
2070 inline basic_ostream<_CharT, _Traits>&
2071 operator<<(basic_ostream<_CharT, _Traits>& __os, const month& __m)
2072 {
2073 using _Ctx = __conditional_t<is_same_v<_CharT, char>,
2074 format_context, wformat_context>;
2075 using _Str = basic_string_view<_CharT>;
2076 _Str __s = _GLIBCXX_WIDEN("{:L%b}{} is not a valid month");
2077 if (__m.ok())
2078 __os << std::vformat(__os.getloc(), __s.substr(0, 6),
2079 make_format_args<_Ctx>(__m));
2080 else
2081 __os << std::vformat(__s.substr(6),
2082 make_format_args<_Ctx>((unsigned)__m));
2083 return __os;
2084 }
2085
2086 // TODO from_stream for month
2087
2088 template<typename _CharT, typename _Traits>
2089 inline basic_ostream<_CharT, _Traits>&
2090 operator<<(basic_ostream<_CharT, _Traits>& __os, const year& __y)
2091 {
2092 using _Ctx = __conditional_t<is_same_v<_CharT, char>,
2093 format_context, wformat_context>;
2094 using _Str = basic_string_view<_CharT>;
2095 _Str __s = _GLIBCXX_WIDEN("-{:04d} is not a valid year");
2096 if (__y.ok())
2097 __s = __s.substr(0, 7);
2098 int __i = (int)__y;
2099 if (__i >= 0) [[likely]]
2100 __s.remove_prefix(1);
2101 else
2102 __i = -__i;
2103 __os << std::vformat(__s, make_format_args<_Ctx>(__i));
2104 return __os;
2105 }
2106
2107 // TODO from_stream for year
2108
2109 template<typename _CharT, typename _Traits>
2110 inline basic_ostream<_CharT, _Traits>&
2111 operator<<(basic_ostream<_CharT, _Traits>& __os, const weekday& __wd)
2112 {
2113 using _Ctx = __conditional_t<is_same_v<_CharT, char>,
2114 format_context, wformat_context>;
2115 using _Str = basic_string_view<_CharT>;
2116 _Str __s = _GLIBCXX_WIDEN("{:L%a}{} is not a valid weekday");
2117 if (__wd.ok())
2118 __os << std::vformat(__os.getloc(), __s.substr(0, 6),
2119 make_format_args<_Ctx>(__wd));
2120 else
2121 __os << std::vformat(__s.substr(6),
2122 make_format_args<_Ctx>(__wd.c_encoding()));
2123 return __os;
2124 }
2125
2126 // TODO from_stream for weekday
2127
2128 template<typename _CharT, typename _Traits>
2129 inline basic_ostream<_CharT, _Traits>&
2130 operator<<(basic_ostream<_CharT, _Traits>& __os,
2131 const weekday_indexed& __wdi)
2132 {
2133 // The standard says to format wdi.weekday() and wdi.index() using
2134 // either "{:L}[{}]" or "{:L}[{} is not a valid index]". The {:L} spec
2135 // means to format the weekday using ostringstream, so just do that.
2136 basic_stringstream<_CharT> __os2;
2137 __os2.imbue(__os.getloc());
2138 __os2 << __wdi.weekday();
2139 const auto __i = __wdi.index();
2140 if constexpr (is_same_v<_CharT, char>)
2141 __os2 << std::format("[{}", __i);
2142 else
2143 __os2 << std::format(L"[{}", __i);
2144 basic_string_view<_CharT> __s = _GLIBCXX_WIDEN(" is not a valid index]");
2145 if (__i >= 1 && __i <= 5)
2146 __os2 << __s.back();
2147 else
2148 __os2 << __s;
2149 __os << __os2.view();
2150 return __os;
2151 }
2152
2153 template<typename _CharT, typename _Traits>
2154 inline basic_ostream<_CharT, _Traits>&
2155 operator<<(basic_ostream<_CharT, _Traits>& __os,
2156 const weekday_last& __wdl)
2157 {
2158 // As above, just write straight to a stringstream, as if by "{:L}[last]"
2159 basic_stringstream<_CharT> __os2;
2160 __os2.imbue(__os.getloc());
2161 __os2 << __wdl.weekday() << _GLIBCXX_WIDEN("[last]");
2162 __os << __os2.view();
2163 return __os;
2164 }
2165
2166 template<typename _CharT, typename _Traits>
2167 inline basic_ostream<_CharT, _Traits>&
2168 operator<<(basic_ostream<_CharT, _Traits>& __os, const month_day& __md)
2169 {
2170 // As above, just write straight to a stringstream, as if by "{:L}/{}"
2171 basic_stringstream<_CharT> __os2;
2172 __os2.imbue(__os.getloc());
2173 __os2 << __md.month();
2174 if constexpr (is_same_v<_CharT, char>)
2175 __os2 << '/';
2176 else
2177 __os2 << L'/';
2178 __os2 << __md.day();
2179 __os << __os2.view();
2180 return __os;
2181 }
2182
2183 // TODO from_stream for month_day
2184
2185 template<typename _CharT, typename _Traits>
2186 inline basic_ostream<_CharT, _Traits>&
2187 operator<<(basic_ostream<_CharT, _Traits>& __os,
2188 const month_day_last& __mdl)
2189 {
2190 // As above, just write straight to a stringstream, as if by "{:L}/last"
2191 basic_stringstream<_CharT> __os2;
2192 __os2.imbue(__os.getloc());
2193 __os2 << __mdl.month();
2194 if constexpr (is_same_v<_CharT, char>)
2195 __os2 << "/last";
2196 else
2197 __os2 << L"/last";
2198 __os << __os2.view();
2199 return __os;
2200 }
2201
2202 template<typename _CharT, typename _Traits>
2203 inline basic_ostream<_CharT, _Traits>&
2204 operator<<(basic_ostream<_CharT, _Traits>& __os,
2205 const month_weekday& __mwd)
2206 {
2207 // As above, just write straight to a stringstream, as if by "{:L}/{:L}"
2208 basic_stringstream<_CharT> __os2;
2209 __os2.imbue(__os.getloc());
2210 __os2 << __mwd.month();
2211 if constexpr (is_same_v<_CharT, char>)
2212 __os2 << '/';
2213 else
2214 __os2 << L'/';
2215 __os2 << __mwd.weekday_indexed();
2216 __os << __os2.view();
2217 return __os;
2218 }
2219
2220 template<typename _CharT, typename _Traits>
2221 inline basic_ostream<_CharT, _Traits>&
2222 operator<<(basic_ostream<_CharT, _Traits>& __os,
2223 const month_weekday_last& __mwdl)
2224 {
2225 // As above, just write straight to a stringstream, as if by "{:L}/{:L}"
2226 basic_stringstream<_CharT> __os2;
2227 __os2.imbue(__os.getloc());
2228 __os2 << __mwdl.month();
2229 if constexpr (is_same_v<_CharT, char>)
2230 __os2 << '/';
2231 else
2232 __os2 << L'/';
2233 __os2 << __mwdl.weekday_last();
2234 __os << __os2.view();
2235 return __os;
2236 }
2237
2238 template<typename _CharT, typename _Traits>
2239 inline basic_ostream<_CharT, _Traits>&
2240 operator<<(basic_ostream<_CharT, _Traits>& __os, const year_month& __ym)
2241 {
2242 // As above, just write straight to a stringstream, as if by "{}/{:L}"
2243 basic_stringstream<_CharT> __os2;
2244 __os2.imbue(__os.getloc());
2245 __os2 << __ym.year();
2246 if constexpr (is_same_v<_CharT, char>)
2247 __os2 << '/';
2248 else
2249 __os2 << L'/';
2250 __os2 << __ym.month();
2251 __os << __os2.view();
2252 return __os;
2253 }
2254
2255 // TODO from_stream for year_month
2256
2257 template<typename _CharT, typename _Traits>
2258 inline basic_ostream<_CharT, _Traits>&
2259 operator<<(basic_ostream<_CharT, _Traits>& __os,
2260 const year_month_day& __ymd)
2261 {
2262 using _Ctx = __conditional_t<is_same_v<_CharT, char>,
2263 format_context, wformat_context>;
2264 using _Str = basic_string_view<_CharT>;
2265 _Str __s = _GLIBCXX_WIDEN("{:%F} is not a valid date");
2266 __os << std::vformat(__ymd.ok() ? __s.substr(0, 5) : __s,
2267 make_format_args<_Ctx>(__ymd));
2268 return __os;
2269 }
2270
2271 // TODO from_stream for year_month_day
2272
2273 template<typename _CharT, typename _Traits>
2274 inline basic_ostream<_CharT, _Traits>&
2275 operator<<(basic_ostream<_CharT, _Traits>& __os,
2276 const year_month_day_last& __ymdl)
2277 {
2278 // As above, just write straight to a stringstream, as if by "{}/{:L}"
2279 basic_stringstream<_CharT> __os2;
2280 __os2.imbue(__os.getloc());
2281 __os2 << __ymdl.year();
2282 if constexpr (is_same_v<_CharT, char>)
2283 __os2 << '/';
2284 else
2285 __os2 << L'/';
2286 __os2 << __ymdl.month_day_last();
2287 __os << __os2.view();
2288 return __os;
2289 }
2290
2291 template<typename _CharT, typename _Traits>
2292 inline basic_ostream<_CharT, _Traits>&
2293 operator<<(basic_ostream<_CharT, _Traits>& __os,
2294 const year_month_weekday& __ymwd)
2295 {
2296 // As above, just write straight to a stringstream, as if by
2297 // "{}/{:L}/{:L}"
2298 basic_stringstream<_CharT> __os2;
2299 __os2.imbue(__os.getloc());
2300 _CharT __slash;
2301 if constexpr (is_same_v<_CharT, char>)
2302 __slash = '/';
2303 else
2304 __slash = L'/';
2305 __os2 << __ymwd.year() << __slash << __ymwd.month() << __slash
2306 << __ymwd.weekday_indexed();
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 year_month_weekday_last& __ymwdl)
2315 {
2316 // As above, just write straight to a stringstream, as if by
2317 // "{}/{:L}/{:L}"
2318 basic_stringstream<_CharT> __os2;
2319 __os2.imbue(__os.getloc());
2320 _CharT __slash;
2321 if constexpr (is_same_v<_CharT, char>)
2322 __slash = '/';
2323 else
2324 __slash = L'/';
2325 __os2 << __ymwdl.year() << __slash << __ymwdl.month() << __slash
2326 << __ymwdl.weekday_last();
2327 __os << __os2.view();
2328 return __os;
2329 }
2330
2331 template<typename _CharT, typename _Traits, typename _Duration>
2332 inline basic_ostream<_CharT, _Traits>&
2333 operator<<(basic_ostream<_CharT, _Traits>& __os,
2334 const hh_mm_ss<_Duration>& __hms)
2335 {
2336 return __os << format(__os.getloc(), _GLIBCXX_WIDEN("{:L%T}"), __hms);
2337 }
2338
2339#if _GLIBCXX_USE_CXX11_ABI || ! _GLIBCXX_USE_DUAL_ABI
2340 /// Writes a sys_info object to an ostream in an unspecified format.
2341 template<typename _CharT, typename _Traits>
2342 basic_ostream<_CharT, _Traits>&
2343 operator<<(basic_ostream<_CharT, _Traits>& __os, const sys_info& __i)
2344 {
2345 __os << '[' << __i.begin << ',' << __i.end
2346 << ',' << hh_mm_ss(__i.offset) << ',' << __i.save
2347 << ',' << __i.abbrev << ']';
2348 return __os;
2349 }
2350
2351 /// Writes a local_info object to an ostream in an unspecified format.
2352 template<typename _CharT, typename _Traits>
2353 basic_ostream<_CharT, _Traits>&
2354 operator<<(basic_ostream<_CharT, _Traits>& __os, const local_info& __li)
2355 {
2356 __os << '[';
2357 if (__li.result == local_info::unique)
2358 __os << __li.first;
2359 else
2360 {
2361 if (__li.result == local_info::nonexistent)
2362 __os << "nonexistent";
2363 else
2364 __os << "ambiguous";
2365 __os << " local time between " << __li.first;
2366 __os << " and " << __li.second;
2367 }
2368 __os << ']';
2369 return __os;
2370 }
2371
2372 template<typename _CharT, typename _Traits, typename _Duration,
2373 typename _TimeZonePtr>
2374 inline basic_ostream<_CharT, _Traits>&
2375 operator<<(basic_ostream<_CharT, _Traits>& __os,
2376 const zoned_time<_Duration, _TimeZonePtr>& __t)
2377 {
2378 __os << format(__os.getloc(), _GLIBCXX_WIDEN("{:L%F %T %Z}"), __t);
2379 return __os;
2380 }
2381#endif
2382
2383 template<typename _CharT, typename _Traits, typename _Duration>
2384 requires (!treat_as_floating_point_v<typename _Duration::rep>)
2385 && ratio_less_v<typename _Duration::period, days::period>
2386 inline basic_ostream<_CharT, _Traits>&
2387 operator<<(basic_ostream<_CharT, _Traits>& __os,
2388 const sys_time<_Duration>& __tp)
2389 {
2390 __os << std::format(__os.getloc(), _GLIBCXX_WIDEN("{:L%F %T}"), __tp);
2391 return __os;
2392 }
2393
2394 template<typename _CharT, typename _Traits>
2395 inline basic_ostream<_CharT, _Traits>&
2396 operator<<(basic_ostream<_CharT, _Traits>& __os, const sys_days& __dp)
2397 {
2398 __os << year_month_day{__dp};
2399 return __os;
2400 }
2401
2402 // TODO: from_stream for sys_time
2403
2404 template<typename _CharT, typename _Traits, typename _Duration>
2405 inline basic_ostream<_CharT, _Traits>&
2406 operator<<(basic_ostream<_CharT, _Traits>& __os,
2407 const utc_time<_Duration>& __t)
2408 {
2409 __os << std::format(__os.getloc(), _GLIBCXX_WIDEN("{:L%F %T}"), __t);
2410 return __os;
2411 }
2412
2413 // TODO: from_stream for utc_time
2414
2415 template<typename _CharT, typename _Traits, typename _Duration>
2416 inline basic_ostream<_CharT, _Traits>&
2417 operator<<(basic_ostream<_CharT, _Traits>& __os,
2418 const tai_time<_Duration>& __t)
2419 {
2420 __os << std::format(__os.getloc(), _GLIBCXX_WIDEN("{:L%F %T}"), __t);
2421 return __os;
2422 }
2423
2424 // TODO: from_stream for tai_time
2425
2426 template<typename _CharT, typename _Traits, typename _Duration>
2427 inline basic_ostream<_CharT, _Traits>&
2428 operator<<(basic_ostream<_CharT, _Traits>& __os,
2429 const gps_time<_Duration>& __t)
2430 {
2431 __os << std::format(__os.getloc(), _GLIBCXX_WIDEN("{:L%F %T}"), __t);
2432 return __os;
2433 }
2434
2435 // TODO: from_stream for gps_time
2436
2437
2438 template<typename _CharT, typename _Traits, typename _Duration>
2439 inline basic_ostream<_CharT, _Traits>&
2440 operator<<(basic_ostream<_CharT, _Traits>& __os,
2441 const file_time<_Duration>& __t)
2442 {
2443 __os << std::format(__os.getloc(), _GLIBCXX_WIDEN("{:L%F %T}"), __t);
2444 return __os;
2445 }
2446
2447 // TODO: from_stream for file_time
2448
2449 template<typename _CharT, typename _Traits, typename _Duration>
2450 inline basic_ostream<_CharT, _Traits>&
2451 operator<<(basic_ostream<_CharT, _Traits>& __os,
2452 const local_time<_Duration>& __lt)
2453 {
2454 __os << sys_time<_Duration>{__lt.time_since_epoch()};
2455 return __os;
2456 }
2457
2458 // TODO: from_stream for local_time
2459#undef _GLIBCXX_WIDEN
2460
2461 /// @} group chrono
2462} // namespace chrono
2463
2464_GLIBCXX_END_NAMESPACE_VERSION
2465} // namespace std
2466
2467#endif // C++20
2468
2469#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< 3600 > > hours
hours
Definition: chrono.h:914
duration< int64_t, ratio< 86400 > > days
days
Definition: chrono.h:918
basic_ostream< _CharT, _Traits > & operator<<(std::basic_ostream< _CharT, _Traits > &__os, const duration< _Rep, _Period > &__d)
Definition: chrono_io.h:149
duration< int64_t, ratio< 60 > > minutes
minutes
Definition: chrono.h:911
constexpr std::remove_reference< _Tp >::type && move(_Tp &&__t) noexcept
Convert a value to an rvalue.
Definition: move.h:104
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
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:524
chrono::time_point represents a point in time as measured by a clock
Definition: chrono.h:934
iterator begin()
Definition: cow_string.h:803
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.