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