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