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