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 #ifdef _GLIBCXX_SYSHDR
34 #pragma GCC system_header
35 #endif
36 
37 #if __cplusplus >= 202002L
38 
39 #include <sstream> // ostringstream
40 #include <format>
41 #include <charconv> // from_chars
42 #include <stdexcept> // __sso_string
43 
45 #include <bits/unique_ptr.h>
46 
47 namespace std _GLIBCXX_VISIBILITY(default)
48 {
49 _GLIBCXX_BEGIN_NAMESPACE_VERSION
50 
51 namespace chrono
52 {
53 /// @addtogroup chrono
54 /// @{
55 
56 /// @cond undocumented
57 namespace __detail
58 {
59 #define _GLIBCXX_WIDEN_(C, S) ::std::__format::_Widen<C>(S, L##S)
60 #define _GLIBCXX_WIDEN(S) _GLIBCXX_WIDEN_(_CharT, S)
61 
62  template<typename _Period, typename _CharT>
63  constexpr basic_string_view<_CharT>
64  __units_suffix() noexcept
65  {
66  // The standard say these are all narrow strings, which would need to
67  // be widened at run-time when inserted into a wide stream. We use
68  // STATICALLY-WIDEN to widen at compile-time.
69 #define _GLIBCXX_UNITS_SUFFIX(period, suffix) \
70  if constexpr (is_same_v<_Period, period>) \
71  return _GLIBCXX_WIDEN(suffix); \
72  else
73 
74  _GLIBCXX_UNITS_SUFFIX(atto, "as")
75  _GLIBCXX_UNITS_SUFFIX(femto, "fs")
76  _GLIBCXX_UNITS_SUFFIX(pico, "ps")
77  _GLIBCXX_UNITS_SUFFIX(nano, "ns")
78  _GLIBCXX_UNITS_SUFFIX(milli, "ms")
79 #if _GLIBCXX_USE_ALT_MICROSECONDS_SUFFIX
80  // Deciding this at compile-time is wrong, maybe use nl_langinfo(CODESET)
81  // to check runtime environment and return u8"\u00b5s", "\xb5s", or "us".
82  _GLIBCXX_UNITS_SUFFIX(micro, "\u00b5s")
83 #else
84  _GLIBCXX_UNITS_SUFFIX(micro, "us")
85 #endif
86  _GLIBCXX_UNITS_SUFFIX(centi, "cs")
87  _GLIBCXX_UNITS_SUFFIX(deci, "ds")
88  _GLIBCXX_UNITS_SUFFIX(ratio<1>, "s")
89  _GLIBCXX_UNITS_SUFFIX(deca, "das")
90  _GLIBCXX_UNITS_SUFFIX(hecto, "hs")
91  _GLIBCXX_UNITS_SUFFIX(kilo, "ks")
92  _GLIBCXX_UNITS_SUFFIX(mega, "Ms")
93  _GLIBCXX_UNITS_SUFFIX(giga, "Gs")
94  _GLIBCXX_UNITS_SUFFIX(tera, "Ts")
95  _GLIBCXX_UNITS_SUFFIX(tera, "Ts")
96  _GLIBCXX_UNITS_SUFFIX(peta, "Ps")
97  _GLIBCXX_UNITS_SUFFIX(exa, "Es")
98  _GLIBCXX_UNITS_SUFFIX(ratio<60>, "min")
99  _GLIBCXX_UNITS_SUFFIX(ratio<3600>, "h")
100  _GLIBCXX_UNITS_SUFFIX(ratio<86400>, "d")
101 #undef _GLIBCXX_UNITS_SUFFIX
102  return {};
103  }
104 
105  template<typename _Period, typename _CharT, typename _Out>
106  inline _Out
107  __fmt_units_suffix(_Out __out) noexcept
108  {
109  if (auto __s = __detail::__units_suffix<_Period, _CharT>(); __s.size())
110  return __format::__write(std::move(__out), __s);
111  else if constexpr (_Period::den == 1)
112  return std::format_to(std::move(__out), _GLIBCXX_WIDEN("[{}]s"),
113  (uintmax_t)_Period::num);
114  else
115  return std::format_to(std::move(__out), _GLIBCXX_WIDEN("[{}/{}]s"),
116  (uintmax_t)_Period::num,
117  (uintmax_t)_Period::den);
118  }
119 } // namespace __detail
120 /// @endcond
121 
122  /** Write a `chrono::duration` to an ostream.
123  *
124  * @since C++20
125  */
126  template<typename _CharT, typename _Traits,
127  typename _Rep, typename _Period>
128  inline basic_ostream<_CharT, _Traits>&
129  operator<<(std::basic_ostream<_CharT, _Traits>& __os,
130  const duration<_Rep, _Period>& __d)
131  {
132  using _Out = ostreambuf_iterator<_CharT, _Traits>;
133  using period = typename _Period::type;
134  std::basic_ostringstream<_CharT, _Traits> __s;
135  __s.flags(__os.flags());
136  __s.imbue(__os.getloc());
137  __s.precision(__os.precision());
138  // _GLIBCXX_RESOLVE_LIB_DEFECTS
139  // 4118. How should duration formatters format custom rep types?
140  __s << +__d.count();
141  __detail::__fmt_units_suffix<period, _CharT>(_Out(__s));
142  __os << std::move(__s).str();
143  return __os;
144  }
145 
146 /// @cond undocumented
147 namespace __detail
148 {
149  // An unspecified type returned by `chrono::local_time_format`.
150  // This is called `local-time-format-t` in the standard.
151  template<typename _Duration>
152  struct __local_time_fmt
153  {
154  local_time<_Duration> _M_time;
155  const string* _M_abbrev;
156  const seconds* _M_offset_sec;
157  };
158 
159  // _GLIBCXX_RESOLVE_LIB_DEFECTS
160  // 4124. Cannot format zoned_time with resolution coarser than seconds
161  template<typename _Duration>
162  using __local_time_fmt_for
163  = __local_time_fmt<common_type_t<_Duration, seconds>>;
164 }
165 /// @endcond
166 
167  /** Return an object that asssociates timezone info with a local time.
168  *
169  * A `chrono::local_time` object has no timezone associated with it. This
170  * function creates an object that allows formatting a `local_time` as
171  * though it refers to a timezone with the given abbreviated name and
172  * offset from UTC.
173  *
174  * @since C++20
175  */
176  template<typename _Duration>
177  inline __detail::__local_time_fmt<_Duration>
178  local_time_format(local_time<_Duration> __time,
179  const string* __abbrev = nullptr,
180  const seconds* __offset_sec = nullptr)
181  { return {__time, __abbrev, __offset_sec}; }
182 
183  /// @}
184 } // namespace chrono
185 
186 /// @cond undocumented
187 namespace __format
188 {
189  [[noreturn,__gnu__::__always_inline__]]
190  inline void
191  __not_valid_for_duration()
192  { __throw_format_error("format error: chrono-format-spec not valid for "
193  "chrono::duration"); }
194 
195  [[noreturn,__gnu__::__always_inline__]]
196  inline void
197  __invalid_chrono_spec()
198  { __throw_format_error("format error: chrono-format-spec not valid for "
199  "argument type"); }
200 
201  // Represents the information provided by a chrono type.
202  // e.g. month_weekday has month and weekday but no year or time of day,
203  // hh_mm_ss has time of day but no date, sys_time is time_point+timezone.
204  enum class _ChronoParts : unsigned short {
205  _None = 0, _TotalSeconds = 1u, _Subseconds = 1u << 2,
206 
207  // time since epoch
208  _EpochUnits = 1u << 3, _UnitSuffix = 1u << 4,
209  _EpochSeconds = _EpochUnits | _TotalSeconds,
210 
211  // local (wall) time
212  _LocalDays = 1u << 5,
213  _LocalSeconds = _LocalDays | _TotalSeconds,
214 
215  _Year = 1u << 6, _Month = 1u << 7, _Day = 1u << 8,
216  _Weekday = 1u << 9, _WeekdayIndex = 1u << 10, _DayOfYear = 1u << 11,
217  _IndexedWeekday = _Weekday | _WeekdayIndex,
218  _YearMonthDay = _Year | _Month | _Day,
219  _Date = _LocalDays | _YearMonthDay | _IndexedWeekday | _DayOfYear,
220 
221  _HoursMinutesSeconds = 1u << 12,
222  _TimeOfDay = _HoursMinutesSeconds | _Subseconds,
223  _Time = _TimeOfDay | _TotalSeconds,
224  _EpochTime = _Time | _EpochUnits | _UnitSuffix,
225  _DateTime = _Date | _Time,
226 
227  _ZoneAbbrev = 1u << 13, _ZoneOffset = 1u << 14,
228  _TimeZone = _ZoneAbbrev | _ZoneOffset,
229  _ZonedDateTime = _DateTime | _TimeZone,
230  };
231 
232  [[__gnu__::__always_inline__]]
233  constexpr _ChronoParts
234  operator&(_ChronoParts __x, _ChronoParts __y) noexcept
235  { return static_cast<_ChronoParts>((unsigned)__x & (unsigned)__y); }
236 
237  [[__gnu__::__always_inline__]]
238  constexpr _ChronoParts&
239  operator&=(_ChronoParts& __x, _ChronoParts __y) noexcept
240  { return __x = __x & __y; }
241 
242  [[__gnu__::__always_inline__]]
243  constexpr _ChronoParts
244  operator|(_ChronoParts __x, _ChronoParts __y) noexcept
245  { return static_cast<_ChronoParts>((unsigned short)__x | (unsigned short)__y); }
246 
247  [[__gnu__::__always_inline__]]
248  constexpr _ChronoParts&
249  operator|=(_ChronoParts& __x, _ChronoParts __y) noexcept
250  { return __x = __x | __y; }
251 
252  // returns copy of x with all bits from y unset.
253  [[__gnu__::__always_inline__]]
254  constexpr _ChronoParts
255  operator-(_ChronoParts __x, _ChronoParts __y) noexcept
256  { return static_cast<_ChronoParts>((unsigned short)__x & ~(unsigned short)__y); }
257 
258  // unsets all bits of x that are set in y
259  [[__gnu__::__always_inline__]]
260  constexpr _ChronoParts&
261  operator-=(_ChronoParts& __x, _ChronoParts __y) noexcept
262  { return __x = __x - __y; }
263 
264  [[__gnu__::__always_inline__]]
265  constexpr bool
266  operator==(_ChronoParts __x, decltype(nullptr)) noexcept
267  { return (unsigned short)__x == 0; }
268 
269  template<typename _CharT>
270  struct _ChronoSpec : _Spec<_CharT>
271  {
272  // When _M_prec_kind is _WP_none, the _M_prec contains the default
273  // value of fraction digits to be used for time '%S'.
274 
275  // Placed in tail-padding of __format::_Spec<C>.
276  // This indicates that a locale-dependent conversion specifier such as
277  // %a is used in the chrono-specs. This is not the same as the
278  // _Spec<C>::_M_localized member which indicates that "L" was present
279  // in the format-spec, e.g. "{:L%a}" is localized and locale-specific,
280  // but "{:L}" is only localized and "{:%a}" is only locale-specific.
281  unsigned _M_locale_specific : 1;
282  // Indicates if parts that are checked for ok come directly from the
283  // input, instead of being computed.
284  unsigned _M_needs_ok_check : 1;
285  // Indicates that duration should be treated as floating point.
286  unsigned _M_floating_point_rep : 1;
287  // Indicate that duration uses user-defined representation.
288  unsigned _M_custom_rep : 1;
289  unsigned _M_unused : 4;
290 
291  // Chrono parts required by format specs
292  _ChronoParts _M_needed;
293  basic_string_view<_CharT> _M_chrono_specs;
294 
295  [[__gnu__::__always_inline__]]
296  constexpr bool
297  _M_needs(_ChronoParts __parts) const
298  { return (_M_needed & __parts) != 0; }
299  };
300 
301  template<typename _CharT>
302  struct _ChronoFormats
303  {
304  using _String_view = basic_string_view<_CharT>;
305 
306  static consteval
307  _String_view
308  _S_ftz() noexcept
309  { return _GLIBCXX_WIDEN("%F %T %Z"); }
310 
311  static consteval
312  _String_view
313  _S_ft() noexcept
314  { return _S_ftz().substr(0, 5); }
315 
316  static consteval
317  _String_view
318  _S_f() noexcept
319  { return _S_ftz().substr(0, 2); }
320 
321  static consteval
322  _String_view
323  _S_t() noexcept
324  { return _S_ftz().substr(3, 2); }
325 
326  static consteval
327  _String_view
328  _S_ymd() noexcept
329  { return _GLIBCXX_WIDEN("%Y/%b/%d"); }
330 
331  static consteval
332  _String_view
333  _S_ym() noexcept
334  { return _S_ymd().substr(0, 5); }
335 
336  static consteval
337  _String_view
338  _S_md() noexcept
339  { return _S_ymd().substr(3); }
340 
341  static consteval
342  _String_view
343  _S_y() noexcept
344  { return _S_ymd().substr(0, 2); }
345 
346  static consteval
347  _String_view
348  _S_m() noexcept
349  { return _S_ymd().substr(3, 2); }
350 
351  static consteval
352  _String_view
353  _S_d() noexcept
354  { return _S_ymd().substr(6, 2); }
355 
356  static consteval
357  _String_view
358  _S_ymwi() noexcept
359  // %\0 is extension for handling weekday index
360  { return _String_view(_GLIBCXX_WIDEN("%Y/%b/%a[%\0]"), 12); }
361 
362  static consteval
363  _String_view
364  _S_mwi() noexcept
365  { return _S_ymwi().substr(3); }
366 
367  static consteval
368  _String_view
369  _S_wi() noexcept
370  { return _S_ymwi().substr(6); }
371 
372  static consteval
373  _String_view
374  _S_w() noexcept
375  { return _S_ymwi().substr(6, 2); }
376 
377  static consteval
378  _String_view
379  _S_ymwl() noexcept
380  { return _GLIBCXX_WIDEN("%Y/%b/%a[last]"); }
381 
382  static consteval
383  _String_view
384  _S_mwl() noexcept
385  { return _S_ymwl().substr(3); }
386 
387  static consteval
388  _String_view
389  _S_wl() noexcept
390  { return _S_ymwl().substr(6); }
391 
392  static consteval
393  _String_view
394  _S_yml() noexcept
395  { return _GLIBCXX_WIDEN("%Y/%b/last"); }
396 
397  static consteval
398  _String_view
399  _S_ml() noexcept
400  { return _S_yml().substr(3); }
401  };
402 
403  template<typename _CharT>
404  struct _ChronoData
405  {
406  static constexpr unsigned _S_max_prec = 18;
407  using _Attoseconds = chrono::duration<__UINT_LEAST64_TYPE__, atto>;
408 
409  using _FormatContext
410  = basic_format_context<_Sink_iter<_CharT>, _CharT>;
411  using _FormatArgs = basic_format_args<_FormatContext>;
412  static inline auto _S_args = std::make_format_args<_FormatContext>();
413 
414  _ChronoData() = default;
415  _ChronoData(_ChronoData&&) = delete;
416 
417  // time since epoch
418  chrono::seconds _M_eseconds;
419  // n.b. due offset being seconds or coarser, local and epoch subseconds
420  // has the same value
421  _Attoseconds _M_subseconds;
422  // _M_ereps.get(0) stores duration units
423  // _M_ereps.get(1) stores subseconds units
424  // _M_ereps.get(2) stores precision
425  _FormatArgs _M_ereps = _S_args;
426  basic_string_view<_CharT> _M_unit_suffix;
427 
428  // local (wall) time
429  chrono::local_seconds _M_lseconds;
430  chrono::local_days _M_ldays;
431 
432  chrono::year _M_year;
433  chrono::month _M_month;
434  chrono::day _M_day;
435  chrono::weekday _M_weekday;
436  unsigned char _M_weekday_index;
437  chrono::days _M_day_of_year;
438 
439  bool _M_is_neg;
440  chrono::hours _M_hours;
441  chrono::minutes _M_minutes;
442  chrono::seconds _M_seconds;
443 
444  chrono::seconds _M_zone_offset;
445  basic_string_view<_CharT> _M_zone_abbrev;
446  const char* _M_zone_cstr = "";
447 
448  template<typename _YearMonth>
449  [[__gnu__::__always_inline__]]
450  _ChronoParts
451  _M_fill_year_month(const _YearMonth& __ym, _ChronoParts __parts)
452  {
453  _M_year = __ym.year();
454  __parts -= _ChronoParts::_Year;
455  _M_month = __ym.month();
456  __parts -= _ChronoParts::_Month;
457  return __parts;
458  }
459 
460  [[__gnu__::__always_inline__]]
461  _ChronoParts
462  _M_fill_day(chrono::day __d, _ChronoParts __parts)
463  {
464  _M_day = __d;
465  __parts -= _ChronoParts::_Day;
466  _M_weekday_index = ((unsigned)__d + 6u) / 7u;
467  __parts -= _ChronoParts::_WeekdayIndex;
468  return __parts;
469  }
470 
471  [[__gnu__::__always_inline__]]
472  _ChronoParts
473  _M_fill_weekday(chrono::weekday_indexed __wi, _ChronoParts __parts)
474  {
475  _M_weekday = __wi.weekday();
476  __parts -= _ChronoParts::_Weekday;
477  _M_weekday_index = __wi.index();
478  __parts -= _ChronoParts::_WeekdayIndex;
479  return __parts;
480  }
481 
482  // pre: _M_year is set
483  [[__gnu__::__always_inline__]]
484  _ChronoParts
485  _M_fill_aux(chrono::local_days __ld, _ChronoParts __parts)
486  {
487  using namespace chrono;
488  if ((__parts & _ChronoParts::_Weekday) != 0)
489  _M_weekday = weekday(__ld);
490  __parts -= _ChronoParts::_Weekday;
491  if ((__parts & _ChronoParts::_DayOfYear) != 0)
492  // See "Calculating Ordinal Dates" at
493  // https://github.com/HowardHinnant/date/wiki/Examples-and-Recipes
494  _M_day_of_year = __ld - local_days(_M_year/January/0);
495  __parts -= _ChronoParts::_DayOfYear;
496  return __parts;
497  }
498 
499  // pre: _M_year is set
500  [[__gnu__::__always_inline__]]
501  _ChronoParts
502  _M_fill_ldays(chrono::local_days __ld, _ChronoParts __parts)
503  {
504  _M_ldays = __ld;
505  __parts -= _ChronoParts::_LocalDays;
506  return _M_fill_aux(__ld, __parts);
507  }
508 
509  void
510  _M_fill_time(chrono::seconds __d)
511  {
512  chrono::hh_mm_ss<chrono::seconds> __hms(__d);
513  _M_hours = __hms.hours();
514  _M_minutes = __hms.minutes();
515  _M_seconds = __hms.seconds();
516  }
517 
518  void
519  _M_fill_date_time(chrono::local_seconds __ls, _ChronoParts __parts)
520  {
521  _M_ldays = chrono::floor<chrono::days>(__ls);
522  __parts -= _ChronoParts::_LocalDays;
523  if ((__parts & _ChronoParts::_HoursMinutesSeconds) != 0)
524  _M_fill_time(_M_lseconds - _M_ldays);
525 
526  if ((__parts & _ChronoParts::_Date) != 0)
527  {
528  const chrono::year_month_day __ymd(_M_ldays);
529  _M_fill_year_month(__ymd, __parts);
530  _M_fill_day(__ymd.day(), __parts);
531  _M_fill_aux(_M_ldays, __parts);
532  }
533  }
534 
535  void
536  _M_fill_zone(const char* __abbrev, const wchar_t* __wabbrev)
537  {
538  if constexpr (is_same_v<_CharT, char>)
539  _M_zone_abbrev = __abbrev;
540  else
541  _M_zone_abbrev = __wabbrev;
542  _M_zone_cstr = __abbrev;
543  }
544 
545  [[__gnu__::__always_inline__]]
546  void
547  _M_fill_utc_zone()
548  { _M_fill_zone("UTC", L"UTC"); }
549  };
550 
551  // TODO rename this to chrono::__formatter? or chrono::__detail::__formatter?
552  template<typename _CharT>
553  struct __formatter_chrono
554  {
555  using __string_view = basic_string_view<_CharT>;
556  using __string = basic_string<_CharT>;
557 
558  __formatter_chrono() = default;
559 
560  constexpr explicit
561  __formatter_chrono(_ChronoSpec<_CharT> __spec) noexcept
562  : _M_spec(__spec)
563  { }
564 
565  constexpr typename basic_format_parse_context<_CharT>::iterator
566  _M_parse(basic_format_parse_context<_CharT>& __pc, _ChronoParts __parts,
567  const _ChronoSpec<_CharT>& __def)
568  {
569  auto __first = __pc.begin();
570  auto __last = __pc.end();
571 
572  _ChronoSpec<_CharT> __spec = __def;
573 
574  auto __finalize = [this, &__spec, &__def] {
575  using enum _ChronoParts;
576  _ChronoParts __checked
577  = __spec._M_debug ? _YearMonthDay|_IndexedWeekday
578  : _Month|_Weekday;
579  // n.b. for calendar types __def._M_needed contains only parts
580  // copied from the input, remaining ones are computed, and thus ok
581  __spec._M_needs_ok_check
582  = __spec._M_needs(__def._M_needed & __checked);
583  _M_spec = __spec;
584  };
585 
586  auto __finished = [&] {
587  if (__first == __last || *__first == '}')
588  {
589  __finalize();
590  return true;
591  }
592  return false;
593  };
594 
595  if (__finished())
596  return __first;
597 
598  __first = __spec._M_parse_fill_and_align(__first, __last);
599  if (__finished())
600  return __first;
601 
602  __first = __spec._M_parse_width(__first, __last, __pc);
603  if (__finished())
604  return __first;
605 
606  if (*__first == '.')
607  {
608  if ((__parts & _ChronoParts::_EpochUnits) == 0
609  || !__spec._M_floating_point_rep)
610  __throw_format_error("format error: invalid precision for duration");
611 
612  // Precision is allowed, but value is ignored.
613  __first = _Spec<_CharT>()._M_parse_precision(__first, __last, __pc);
614  // Still inditate that there was user supplied precision.
615  __spec._M_prec_kind = _WP_value;
616  if (__finished())
617  return __first;
618  }
619 
620  __spec._M_localized = false;
621  __first = __spec._M_parse_locale(__first, __last);
622  if (__finished())
623  return __first;
624 
625  // Everything up to the end of the string or the first '}' is a
626  // chrono-specs string. Check it is valid.
627  {
628  __string_view __str(__first, __last - __first);
629  auto __end = __str.find('}');
630  if (__end != __str.npos)
631  {
632  __str.remove_suffix(__str.length() - __end);
633  __last = __first + __end;
634  }
635  if (__str.find('{') != __str.npos)
636  __throw_format_error("chrono format error: '{' in chrono-specs");
637  }
638 
639  // Parse chrono-specs in [first,last), checking each conversion-spec
640  // against __parts (so fail for %Y if no year in parts).
641  // Save range in __spec._M_chrono_specs.
642  __spec._M_debug = false;
643  __spec._M_locale_specific = false;
644  __spec._M_needed = _ChronoParts::_None;
645  __spec._M_chrono_specs = __string_view();
646 
647  const auto __chrono_specs = __first++; // Skip leading '%'
648  if (*__chrono_specs != '%')
649  __throw_format_error("chrono format error: no '%' at start of "
650  "chrono-specs");
651 
652  _CharT __mod{};
653  bool __conv = true;
654  while (__first != __last)
655  {
656  enum _Mods { _Mod_none, _Mod_E, _Mod_O, _Mod_E_O };
657  _Mods __allowed_mods = _Mod_none;
658 
659  _ChronoParts __needed = _ChronoParts::_None;
660  bool __locale_specific = false;
661 
662  _CharT __c = *__first++;
663  switch (__c)
664  {
665  using enum _ChronoParts;
666  case 'a':
667  case 'A':
668  __needed = _Weekday;
669  __locale_specific = true;
670  break;
671  case 'b':
672  case 'h':
673  case 'B':
674  __needed = _Month;
675  __locale_specific = true;
676  break;
677  case 'c':
678  __needed = _Date|_HoursMinutesSeconds;
679  __allowed_mods = _Mod_E;
680  __locale_specific = true;
681  break;
682  case 'C':
683  __needed = _Year;
684  __allowed_mods = _Mod_E;
685  break;
686  case 'd':
687  case 'e':
688  __needed = _Day;
689  __allowed_mods = _Mod_O;
690  break;
691  case 'D':
692  case 'F':
693  __needed = _YearMonthDay;
694  break;
695  case 'g':
696  case 'G':
697  case 'V':
698  __needed = _LocalDays|_Year|_DayOfYear|_Weekday;
699  break;
700  case 'H':
701  case 'I':
702  __needed = _HoursMinutesSeconds;
703  __allowed_mods = _Mod_O;
704  break;
705  case 'j':
706  __needed = __parts & _DayOfYear;
707  // If we do not know day-of-year then we must have a duration,
708  // which is to be formatted as decimal number of days.
709  if (__needed == _None)
710  __needed = _HoursMinutesSeconds;
711  break;
712  case 'm':
713  __needed = _Month;
714  __allowed_mods = _Mod_O;
715  break;
716  case 'M':
717  __needed = _HoursMinutesSeconds;
718  __allowed_mods = _Mod_O;
719  break;
720  case 'p':
721  case 'r':
722  __locale_specific = true;
723  [[fallthrough]];
724  case 'R':
725  __needed = _HoursMinutesSeconds;
726  break;
727  case 'T':
728  __needed = _TimeOfDay;
729  break;
730  case 'q':
731  __needed = _UnitSuffix;
732  break;
733  case 'Q':
734  __needed = _EpochUnits;
735  break;
736  case 'S':
737  __needed = _TimeOfDay;
738  __allowed_mods = _Mod_O;
739  break;
740  case 'u':
741  case 'w':
742  __needed = _Weekday;
743  __allowed_mods = _Mod_O;
744  break;
745  case 'U':
746  case 'W':
747  __needed = _DayOfYear|_Weekday;
748  __allowed_mods = _Mod_O;
749  break;
750  case 'x':
751  __needed = _Date;
752  __locale_specific = true;
753  __allowed_mods = _Mod_E;
754  break;
755  case 'X':
756  __needed = _HoursMinutesSeconds;
757  __locale_specific = true;
758  __allowed_mods = _Mod_E;
759  break;
760  case 'y':
761  __needed = _Year;
762  __allowed_mods = _Mod_E_O;
763  break;
764  case 'Y':
765  __needed = _Year;
766  __allowed_mods = _Mod_E;
767  break;
768  case 'z':
769  __needed = _ZoneOffset;
770  __allowed_mods = _Mod_E_O;
771  break;
772  case 'Z':
773  __needed = _ZoneAbbrev;
774  break;
775  case 'n':
776  case 't':
777  case '%':
778  break;
779  case 'O':
780  case 'E':
781  if (__mod) [[unlikely]]
782  {
783  __allowed_mods = _Mod_none;
784  break;
785  }
786  __mod = __c;
787  continue;
788  default:
789  __throw_format_error("chrono format error: invalid specifier "
790  "in chrono-specs");
791  }
792 
793  if ((__mod == 'E' && !(__allowed_mods & _Mod_E))
794  || (__mod == 'O' && !(__allowed_mods & _Mod_O)))
795  __throw_format_error("chrono format error: invalid modifier "
796  "in chrono-specs");
797  if (__mod && __c != 'z')
798  __locale_specific = true;
799  __mod = _CharT();
800 
801  // localized formats do not include subseconds
802  if (__locale_specific)
803  __needed -= _ChronoParts::_Subseconds;
804 
805  if ((__parts & __needed) != __needed)
806  __throw_format_error("chrono format error: format argument does "
807  "not contain the information required by the "
808  "chrono-specs");
809  __spec._M_needed |= __needed;
810  __spec._M_locale_specific |= __locale_specific;
811 
812  // Scan for next '%', ignoring literal-chars before it.
813  size_t __pos = __string_view(__first, __last - __first).find('%');
814  if (__pos == 0)
815  ++__first;
816  else
817  {
818  if (__pos == __string_view::npos)
819  {
820  __first = __last;
821  __conv = false;
822  }
823  else
824  __first += __pos + 1;
825  }
826  }
827 
828  // Check for a '%' conversion-spec without a type.
829  if (__conv || __mod != _CharT())
830  __throw_format_error("chrono format error: unescaped '%' in "
831  "chrono-specs");
832 
833  __spec._M_chrono_specs
834  = __string_view(__chrono_specs, __first - __chrono_specs);
835 
836  __finalize();
837  return __first;
838  }
839 
840  // pre: !_M_spec._M_chrono_specs.empty()
841  template<typename _FormatContext>
842  typename _FormatContext::iterator
843  _M_format(const _ChronoData<_CharT>& __t, _FormatContext& __fc) const
844  {
845 #if defined _GLIBCXX_USE_NL_LANGINFO_L && __CHAR_BIT__ == 8
846  // _GLIBCXX_RESOLVE_LIB_DEFECTS
847  // 3565. Handling of encodings in localized formatting
848  // of chrono types is underspecified
849  if constexpr (is_same_v<_CharT, char>)
850  if constexpr (__unicode::__literal_encoding_is_utf8())
851  if (_M_spec._M_localized && _M_spec._M_locale_specific)
852  {
853  extern locale __with_encoding_conversion(const locale&);
854 
855  // Allocate and cache the necessary state to convert strings
856  // in the locale's encoding to UTF-8.
857  locale __loc = __fc.locale();
858  if (__loc != locale::classic())
859  __fc._M_loc = __with_encoding_conversion(__loc);
860  }
861 #endif
862 
863  const size_t __padwidth = _M_spec._M_get_width(__fc);
864  if (__padwidth == 0)
865  return _M_format_to(__t, __fc.out(), __fc);
866 
867  using _Out = typename _FormatContext::iterator;
868  _Padding_sink<_Out, _CharT> __sink(__fc.out(), __padwidth);
869  _M_format_to(__t, __sink.out(), __fc);
870  return __sink._M_finish(_M_spec._M_align, _M_spec._M_fill);
871  }
872 
873  _ChronoSpec<_CharT> _M_spec;
874 
875  protected:
876  static constexpr const _CharT* _S_chars
877  = _GLIBCXX_WIDEN("0123456789.Lf:/ +-{}");
878  static constexpr _CharT _S_dot = _S_chars[10];
879  static constexpr _CharT _S_colon = _S_chars[13];
880  static constexpr _CharT _S_slash = _S_chars[14];
881  static constexpr _CharT _S_space = _S_chars[15];
882  static constexpr const _CharT* _S_fp_fmt = _S_chars + 11;
883  static constexpr const _CharT* _S_plus_minus = _S_chars + 16;
884  static constexpr const _CharT* _S_minus_empty_spec = _S_chars + 17;
885  static constexpr const _CharT* _S_empty_spec = _S_chars + 18;
886 
887  [[__gnu__::__always_inline__]]
888  static _Dynamic_format_string<_CharT>
889  _S_empty_fs()
890  { return _Dynamic_format_string<_CharT>(_S_empty_spec); }
891 
892  static constexpr const _CharT* _S_weekdays[]
893  {
894  _GLIBCXX_WIDEN("Sunday"),
895  _GLIBCXX_WIDEN("Monday"),
896  _GLIBCXX_WIDEN("Tuesday"),
897  _GLIBCXX_WIDEN("Wednesday"),
898  _GLIBCXX_WIDEN("Thursday"),
899  _GLIBCXX_WIDEN("Friday"),
900  _GLIBCXX_WIDEN("Saturday"),
901  };
902 
903  static constexpr const _CharT* _S_months[]
904  {
905  _GLIBCXX_WIDEN("January"),
906  _GLIBCXX_WIDEN("February"),
907  _GLIBCXX_WIDEN("March"),
908  _GLIBCXX_WIDEN("April"),
909  _GLIBCXX_WIDEN("May"),
910  _GLIBCXX_WIDEN("June"),
911  _GLIBCXX_WIDEN("July"),
912  _GLIBCXX_WIDEN("August"),
913  _GLIBCXX_WIDEN("September"),
914  _GLIBCXX_WIDEN("October"),
915  _GLIBCXX_WIDEN("November"),
916  _GLIBCXX_WIDEN("December"),
917  };
918 
919  private:
920  template<typename _OutIter>
921  _OutIter
922  _M_write(_OutIter __out, [[maybe_unused]] const locale& __loc,
923  __string_view __s) const
924  {
925 #if defined _GLIBCXX_USE_NL_LANGINFO_L && __CHAR_BIT__ == 8
926  __sso_string __buf;
927  // _GLIBCXX_RESOLVE_LIB_DEFECTS
928  // 3565. Handling of encodings in localized formatting
929  // of chrono types is underspecified
930  if constexpr (is_same_v<_CharT, char>)
931  if constexpr (__unicode::__literal_encoding_is_utf8())
932  if (_M_spec._M_localized && _M_spec._M_locale_specific
933  && __loc != locale::classic())
934  {
935  extern string_view
936  __locale_encoding_to_utf8(const locale&, string_view, void*);
937 
938  __s = __locale_encoding_to_utf8(__loc, __s, &__buf);
939  }
940 #endif
941  return __format::__write(std::move(__out), __s);
942  }
943 
944  [[__gnu__::__always_inline__]]
945  static bool
946  _S_localized_spec(_CharT __conv, _CharT __mod)
947  {
948  switch (__conv)
949  {
950  case 'a':
951  case 'A':
952  case 'b':
953  case 'B':
954  case 'c':
955  case 'h':
956  case 'p':
957  case 'r':
958  case 'x':
959  case 'X':
960  return true;
961  case 'z':
962  return false;
963  default:
964  return (bool)__mod;
965  };
966  }
967 
968  // Use the formatting locale's std::time_put facet to produce
969  // a locale-specific representation.
970  template<typename _Iter>
971  _Iter
972  _M_locale_fmt(_Iter __out, const locale& __loc, const struct tm& __tm,
973  char __fmt, char __mod) const
974  {
975  basic_ostringstream<_CharT> __os;
976  __os.imbue(__loc);
977  const auto& __tp = use_facet<time_put<_CharT>>(__loc);
978  __tp.put(__os, __os, _S_space, &__tm, __fmt, __mod);
979  if (__os)
980  __out = _M_write(std::move(__out), __loc, __os.view());
981  return __out;
982  }
983 
984  __string_view
985  _M_check_ok(const _ChronoData<_CharT>& __t, _CharT& __conv) const
986  {
987  if (!_M_spec._M_debug)
988  {
989  switch (__conv)
990  {
991  case 'a':
992  case 'A':
993  if (!__t._M_weekday.ok()) [[unlikely]]
994  __throw_format_error("format error: invalid weekday");
995  break;
996  case 'b':
997  case 'h':
998  case 'B':
999  if (!__t._M_month.ok()) [[unlikely]]
1000  __throw_format_error("format error: invalid month");
1001  break;
1002  default:
1003  break;
1004  }
1005  return __string_view();
1006  }
1007 
1008  switch (__conv)
1009  {
1010  // %\0 is extension for handling weekday index
1011  case '\0':
1012  if (__t._M_weekday_index < 1 || __t._M_weekday_index > 5) [[unlikely]]
1013  return _GLIBCXX_WIDEN("index");
1014  break;
1015  case 'a':
1016  case 'A':
1017  if (!__t._M_weekday.ok()) [[unlikely]]
1018  {
1019  __conv = 'w'; // print as decimal number
1020  return _GLIBCXX_WIDEN("weekday");
1021  }
1022  break;
1023  case 'b':
1024  case 'h':
1025  case 'B':
1026  if (!__t._M_month.ok()) [[unlikely]]
1027  {
1028  __conv = 'm'; // print as decimal number
1029  return _GLIBCXX_WIDEN("month");
1030  }
1031  break;
1032  case 'd':
1033  case 'e':
1034  if (!__t._M_day.ok()) [[unlikely]]
1035  return _GLIBCXX_WIDEN("day");
1036  break;
1037  case 'F':
1038  if (!(__t._M_year/__t._M_month/__t._M_day).ok()) [[unlikely]]
1039  return _GLIBCXX_WIDEN("date");
1040  break;
1041  case 'Y':
1042  if (!__t._M_year.ok()) [[unlikely]]
1043  return _GLIBCXX_WIDEN("year");
1044  break;
1045  default:
1046  break;
1047  }
1048  return __string_view();
1049  }
1050 
1051  template<typename _OutIter, typename _FormatContext>
1052  _OutIter
1053  _M_format_to(const _ChronoData<_CharT>& __t, _OutIter __out,
1054  _FormatContext& __fc) const
1055  {
1056  auto __first = _M_spec._M_chrono_specs.begin();
1057  const auto __last = _M_spec._M_chrono_specs.end();
1058 
1059  auto __print_sign = [__is_neg = __t._M_is_neg, &__out] () mutable {
1060  if (__is_neg)
1061  {
1062  *__out++ = _S_plus_minus[1];
1063  __is_neg = false;
1064  }
1065  return std::move(__out);
1066  };
1067 
1068  struct tm __tm{};
1069  bool __use_locale_fmt = false;
1070  if (_M_spec._M_localized && _M_spec._M_locale_specific)
1071  if (__fc.locale() != locale::classic())
1072  {
1073  __use_locale_fmt = true;
1074 
1075  __tm.tm_year = (int)__t._M_year - 1900;
1076  __tm.tm_yday = __t._M_day_of_year.count();
1077  __tm.tm_mon = (unsigned)__t._M_month - 1;
1078  __tm.tm_mday = (unsigned)__t._M_day;
1079  __tm.tm_wday = __t._M_weekday.c_encoding();
1080  __tm.tm_hour = __t._M_hours.count();
1081  __tm.tm_min = __t._M_minutes.count();
1082  __tm.tm_sec = __t._M_seconds.count();
1083 
1084  // Some locales use %Z in their %c format but we don't want strftime
1085  // to use the system's local time zone (from /etc/localtime or $TZ)
1086  // as the output for %Z. Setting tm_isdst to -1 says there is no
1087  // time zone info available for the time in __tm.
1088  __tm.tm_isdst = -1;
1089 
1090 #ifdef _GLIBCXX_USE_STRUCT_TM_TM_ZONE
1091  // POSIX.1-2024 adds tm.tm_zone which will be used for %Z.
1092  // BSD has had tm_zone since 1987 but as char* so cast away const.
1093  if (__t._M_zone_cstr)
1094  __tm.tm_zone = const_cast<char*>(__t._M_zone_cstr);
1095 #endif
1096  }
1097 
1098  // Characters to output for "%n", "%t" and "%%" specifiers.
1099  constexpr const _CharT* __literals = _GLIBCXX_WIDEN("\n\t%");
1100 
1101  ++__first; // Skip leading '%' at start of chrono-specs.
1102 
1103  _CharT __mod{};
1104  do
1105  {
1106  _CharT __c = *__first++;
1107  __string_view __invalid;
1108  if (_M_spec._M_needs_ok_check)
1109  __invalid = _M_check_ok(__t, __c);
1110 
1111  if (__invalid.empty() &&__use_locale_fmt
1112  && _S_localized_spec(__c, __mod)) [[unlikely]]
1113  __out = _M_locale_fmt(std::move(__out), __fc.locale(),
1114  __tm, __c, __mod);
1115  else switch (__c)
1116  {
1117  // %\0 is extension for handling weekday index
1118  case '\0':
1119  __out = _M_wi(__t._M_weekday_index, std::move(__out));
1120  break;
1121  case 'a':
1122  case 'A':
1123  __out = _M_a_A(__t._M_weekday, std::move(__out), __c == 'A');
1124  break;
1125  case 'b':
1126  case 'h':
1127  case 'B':
1128  __out = _M_b_B(__t._M_month, std::move(__out), __c == 'B');
1129  break;
1130  case 'c':
1131  __out = _M_c(__t, std::move(__out));
1132  break;
1133  case 'C':
1134  case 'y':
1135  case 'Y':
1136  __out = _M_C_y_Y(__t._M_year, std::move(__out), __c);
1137  break;
1138  case 'd':
1139  case 'e':
1140  __out = _M_d_e(__t._M_day, std::move(__out), __c);
1141  break;
1142  case 'D':
1143  case 'x':
1144  __out = _M_D_x(__t, std::move(__out));
1145  break;
1146  case 'F':
1147  __out = _M_F(__t, std::move(__out));
1148  break;
1149  case 'g':
1150  case 'G':
1151  case 'V':
1152  __out = _M_g_G_V(__t, std::move(__out), __c);
1153  break;
1154  case 'H':
1155  case 'I':
1156  __out = _M_H_I(__t._M_hours, __print_sign(), __c);
1157  break;
1158  case 'j':
1159  __out = _M_j(__t, __print_sign());
1160  break;
1161  case 'm':
1162  __out = _M_m(__t._M_month, std::move(__out));
1163  break;
1164  case 'M':
1165  __out = _M_M(__t._M_minutes, __print_sign());
1166  break;
1167  case 'p':
1168  __out = _M_p(__t._M_hours, std::move(__out));
1169  break;
1170  case 'q':
1171  __out = _M_q(__t._M_unit_suffix, std::move(__out));
1172  break;
1173  case 'Q':
1174  __out = _M_Q(__t, __print_sign(), __fc);
1175  break;
1176  case 'r':
1177  __out = _M_r(__t, __print_sign());
1178  break;
1179  case 'R':
1180  case 'X':
1181  __out = _M_R_X(__t, __print_sign(), __c != 'R');
1182  break;
1183  case 'T':
1184  __out = _M_T(__t, __print_sign(), __fc);
1185  break;
1186  case 'S':
1187  __out = _M_S(__t, __print_sign(), __fc, __mod != 'O');
1188  break;
1189  case 'u':
1190  case 'w':
1191  __out = _M_u_w(__t._M_weekday, std::move(__out), __c);
1192  break;
1193  case 'U':
1194  case 'W':
1195  __out = _M_U_W(__t, std::move(__out), __c);
1196  break;
1197  case 'z':
1198  __out = _M_z(__t._M_zone_offset, std::move(__out), (bool)__mod);
1199  break;
1200  case 'Z':
1201  __out = _M_Z(__t._M_zone_abbrev, std::move(__out));
1202  break;
1203  case 'n':
1204  *__out++ = __literals[0];
1205  break;
1206  case 't':
1207  *__out++ = __literals[1];
1208  break;
1209  case '%':
1210  *__out++ = __literals[2];
1211  break;
1212  case 'O':
1213  case 'E':
1214  __mod = __c;
1215  continue;
1216  case '}':
1217  __first = __last;
1218  break;
1219  }
1220 
1221  if (!__invalid.empty())
1222  {
1223  constexpr __string_view __pref = _GLIBCXX_WIDEN(" is not a valid ");
1224  __out = __format::__write(std::move(__out), __pref);
1225  __out = __format::__write(std::move(__out), __invalid);
1226  }
1227 
1228  __mod = _CharT();
1229  // Scan for next '%' and write out everything before it.
1230  __string_view __str(__first, __last - __first);
1231  size_t __pos = __str.find('%');
1232  if (__pos == 0)
1233  ++__first;
1234  else
1235  {
1236  if (__pos == __str.npos)
1237  __first = __last;
1238  else
1239  {
1240  __str.remove_suffix(__str.length() - __pos);
1241  __first += __pos + 1;
1242  }
1243  __out = __format::__write(std::move(__out), __str);
1244  }
1245  }
1246  while (__first != __last);
1247  return std::move(__out);
1248  }
1249 
1250  template<typename _OutIter>
1251  _OutIter
1252  _M_wi(unsigned __wi, _OutIter __out) const
1253  {
1254  // %\0 Extension to format weekday index, used only by empty format spec
1255  _CharT __buf[3];
1256  __out = __format::__write(std::move(__out), _S_str_d1(__buf, __wi));
1257  return std::move(__out);
1258  }
1259 
1260  template<typename _OutIter>
1261  _OutIter
1262  _M_a_A(chrono::weekday __wd, _OutIter __out, bool __full) const
1263  {
1264  // %a Locale's abbreviated weekday name.
1265  // %A Locale's full weekday name.
1266  __string_view __str = _S_weekdays[__wd.c_encoding()];
1267  if (!__full)
1268  __str = __str.substr(0, 3);
1269  return __format::__write(std::move(__out), __str);
1270  }
1271 
1272  template<typename _OutIter>
1273  _OutIter
1274  _M_b_B(chrono::month __m, _OutIter __out, bool __full) const
1275  {
1276  // %b Locale's abbreviated month name.
1277  // %B Locale's full month name.
1278  __string_view __str = _S_months[(unsigned)__m - 1];
1279  if (!__full)
1280  __str = __str.substr(0, 3);
1281  return __format::__write(std::move(__out), __str);
1282  }
1283 
1284  template<typename _OutIter>
1285  _OutIter
1286  _M_c(const _ChronoData<_CharT>& __t, _OutIter __out) const
1287  {
1288  // %c Locale's date and time representation, for C-locale: %a %b %e %T %Y
1289  // %Ec Locale's alternate date and time representation, for C-locale same as above
1290 
1291  __out = _M_a_A(__t._M_weekday, std::move(__out), false);
1292  *__out = _S_space;
1293  __out = _M_b_B(__t._M_month, std::move(++__out), false);
1294  *__out = _S_space;
1295  __out = _M_d_e(__t._M_day, std::move(++__out), 'e');
1296  *__out = _S_space;
1297  __out = _M_R_X(__t, std::move(++__out), true);
1298  *__out = _S_space;
1299  return _M_C_y_Y(__t._M_year, std::move(++__out), 'Y');
1300  }
1301 
1302  template<typename _OutIter>
1303  _OutIter
1304  _M_C_y_Y(chrono::year __y, _OutIter __out, _CharT __conv) const
1305  {
1306  // %C Year divided by 100 using floored division.
1307  // %EC Locale's alternative preresentation of the century (era name).
1308  // %y Last two decimal digits of the year.
1309  // %Oy Locale's alternative representation.
1310  // %Ey Locale's alternative representation of offset from %EC.
1311  // %Y Year as a decimal number.
1312  // %EY Locale's alternative full year representation.
1313 
1314  int __yi = (int)__y;
1315  const bool __is_neg = __yi < 0;
1316  // _GLIBCXX_RESOLVE_LIB_DEFECTS
1317  // 3831. Two-digit formatting of negative year is ambiguous
1318  __yi = __builtin_abs(__yi);
1319  int __ci = __yi / 100;
1320  // For floored division -123//100 is -2 and -100//100 is -1
1321  if (__conv == 'C' && __is_neg && (__ci * 100) != __yi) [[unlikely]]
1322  ++__ci;
1323 
1324  if (__conv != 'y' && __ci >= 100) [[unlikely]]
1325  {
1326  using _FmtStr = _Dynamic_format_string<_CharT>;
1327  __string_view __fs = _S_minus_empty_spec + !__is_neg;
1328  __out = std::format_to(std::move(__out), _FmtStr(__fs),
1329  __conv == 'C' ? __ci : __yi);
1330  }
1331  else
1332  {
1333  _CharT __buf[5];
1334  __buf[0] = _S_plus_minus[1];
1335  __string_view __sv(__buf + 3, __buf + 3);
1336  if (__conv != 'y')
1337  {
1338  _S_fill_two_digits(__buf + 1, __ci);
1339  __sv = __string_view(__buf + !__is_neg, __buf + 3);
1340  }
1341  if (__conv != 'C')
1342  {
1343  _S_fill_two_digits(__buf + 3, __yi % 100);
1344  __sv = __string_view(__sv.data(), __buf + 5);
1345  }
1346  __out = __format::__write(std::move(__out), __sv);
1347  }
1348  return __out;
1349  }
1350 
1351  template<typename _OutIter>
1352  _OutIter
1353  _M_D_x(const _ChronoData<_CharT>& __t, _OutIter __out) const
1354  {
1355  // %D Equivalent to %m/%d/%y
1356  // %x Locale's date rep, for C-locale: %m/%d/%y
1357  // %Ex Locale's alternative date representation, for C-locale same as above
1358 
1359  auto __di = (unsigned)__t._M_day;
1360  auto __mi = (unsigned)__t._M_month;
1361  auto __yi = __builtin_abs((int)__t._M_year) % 100;
1362 
1363  if (__mi >= 100 || __di >= 100) [[unlikely]]
1364  {
1365  using _FmtStr = _Dynamic_format_string<_CharT>;
1366  __string_view __fs = _GLIBCXX_WIDEN("{:02d}/{:02d}/{:02d}");
1367  __out = std::format_to(std::move(__out), _FmtStr(__fs),
1368  __mi, __di, __yi);
1369  }
1370  else
1371  {
1372  _CharT __buf[8];
1373  __buf[2] = _S_slash;
1374  __buf[5] = _S_slash;
1375  __string_view __sv(__buf, __buf + 8);
1376 
1377  _S_fill_two_digits(__buf, __mi);
1378  _S_fill_two_digits(__buf + 3, __di);
1379  _S_fill_two_digits(__buf + 6, __yi);
1380  __out = __format::__write(std::move(__out), __sv);
1381  }
1382  return std::move(__out);
1383  }
1384 
1385  template<typename _OutIter>
1386  _OutIter
1387  _M_d_e(chrono::day __d, _OutIter __out, _CharT __conv) const
1388  {
1389  // %d The day of month as a decimal number.
1390  // %Od Locale's alternative representation.
1391  // %e Day of month as decimal number, padded with space.
1392  // %Oe Locale's alternative digits.
1393 
1394  unsigned __i = (unsigned)__d;
1395 
1396  _CharT __buf[3];
1397  auto __sv = _S_str_d2(__buf, __i);
1398  if (__conv == _CharT('e') && __i < 10)
1399  {
1400  __buf[1] = __sv[1];
1401  __buf[0] = _S_space;
1402  __sv = {__buf, 2};
1403  }
1404 
1405  __out = __format::__write(std::move(__out), __sv);
1406  return std::move(__out);
1407  }
1408 
1409  template<typename _OutIter>
1410  _OutIter
1411  _M_F(const _ChronoData<_CharT>& __t, _OutIter __out) const
1412  {
1413  auto __di = (unsigned)__t._M_day;
1414  auto __mi = (unsigned)__t._M_month;
1415  auto __yi = (int)__t._M_year;
1416  const bool __is_neg = __yi < 0;
1417  __yi = __builtin_abs(__yi);
1418 
1419  if (__yi >= 10000 || __mi >= 100 || __di >= 100) [[unlikely]]
1420  {
1421  using _FmtStr = _Dynamic_format_string<_CharT>;
1422  __string_view __fs
1423  = _GLIBCXX_WIDEN("-{:04d}-{:02d}-{:02d}") + !__is_neg;
1424  __out = std::format_to(std::move(__out), _FmtStr(__fs),
1425  __yi, __mi, __di);
1426  }
1427  else
1428  {
1429  _CharT __buf[11];
1430  __buf[0] = _S_plus_minus[1];
1431  __buf[5] = _S_plus_minus[1];
1432  __buf[8] = _S_plus_minus[1];
1433  __string_view __sv(__buf + !__is_neg, __buf + 11);
1434 
1435  _S_fill_two_digits(__buf + 1, __yi / 100);
1436  _S_fill_two_digits(__buf + 3, __yi % 100);
1437  _S_fill_two_digits(__buf + 6, __mi);
1438  _S_fill_two_digits(__buf + 9, __di);
1439  __out = __format::__write(std::move(__out), __sv);
1440  }
1441 
1442  return std::move(__out);
1443  }
1444 
1445  template<typename _OutIter>
1446  _OutIter
1447  _M_g_G_V(const _ChronoData<_CharT>& __t, _OutIter __out,
1448  _CharT __conv) const
1449  {
1450  // %g last two decimal digits of the ISO week-based year.
1451  // %G ISO week-based year.
1452  // %V ISO week-based week number as a decimal number.
1453  // %OV Locale's alternative numeric rep.
1454 
1455  // ISO week-based year of __t is the year that contains the nearest
1456  // Thursday. The ISO week of __t is the number of weeks since
1457  // January 1 of that year.
1458 
1459  using namespace chrono;
1460  // Offset of the nearest Thursday:
1461  const days __offset = (__t._M_weekday - Monday) - days(3);
1462  // Nearest Thursday as local days:
1463  const local_days __ild = __t._M_ldays - __offset;
1464  // Day of year of nearest Thursday:
1465  days __idoy = __t._M_day_of_year - __offset;
1466 
1467  // Year of nearest Thursday:
1468  year __iyear;
1469  if (__idoy <= days(0))
1470  __iyear = __t._M_year - years(1);
1471  else if (__idoy <= days(365))
1472  __iyear = __t._M_year;
1473  else if (__idoy == days(366) && __t._M_year.is_leap())
1474  __iyear = __t._M_year;
1475  else if (__idoy <= days(730))
1476  __iyear = __t._M_year + years(1);
1477  else [[unlikely]]
1478  __iyear = year_month_day(__ild).year();
1479 
1480  if (__conv != 'V')
1481  return _M_C_y_Y(__iyear, std::move(__out), "yY"[__conv == 'G']);
1482 
1483  if (__iyear != __t._M_year)
1484  __idoy = __ild - local_days(__iyear/January/0);
1485 
1486  const auto __wi = chrono::floor<weeks>(__idoy - days(1)).count() + 1;
1487  return __format::__write(std::move(__out), _S_two_digits(__wi));
1488  }
1489 
1490  template<typename _OutIter>
1491  _OutIter
1492  _M_H_I(chrono::hours __h, _OutIter __out, _CharT __conv) const
1493  {
1494  // %H The hour (24-hour clock) as a decimal number.
1495  // %OH Locale's alternative representation.
1496  // %I The hour (12-hour clock) as a decimal number.
1497  // %OI Locale's alternative representation.
1498 
1499  int __i = __h.count();
1500 
1501  if (__conv == _CharT('I'))
1502  {
1503  __i %= 12;
1504  if (__i == 0)
1505  __i = 12;
1506  }
1507  else if (__i >= 100) [[unlikely]]
1508  return std::format_to(std::move(__out), _S_empty_fs(), __i);
1509 
1510  return __format::__write(std::move(__out), _S_two_digits(__i));
1511  }
1512 
1513  template<typename _OutIter>
1514  _OutIter
1515  _M_j(const _ChronoData<_CharT>& __t, _OutIter __out) const
1516  {
1517  if (!_M_spec._M_needs(_ChronoParts::_DayOfYear))
1518  {
1519  // Decimal number of days, without padding.
1520  auto __d = chrono::floor<chrono::days>(__t._M_hours).count();
1521  return std::format_to(std::move(__out), _S_empty_fs(), __d);
1522  }
1523 
1524  auto __d = __t._M_day_of_year.count();
1525  if (__d >= 1000) [[unlikely]]
1526  return std::format_to(std::move(__out), _S_empty_fs(), __d);
1527 
1528  _CharT __buf[3];
1529  return __format::__write(std::move(__out), _S_str_d3(__buf, __d));
1530  }
1531 
1532  template<typename _OutIter>
1533  _OutIter
1534  _M_m(chrono::month __m, _OutIter __out) const
1535  {
1536  // %m month as a decimal number.
1537  // %Om Locale's alternative representation.
1538  auto __i = (unsigned)__m;
1539  if (__i == 0 && _M_spec._M_debug) [[unlikely]]
1540  // 0 should not be padded to two digits
1541  return __format::__write(std::move(__out), _S_digit(0));
1542 
1543  _CharT __buf[3];
1544  return __format::__write(std::move(__out), _S_str_d2(__buf, __i));
1545  }
1546 
1547  template<typename _OutIter>
1548  _OutIter
1549  _M_M(chrono::minutes __m, _OutIter __out) const
1550  {
1551  // %M The minute as a decimal number.
1552  // %OM Locale's alternative representation.
1553 
1554  auto __i = __m.count();
1555  return __format::__write(std::move(__out), _S_two_digits(__i));
1556  }
1557 
1558  template<typename _OutIter>
1559  _OutIter
1560  _M_p(chrono::hours __h, _OutIter __out) const
1561  {
1562  // %p The locale's equivalent of the AM/PM designations.
1563 
1564  _CharT __buf[2];
1565  _S_fill_ampm(__buf, __h);
1566  return __format::__write(std::move(__out), __string_view(__buf, 2));
1567  }
1568 
1569  template<typename _OutIter>
1570  _OutIter
1571  _M_q(__string_view __us, _OutIter __out) const
1572  {
1573  // %q The duration's unit suffix
1574  return __format::__write(std::move(__out), __us);
1575  }
1576 
1577  template<typename _OutIter, typename _FormatContext>
1578  _OutIter
1579  _M_Q(const _ChronoData<_CharT>& __t, _OutIter __out,
1580  _FormatContext&) const
1581  {
1582  // %Q The duration's numeric value.
1583  return std::vformat_to(std::move(__out), _S_empty_spec, __t._M_ereps);
1584  }
1585 
1586  template<typename _OutIter>
1587  _OutIter
1588  _M_r(const _ChronoData<_CharT>& __t, _OutIter __out) const
1589  {
1590  // %r Locale's 12-hour clock time, for C-locale: %I:%M:%S %p
1591  auto __hi = __t._M_hours.count() % 12;
1592  if (__hi == 0)
1593  __hi = 12;
1594 
1595  _CharT __buf[11];
1596  __buf[2] = _S_colon;
1597  __buf[5] = _S_colon;
1598  __buf[8] = _S_space;
1599  _S_fill_two_digits(__buf, __hi);
1600  _S_fill_two_digits(__buf + 3, __t._M_minutes.count());
1601  _S_fill_two_digits(__buf + 6, __t._M_seconds.count());
1602  _S_fill_ampm(__buf + 9, __t._M_hours);
1603 
1604  return __format::__write(std::move(__out), __string_view(__buf, 11));
1605  }
1606 
1607  template<typename _OutIter>
1608  _OutIter
1609  _M_R_X(const _ChronoData<_CharT>& __t, _OutIter __out,
1610  bool __secs) const
1611  {
1612  // %R Equivalent to %H:%M
1613  // %X Locale's time rep, for C-locale: %H:%M:%S (without subseconds)
1614  // %EX Locale's alternative time representation, for C-locale same as above
1615 
1616  auto __hi = __t._M_hours.count();
1617 
1618  _CharT __buf[8];
1619  __buf[2] = _S_colon;
1620  __buf[5] = _S_colon;
1621  __string_view __sv(__buf, 8);
1622 
1623  if (__hi >= 100) [[unlikely]]
1624  {
1625  __out = std::format_to(std::move(__out), _S_empty_fs(), __hi);
1626  __sv.remove_prefix(2);
1627  }
1628  else
1629  _S_fill_two_digits(__buf, __hi);
1630 
1631  _S_fill_two_digits(__buf + 3, __t._M_minutes.count());
1632  if (__secs)
1633  _S_fill_two_digits(__buf + 6, __t._M_seconds.count());
1634  else
1635  __sv.remove_suffix(3);
1636 
1637  return __format::__write(std::move(__out), __sv);
1638  }
1639 
1640  template<typename _OutIter, typename _FormatContext>
1641  _OutIter
1642  _M_S(const _ChronoData<_CharT>& __t, _OutIter __out,
1643  _FormatContext& __ctx, bool __subs = true) const
1644  {
1645  // %S Seconds as a decimal number.
1646  // %OS The locale's alternative representation.
1647  auto __s = __t._M_seconds;
1648 
1649  __out = __format::__write(std::move(__out),
1650  _S_two_digits(__s.count()));
1651  if (__subs)
1652  __out = _M_subsecs(__t, std::move(__out), __ctx);
1653  return __out;
1654  }
1655 
1656  template<typename _OutIter, typename _FormatContext>
1657  _OutIter
1658  _M_subsecs(const _ChronoData<_CharT>& __t, _OutIter __out,
1659  _FormatContext& __ctx) const
1660  {
1661  unsigned __prec = _M_spec._M_prec_kind != _WP_none
1662  ? _M_spec._M_get_precision(__ctx)
1663  : _M_spec._M_prec;
1664  if (__prec == 0)
1665  return __out;
1666 
1667  _CharT __dot = _S_dot;
1668  if (_M_spec._M_localized) [[unlikely]]
1669  {
1670  auto __loc = __ctx.locale();
1671  const auto& __np = use_facet<numpunct<_CharT>>(__loc);
1672  __dot = __np.decimal_point();
1673  }
1674  *__out = __dot;
1675  ++__out;
1676 
1677  if (_M_spec._M_floating_point_rep)
1678  {
1679  _Str_sink<_CharT> __sink;
1680  if (_M_spec._M_localized && _M_spec._M_custom_rep) [[unlikely]]
1681  std::vformat_to(__sink.out(), __ctx.locale(),
1682  _GLIBCXX_WIDEN("{1:0.{2}Lf}"), __t._M_ereps);
1683  else
1684  std::vformat_to(__sink.out(),
1685  _GLIBCXX_WIDEN("{1:0.{2}f}"), __t._M_ereps);
1686 
1687  auto __sv = __sink.view();
1688  // Skip leading zero and dot
1689  __sv.remove_prefix(2);
1690  return __format::__write(std::move(__out), __sv);
1691  }
1692 
1693  constexpr unsigned __max_prec = _ChronoData<_CharT>::_S_max_prec;
1694  constexpr typename _ChronoData<_CharT>::_Attoseconds::rep __pow10t[]
1695  {
1696  1u,
1697  10u, 100u, 1000u,
1698  10'000u, 100'000u, 1000'000u,
1699  10'000'000u, 100'000'000u, 1000'000'000u,
1700  10'000'000'000u, 100'000'000'000u, 1000'000'000'000u,
1701  10'000'000'000'000u, 100'000'000'000'000u, 1000'000'000'000'000u,
1702  10'000'000'000'000'000u, 100'000'000'000'000'000u, 1000'000'000'000'000'000u,
1703  };
1704 
1705  auto __subs = __t._M_subseconds.count();
1706  if (__prec < __max_prec)
1707  __subs /= __pow10t[__max_prec - __prec];
1708  else if (__prec > __max_prec)
1709  __prec = __max_prec;
1710 
1711  using _FmtStr = _Dynamic_format_string<_CharT>;
1712  return std::format_to(__out, _FmtStr(_GLIBCXX_WIDEN("{0:0{1}}")),
1713  __subs, __prec);
1714  }
1715 
1716  // %t handled in _M_format
1717 
1718  template<typename _OutIter, typename _FormatContext>
1719  _OutIter
1720  _M_T(const _ChronoData<_CharT>& __t, _OutIter __out,
1721  _FormatContext& __ctx) const
1722  {
1723  // %T Equivalent to %H:%M:%S, with subseconds
1724  __out = _M_R_X(__t, std::move(__out), true);
1725  return _M_subsecs(__t, std::move(__out), __ctx);
1726  }
1727 
1728  template<typename _OutIter>
1729  _OutIter
1730  _M_u_w(chrono::weekday __wd, _OutIter __out, _CharT __conv) const
1731  {
1732  // %u ISO weekday as a decimal number (1-7), where Monday is 1.
1733  // %Ou Locale's alternative numeric rep.
1734  // %w Weekday as a decimal number (0-6), where Sunday is 0.
1735  // %Ow Locale's alternative numeric rep.
1736  unsigned __wdi = __conv == 'u' ? __wd.iso_encoding()
1737  : __wd.c_encoding();
1738  _CharT __buf[3];
1739  return __format::__write(std::move(__out), _S_str_d1(__buf, __wdi));
1740  }
1741 
1742  template<typename _OutIter>
1743  _OutIter
1744  _M_U_W(const _ChronoData<_CharT>& __t, _OutIter __out,
1745  _CharT __conv) const
1746  {
1747  // %U Week number of the year as a decimal number, from first Sunday.
1748  // %OU Locale's alternative numeric rep.
1749  // %W Week number of the year as a decimal number, from first Monday.
1750  // %OW Locale's alternative numeric rep.
1751 
1752  using namespace chrono;
1753  const weekday __weekstart = __conv == 'U' ? Sunday : Monday;
1754  const days __offset = __t._M_weekday - __weekstart;
1755  auto __weeks = chrono::floor<weeks>(__t._M_day_of_year - __offset - days(1));
1756  return __format::__write(std::move(__out), _S_two_digits(__weeks.count() + 1));
1757  }
1758 
1759  template<typename _OutIter>
1760  _OutIter
1761  _M_z(chrono::seconds __ts, _OutIter __out, bool __mod = false) const
1762  {
1763  if (__ts == 0s)
1764  {
1765  __string_view __zero
1766  = __mod ? _GLIBCXX_WIDEN("+00:00") : _GLIBCXX_WIDEN("+0000");
1767  return __format::__write(std::move(__out), __zero);
1768  }
1769 
1770  chrono::hh_mm_ss<chrono::seconds> __hms(__ts);
1771  unsigned __mo = 3 + __mod;
1772 
1773  _CharT __buf[6];
1774  __buf[0] = _S_plus_minus[__hms.is_negative()];
1775  __buf[3] = _S_colon;
1776  _S_fill_two_digits(__buf + 1, __hms.hours().count());
1777  _S_fill_two_digits(__buf + __mo, __hms.minutes().count());
1778 
1779  __string_view __sv(__buf, __mo + 2);
1780  return __format::__write(std::move(__out), __sv);
1781  }
1782 
1783  template<typename _OutIter>
1784  _OutIter
1785  _M_Z(__string_view __abbrev, _OutIter __out) const
1786  { return __format::__write(std::move(__out), __abbrev); }
1787 
1788  // %% handled in _M_format
1789 
1790  // A string view of single digit character, "0".."9".
1791  static basic_string_view<_CharT>
1792  _S_digit(int __n) noexcept
1793  {
1794  // Extra 9s avoid past-the-end read on bad input.
1795  return { _GLIBCXX_WIDEN("0123456789999999") + (__n & 0xf), 1 };
1796  }
1797 
1798  // A string view of two digit characters, "00".."99".
1799  static basic_string_view<_CharT>
1800  _S_two_digits(int __n) noexcept
1801  {
1802  return {
1803  _GLIBCXX_WIDEN("0001020304050607080910111213141516171819"
1804  "2021222324252627282930313233343536373839"
1805  "4041424344454647484950515253545556575859"
1806  "6061626364656667686970717273747576777879"
1807  "8081828384858687888990919293949596979899"
1808  "9999999999999999999999999999999999999999"
1809  "9999999999999999") + 2 * (__n & 0x7f),
1810  2
1811  };
1812  }
1813 
1814  // Fills __buf[0] and __buf[1] with 2 digit value of __n.
1815  [[__gnu__::__always_inline__]]
1816  static void
1817  _S_fill_two_digits(_CharT* __buf, unsigned __n)
1818  {
1819  auto __sv = _S_two_digits(__n);
1820  __buf[0] = __sv[0];
1821  __buf[1] = __sv[1];
1822  }
1823 
1824  // Fills __buf[0] and __buf[1] with "AM", "PM" depending on __h.
1825  [[__gnu__::__always_inline__]]
1826  static void
1827  _S_fill_ampm(_CharT* __buf, chrono::hours __h)
1828  {
1829  auto __hi = __h.count();
1830  if (__hi >= 24) [[unlikely]]
1831  __hi %= 24;
1832 
1833  constexpr const _CharT* __apm = _GLIBCXX_WIDEN("APM");
1834  __buf[0] = __apm[__hi >= 12];
1835  __buf[1] = __apm[2];
1836  }
1837 
1838  // Returns decimal representation of __n.
1839  // Returned string_view may point to __buf.
1840  [[__gnu__::__always_inline__]]
1841  static basic_string_view<_CharT>
1842  _S_str_d1(span<_CharT, 3> __buf, unsigned __n)
1843  {
1844  if (__n < 10) [[likely]]
1845  return _S_digit(__n);
1846  return _S_str_d2(__buf, __n);
1847  }
1848 
1849  // Returns decimal representation of __n, padded to 2 digits.
1850  // Returned string_view may point to __buf.
1851  [[__gnu__::__always_inline__]]
1852  static basic_string_view<_CharT>
1853  _S_str_d2(span<_CharT, 3> __buf, unsigned __n)
1854  {
1855  if (__n < 100) [[likely]]
1856  return _S_two_digits(__n);
1857  return _S_str_d3(__buf, __n);
1858  }
1859 
1860  // Returns decimal representation of __n, padded to 3 digits.
1861  // Returned string_view points to __buf.
1862  [[__gnu__::__always_inline__]]
1863  static basic_string_view<_CharT>
1864  _S_str_d3(span<_CharT, 3> __buf, unsigned __n)
1865  {
1866  _S_fill_two_digits(__buf.data(), __n / 10);
1867  __buf[2] = _S_chars[__n % 10];
1868  return __string_view(__buf.data(), 3);
1869  }
1870  };
1871 
1872  template<typename _CharT>
1873  struct __formatter_duration : private __formatter_chrono<_CharT>
1874  {
1875  template<typename _Rep, typename _Period>
1876  constexpr static auto
1877  _S_subseconds(const chrono::duration<_Rep, _Period>& __d)
1878  {
1879  if constexpr (chrono::treat_as_floating_point_v<_Rep>)
1880  return chrono::duration<_Rep>(__d);
1881  else if constexpr (_Period::den == 1)
1882  return chrono::seconds(0);
1883  else
1884  {
1885  using _Attoseconds = _ChronoData<_CharT>::_Attoseconds;
1886  using _CRep = common_type_t<_Rep, typename _Attoseconds::rep>;
1887  chrono::duration<_CRep, _Period> __subs(__d.count());
1888  return chrono::duration_cast<_Attoseconds>(__subs);
1889  }
1890  }
1891 
1892  public:
1893  template<typename _Duration>
1894  static consteval
1895  _ChronoSpec<_CharT>
1896  _S_spec_for(_ChronoParts __parts)
1897  {
1898  using _Rep = typename _Duration::rep;
1899  using enum _ChronoParts;
1900 
1901  _ChronoSpec<_CharT> __res{};
1902  __res._M_floating_point_rep = chrono::treat_as_floating_point_v<_Rep>;
1903  __res._M_custom_rep = !is_arithmetic_v<_Rep>;
1904  __res._M_prec = chrono::hh_mm_ss<_Duration>::fractional_width;
1905  if ((__parts & _TimeOfDay) != 0)
1906  __res._M_localized = __res._M_prec > 0 || __res._M_floating_point_rep;
1907 
1908  if ((__parts & _TimeOfDay) != 0)
1909  __res._M_needed |= _TimeOfDay;
1910  if ((__parts & _Date) != 0)
1911  __res._M_needed |= _YearMonthDay;
1912  if ((__parts & _ZoneAbbrev) != 0)
1913  __res._M_needed |= _ZoneAbbrev;
1914 
1915  switch (__parts)
1916  {
1917  case _ZonedDateTime:
1918  __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_ftz();
1919  break;
1920  case _DateTime:
1921  __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_ft();
1922  break;
1923  case _Date:
1924  __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_f();
1925  break;
1926  case _Time:
1927  __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_t();
1928  break;
1929  case _None:
1930  break;
1931  default:
1932  __builtin_unreachable();
1933  }
1934  return __res;
1935  };
1936 
1937  template<typename _Duration>
1938  static consteval
1939  _ChronoSpec<_CharT>
1940  _S_spec_for_tp()
1941  {
1942  using enum _ChronoParts;
1943  // streaming of local_time is defined in terms of sys_time
1944  constexpr bool __stream_insertable =
1945  requires (basic_ostream<_CharT>& __os, chrono::sys_time<_Duration> __t)
1946  { __os << __t; };
1947  if constexpr (!__stream_insertable)
1948  return _S_spec_for<_Duration>(_None);
1949  else if constexpr (is_convertible_v<_Duration, chrono::days>)
1950  return _S_spec_for<_Duration>(_Date);
1951  else
1952  return _S_spec_for<_Duration>(_DateTime);
1953  }
1954 
1955  using __formatter_chrono<_CharT>::__formatter_chrono;
1956  using __formatter_chrono<_CharT>::_M_spec;
1957 
1958  template<typename _Duration>
1959  constexpr typename basic_format_parse_context<_CharT>::iterator
1960  _M_parse(basic_format_parse_context<_CharT>& __pc, _ChronoParts __parts,
1961  const _ChronoSpec<_CharT>& __def)
1962  {
1963  using _Rep = typename _Duration::rep;
1964  using enum _ChronoParts;
1965 
1966  auto __res
1967  = __formatter_chrono<_CharT>::_M_parse(__pc, __parts, __def);
1968  // n.b. durations do not contain date parts, and for time point all
1969  // date parts are computed, and they are always ok.
1970  _M_spec._M_needs_ok_check = false;
1971 
1972  // check for custom floating point durations, if digits of output
1973  // will contain subseconds, then formatters must support specifying
1974  // precision.
1975  if constexpr (!is_floating_point_v<_Rep>)
1976  if constexpr (chrono::treat_as_floating_point_v<_Rep>)
1977  if (_M_spec._M_needs(_Subseconds|_EpochUnits)
1978  || _M_spec._M_prec_kind != _WP_none
1979  || _M_spec._M_prec_value > 0)
1980  {
1981  constexpr const _CharT* __fs = _GLIBCXX_WIDEN("#02.5Lf");
1982  basic_format_parse_context<_CharT> __npc(__fs);
1983  formatter<_Rep, _CharT> __fmtter;
1984  __fmtter.parse(__npc);
1985  }
1986  return __res;
1987  }
1988 
1989  // Return the formatting locale.
1990  template<typename _FormatContext>
1991  std::locale
1992  _M_locale(_FormatContext& __fc) const
1993  {
1994  if (!_M_spec._M_localized)
1995  return std::locale::classic();
1996  else
1997  return __fc.locale();
1998  }
1999 
2000  // Format duration for empty chrono-specs, e.g. "{}" (C++20 [time.format] p6).
2001  template<typename _Rep, typename _Period, typename _FormatContext>
2002  typename _FormatContext::iterator
2003  _M_format_to_ostream(const chrono::duration<_Rep, _Period>& __d,
2004  bool __is_neg,
2005  _FormatContext& __fc) const
2006  {
2007  basic_ostringstream<_CharT> __os;
2008  __os.imbue(this->_M_locale(__fc));
2009 
2010  if (__is_neg) [[unlikely]]
2011  __os << this->_S_plus_minus[1];
2012  __os << __d;
2013 
2014  auto __str = std::move(__os).str();
2015  return __format::__write_padded_as_spec(__str, __str.size(),
2016  __fc, _M_spec);
2017  }
2018 
2019  template<typename _Rep1, typename _Period1,
2020  typename _Rep2, typename _Period2,
2021  typename _FormatContext>
2022  typename _FormatContext::iterator
2023  _M_format_units(_ChronoData<_CharT>& __cd,
2024  const chrono::duration<_Rep1, _Period1>& __ed,
2025  const chrono::duration<_Rep2, _Period2>& __ss,
2026  _FormatContext& __fc) const
2027  {
2028  __format::_Str_sink<_CharT> __suffix_store;
2029  constexpr auto _S_unit_suffix
2030  = chrono::__detail::__units_suffix<_Period1, _CharT>();
2031  if constexpr (!_S_unit_suffix.empty())
2032  __cd._M_unit_suffix = _S_unit_suffix;
2033  else if (_M_spec._M_needs(_ChronoParts::_UnitSuffix))
2034  {
2035  chrono::__detail::
2036  __fmt_units_suffix<_Period1, _CharT>(__suffix_store.out());
2037  __cd._M_unit_suffix = __suffix_store.view();
2038  }
2039 
2040  const auto __prec = _M_spec._M_prec_kind != _WP_none
2041  ? _M_spec._M_get_precision(__fc)
2042  : _M_spec._M_prec;
2043 
2044  using _ErasedContext = typename _ChronoData<_CharT>::_FormatContext;
2045  // _GLIBCXX_RESOLVE_LIB_DEFECTS
2046  // 4118. How should duration formatters format custom rep?
2047  auto __ereps = +__ed.count();
2048  if (!_M_spec._M_needs(_ChronoParts::_Subseconds))
2049  {
2050  auto __ssreps = 0u;
2051  auto __args_store
2052  = std::make_format_args<_ErasedContext>(__ereps, __ssreps, __prec);
2053  __cd._M_ereps = __args_store;
2054  return this->_M_format(__cd, __fc);
2055  }
2056 
2057  using _Attoseconds = _ChronoData<_CharT>::_Attoseconds;
2058  auto __nss = _S_subseconds(__ss);
2059  __cd._M_subseconds = chrono::duration_cast<_Attoseconds>(__nss);
2060 
2061  auto __ssreps = __nss.count();
2062  auto __args_store
2063  = std::make_format_args<_ErasedContext>(__ereps, __ssreps, __prec);
2064  __cd._M_ereps = __args_store;
2065 
2066  return this->_M_format(__cd, __fc);
2067  }
2068 
2069  // pre: __cd._M_lseconds and __cd._M_eseconds are set.
2070  template<typename _Rep1, typename _Period1, typename _FormatContext>
2071  typename _FormatContext::iterator
2072  _M_format_time_point(_ChronoData<_CharT>& __cd,
2073  const chrono::duration<_Rep1, _Period1>& __ed,
2074  _FormatContext& __fc) const
2075  {
2076  auto __parts = _M_spec._M_needed - _ChronoParts::_TotalSeconds;
2077  if ((__parts & _ChronoParts::_DateTime) != 0)
2078  __cd._M_fill_date_time(__cd._M_lseconds, __parts);
2079  return _M_format_units(__cd, __ed, __ed - __cd._M_eseconds, __fc);
2080  }
2081  };
2082 
2083 #if _GLIBCXX_USE_CXX11_ABI || ! _GLIBCXX_USE_DUAL_ABI
2084  template<typename _CharT>
2085  struct __formatter_chrono_info
2086  {
2087  constexpr typename basic_format_parse_context<_CharT>::iterator
2088  parse(basic_format_parse_context<_CharT>& __pc)
2089  { return _M_f._M_parse(__pc, _ChronoParts(), {}); }
2090 
2091  template<typename _Info, typename _Out>
2092  typename basic_format_context<_Out, _CharT>::iterator
2093  format(const _Info& __i,
2094  basic_format_context<_Out, _CharT>& __fc) const
2095  {
2096  // n.b. only acceptable chrono-spec for info is one containing
2097  // only whitespaces and %%, that do not depend on formatted object.
2098  if (!_M_f._M_spec._M_chrono_specs.empty()) [[unlikely]]
2099  return _M_f._M_format(_ChronoData<_CharT>{}, __fc);
2100 
2101  const size_t __padwidth = _M_f._M_spec._M_get_width(__fc);
2102  if (__padwidth == 0)
2103  return _M_format_to(__fc.out(), __i);
2104 
2105  _Padding_sink<_Out, _CharT> __sink(__fc.out(), __padwidth);
2106  _M_format_to(__sink.out(), __i);
2107  return __sink._M_finish(_M_f._M_spec._M_align, _M_f._M_spec._M_fill);
2108  }
2109 
2110  private:
2111  template<typename _Out>
2112  _Out
2113  _M_format_to(_Out __out, const chrono::sys_info& __si) const
2114  {
2115  using _FmtStr = _Dynamic_format_string<_CharT>;
2116  // n.b. only decimal separator is locale dependent for specifiers
2117  // used below, as sys_info uses seconds and minutes duration, the
2118  // output is locale-independent.
2119  constexpr auto* __fs
2120  = _GLIBCXX_WIDEN("[{0:%F %T},{1:%F %T},{2:%T},{3:%Q%q},{0:%Z}]");
2121  const chrono::local_seconds __lb(__si.begin.time_since_epoch());
2122  return std::format_to(std::move(__out), _FmtStr(__fs),
2123  chrono::local_time_format(__lb, &__si.abbrev),
2124  __si.end, __si.offset, __si.save);
2125  }
2126 
2127  template<typename _Out>
2128  _Out
2129  _M_format_to(_Out __out, const chrono::local_info& __li) const
2130  {
2131  *__out = _Separators<_CharT>::_S_squares()[0];
2132  ++__out;
2133  if (__li.result == chrono::local_info::unique)
2134  __out = _M_format_to(std::move(__out), __li.first);
2135  else
2136  {
2137  basic_string_view<_CharT> __sv;
2138  if (__li.result == chrono::local_info::nonexistent)
2139  __sv =_GLIBCXX_WIDEN("nonexistent");
2140  else
2141  __sv = _GLIBCXX_WIDEN("ambiguous");
2142  __out = __format::__write(std::move(__out), __sv);
2143 
2144  __sv = _GLIBCXX_WIDEN(" local time between ");
2145  __out = __format::__write(std::move(__out), __sv);
2146  __out = _M_format_to(std::move(__out), __li.first);
2147 
2148  __sv = _GLIBCXX_WIDEN(" and ");
2149  __out = __format::__write(std::move(__out), __sv);
2150  __out = _M_format_to(std::move(__out), __li.second);
2151  }
2152  *__out = _Separators<_CharT>::_S_squares()[1];
2153  ++__out;
2154  return std::move(__out);
2155  }
2156 
2157  __formatter_chrono<_CharT> _M_f;
2158  };
2159 #endif
2160 
2161 } // namespace __format
2162 /// @endcond
2163 
2164  template<typename _Rep, typename _Period, typename _CharT>
2165  requires __format::__formattable_impl<_Rep, _CharT>
2166  struct formatter<chrono::duration<_Rep, _Period>, _CharT>
2167  {
2168  constexpr typename basic_format_parse_context<_CharT>::iterator
2169  parse(basic_format_parse_context<_CharT>& __pc)
2170  {
2171  using enum __format::_ChronoParts;
2172  return _M_f.template _M_parse<_Duration>(__pc, _EpochTime, __defSpec);
2173  }
2174 
2175  template<typename _Out>
2176  typename basic_format_context<_Out, _CharT>::iterator
2177  format(const chrono::duration<_Rep, _Period>& __d,
2178  basic_format_context<_Out, _CharT>& __fc) const
2179  {
2180  if constexpr (numeric_limits<_Rep>::is_signed)
2181  if (__d < __d.zero()) [[unlikely]]
2182  {
2183  if constexpr (is_integral_v<_Rep>)
2184  {
2185  // -d is undefined for the most negative integer.
2186  // Convert duration to corresponding unsigned rep.
2187  using _URep = make_unsigned_t<_Rep>;
2188  auto __ucnt = -static_cast<_URep>(__d.count());
2189  auto __ud = chrono::duration<_URep, _Period>(__ucnt);
2190  return _M_format(__ud, true, __fc);
2191  }
2192  else
2193  return _M_format(-__d, true, __fc);
2194  }
2195  return _M_format(__d, false, __fc);
2196  }
2197 
2198  private:
2199  using _Duration = chrono::duration<_Rep, _Period>;
2200 
2201  static constexpr __format::_ChronoSpec<_CharT> __defSpec = []
2202  {
2203  using enum __format::_ChronoParts;
2204  auto __res = __format::__formatter_duration<_CharT>::
2205  template _S_spec_for<_Duration>(_None);
2206  __res._M_localized = !is_integral_v<_Rep>;
2207  // n.b. for integral format output is the same as ostream output
2208  if constexpr (is_integral_v<_Rep>)
2209  {
2210  __res._M_needed = _EpochUnits|_UnitSuffix;
2211  __res._M_chrono_specs = _GLIBCXX_WIDEN("%Q%q");
2212  }
2213  return __res;
2214  }();
2215 
2216  template<typename _Rep2, typename _Out>
2217  typename basic_format_context<_Out, _CharT>::iterator
2218  _M_format(const chrono::duration<_Rep2, _Period>& __d,
2219  bool __is_neg,
2220  basic_format_context<_Out, _CharT>& __fc) const
2221  {
2222  using namespace chrono;
2223  using enum __format::_ChronoParts;
2224  if constexpr (!is_integral_v<_Rep>)
2225  if (_M_f._M_spec._M_chrono_specs.empty())
2226  return _M_f._M_format_to_ostream(__d, __is_neg, __fc);
2227 
2228  __format::_ChronoData<_CharT> __cd;
2229  __cd._M_is_neg = __is_neg;
2230  auto __ts = chrono::floor<chrono::seconds>(__d);
2231  __cd._M_eseconds = __ts;
2232  if (_M_f._M_spec._M_needs(_HoursMinutesSeconds))
2233  __cd._M_fill_time(__ts);
2234  return _M_f._M_format_units(__cd, __d, __d - __ts, __fc);
2235  }
2236 
2237  __format::__formatter_duration<_CharT> _M_f{__defSpec};
2238  };
2239 
2240 #if __glibcxx_print >= 202406L
2241  // _GLIBCXX_RESOLVE_LIB_DEFECTS
2242  // 4400. enable_nonlocking_formatter_optimization for durations with custom rep
2243  template<typename _Rep, typename _Period>
2244  constexpr bool
2245  enable_nonlocking_formatter_optimization<chrono::duration<_Rep, _Period>>
2246  = is_arithmetic_v<_Rep>;
2247 #endif
2248 
2249  template<__format::__char _CharT>
2250  struct formatter<chrono::day, _CharT>
2251  {
2252  constexpr typename basic_format_parse_context<_CharT>::iterator
2253  parse(basic_format_parse_context<_CharT>& __pc)
2254  {
2255  using enum __format::_ChronoParts;
2256  return _M_f._M_parse(__pc, _Day|_WeekdayIndex, __defSpec);
2257  }
2258 
2259  template<typename _Out>
2260  typename basic_format_context<_Out, _CharT>::iterator
2261  format(const chrono::day& __t,
2262  basic_format_context<_Out, _CharT>& __fc) const
2263  {
2264  __format::_ChronoData<_CharT> __cd{};
2265  __cd._M_fill_day(__t, __defSpec._M_needed);
2266  return _M_f._M_format(__cd, __fc);
2267  }
2268 
2269  private:
2270  static constexpr __format::_ChronoSpec<_CharT> __defSpec = []
2271  {
2272  using __format::_ChronoFormats;
2273  using enum __format::_ChronoParts;
2274 
2275  __format::_ChronoSpec<_CharT> __res{};
2276  __res._M_debug = true;
2277  __res._M_needed = _Day;
2278  __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_d();
2279  return __res;
2280  }();
2281 
2282  __format::__formatter_chrono<_CharT> _M_f{__defSpec};
2283  };
2284 
2285 #if __glibcxx_print >= 202406L
2286  template<>
2287  inline constexpr bool
2288  enable_nonlocking_formatter_optimization<chrono::day> = true;
2289 #endif
2290 
2291  template<__format::__char _CharT>
2292  struct formatter<chrono::month, _CharT>
2293  {
2294  constexpr typename basic_format_parse_context<_CharT>::iterator
2295  parse(basic_format_parse_context<_CharT>& __pc)
2296  {
2297  using enum __format::_ChronoParts;
2298  return _M_f._M_parse(__pc, _Month, __defSpec);
2299  }
2300 
2301  template<typename _Out>
2302  typename basic_format_context<_Out, _CharT>::iterator
2303  format(const chrono::month& __t,
2304  basic_format_context<_Out, _CharT>& __fc) const
2305  {
2306  __format::_ChronoData<_CharT> __cd{};
2307  __cd._M_month = __t;
2308  return _M_f._M_format(__cd, __fc);
2309  }
2310 
2311  private:
2312  static constexpr __format::_ChronoSpec<_CharT> __defSpec = []
2313  {
2314  using __format::_ChronoFormats;
2315  using enum __format::_ChronoParts;
2316 
2317  __format::_ChronoSpec<_CharT> __res{};
2318  __res._M_debug = true;
2319  __res._M_localized = true;
2320  __res._M_locale_specific = true;
2321  __res._M_needed = _Month;
2322  __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_m();
2323  return __res;
2324  }();
2325 
2326  __format::__formatter_chrono<_CharT> _M_f{__defSpec};
2327  };
2328 
2329 #if __glibcxx_print >= 202406L
2330  template<>
2331  inline constexpr bool
2332  enable_nonlocking_formatter_optimization<chrono::month> = true;
2333 #endif
2334 
2335  template<__format::__char _CharT>
2336  struct formatter<chrono::year, _CharT>
2337  {
2338  constexpr typename basic_format_parse_context<_CharT>::iterator
2339  parse(basic_format_parse_context<_CharT>& __pc)
2340  {
2341  using enum __format::_ChronoParts;
2342  return _M_f._M_parse(__pc, _Year, __defSpec);
2343  }
2344 
2345  template<typename _Out>
2346  typename basic_format_context<_Out, _CharT>::iterator
2347  format(const chrono::year& __t,
2348  basic_format_context<_Out, _CharT>& __fc) const
2349  {
2350  __format::_ChronoData<_CharT> __cd{};
2351  __cd._M_year = __t;
2352  return _M_f._M_format(__cd, __fc);
2353  }
2354 
2355  private:
2356  static constexpr __format::_ChronoSpec<_CharT> __defSpec = []
2357  {
2358  using __format::_ChronoFormats;
2359  using enum __format::_ChronoParts;
2360 
2361  __format::_ChronoSpec<_CharT> __res{};
2362  __res._M_debug = true;
2363  __res._M_needed = _Year;
2364  __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_y();
2365  return __res;
2366  }();
2367 
2368  __format::__formatter_chrono<_CharT> _M_f{__defSpec};
2369  };
2370 
2371 #if __glibcxx_print >= 202406L
2372  template<>
2373  inline constexpr bool
2374  enable_nonlocking_formatter_optimization<chrono::year> = true;
2375 #endif
2376 
2377  template<__format::__char _CharT>
2378  struct formatter<chrono::weekday, _CharT>
2379  {
2380  constexpr typename basic_format_parse_context<_CharT>::iterator
2381  parse(basic_format_parse_context<_CharT>& __pc)
2382  {
2383  using enum __format::_ChronoParts;
2384  return _M_f._M_parse(__pc, _Weekday, __defSpec);
2385  }
2386 
2387  template<typename _Out>
2388  typename basic_format_context<_Out, _CharT>::iterator
2389  format(const chrono::weekday& __t,
2390  basic_format_context<_Out, _CharT>& __fc) const
2391  {
2392  __format::_ChronoData<_CharT> __cd{};
2393  __cd._M_weekday = __t;
2394  return _M_f._M_format(__cd, __fc);
2395  }
2396 
2397  private:
2398  static constexpr __format::_ChronoSpec<_CharT> __defSpec = []
2399  {
2400  using __format::_ChronoFormats;
2401  using enum __format::_ChronoParts;
2402 
2403  __format::_ChronoSpec<_CharT> __res{};
2404  __res._M_debug = true;
2405  __res._M_localized = true;
2406  __res._M_locale_specific = true;
2407  __res._M_needed = _Weekday;
2408  __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_w();
2409  return __res;
2410  }();
2411 
2412  __format::__formatter_chrono<_CharT> _M_f{__defSpec};
2413  };
2414 
2415 #if __glibcxx_print >= 202406L
2416  template<>
2417  inline constexpr bool
2418  enable_nonlocking_formatter_optimization<chrono::weekday> = true;
2419 #endif
2420 
2421  template<__format::__char _CharT>
2422  struct formatter<chrono::weekday_indexed, _CharT>
2423  {
2424  constexpr typename basic_format_parse_context<_CharT>::iterator
2425  parse(basic_format_parse_context<_CharT>& __pc)
2426  {
2427  using enum __format::_ChronoParts;
2428  return _M_f._M_parse(__pc, _IndexedWeekday, __defSpec);
2429  }
2430 
2431  template<typename _Out>
2432  typename basic_format_context<_Out, _CharT>::iterator
2433  format(const chrono::weekday_indexed& __t,
2434  basic_format_context<_Out, _CharT>& __fc) const
2435  {
2436  __format::_ChronoData<_CharT> __cd{};
2437  __cd._M_fill_weekday(__t, __defSpec._M_needed);
2438  return _M_f._M_format(__cd, __fc);
2439  }
2440 
2441  private:
2442  static constexpr __format::_ChronoSpec<_CharT> __defSpec = []
2443  {
2444  using __format::_ChronoFormats;
2445  using enum __format::_ChronoParts;
2446 
2447  __format::_ChronoSpec<_CharT> __res{};
2448  __res._M_debug = true;
2449  __res._M_localized = true;
2450  __res._M_locale_specific = true;
2451  __res._M_needed = _IndexedWeekday;
2452  __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_wi();
2453  return __res;
2454  }();
2455 
2456  __format::__formatter_chrono<_CharT> _M_f{__defSpec};
2457  };
2458 
2459 #if __glibcxx_print >= 202406L
2460  template<>
2461  inline constexpr bool
2462  enable_nonlocking_formatter_optimization<chrono::weekday_indexed> = true;
2463 #endif
2464 
2465  template<__format::__char _CharT>
2466  struct formatter<chrono::weekday_last, _CharT>
2467  {
2468  constexpr typename basic_format_parse_context<_CharT>::iterator
2469  parse(basic_format_parse_context<_CharT>& __pc)
2470  {
2471  using enum __format::_ChronoParts;
2472  return _M_f._M_parse(__pc, _Weekday, __defSpec);
2473  }
2474 
2475  template<typename _Out>
2476  typename basic_format_context<_Out, _CharT>::iterator
2477  format(const chrono::weekday_last& __t,
2478  basic_format_context<_Out, _CharT>& __fc) const
2479  {
2480  __format::_ChronoData<_CharT> __cd{};
2481  __cd._M_weekday = __t.weekday();
2482  return _M_f._M_format(__cd, __fc);
2483  }
2484 
2485  private:
2486  static constexpr __format::_ChronoSpec<_CharT> __defSpec = []
2487  {
2488  using __format::_ChronoFormats;
2489  using enum __format::_ChronoParts;
2490 
2491  __format::_ChronoSpec<_CharT> __res{};
2492  __res._M_debug = true;
2493  __res._M_localized = true;
2494  __res._M_locale_specific = true;
2495  __res._M_needed = _Weekday;
2496  __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_wl();
2497  return __res;
2498  }();
2499 
2500  __format::__formatter_chrono<_CharT> _M_f{__defSpec};
2501  };
2502 
2503 #if __glibcxx_print >= 202406L
2504  template<>
2505  inline constexpr bool
2506  enable_nonlocking_formatter_optimization<chrono::weekday_last> = true;
2507 #endif
2508 
2509  template<__format::__char _CharT>
2510  struct formatter<chrono::month_day, _CharT>
2511  {
2512  constexpr typename basic_format_parse_context<_CharT>::iterator
2513  parse(basic_format_parse_context<_CharT>& __pc)
2514  {
2515  using enum __format::_ChronoParts;
2516  return _M_f._M_parse(__pc, _Month|_Day|_WeekdayIndex, __defSpec);
2517  }
2518 
2519  template<typename _Out>
2520  typename basic_format_context<_Out, _CharT>::iterator
2521  format(const chrono::month_day& __t,
2522  basic_format_context<_Out, _CharT>& __fc) const
2523  {
2524  __format::_ChronoData<_CharT> __cd{};
2525  __cd._M_month = __t.month();
2526  __cd._M_fill_day(__t.day(), __defSpec._M_needed);
2527  return _M_f._M_format(__cd, __fc);
2528  }
2529 
2530  private:
2531  static constexpr __format::_ChronoSpec<_CharT> __defSpec = []
2532  {
2533  using __format::_ChronoFormats;
2534  using enum __format::_ChronoParts;
2535 
2536  __format::_ChronoSpec<_CharT> __res{};
2537  __res._M_debug = true;
2538  __res._M_localized = true;
2539  __res._M_locale_specific = true;
2540  __res._M_needed = _Month|_Day;
2541  __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_md();
2542  return __res;
2543  }();
2544 
2545  __format::__formatter_chrono<_CharT> _M_f{__defSpec};
2546  };
2547 
2548 #if __glibcxx_print >= 202406L
2549  template<>
2550  inline constexpr bool
2551  enable_nonlocking_formatter_optimization<chrono::month_day> = true;
2552 #endif
2553 
2554  template<__format::__char _CharT>
2555  struct formatter<chrono::month_day_last, _CharT>
2556  {
2557  constexpr typename basic_format_parse_context<_CharT>::iterator
2558  parse(basic_format_parse_context<_CharT>& __pc)
2559  {
2560  using enum __format::_ChronoParts;
2561  return _M_f._M_parse(__pc, _Month, __defSpec);
2562  }
2563 
2564  template<typename _Out>
2565  typename basic_format_context<_Out, _CharT>::iterator
2566  format(const chrono::month_day_last& __t,
2567  basic_format_context<_Out, _CharT>& __fc) const
2568  {
2569  __format::_ChronoData<_CharT> __cd{};
2570  __cd._M_month = __t.month();
2571  return _M_f._M_format(__cd, __fc);
2572  }
2573 
2574  private:
2575  static constexpr __format::_ChronoSpec<_CharT> __defSpec = []
2576  {
2577  using __format::_ChronoFormats;
2578  using enum __format::_ChronoParts;
2579 
2580  __format::_ChronoSpec<_CharT> __res{};
2581  __res._M_debug = true;
2582  __res._M_localized = true;
2583  __res._M_locale_specific = true;
2584  __res._M_needed = _Month;
2585  __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_ml();
2586  return __res;
2587  }();
2588 
2589  __format::__formatter_chrono<_CharT> _M_f{__defSpec};
2590  };
2591 
2592 #if __glibcxx_print >= 202406L
2593  template<>
2594  inline constexpr bool
2595  enable_nonlocking_formatter_optimization<chrono::month_day_last> = true;
2596 #endif
2597 
2598  template<__format::__char _CharT>
2599  struct formatter<chrono::month_weekday, _CharT>
2600  {
2601  constexpr typename basic_format_parse_context<_CharT>::iterator
2602  parse(basic_format_parse_context<_CharT>& __pc)
2603  {
2604  using enum __format::_ChronoParts;
2605  return _M_f._M_parse(__pc, _Month|_IndexedWeekday, __defSpec);
2606  }
2607 
2608  template<typename _Out>
2609  typename basic_format_context<_Out, _CharT>::iterator
2610  format(const chrono::month_weekday& __t,
2611  basic_format_context<_Out, _CharT>& __fc) const
2612  {
2613  __format::_ChronoData<_CharT> __cd{};
2614  __cd._M_month = __t.month();
2615  __cd._M_fill_weekday(__t.weekday_indexed(), __defSpec._M_needed);
2616  return _M_f._M_format(__cd, __fc);
2617  }
2618 
2619  private:
2620  static constexpr __format::_ChronoSpec<_CharT> __defSpec = []
2621  {
2622  using __format::_ChronoFormats;
2623  using enum __format::_ChronoParts;
2624 
2625  __format::_ChronoSpec<_CharT> __res{};
2626  __res._M_debug = true;
2627  __res._M_localized = true;
2628  __res._M_locale_specific = true;
2629  __res._M_needed = _Month|_IndexedWeekday;
2630  __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_mwi();
2631  return __res;
2632  }();
2633 
2634  __format::__formatter_chrono<_CharT> _M_f{__defSpec};
2635  };
2636 
2637 #if __glibcxx_print >= 202406L
2638  template<>
2639  inline constexpr bool
2640  enable_nonlocking_formatter_optimization<chrono::month_weekday> = true;
2641 #endif
2642 
2643  template<__format::__char _CharT>
2644  struct formatter<chrono::month_weekday_last, _CharT>
2645  {
2646  constexpr typename basic_format_parse_context<_CharT>::iterator
2647  parse(basic_format_parse_context<_CharT>& __pc)
2648  {
2649  using enum __format::_ChronoParts;
2650  return _M_f._M_parse(__pc, _Month|_Weekday, __defSpec);
2651  }
2652 
2653  template<typename _Out>
2654  typename basic_format_context<_Out, _CharT>::iterator
2655  format(const chrono::month_weekday_last& __t,
2656  basic_format_context<_Out, _CharT>& __fc) const
2657  {
2658  __format::_ChronoData<_CharT> __cd{};
2659  __cd._M_month = __t.month();
2660  __cd._M_weekday = __t.weekday_last().weekday();
2661  return _M_f._M_format(__cd, __fc);
2662  }
2663 
2664  private:
2665  static constexpr __format::_ChronoSpec<_CharT> __defSpec = []
2666  {
2667  using __format::_ChronoFormats;
2668  using enum __format::_ChronoParts;
2669 
2670  __format::_ChronoSpec<_CharT> __res{};
2671  __res._M_debug = true;
2672  __res._M_localized = true;
2673  __res._M_locale_specific = true;
2674  __res._M_needed = _Month|_Weekday;
2675  __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_mwl();
2676  return __res;
2677  }();
2678 
2679  __format::__formatter_chrono<_CharT> _M_f{__defSpec};
2680  };
2681 
2682 #if __glibcxx_print >= 202406L
2683  template<>
2684  inline constexpr bool
2685  enable_nonlocking_formatter_optimization<chrono::month_weekday_last> = true;
2686 #endif
2687 
2688  template<__format::__char _CharT>
2689  struct formatter<chrono::year_month, _CharT>
2690  {
2691  constexpr typename basic_format_parse_context<_CharT>::iterator
2692  parse(basic_format_parse_context<_CharT>& __pc)
2693  {
2694  using enum __format::_ChronoParts;
2695  return _M_f._M_parse(__pc, _Year|_Month, __defSpec);
2696  }
2697 
2698  template<typename _Out>
2699  typename basic_format_context<_Out, _CharT>::iterator
2700  format(const chrono::year_month& __t,
2701  basic_format_context<_Out, _CharT>& __fc) const
2702  {
2703  __format::_ChronoData<_CharT> __cd{};
2704  __cd._M_fill_year_month(__t, __defSpec._M_needed);
2705  return _M_f._M_format(__cd, __fc);
2706  }
2707 
2708  private:
2709  static constexpr __format::_ChronoSpec<_CharT> __defSpec = []
2710  {
2711  using __format::_ChronoFormats;
2712  using enum __format::_ChronoParts;
2713 
2714  __format::_ChronoSpec<_CharT> __res{};
2715  __res._M_debug = true;
2716  __res._M_localized = true;
2717  __res._M_locale_specific = true;
2718  __res._M_needed = _Year|_Month;
2719  __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_ym();
2720  return __res;
2721  }();
2722 
2723  __format::__formatter_chrono<_CharT> _M_f{__defSpec};
2724  };
2725 
2726 #if __glibcxx_print >= 202406L
2727  template<>
2728  inline constexpr bool
2729  enable_nonlocking_formatter_optimization<chrono::year_month> = true;
2730 #endif
2731 
2732  template<__format::__char _CharT>
2733  struct formatter<chrono::year_month_day, _CharT>
2734  {
2735  constexpr typename basic_format_parse_context<_CharT>::iterator
2736  parse(basic_format_parse_context<_CharT>& __pc)
2737  {
2738  using enum __format::_ChronoParts;
2739  return _M_f._M_parse(__pc, _Date, __defSpec);
2740  }
2741 
2742  template<typename _Out>
2743  typename basic_format_context<_Out, _CharT>::iterator
2744  format(const chrono::year_month_day& __t,
2745  basic_format_context<_Out, _CharT>& __fc) const
2746  {
2747  __format::_ChronoData<_CharT> __cd{};
2748  auto __parts = _M_f._M_spec._M_needed;
2749  __parts = __cd._M_fill_year_month(__t, __parts);
2750  __parts = __cd._M_fill_day(__t.day(), __parts);
2751  if (__parts == 0)
2752  return _M_f._M_format(__cd, __fc);
2753 
2754  __cd._M_fill_ldays(chrono::local_days(__t), __parts);
2755  return _M_f._M_format(__cd, __fc);
2756  }
2757 
2758  private:
2759  static constexpr __format::_ChronoSpec<_CharT> __defSpec = []
2760  {
2761  using __format::_ChronoFormats;
2762  using enum __format::_ChronoParts;
2763 
2764  __format::_ChronoSpec<_CharT> __res{};
2765  __res._M_debug = true;
2766  __res._M_needed = _YearMonthDay;
2767  __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_f();
2768  return __res;
2769  }();
2770 
2771  __format::__formatter_chrono<_CharT> _M_f{__defSpec};
2772  };
2773 
2774 #if __glibcxx_print >= 202406L
2775  template<>
2776  inline constexpr bool
2777  enable_nonlocking_formatter_optimization<chrono::year_month_day> = true;
2778 #endif
2779 
2780  template<__format::__char _CharT>
2781  struct formatter<chrono::year_month_day_last, _CharT>
2782  {
2783  constexpr typename basic_format_parse_context<_CharT>::iterator
2784  parse(basic_format_parse_context<_CharT>& __pc)
2785  {
2786  using enum __format::_ChronoParts;
2787  return _M_f._M_parse(__pc, _Date, __defSpec);
2788  }
2789 
2790  template<typename _Out>
2791  typename basic_format_context<_Out, _CharT>::iterator
2792  format(const chrono::year_month_day_last& __t,
2793  basic_format_context<_Out, _CharT>& __fc) const
2794  {
2795  using enum __format::_ChronoParts;
2796 
2797  __format::_ChronoData<_CharT> __cd{};
2798  auto __parts = _M_f._M_spec._M_needed;
2799  __parts = __cd._M_fill_year_month(__t, __parts);
2800  if (_M_f._M_spec._M_needs(_Day|_WeekdayIndex))
2801  __parts = __cd._M_fill_day(__t.day(), __parts);
2802  if (__parts == 0)
2803  return _M_f._M_format(__cd, __fc);
2804 
2805  __cd._M_fill_ldays(chrono::local_days(__t), __parts);
2806  return _M_f._M_format(__cd, __fc);
2807  }
2808 
2809  private:
2810  static constexpr __format::_ChronoSpec<_CharT> __defSpec = []
2811  {
2812  using __format::_ChronoFormats;
2813  using enum __format::_ChronoParts;
2814 
2815  __format::_ChronoSpec<_CharT> __res{};
2816  __res._M_debug = true;
2817  __res._M_localized = true;
2818  __res._M_locale_specific = true;
2819  __res._M_needed = _Year|_Month;
2820  __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_yml();
2821  return __res;
2822  }();
2823 
2824  __format::__formatter_chrono<_CharT> _M_f{__defSpec};
2825  };
2826 
2827 #if __glibcxx_print >= 202406L
2828  template<>
2829  inline constexpr bool
2830  enable_nonlocking_formatter_optimization<chrono::year_month_day_last> = true;
2831 #endif
2832 
2833  template<__format::__char _CharT>
2834  struct formatter<chrono::year_month_weekday, _CharT>
2835  {
2836  constexpr typename basic_format_parse_context<_CharT>::iterator
2837  parse(basic_format_parse_context<_CharT>& __pc)
2838  {
2839  using enum __format::_ChronoParts;
2840  return _M_f._M_parse(__pc, _Date, __defSpec);
2841  }
2842 
2843  template<typename _Out>
2844  typename basic_format_context<_Out, _CharT>::iterator
2845  format(const chrono::year_month_weekday& __t,
2846  basic_format_context<_Out, _CharT>& __fc) const
2847  {
2848  __format::_ChronoData<_CharT> __cd{};
2849  auto __parts = _M_f._M_spec._M_needed;
2850  __parts = __cd._M_fill_year_month(__t, __parts);
2851  __parts = __cd._M_fill_weekday(__t.weekday_indexed(), __parts);
2852  if (__t.index() == 0) [[unlikely]]
2853  // n.b. day cannot be negative, so any 0th weekday uses
2854  // value-initialized (0) day of month
2855  __parts -= __format::_ChronoParts::_Day;
2856  if (__parts == 0)
2857  return _M_f._M_format(__cd, __fc);
2858 
2859  chrono::local_days __ld(__t);
2860  __parts = __cd._M_fill_ldays(__ld, __parts);
2861  if (__parts == 0)
2862  return _M_f._M_format(__cd, __fc);
2863 
2864  auto __dom = __ld - chrono::local_days(__t.year()/__t.month()/0);
2865  // n.b. weekday index is supplied by input, do not override it
2866  __cd._M_day = chrono::day(__dom.count());
2867  return _M_f._M_format(__cd, __fc);
2868  }
2869 
2870  private:
2871  static constexpr __format::_ChronoSpec<_CharT> __defSpec = []
2872  {
2873  using __format::_ChronoFormats;
2874  using enum __format::_ChronoParts;
2875 
2876  __format::_ChronoSpec<_CharT> __res{};
2877  __res._M_debug = true;
2878  __res._M_localized = true;
2879  __res._M_locale_specific = true;
2880  __res._M_needed = _Year|_Month|_IndexedWeekday;
2881  __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_ymwi();
2882  return __res;
2883  }();
2884 
2885  __format::__formatter_chrono<_CharT> _M_f{__defSpec};
2886  };
2887 
2888 #if __glibcxx_print >= 202406L
2889  template<>
2890  inline constexpr bool
2891  enable_nonlocking_formatter_optimization<chrono::year_month_weekday> = true;
2892 #endif
2893 
2894  template<__format::__char _CharT>
2895  struct formatter<chrono::year_month_weekday_last, _CharT>
2896  {
2897  constexpr typename basic_format_parse_context<_CharT>::iterator
2898  parse(basic_format_parse_context<_CharT>& __pc)
2899  {
2900  using enum __format::_ChronoParts;
2901  return _M_f._M_parse(__pc, _Date, __defSpec);
2902  }
2903 
2904  template<typename _Out>
2905  typename basic_format_context<_Out, _CharT>::iterator
2906  format(const chrono::year_month_weekday_last& __t,
2907  basic_format_context<_Out, _CharT>& __fc) const
2908  {
2909  __format::_ChronoData<_CharT> __cd{};
2910  auto __parts = _M_f._M_spec._M_needed;
2911  __parts = __cd._M_fill_year_month(__t, __parts);
2912  __cd._M_weekday = __t.weekday_last().weekday();
2913  __parts -= __format::_ChronoParts::_Weekday;
2914  if (__parts == 0)
2915  return _M_f._M_format(__cd, __fc);
2916 
2917  chrono::local_days __ld(__t);
2918  __parts = __cd._M_fill_ldays(__ld, __parts);
2919  if (__parts == 0)
2920  return _M_f._M_format(__cd, __fc);
2921 
2922  auto __dom = __ld - chrono::local_days(__t.year()/__t.month()/0);
2923  __cd._M_fill_day(chrono::day(__dom.count()), __parts);
2924  return _M_f._M_format(__cd, __fc);
2925  }
2926 
2927  private:
2928  static constexpr __format::_ChronoSpec<_CharT> __defSpec = []
2929  {
2930  using __format::_ChronoFormats;
2931  using enum __format::_ChronoParts;
2932 
2933  __format::_ChronoSpec<_CharT> __res{};
2934  __res._M_debug = true;
2935  __res._M_localized = true;
2936  __res._M_locale_specific = true;
2937  __res._M_needed = _Year|_Month|_Weekday;
2938  __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_ymwl();
2939  return __res;
2940  }();
2941 
2942  __format::__formatter_chrono<_CharT> _M_f{__defSpec};
2943  };
2944 
2945 #if __glibcxx_print >= 202406L
2946  template<>
2947  inline constexpr bool
2948  enable_nonlocking_formatter_optimization<chrono::year_month_weekday_last> = true;
2949 #endif
2950 
2951  template<typename _Rep, typename _Period, __format::__char _CharT>
2952  struct formatter<chrono::hh_mm_ss<chrono::duration<_Rep, _Period>>, _CharT>
2953  {
2954  constexpr typename basic_format_parse_context<_CharT>::iterator
2955  parse(basic_format_parse_context<_CharT>& __pc)
2956  {
2957  using enum __format::_ChronoParts;
2958  return _M_f.template _M_parse<_Precision>(__pc, _Time, __defSpec);
2959  }
2960 
2961  template<typename _Out>
2962  typename basic_format_context<_Out, _CharT>::iterator
2963  format(const chrono::hh_mm_ss<chrono::duration<_Rep, _Period>>& __t,
2964  basic_format_context<_Out, _CharT>& __fc) const
2965  {
2966  using enum __format::_ChronoParts;
2967 
2968  __format::_ChronoData<_CharT> __cd;
2969  __cd._M_is_neg = __t.is_negative();
2970  __cd._M_hours = __t.hours();
2971  __cd._M_minutes = __t.minutes();
2972  __cd._M_seconds = __t.seconds();
2973 
2974  _Precision __d(0);
2975  // n.b. computing total duration or total seconds may overflow,
2976  // do not compute them if not requested.
2977  if (_M_f._M_spec._M_needs(_EpochUnits))
2978  __d = __t.to_duration();
2979  if (_M_f._M_spec._M_needs(_TotalSeconds))
2980  __cd._M_eseconds
2981  = __cd._M_hours + __cd._M_minutes + __cd._M_seconds;
2982  return _M_f._M_format_units(__cd, __d, __t.subseconds(), __fc);
2983  }
2984 
2985  private:
2986  using _Precision
2987  = typename chrono::hh_mm_ss<chrono::duration<_Rep, _Period>>::precision;
2988  static constexpr __format::_ChronoSpec<_CharT> __defSpec =
2989  __format::__formatter_duration<_CharT>::
2990  template _S_spec_for<_Precision>(__format::_ChronoParts::_Time);
2991 
2992  __format::__formatter_duration<_CharT> _M_f{__defSpec};
2993  };
2994 
2995 #if __glibcxx_print >= 202406L
2996  // _GLIBCXX_RESOLVE_LIB_DEFECTS
2997  // 4400. enable_nonlocking_formatter_optimization for durations with custom rep
2998  template<typename _Duration>
2999  constexpr bool
3000  enable_nonlocking_formatter_optimization<chrono::hh_mm_ss<_Duration>>
3001  = enable_nonlocking_formatter_optimization<_Duration>;
3002 #endif
3003 
3004 #if _GLIBCXX_USE_CXX11_ABI || ! _GLIBCXX_USE_DUAL_ABI
3005  template<__format::__char _CharT>
3006  struct formatter<chrono::sys_info, _CharT>
3007  {
3008  constexpr typename basic_format_parse_context<_CharT>::iterator
3009  parse(basic_format_parse_context<_CharT>& __pc)
3010  { return _M_f.parse(__pc); }
3011 
3012  template<typename _Out>
3013  typename basic_format_context<_Out, _CharT>::iterator
3014  format(const chrono::sys_info& __i,
3015  basic_format_context<_Out, _CharT>& __fc) const
3016  { return _M_f.format(__i, __fc); }
3017 
3018  private:
3019  __format::__formatter_chrono_info<_CharT> _M_f;
3020  };
3021 
3022 #if __glibcxx_print >= 202406L
3023  template<>
3024  inline constexpr bool
3025  enable_nonlocking_formatter_optimization<chrono::sys_info> = true;
3026 #endif
3027 
3028  template<__format::__char _CharT>
3029  struct formatter<chrono::local_info, _CharT>
3030  {
3031  constexpr typename basic_format_parse_context<_CharT>::iterator
3032  parse(basic_format_parse_context<_CharT>& __pc)
3033  { return _M_f.parse(__pc); }
3034 
3035  template<typename _Out>
3036  typename basic_format_context<_Out, _CharT>::iterator
3037  format(const chrono::local_info& __i,
3038  basic_format_context<_Out, _CharT>& __fc) const
3039  { return _M_f.format(__i, __fc); }
3040 
3041  private:
3042  __format::__formatter_chrono_info<_CharT> _M_f;
3043  };
3044 
3045 #if __glibcxx_print >= 202406L
3046  template<>
3047  inline constexpr bool
3048  enable_nonlocking_formatter_optimization<chrono::local_info> = true;
3049 #endif
3050 #endif
3051 
3052  template<typename _Duration, __format::__char _CharT>
3053  struct formatter<chrono::sys_time<_Duration>, _CharT>
3054  {
3055  constexpr typename basic_format_parse_context<_CharT>::iterator
3056  parse(basic_format_parse_context<_CharT>& __pc)
3057  {
3058  using enum __format::_ChronoParts;
3059  auto __res
3060  = _M_f.template _M_parse<_Duration>(__pc, _ZonedDateTime, __defSpec);
3061  if constexpr (__defSpec._M_chrono_specs.empty())
3062  if (_M_f._M_spec._M_chrono_specs.empty())
3063  __format::__invalid_chrono_spec(); // chrono-specs can't be empty
3064  return __res;
3065  }
3066 
3067  template<typename _Out>
3068  typename basic_format_context<_Out, _CharT>::iterator
3069  format(const chrono::sys_time<_Duration>& __t,
3070  basic_format_context<_Out, _CharT>& __fc) const
3071  {
3072  __format::_ChronoData<_CharT> __cd{};
3073  __cd._M_fill_utc_zone();
3074 
3075  _Duration __ed = __t.time_since_epoch();
3076  __cd._M_eseconds = chrono::floor<chrono::seconds>(__ed);
3077  __cd._M_lseconds = chrono::local_seconds(__cd._M_eseconds);
3078  return _M_f._M_format_time_point(__cd, __ed, __fc);
3079  }
3080 
3081  private:
3082  static constexpr __format::_ChronoSpec<_CharT> __defSpec =
3083  __format::__formatter_duration<_CharT>::template _S_spec_for_tp<_Duration>();
3084 
3085  __format::__formatter_duration<_CharT> _M_f{__defSpec};
3086  };
3087 
3088 #if __glibcxx_print >= 202406L
3089  // _GLIBCXX_RESOLVE_LIB_DEFECTS
3090  // 4400. enable_nonlocking_formatter_optimization for durations with custom rep
3091  template<typename _Duration>
3092  constexpr bool
3093  enable_nonlocking_formatter_optimization<chrono::sys_time<_Duration>>
3094  = enable_nonlocking_formatter_optimization<_Duration>;
3095 #endif
3096 
3097  template<typename _Duration, __format::__char _CharT>
3098  struct formatter<chrono::utc_time<_Duration>, _CharT>
3099  {
3100  constexpr typename basic_format_parse_context<_CharT>::iterator
3101  parse(basic_format_parse_context<_CharT>& __pc)
3102  {
3103  using enum __format::_ChronoParts;
3104  return _M_f.template _M_parse<_Duration>(__pc, _ZonedDateTime, __defSpec);
3105  }
3106 
3107  template<typename _Out>
3108  typename basic_format_context<_Out, _CharT>::iterator
3109  format(const chrono::utc_time<_Duration>& __t,
3110  basic_format_context<_Out, _CharT>& __fc) const
3111  {
3112  using __format::_ChronoParts;
3113  using namespace chrono;
3114  __format::_ChronoData<_CharT> __cd{};
3115  __cd._M_fill_utc_zone();
3116 
3117  _Duration __ed = __t.time_since_epoch();
3118  __cd._M_eseconds = chrono::floor<seconds>(__ed);
3119  // Adjust by removing leap seconds to get equivalent sys_time.
3120  // We can't just use clock_cast because we want to know if the time
3121  // falls within a leap second insertion, and format seconds as "60".
3122  const auto __li = chrono::get_leap_second_info(__t);
3123  __cd._M_lseconds = local_seconds(__cd._M_eseconds - __li.elapsed);
3124  auto __parts = _M_f._M_spec._M_needed - _ChronoParts::_TotalSeconds;
3125  if ((__parts & _ChronoParts::_DateTime) != 0)
3126  {
3127  __cd._M_fill_date_time(__cd._M_lseconds, __parts);
3128  __cd._M_seconds += seconds(__li.is_leap_second);
3129  }
3130  return _M_f._M_format_units(__cd, __ed, __ed - __cd._M_eseconds, __fc);
3131  }
3132 
3133  private:
3134  static constexpr __format::_ChronoSpec<_CharT> __defSpec =
3135  __format::__formatter_duration<_CharT>::
3136  template _S_spec_for<_Duration>(__format::_ChronoParts::_DateTime);
3137 
3138  __format::__formatter_duration<_CharT> _M_f{__defSpec};
3139  };
3140 
3141 #if __glibcxx_print >= 202406L
3142  // _GLIBCXX_RESOLVE_LIB_DEFECTS
3143  // 4400. enable_nonlocking_formatter_optimization for durations with custom rep
3144  template<typename _Duration>
3145  constexpr bool
3146  enable_nonlocking_formatter_optimization<chrono::utc_time<_Duration>>
3147  = enable_nonlocking_formatter_optimization<_Duration>;
3148 #endif
3149 
3150  template<typename _Duration, __format::__char _CharT>
3151  struct formatter<chrono::tai_time<_Duration>, _CharT>
3152  {
3153  constexpr typename basic_format_parse_context<_CharT>::iterator
3154  parse(basic_format_parse_context<_CharT>& __pc)
3155  {
3156  using enum __format::_ChronoParts;
3157  return _M_f.template _M_parse<_Duration>(__pc, _ZonedDateTime, __defSpec);
3158  }
3159 
3160  template<typename _Out>
3161  typename basic_format_context<_Out, _CharT>::iterator
3162  format(const chrono::tai_time<_Duration>& __t,
3163  basic_format_context<_Out, _CharT>& __fc) const
3164  {
3165  using namespace chrono;
3166  __format::_ChronoData<_CharT> __cd{};
3167  __cd._M_fill_zone("TAI", L"TAI");
3168 
3169  _Duration __ed = __t.time_since_epoch();
3170  __cd._M_eseconds = chrono::floor<seconds>(__ed);
3171  // Offset is 1970y/January/1 - 1958y/January/1
3172  constexpr chrono::days __tai_offset = chrono::days(4383);
3173  __cd._M_lseconds = local_seconds(__cd._M_eseconds - __tai_offset);
3174  return _M_f._M_format_time_point(__cd, __ed, __fc);
3175  }
3176 
3177  private:
3178  static constexpr __format::_ChronoSpec<_CharT> __defSpec =
3179  __format::__formatter_duration<_CharT>::
3180  template _S_spec_for<_Duration>(__format::_ChronoParts::_DateTime);
3181 
3182  __format::__formatter_duration<_CharT> _M_f{__defSpec};
3183  };
3184 
3185 #if __glibcxx_print >= 202406L
3186  // _GLIBCXX_RESOLVE_LIB_DEFECTS
3187  // 4400. enable_nonlocking_formatter_optimization for durations with custom rep
3188  template<typename _Duration>
3189  constexpr bool
3190  enable_nonlocking_formatter_optimization<chrono::tai_time<_Duration>>
3191  = enable_nonlocking_formatter_optimization<_Duration>;
3192 #endif
3193 
3194  template<typename _Duration, __format::__char _CharT>
3195  struct formatter<chrono::gps_time<_Duration>, _CharT>
3196  {
3197  constexpr typename basic_format_parse_context<_CharT>::iterator
3198  parse(basic_format_parse_context<_CharT>& __pc)
3199  {
3200  using enum __format::_ChronoParts;
3201  return _M_f.template _M_parse<_Duration>(__pc, _ZonedDateTime, __defSpec);
3202  }
3203 
3204  template<typename _Out>
3205  typename basic_format_context<_Out, _CharT>::iterator
3206  format(const chrono::gps_time<_Duration>& __t,
3207  basic_format_context<_Out, _CharT>& __fc) const
3208  {
3209  using namespace chrono;
3210  __format::_ChronoData<_CharT> __cd{};
3211  __cd._M_fill_zone("GPS", L"GPS");
3212 
3213  _Duration __ed = __t.time_since_epoch();
3214  __cd._M_eseconds = chrono::floor<seconds>(__ed);
3215  // Offset is 1980y/January/Sunday[1] - 1970y/January/1
3216  constexpr chrono::days __gps_offset = chrono::days(3657);
3217  __cd._M_lseconds = local_seconds(__cd._M_eseconds + __gps_offset);
3218  return _M_f._M_format_time_point(__cd, __ed, __fc);
3219  }
3220 
3221  private:
3222  static constexpr __format::_ChronoSpec<_CharT> __defSpec =
3223  __format::__formatter_duration<_CharT>::
3224  template _S_spec_for<_Duration>(__format::_ChronoParts::_DateTime);
3225 
3226  __format::__formatter_duration<_CharT> _M_f{__defSpec};
3227  };
3228 
3229 #if __glibcxx_print >= 202406L
3230  // _GLIBCXX_RESOLVE_LIB_DEFECTS
3231  // 4400. enable_nonlocking_formatter_optimization for durations with custom rep
3232  template<typename _Duration>
3233  constexpr bool
3234  enable_nonlocking_formatter_optimization<chrono::gps_time<_Duration>>
3235  = enable_nonlocking_formatter_optimization<_Duration>;
3236 #endif
3237 
3238  template<typename _Duration, __format::__char _CharT>
3239  struct formatter<chrono::file_time<_Duration>, _CharT>
3240  {
3241  constexpr typename basic_format_parse_context<_CharT>::iterator
3242  parse(basic_format_parse_context<_CharT>& __pc)
3243  {
3244  using enum __format::_ChronoParts;
3245  return _M_f.template _M_parse<_Duration>(__pc, _ZonedDateTime, __defSpec);
3246  }
3247 
3248  template<typename _Out>
3249  typename basic_format_context<_Out, _CharT>::iterator
3250  format(const chrono::file_time<_Duration>& __t,
3251  basic_format_context<_Out, _CharT>& __fc) const
3252  {
3253  using namespace chrono;
3254  __format::_ChronoData<_CharT> __cd{};
3255  __cd._M_fill_utc_zone();
3256 
3257  _Duration __ed = __t.time_since_epoch();
3258  __cd._M_eseconds = chrono::floor<seconds>(__ed);
3259  auto __st = chrono::clock_cast<system_clock>(__t);
3260  __cd._M_lseconds
3261  = local_seconds(chrono::floor<seconds>(__st.time_since_epoch()));
3262  return _M_f._M_format_time_point(__cd, __ed, __fc);
3263  }
3264 
3265  private:
3266  static constexpr __format::_ChronoSpec<_CharT> __defSpec =
3267  __format::__formatter_duration<_CharT>::
3268  template _S_spec_for<_Duration>(__format::_ChronoParts::_DateTime);
3269 
3270  __format::__formatter_duration<_CharT> _M_f{__defSpec};
3271  };
3272 
3273 #if __glibcxx_print >= 202406L
3274  // _GLIBCXX_RESOLVE_LIB_DEFECTS
3275  // 4400. enable_nonlocking_formatter_optimization for durations with custom rep
3276  template<typename _Duration>
3277  constexpr bool
3278  enable_nonlocking_formatter_optimization<chrono::file_time<_Duration>>
3279  = enable_nonlocking_formatter_optimization<_Duration>;
3280 #endif
3281 
3282  template<typename _Duration, __format::__char _CharT>
3283  struct formatter<chrono::local_time<_Duration>, _CharT>
3284  {
3285  constexpr typename basic_format_parse_context<_CharT>::iterator
3286  parse(basic_format_parse_context<_CharT>& __pc)
3287  {
3288  using enum __format::_ChronoParts;
3289  auto __res
3290  = _M_f.template _M_parse<_Duration>(__pc, _DateTime, __defSpec);
3291  if constexpr (__defSpec._M_chrono_specs.empty())
3292  if (_M_f._M_spec._M_chrono_specs.empty())
3293  __format::__invalid_chrono_spec(); // chrono-specs can't be empty
3294  return __res;
3295  }
3296 
3297  template<typename _Out>
3298  typename basic_format_context<_Out, _CharT>::iterator
3299  format(const chrono::local_time<_Duration>& __lt,
3300  basic_format_context<_Out, _CharT>& __fc) const
3301  {
3302  __format::_ChronoData<_CharT> __cd{};
3303  _Duration __ed = __lt.time_since_epoch();
3304  __cd._M_lseconds = chrono::floor<chrono::seconds>(__lt);
3305  __cd._M_eseconds = __cd._M_lseconds.time_since_epoch();
3306  return _M_f._M_format_time_point(__cd, __ed, __fc);
3307  }
3308 
3309  private:
3310  static constexpr __format::_ChronoSpec<_CharT> __defSpec =
3311  __format::__formatter_duration<_CharT>::template _S_spec_for_tp<_Duration>();
3312 
3313  __format::__formatter_duration<_CharT> _M_f{__defSpec};
3314  };
3315 
3316 #if __glibcxx_print >= 202406L
3317  // _GLIBCXX_RESOLVE_LIB_DEFECTS
3318  // 4400. enable_nonlocking_formatter_optimization for durations with custom rep
3319  template<typename _Duration>
3320  constexpr bool
3321  enable_nonlocking_formatter_optimization<chrono::local_time<_Duration>>
3322  = enable_nonlocking_formatter_optimization<_Duration>;
3323 #endif
3324 
3325  template<typename _Duration, __format::__char _CharT>
3326  struct formatter<chrono::__detail::__local_time_fmt<_Duration>, _CharT>
3327  {
3328  constexpr typename basic_format_parse_context<_CharT>::iterator
3329  parse(basic_format_parse_context<_CharT>& __pc)
3330  {
3331  using enum __format::_ChronoParts;
3332  return _M_f.template _M_parse<_Duration>(__pc, _ZonedDateTime, __defSpec);
3333  }
3334 
3335  template<typename _Out>
3336  typename basic_format_context<_Out, _CharT>::iterator
3337  format(const chrono::__detail::__local_time_fmt<_Duration>& __zt,
3338  basic_format_context<_Out, _CharT>& __fc) const
3339  {
3340  using enum __format::_ChronoParts;
3341  __format::_ChronoData<_CharT> __cd{};
3342 
3343  if (_M_f._M_spec._M_needs(_ZoneOffset))
3344  {
3345  if (!__zt._M_offset_sec)
3346  std::__throw_format_error("format error: no timezone available for %z");
3347  __cd._M_zone_offset = *__zt._M_offset_sec;
3348  }
3349 
3350  basic_string<_CharT> __zone_store;
3351  if (_M_f._M_spec._M_needs(_ZoneAbbrev))
3352  {
3353  if (!__zt._M_abbrev)
3354  std::__throw_format_error("format error: no timezone available for %Z");
3355 
3356  __cd._M_zone_cstr = __zt._M_abbrev->data();
3357  if constexpr (is_same_v<_CharT, char>)
3358  __cd._M_zone_abbrev = *__zt._M_abbrev;
3359  else
3360  {
3361  // TODO: use resize_and_overwrite
3362  __zone_store.resize(__zt._M_abbrev->size());
3363  auto& __ct = use_facet<ctype<_CharT>>(_M_f._M_locale(__fc));
3364  __ct.widen(__zt._M_abbrev->data(),
3365  __zt._M_abbrev->data() + __zt._M_abbrev->size(),
3366  __zone_store.data());
3367  __cd._M_zone_abbrev = __zone_store;
3368  }
3369  }
3370 
3371  _Duration __ed = __zt._M_time.time_since_epoch();
3372  __cd._M_lseconds = chrono::floor<chrono::seconds>(__zt._M_time);
3373  __cd._M_eseconds = __cd._M_lseconds.time_since_epoch();
3374  return _M_f._M_format_time_point(__cd, __ed, __fc);
3375  }
3376 
3377  private:
3378  static constexpr __format::_ChronoSpec<_CharT> __defSpec =
3379  __format::__formatter_duration<_CharT>::
3380  template _S_spec_for<_Duration>(__format::_ChronoParts::_ZonedDateTime);
3381 
3382  __format::__formatter_duration<_CharT> _M_f{__defSpec};
3383  };
3384 
3385 #if __glibcxx_print >= 202406L
3386  // _GLIBCXX_RESOLVE_LIB_DEFECTS
3387  // 4400. enable_nonlocking_formatter_optimization for durations with custom rep
3388  template<typename _Duration>
3389  constexpr bool
3390  enable_nonlocking_formatter_optimization<
3391  chrono::__detail::__local_time_fmt<_Duration>>
3392  = enable_nonlocking_formatter_optimization<_Duration>;
3393 #endif
3394 
3395 #if _GLIBCXX_USE_CXX11_ABI || ! _GLIBCXX_USE_DUAL_ABI
3396  template<typename _Duration, typename _TimeZonePtr, __format::__char _CharT>
3397  struct formatter<chrono::zoned_time<_Duration, _TimeZonePtr>, _CharT>
3398  : formatter<chrono::__detail::__local_time_fmt_for<_Duration>, _CharT>
3399  {
3400  template<typename _Out>
3401  typename basic_format_context<_Out, _CharT>::iterator
3402  format(const chrono::zoned_time<_Duration, _TimeZonePtr>& __tp,
3403  basic_format_context<_Out, _CharT>& __fc) const
3404  {
3405  using _Ltf = chrono::__detail::__local_time_fmt_for<_Duration>;
3406  using _Base = formatter<_Ltf, _CharT>;
3407  const chrono::sys_info __info = __tp.get_info();
3408  const auto __lf = chrono::local_time_format(__tp.get_local_time(),
3409  &__info.abbrev,
3410  &__info.offset);
3411  return _Base::format(__lf, __fc);
3412  }
3413  };
3414 
3415 #if __glibcxx_print >= 202406L
3416  // _GLIBCXX_RESOLVE_LIB_DEFECTS
3417  // 4400. enable_nonlocking_formatter_optimization for durations with custom rep
3418  template<typename _Duration>
3419  constexpr bool
3420  enable_nonlocking_formatter_optimization<
3421  chrono::zoned_time<_Duration, const chrono::time_zone*>>
3422  = enable_nonlocking_formatter_optimization<_Duration>;
3423 #endif
3424 #endif
3425 
3426 namespace chrono
3427 {
3428 /// @addtogroup chrono
3429 /// @{
3430 
3431 /// @cond undocumented
3432 namespace __detail
3433 {
3434  template<typename _Duration = seconds>
3435  struct _Parser
3436  {
3437  static_assert(is_same_v<common_type_t<_Duration, seconds>, _Duration>);
3438 
3439  explicit
3440  _Parser(__format::_ChronoParts __need) : _M_need(__need) { }
3441 
3442  _Parser(_Parser&&) = delete;
3443  void operator=(_Parser&&) = delete;
3444 
3445  _Duration _M_time{}; // since midnight
3446  sys_days _M_sys_days{};
3447  year_month_day _M_ymd{};
3448  weekday _M_wd{};
3449  __format::_ChronoParts _M_need;
3450  unsigned _M_is_leap_second : 1 {};
3451  unsigned _M_reserved : 15 {};
3452 
3453  template<typename _CharT, typename _Traits, typename _Alloc>
3454  basic_istream<_CharT, _Traits>&
3455  operator()(basic_istream<_CharT, _Traits>& __is, const _CharT* __fmt,
3456  basic_string<_CharT, _Traits, _Alloc>* __abbrev = nullptr,
3457  minutes* __offset = nullptr);
3458 
3459  private:
3460  // Read an unsigned integer from the stream and return it.
3461  // Extract no more than __n digits. Set failbit if an integer isn't read.
3462  template<typename _CharT, typename _Traits>
3463  static int_least32_t
3464  _S_read_unsigned(basic_istream<_CharT, _Traits>& __is,
3465  ios_base::iostate& __err, int __n)
3466  {
3467  int_least32_t __val = _S_try_read_digit(__is, __err);
3468  if (__val == -1) [[unlikely]]
3469  __err |= ios_base::failbit;
3470  else
3471  {
3472  int __n1 = (std::min)(__n, 9);
3473  // Cannot overflow __val unless we read more than 9 digits
3474  for (int __i = 1; __i < __n1; ++__i)
3475  if (auto __dig = _S_try_read_digit(__is, __err); __dig != -1)
3476  {
3477  __val *= 10;
3478  __val += __dig;
3479  }
3480 
3481  while (__n1++ < __n) [[unlikely]]
3482  if (auto __dig = _S_try_read_digit(__is, __err); __dig != -1)
3483  {
3484  if (__builtin_mul_overflow(__val, 10, &__val)
3485  || __builtin_add_overflow(__val, __dig, &__val))
3486  {
3487  __err |= ios_base::failbit;
3488  return -1;
3489  }
3490  }
3491  }
3492  return __val;
3493  }
3494 
3495  // Read an unsigned integer from the stream and return it.
3496  // Extract no more than __n digits. Set failbit if an integer isn't read.
3497  template<typename _CharT, typename _Traits>
3498  static int_least32_t
3499  _S_read_signed(basic_istream<_CharT, _Traits>& __is,
3500  ios_base::iostate& __err, int __n)
3501  {
3502  auto __sign = __is.peek();
3503  if (__sign == '-' || __sign == '+')
3504  (void) __is.get();
3505  int_least32_t __val = _S_read_unsigned(__is, __err, __n);
3506  if (__err & ios_base::failbit)
3507  {
3508  if (__sign == '-') [[unlikely]]
3509  __val *= -1;
3510  }
3511  return __val;
3512  }
3513 
3514  // Read a digit from the stream and return it, or return -1.
3515  // If no digit is read eofbit will be set (but not failbit).
3516  template<typename _CharT, typename _Traits>
3517  static int_least32_t
3518  _S_try_read_digit(basic_istream<_CharT, _Traits>& __is,
3519  ios_base::iostate& __err)
3520  {
3521  int_least32_t __val = -1;
3522  auto __i = __is.peek();
3523  if (!_Traits::eq_int_type(__i, _Traits::eof())) [[likely]]
3524  {
3525  _CharT __c = _Traits::to_char_type(__i);
3526  if (_CharT('0') <= __c && __c <= _CharT('9')) [[likely]]
3527  {
3528  (void) __is.get();
3529  __val = __c - _CharT('0');
3530  }
3531  }
3532  else
3533  __err |= ios_base::eofbit;
3534  return __val;
3535  }
3536 
3537  // Read the specified character and return true.
3538  // If the character is not found, set failbit and return false.
3539  template<typename _CharT, typename _Traits>
3540  static bool
3541  _S_read_chr(basic_istream<_CharT, _Traits>& __is,
3542  ios_base::iostate& __err, _CharT __c)
3543  {
3544  auto __i = __is.peek();
3545  if (_Traits::eq_int_type(__i, _Traits::eof()))
3546  __err |= ios_base::eofbit;
3547  else if (_Traits::to_char_type(__i) == __c) [[likely]]
3548  {
3549  (void) __is.get();
3550  return true;
3551  }
3552  __err |= ios_base::failbit;
3553  return false;
3554  }
3555  };
3556 
3557  template<typename _Duration>
3558  using _Parser_t = _Parser<common_type_t<_Duration, seconds>>;
3559 
3560  template<typename _Duration>
3561  consteval bool
3562  __use_floor()
3563  {
3564  if constexpr (_Duration::period::den == 1)
3565  {
3566  switch (_Duration::period::num)
3567  {
3568  case minutes::period::num:
3569  case hours::period::num:
3570  case days::period::num:
3571  case weeks::period::num:
3572  case years::period::num:
3573  return true;
3574  }
3575  }
3576  return false;
3577  }
3578 
3579  // A "do the right thing" rounding function for duration and time_point
3580  // values extracted by from_stream. When treat_as_floating_point is true
3581  // we don't want to do anything, just a straightforward conversion.
3582  // When the destination type has a period of minutes, hours, days, weeks,
3583  // or years, we use chrono::floor to truncate towards negative infinity.
3584  // This ensures that an extracted timestamp such as 2024-09-05 13:00:00
3585  // will produce 2024-09-05 when rounded to days, rather than rounding up
3586  // to 2024-09-06 (a different day).
3587  // Otherwise, use chrono::round to get the nearest value representable
3588  // in the destination type.
3589  template<typename _ToDur, typename _Tp>
3590  constexpr auto
3591  __round(const _Tp& __t)
3592  {
3593  if constexpr (__is_duration_v<_Tp>)
3594  {
3595  if constexpr (treat_as_floating_point_v<typename _Tp::rep>)
3596  return chrono::duration_cast<_ToDur>(__t);
3597  else if constexpr (__detail::__use_floor<_ToDur>())
3598  return chrono::floor<_ToDur>(__t);
3599  else
3600  return chrono::round<_ToDur>(__t);
3601  }
3602  else
3603  {
3604  static_assert(__is_time_point_v<_Tp>);
3605  using _Tpt = time_point<typename _Tp::clock, _ToDur>;
3606  return _Tpt(__detail::__round<_ToDur>(__t.time_since_epoch()));
3607  }
3608  }
3609 
3610 } // namespace __detail
3611 /// @endcond
3612 
3613  template<typename _CharT, typename _Traits, typename _Rep, typename _Period,
3614  typename _Alloc = allocator<_CharT>>
3615  inline basic_istream<_CharT, _Traits>&
3616  from_stream(basic_istream<_CharT, _Traits>& __is, const _CharT* __fmt,
3617  duration<_Rep, _Period>& __d,
3618  basic_string<_CharT, _Traits, _Alloc>* __abbrev = nullptr,
3619  minutes* __offset = nullptr)
3620  {
3621  auto __need = __format::_ChronoParts::_TimeOfDay;
3622  __detail::_Parser_t<duration<_Rep, _Period>> __p(__need);
3623  if (__p(__is, __fmt, __abbrev, __offset))
3624  __d = __detail::__round<duration<_Rep, _Period>>(__p._M_time);
3625  return __is;
3626  }
3627 
3628  template<typename _CharT, typename _Traits>
3629  inline basic_ostream<_CharT, _Traits>&
3630  operator<<(basic_ostream<_CharT, _Traits>& __os, const day& __d)
3631  {
3632  using _Ctx = __format::__format_context<_CharT>;
3633  using _Str = basic_string_view<_CharT>;
3634  _Str __s = _GLIBCXX_WIDEN("{:02d} is not a valid day");
3635  if (__d.ok())
3636  __s = __s.substr(0, 6);
3637  auto __u = (unsigned)__d;
3638  __os << std::vformat(__s, make_format_args<_Ctx>(__u));
3639  return __os;
3640  }
3641 
3642  template<typename _CharT, typename _Traits,
3643  typename _Alloc = allocator<_CharT>>
3644  inline basic_istream<_CharT, _Traits>&
3645  from_stream(basic_istream<_CharT, _Traits>& __is, const _CharT* __fmt,
3646  day& __d,
3647  basic_string<_CharT, _Traits, _Alloc>* __abbrev = nullptr,
3648  minutes* __offset = nullptr)
3649  {
3650  __detail::_Parser<> __p(__format::_ChronoParts::_Day);
3651  if (__p(__is, __fmt, __abbrev, __offset))
3652  __d = __p._M_ymd.day();
3653  return __is;
3654  }
3655 
3656  template<typename _CharT, typename _Traits>
3657  inline basic_ostream<_CharT, _Traits>&
3658  operator<<(basic_ostream<_CharT, _Traits>& __os, const month& __m)
3659  {
3660  using _Ctx = __format::__format_context<_CharT>;
3661  using _Str = basic_string_view<_CharT>;
3662  _Str __s = _GLIBCXX_WIDEN("{:L%b}{} is not a valid month");
3663  if (__m.ok())
3664  __os << std::vformat(__os.getloc(), __s.substr(0, 6),
3665  make_format_args<_Ctx>(__m));
3666  else
3667  {
3668  auto __u = (unsigned)__m;
3669  __os << std::vformat(__s.substr(6), make_format_args<_Ctx>(__u));
3670  }
3671  return __os;
3672  }
3673 
3674  template<typename _CharT, typename _Traits,
3675  typename _Alloc = allocator<_CharT>>
3676  inline basic_istream<_CharT, _Traits>&
3677  from_stream(basic_istream<_CharT, _Traits>& __is, const _CharT* __fmt,
3678  month& __m,
3679  basic_string<_CharT, _Traits, _Alloc>* __abbrev = nullptr,
3680  minutes* __offset = nullptr)
3681  {
3682  __detail::_Parser<> __p(__format::_ChronoParts::_Month);
3683  if (__p(__is, __fmt, __abbrev, __offset))
3684  __m = __p._M_ymd.month();
3685  return __is;
3686  }
3687 
3688  template<typename _CharT, typename _Traits>
3689  inline basic_ostream<_CharT, _Traits>&
3690  operator<<(basic_ostream<_CharT, _Traits>& __os, const year& __y)
3691  {
3692  using _Ctx = __format::__format_context<_CharT>;
3693  using _Str = basic_string_view<_CharT>;
3694  _Str __s = _GLIBCXX_WIDEN("-{:04d} is not a valid year");
3695  if (__y.ok())
3696  __s = __s.substr(0, 7);
3697  int __i = (int)__y;
3698  if (__i >= 0) [[likely]]
3699  __s.remove_prefix(1);
3700  else
3701  __i = -__i;
3702  __os << std::vformat(__s, make_format_args<_Ctx>(__i));
3703  return __os;
3704  }
3705 
3706  template<typename _CharT, typename _Traits,
3707  typename _Alloc = allocator<_CharT>>
3708  inline basic_istream<_CharT, _Traits>&
3709  from_stream(basic_istream<_CharT, _Traits>& __is, const _CharT* __fmt,
3710  year& __y,
3711  basic_string<_CharT, _Traits, _Alloc>* __abbrev = nullptr,
3712  minutes* __offset = nullptr)
3713  {
3714  __detail::_Parser<> __p(__format::_ChronoParts::_Year);
3715  if (__p(__is, __fmt, __abbrev, __offset))
3716  __y = __p._M_ymd.year();
3717  return __is;
3718  }
3719 
3720  template<typename _CharT, typename _Traits>
3721  inline basic_ostream<_CharT, _Traits>&
3722  operator<<(basic_ostream<_CharT, _Traits>& __os, const weekday& __wd)
3723  {
3724  using _Ctx = __format::__format_context<_CharT>;
3725  using _Str = basic_string_view<_CharT>;
3726  _Str __s = _GLIBCXX_WIDEN("{:L%a}{} is not a valid weekday");
3727  if (__wd.ok())
3728  __os << std::vformat(__os.getloc(), __s.substr(0, 6),
3729  make_format_args<_Ctx>(__wd));
3730  else
3731  {
3732  auto __c = __wd.c_encoding();
3733  __os << std::vformat(__s.substr(6), make_format_args<_Ctx>(__c));
3734  }
3735  return __os;
3736  }
3737 
3738  template<typename _CharT, typename _Traits,
3739  typename _Alloc = allocator<_CharT>>
3740  inline basic_istream<_CharT, _Traits>&
3741  from_stream(basic_istream<_CharT, _Traits>& __is, const _CharT* __fmt,
3742  weekday& __wd,
3743  basic_string<_CharT, _Traits, _Alloc>* __abbrev = nullptr,
3744  minutes* __offset = nullptr)
3745  {
3746  __detail::_Parser<> __p(__format::_ChronoParts::_Weekday);
3747  if (__p(__is, __fmt, __abbrev, __offset))
3748  __wd = __p._M_wd;
3749  return __is;
3750  }
3751 
3752  template<typename _CharT, typename _Traits>
3753  inline basic_ostream<_CharT, _Traits>&
3754  operator<<(basic_ostream<_CharT, _Traits>& __os,
3755  const weekday_indexed& __wdi)
3756  {
3757  // The standard says to format wdi.weekday() and wdi.index() using
3758  // either "{:L}[{}]" or "{:L}[{} is not a valid index]". The {:L} spec
3759  // means to format the weekday using ostringstream, so just do that.
3760  basic_stringstream<_CharT> __os2;
3761  __os2.imbue(__os.getloc());
3762  __os2 << __wdi.weekday();
3763  const auto __i = __wdi.index();
3764  basic_string_view<_CharT> __s
3765  = _GLIBCXX_WIDEN("[ is not a valid index]");
3766  __os2 << __s[0];
3767  __os2 << std::format(_GLIBCXX_WIDEN("{}"), __i);
3768  if (__i >= 1 && __i <= 5)
3769  __os2 << __s.back();
3770  else
3771  __os2 << __s.substr(1);
3772  __os << __os2.view();
3773  return __os;
3774  }
3775 
3776  template<typename _CharT, typename _Traits>
3777  inline basic_ostream<_CharT, _Traits>&
3778  operator<<(basic_ostream<_CharT, _Traits>& __os,
3779  const weekday_last& __wdl)
3780  {
3781  // As above, just write straight to a stringstream, as if by "{:L}[last]"
3782  basic_stringstream<_CharT> __os2;
3783  __os2.imbue(__os.getloc());
3784  __os2 << __wdl.weekday() << _GLIBCXX_WIDEN("[last]");
3785  __os << __os2.view();
3786  return __os;
3787  }
3788 
3789  template<typename _CharT, typename _Traits>
3790  inline basic_ostream<_CharT, _Traits>&
3791  operator<<(basic_ostream<_CharT, _Traits>& __os, const month_day& __md)
3792  {
3793  // As above, just write straight to a stringstream, as if by "{:L}/{}"
3794  basic_stringstream<_CharT> __os2;
3795  __os2.imbue(__os.getloc());
3796  __os2 << __md.month();
3797  if constexpr (is_same_v<_CharT, char>)
3798  __os2 << '/';
3799  else
3800  __os2 << L'/';
3801  __os2 << __md.day();
3802  __os << __os2.view();
3803  return __os;
3804  }
3805 
3806  template<typename _CharT, typename _Traits,
3807  typename _Alloc = allocator<_CharT>>
3808  inline basic_istream<_CharT, _Traits>&
3809  from_stream(basic_istream<_CharT, _Traits>& __is, const _CharT* __fmt,
3810  month_day& __md,
3811  basic_string<_CharT, _Traits, _Alloc>* __abbrev = nullptr,
3812  minutes* __offset = nullptr)
3813  {
3814  using __format::_ChronoParts;
3815  auto __need = _ChronoParts::_Month | _ChronoParts::_Day;
3816  __detail::_Parser<> __p(__need);
3817  if (__p(__is, __fmt, __abbrev, __offset))
3818  __md = month_day(__p._M_ymd.month(), __p._M_ymd.day());
3819  return __is;
3820  }
3821 
3822  template<typename _CharT, typename _Traits>
3823  inline basic_ostream<_CharT, _Traits>&
3824  operator<<(basic_ostream<_CharT, _Traits>& __os,
3825  const month_day_last& __mdl)
3826  {
3827  // As above, just write straight to a stringstream, as if by "{:L}/last"
3828  basic_stringstream<_CharT> __os2;
3829  __os2.imbue(__os.getloc());
3830  __os2 << __mdl.month() << _GLIBCXX_WIDEN("/last");
3831  __os << __os2.view();
3832  return __os;
3833  }
3834 
3835  template<typename _CharT, typename _Traits>
3836  inline basic_ostream<_CharT, _Traits>&
3837  operator<<(basic_ostream<_CharT, _Traits>& __os,
3838  const month_weekday& __mwd)
3839  {
3840  // As above, just write straight to a stringstream, as if by "{:L}/{:L}"
3841  basic_stringstream<_CharT> __os2;
3842  __os2.imbue(__os.getloc());
3843  __os2 << __mwd.month();
3844  if constexpr (is_same_v<_CharT, char>)
3845  __os2 << '/';
3846  else
3847  __os2 << L'/';
3848  __os2 << __mwd.weekday_indexed();
3849  __os << __os2.view();
3850  return __os;
3851  }
3852 
3853  template<typename _CharT, typename _Traits>
3854  inline basic_ostream<_CharT, _Traits>&
3855  operator<<(basic_ostream<_CharT, _Traits>& __os,
3856  const month_weekday_last& __mwdl)
3857  {
3858  // As above, just write straight to a stringstream, as if by "{:L}/{:L}"
3859  basic_stringstream<_CharT> __os2;
3860  __os2.imbue(__os.getloc());
3861  __os2 << __mwdl.month();
3862  if constexpr (is_same_v<_CharT, char>)
3863  __os2 << '/';
3864  else
3865  __os2 << L'/';
3866  __os2 << __mwdl.weekday_last();
3867  __os << __os2.view();
3868  return __os;
3869  }
3870 
3871  template<typename _CharT, typename _Traits>
3872  inline basic_ostream<_CharT, _Traits>&
3873  operator<<(basic_ostream<_CharT, _Traits>& __os, const year_month& __ym)
3874  {
3875  // As above, just write straight to a stringstream, as if by "{}/{:L}"
3876  basic_stringstream<_CharT> __os2;
3877  __os2.imbue(__os.getloc());
3878  __os2 << __ym.year();
3879  if constexpr (is_same_v<_CharT, char>)
3880  __os2 << '/';
3881  else
3882  __os2 << L'/';
3883  __os2 << __ym.month();
3884  __os << __os2.view();
3885  return __os;
3886  }
3887 
3888  template<typename _CharT, typename _Traits,
3889  typename _Alloc = allocator<_CharT>>
3890  inline basic_istream<_CharT, _Traits>&
3891  from_stream(basic_istream<_CharT, _Traits>& __is, const _CharT* __fmt,
3892  year_month& __ym,
3893  basic_string<_CharT, _Traits, _Alloc>* __abbrev = nullptr,
3894  minutes* __offset = nullptr)
3895  {
3896  using __format::_ChronoParts;
3897  auto __need = _ChronoParts::_Year | _ChronoParts::_Month;
3898  __detail::_Parser<> __p(__need);
3899  if (__p(__is, __fmt, __abbrev, __offset))
3900  __ym = year_month(__p._M_ymd.year(), __p._M_ymd.month());
3901  return __is;
3902  }
3903 
3904  template<typename _CharT, typename _Traits>
3905  inline basic_ostream<_CharT, _Traits>&
3906  operator<<(basic_ostream<_CharT, _Traits>& __os,
3907  const year_month_day& __ymd)
3908  {
3909  using _Ctx = __format::__format_context<_CharT>;
3910  using _Str = basic_string_view<_CharT>;
3911  _Str __s = _GLIBCXX_WIDEN("{:%F} is not a valid date");
3912  __os << std::vformat(__ymd.ok() ? __s.substr(0, 5) : __s,
3913  make_format_args<_Ctx>(__ymd));
3914  return __os;
3915  }
3916 
3917  template<typename _CharT, typename _Traits,
3918  typename _Alloc = allocator<_CharT>>
3919  inline basic_istream<_CharT, _Traits>&
3920  from_stream(basic_istream<_CharT, _Traits>& __is, const _CharT* __fmt,
3921  year_month_day& __ymd,
3922  basic_string<_CharT, _Traits, _Alloc>* __abbrev = nullptr,
3923  minutes* __offset = nullptr)
3924  {
3925  using __format::_ChronoParts;
3926  auto __need = _ChronoParts::_Year | _ChronoParts::_Month
3927  | _ChronoParts::_Day;
3928  __detail::_Parser<> __p(__need);
3929  if (__p(__is, __fmt, __abbrev, __offset))
3930  __ymd = __p._M_ymd;
3931  return __is;
3932  }
3933 
3934  template<typename _CharT, typename _Traits>
3935  inline basic_ostream<_CharT, _Traits>&
3936  operator<<(basic_ostream<_CharT, _Traits>& __os,
3937  const year_month_day_last& __ymdl)
3938  {
3939  // As above, just write straight to a stringstream, as if by "{}/{:L}"
3940  basic_stringstream<_CharT> __os2;
3941  __os2.imbue(__os.getloc());
3942  __os2 << __ymdl.year();
3943  if constexpr (is_same_v<_CharT, char>)
3944  __os2 << '/';
3945  else
3946  __os2 << L'/';
3947  __os2 << __ymdl.month_day_last();
3948  __os << __os2.view();
3949  return __os;
3950  }
3951 
3952  template<typename _CharT, typename _Traits>
3953  inline basic_ostream<_CharT, _Traits>&
3954  operator<<(basic_ostream<_CharT, _Traits>& __os,
3955  const year_month_weekday& __ymwd)
3956  {
3957  // As above, just write straight to a stringstream, as if by
3958  // "{}/{:L}/{:L}"
3959  basic_stringstream<_CharT> __os2;
3960  __os2.imbue(__os.getloc());
3961  _CharT __slash;
3962  if constexpr (is_same_v<_CharT, char>)
3963  __slash = '/';
3964  else
3965  __slash = L'/';
3966  __os2 << __ymwd.year() << __slash << __ymwd.month() << __slash
3967  << __ymwd.weekday_indexed();
3968  __os << __os2.view();
3969  return __os;
3970  }
3971 
3972  template<typename _CharT, typename _Traits>
3973  inline basic_ostream<_CharT, _Traits>&
3974  operator<<(basic_ostream<_CharT, _Traits>& __os,
3975  const year_month_weekday_last& __ymwdl)
3976  {
3977  // As above, just write straight to a stringstream, as if by
3978  // "{}/{:L}/{:L}"
3979  basic_stringstream<_CharT> __os2;
3980  __os2.imbue(__os.getloc());
3981  _CharT __slash;
3982  if constexpr (is_same_v<_CharT, char>)
3983  __slash = '/';
3984  else
3985  __slash = L'/';
3986  __os2 << __ymwdl.year() << __slash << __ymwdl.month() << __slash
3987  << __ymwdl.weekday_last();
3988  __os << __os2.view();
3989  return __os;
3990  }
3991 
3992  template<typename _CharT, typename _Traits, typename _Duration>
3993  inline basic_ostream<_CharT, _Traits>&
3994  operator<<(basic_ostream<_CharT, _Traits>& __os,
3995  const hh_mm_ss<_Duration>& __hms)
3996  {
3997  return __os << format(__os.getloc(), _GLIBCXX_WIDEN("{:L%T}"), __hms);
3998  }
3999 
4000 #if _GLIBCXX_USE_CXX11_ABI || ! _GLIBCXX_USE_DUAL_ABI
4001  /// Writes a sys_info object to an ostream in an unspecified format.
4002  template<typename _CharT, typename _Traits>
4003  basic_ostream<_CharT, _Traits>&
4004  operator<<(basic_ostream<_CharT, _Traits>& __os, const sys_info& __i)
4005  {
4006  return __os << std::format(__os.getloc(), _GLIBCXX_WIDEN("{}"), __i);
4007  }
4008 
4009  /// Writes a local_info object to an ostream in an unspecified format.
4010  template<typename _CharT, typename _Traits>
4011  basic_ostream<_CharT, _Traits>&
4012  operator<<(basic_ostream<_CharT, _Traits>& __os, const local_info& __li)
4013  {
4014  __os << __format::_Separators<_CharT>::_S_squares()[0];
4015  if (__li.result == local_info::unique)
4016  __os << __li.first;
4017  else
4018  {
4019  if (__li.result == local_info::nonexistent)
4020  __os << _GLIBCXX_WIDEN("nonexistent");
4021  else
4022  __os << _GLIBCXX_WIDEN("ambiguous");
4023  __os << _GLIBCXX_WIDEN(" local time between ") << __li.first;
4024  __os << _GLIBCXX_WIDEN(" and ") << __li.second;
4025  }
4026  __os << __format::_Separators<_CharT>::_S_squares()[1];
4027  return __os;
4028  }
4029 
4030  template<typename _CharT, typename _Traits, typename _Duration,
4031  typename _TimeZonePtr>
4032  inline basic_ostream<_CharT, _Traits>&
4033  operator<<(basic_ostream<_CharT, _Traits>& __os,
4034  const zoned_time<_Duration, _TimeZonePtr>& __t)
4035  {
4036  __os << format(__os.getloc(), _GLIBCXX_WIDEN("{:L%F %T %Z}"), __t);
4037  return __os;
4038  }
4039 #endif
4040 
4041  template<typename _CharT, typename _Traits, typename _Duration>
4042  requires (!treat_as_floating_point_v<typename _Duration::rep>)
4043  && ratio_less_v<typename _Duration::period, days::period>
4044  inline basic_ostream<_CharT, _Traits>&
4045  operator<<(basic_ostream<_CharT, _Traits>& __os,
4046  const sys_time<_Duration>& __tp)
4047  {
4048  __os << std::format(__os.getloc(), _GLIBCXX_WIDEN("{:L%F %T}"), __tp);
4049  return __os;
4050  }
4051 
4052  template<typename _CharT, typename _Traits>
4053  inline basic_ostream<_CharT, _Traits>&
4054  operator<<(basic_ostream<_CharT, _Traits>& __os, const sys_days& __dp)
4055  {
4056  __os << year_month_day{__dp};
4057  return __os;
4058  }
4059 
4060  template<typename _CharT, typename _Traits, typename _Duration,
4061  typename _Alloc = allocator<_CharT>>
4062  basic_istream<_CharT, _Traits>&
4063  from_stream(basic_istream<_CharT, _Traits>& __is, const _CharT* __fmt,
4064  sys_time<_Duration>& __tp,
4065  basic_string<_CharT, _Traits, _Alloc>* __abbrev = nullptr,
4066  minutes* __offset = nullptr)
4067  {
4068  minutes __off{};
4069  if (!__offset)
4070  __offset = &__off;
4071  using __format::_ChronoParts;
4072  auto __need = _ChronoParts::_Year | _ChronoParts::_Month
4073  | _ChronoParts::_Day | _ChronoParts::_TimeOfDay;
4074  __detail::_Parser_t<_Duration> __p(__need);
4075  if (__p(__is, __fmt, __abbrev, __offset))
4076  {
4077  if (__p._M_is_leap_second)
4078  __is.setstate(ios_base::failbit);
4079  else
4080  {
4081  auto __st = __p._M_sys_days + __p._M_time - *__offset;
4082  __tp = __detail::__round<_Duration>(__st);
4083  }
4084  }
4085  return __is;
4086  }
4087 
4088  template<typename _CharT, typename _Traits, typename _Duration>
4089  inline basic_ostream<_CharT, _Traits>&
4090  operator<<(basic_ostream<_CharT, _Traits>& __os,
4091  const utc_time<_Duration>& __t)
4092  {
4093  __os << std::format(__os.getloc(), _GLIBCXX_WIDEN("{:L%F %T}"), __t);
4094  return __os;
4095  }
4096 
4097  template<typename _CharT, typename _Traits, typename _Duration,
4098  typename _Alloc = allocator<_CharT>>
4099  inline basic_istream<_CharT, _Traits>&
4100  from_stream(basic_istream<_CharT, _Traits>& __is, const _CharT* __fmt,
4101  utc_time<_Duration>& __tp,
4102  basic_string<_CharT, _Traits, _Alloc>* __abbrev = nullptr,
4103  minutes* __offset = nullptr)
4104  {
4105  minutes __off{};
4106  if (!__offset)
4107  __offset = &__off;
4108  using __format::_ChronoParts;
4109  auto __need = _ChronoParts::_Year | _ChronoParts::_Month
4110  | _ChronoParts::_Day | _ChronoParts::_TimeOfDay;
4111  __detail::_Parser_t<_Duration> __p(__need);
4112  if (__p(__is, __fmt, __abbrev, __offset))
4113  {
4114  // Converting to utc_time before adding _M_time is necessary for
4115  // "23:59:60" to correctly produce a time within a leap second.
4116  auto __ut = utc_clock::from_sys(__p._M_sys_days) + __p._M_time
4117  - *__offset;
4118  __tp = __detail::__round<_Duration>(__ut);
4119  }
4120  return __is;
4121  }
4122 
4123  template<typename _CharT, typename _Traits, typename _Duration>
4124  inline basic_ostream<_CharT, _Traits>&
4125  operator<<(basic_ostream<_CharT, _Traits>& __os,
4126  const tai_time<_Duration>& __t)
4127  {
4128  __os << std::format(__os.getloc(), _GLIBCXX_WIDEN("{:L%F %T}"), __t);
4129  return __os;
4130  }
4131 
4132  template<typename _CharT, typename _Traits, typename _Duration,
4133  typename _Alloc = allocator<_CharT>>
4134  inline basic_istream<_CharT, _Traits>&
4135  from_stream(basic_istream<_CharT, _Traits>& __is, const _CharT* __fmt,
4136  tai_time<_Duration>& __tp,
4137  basic_string<_CharT, _Traits, _Alloc>* __abbrev = nullptr,
4138  minutes* __offset = nullptr)
4139  {
4140  minutes __off{};
4141  if (!__offset)
4142  __offset = &__off;
4143  using __format::_ChronoParts;
4144  auto __need = _ChronoParts::_Year | _ChronoParts::_Month
4145  | _ChronoParts::_Day | _ChronoParts::_TimeOfDay;
4146  __detail::_Parser_t<_Duration> __p(__need);
4147  if (__p(__is, __fmt, __abbrev, __offset))
4148  {
4149  if (__p._M_is_leap_second)
4150  __is.setstate(ios_base::failbit);
4151  else
4152  {
4153  constexpr sys_days __epoch(-days(4383)); // 1958y/1/1
4154  auto __d = __p._M_sys_days - __epoch + __p._M_time - *__offset;
4155  tai_time<common_type_t<_Duration, seconds>> __tt(__d);
4156  __tp = __detail::__round<_Duration>(__tt);
4157  }
4158  }
4159  return __is;
4160  }
4161 
4162  template<typename _CharT, typename _Traits, typename _Duration>
4163  inline basic_ostream<_CharT, _Traits>&
4164  operator<<(basic_ostream<_CharT, _Traits>& __os,
4165  const gps_time<_Duration>& __t)
4166  {
4167  __os << std::format(__os.getloc(), _GLIBCXX_WIDEN("{:L%F %T}"), __t);
4168  return __os;
4169  }
4170 
4171  template<typename _CharT, typename _Traits, typename _Duration,
4172  typename _Alloc = allocator<_CharT>>
4173  inline basic_istream<_CharT, _Traits>&
4174  from_stream(basic_istream<_CharT, _Traits>& __is, const _CharT* __fmt,
4175  gps_time<_Duration>& __tp,
4176  basic_string<_CharT, _Traits, _Alloc>* __abbrev = nullptr,
4177  minutes* __offset = nullptr)
4178  {
4179  minutes __off{};
4180  if (!__offset)
4181  __offset = &__off;
4182  using __format::_ChronoParts;
4183  auto __need = _ChronoParts::_YearMonthDay | _ChronoParts::_TimeOfDay;
4184  __detail::_Parser_t<_Duration> __p(__need);
4185  if (__p(__is, __fmt, __abbrev, __offset))
4186  {
4187  if (__p._M_is_leap_second)
4188  __is.setstate(ios_base::failbit);
4189  else
4190  {
4191  constexpr sys_days __epoch(days(3657)); // 1980y/1/Sunday[1]
4192  auto __d = __p._M_sys_days - __epoch + __p._M_time - *__offset;
4193  gps_time<common_type_t<_Duration, seconds>> __gt(__d);
4194  __tp = __detail::__round<_Duration>(__gt);
4195  }
4196  }
4197  return __is;
4198  }
4199 
4200  template<typename _CharT, typename _Traits, typename _Duration>
4201  inline basic_ostream<_CharT, _Traits>&
4202  operator<<(basic_ostream<_CharT, _Traits>& __os,
4203  const file_time<_Duration>& __t)
4204  {
4205  __os << std::format(__os.getloc(), _GLIBCXX_WIDEN("{:L%F %T}"), __t);
4206  return __os;
4207  }
4208 
4209  template<typename _CharT, typename _Traits, typename _Duration,
4210  typename _Alloc = allocator<_CharT>>
4211  inline basic_istream<_CharT, _Traits>&
4212  from_stream(basic_istream<_CharT, _Traits>& __is, const _CharT* __fmt,
4213  file_time<_Duration>& __tp,
4214  basic_string<_CharT, _Traits, _Alloc>* __abbrev = nullptr,
4215  minutes* __offset = nullptr)
4216  {
4217  sys_time<_Duration> __st;
4218  if (chrono::from_stream(__is, __fmt, __st, __abbrev, __offset))
4219  __tp = __detail::__round<_Duration>(file_clock::from_sys(__st));
4220  return __is;
4221  }
4222 
4223  template<typename _CharT, typename _Traits, typename _Duration>
4224  inline basic_ostream<_CharT, _Traits>&
4225  operator<<(basic_ostream<_CharT, _Traits>& __os,
4226  const local_time<_Duration>& __lt)
4227  // _GLIBCXX_RESOLVE_LIB_DEFECTS
4228  // 4257. Stream insertion for chrono::local_time should be constrained
4229  requires requires(const sys_time<_Duration>& __st) { __os << __st; }
4230  {
4231  __os << sys_time<_Duration>{__lt.time_since_epoch()};
4232  return __os;
4233  }
4234 
4235  template<typename _CharT, typename _Traits, typename _Duration,
4236  typename _Alloc = allocator<_CharT>>
4237  basic_istream<_CharT, _Traits>&
4238  from_stream(basic_istream<_CharT, _Traits>& __is, const _CharT* __fmt,
4239  local_time<_Duration>& __tp,
4240  basic_string<_CharT, _Traits, _Alloc>* __abbrev = nullptr,
4241  minutes* __offset = nullptr)
4242  {
4243  using __format::_ChronoParts;
4244  auto __need = _ChronoParts::_YearMonthDay | _ChronoParts::_TimeOfDay;
4245  __detail::_Parser_t<_Duration> __p(__need);
4246  if (__p(__is, __fmt, __abbrev, __offset))
4247  {
4248  days __d = __p._M_sys_days.time_since_epoch();
4249  auto __t = local_days(__d) + __p._M_time; // ignore offset
4250  __tp = __detail::__round<_Duration>(__t);
4251  }
4252  return __is;
4253  }
4254 
4255  // [time.parse] parsing
4256 
4257 namespace __detail
4258 {
4259  // _GLIBCXX_RESOLVE_LIB_DEFECTS
4260  // 3956. chrono::parse uses from_stream as a customization point
4261  void from_stream() = delete;
4262 
4263  template<typename _Parsable, typename _CharT,
4264  typename _Traits = std::char_traits<_CharT>,
4265  typename... _OptArgs>
4266  concept __parsable = requires (basic_istream<_CharT, _Traits>& __is,
4267  const _CharT* __fmt, _Parsable& __tp,
4268  _OptArgs*... __args)
4269  { from_stream(__is, __fmt, __tp, __args...); };
4270 
4271  template<typename _Parsable, typename _CharT,
4272  typename _Traits = char_traits<_CharT>,
4273  typename _Alloc = allocator<_CharT>>
4274  struct _Parse
4275  {
4276  private:
4277  using __string_type = basic_string<_CharT, _Traits, _Alloc>;
4278 
4279  public:
4280  _Parse(const _CharT* __fmt, _Parsable& __tp,
4281  basic_string<_CharT, _Traits, _Alloc>* __abbrev = nullptr,
4282  minutes* __offset = nullptr)
4283  : _M_fmt(__fmt), _M_tp(std::__addressof(__tp)),
4284  _M_abbrev(__abbrev), _M_offset(__offset)
4285  { }
4286 
4287  _Parse(_Parse&&) = delete;
4288  _Parse& operator=(_Parse&&) = delete;
4289 
4290  private:
4291  using __stream_type = basic_istream<_CharT, _Traits>;
4292 
4293  const _CharT* const _M_fmt;
4294  _Parsable* const _M_tp;
4295  __string_type* const _M_abbrev;
4296  minutes* const _M_offset;
4297 
4298  friend __stream_type&
4299  operator>>(__stream_type& __is, _Parse&& __p)
4300  {
4301  if (__p._M_offset)
4302  from_stream(__is, __p._M_fmt, *__p._M_tp, __p._M_abbrev,
4303  __p._M_offset);
4304  else if (__p._M_abbrev)
4305  from_stream(__is, __p._M_fmt, *__p._M_tp, __p._M_abbrev);
4306  else
4307  from_stream(__is, __p._M_fmt, *__p._M_tp);
4308  return __is;
4309  }
4310 
4311  friend void operator>>(__stream_type&, _Parse&) = delete;
4312  friend void operator>>(__stream_type&, const _Parse&) = delete;
4313  };
4314 } // namespace __detail
4315 
4316  template<typename _CharT, __detail::__parsable<_CharT> _Parsable>
4317  [[nodiscard, __gnu__::__access__(__read_only__, 1)]]
4318  inline auto
4319  parse(const _CharT* __fmt, _Parsable& __tp)
4320  { return __detail::_Parse<_Parsable, _CharT>(__fmt, __tp); }
4321 
4322  template<typename _CharT, typename _Traits, typename _Alloc,
4323  __detail::__parsable<_CharT, _Traits> _Parsable>
4324  [[nodiscard]]
4325  inline auto
4326  parse(const basic_string<_CharT, _Traits, _Alloc>& __fmt, _Parsable& __tp)
4327  {
4328  return __detail::_Parse<_Parsable, _CharT, _Traits>(__fmt.c_str(), __tp);
4329  }
4330 
4331  template<typename _CharT, typename _Traits, typename _Alloc,
4332  typename _StrT = basic_string<_CharT, _Traits, _Alloc>,
4333  __detail::__parsable<_CharT, _Traits, _StrT> _Parsable>
4334  [[nodiscard, __gnu__::__access__(__read_only__, 1)]]
4335  inline auto
4336  parse(const _CharT* __fmt, _Parsable& __tp,
4337  basic_string<_CharT, _Traits, _Alloc>& __abbrev)
4338  {
4339  auto __pa = std::__addressof(__abbrev);
4340  return __detail::_Parse<_Parsable, _CharT, _Traits, _Alloc>(__fmt, __tp,
4341  __pa);
4342  }
4343 
4344  template<typename _CharT, typename _Traits, typename _Alloc,
4345  typename _StrT = basic_string<_CharT, _Traits, _Alloc>,
4346  __detail::__parsable<_CharT, _Traits, _StrT> _Parsable>
4347  [[nodiscard]]
4348  inline auto
4349  parse(const basic_string<_CharT, _Traits, _Alloc>& __fmt, _Parsable& __tp,
4350  basic_string<_CharT, _Traits, _Alloc>& __abbrev)
4351  {
4352  auto __pa = std::__addressof(__abbrev);
4353  return __detail::_Parse<_Parsable, _CharT, _Traits, _Alloc>(__fmt.c_str(),
4354  __tp, __pa);
4355  }
4356 
4357  template<typename _CharT, typename _Traits = char_traits<_CharT>,
4358  typename _StrT = basic_string<_CharT, _Traits>,
4359  __detail::__parsable<_CharT, _Traits, _StrT, minutes> _Parsable>
4360  [[nodiscard, __gnu__::__access__(__read_only__, 1)]]
4361  inline auto
4362  parse(const _CharT* __fmt, _Parsable& __tp, minutes& __offset)
4363  {
4364  return __detail::_Parse<_Parsable, _CharT>(__fmt, __tp, nullptr,
4365  &__offset);
4366  }
4367 
4368  template<typename _CharT, typename _Traits, typename _Alloc,
4369  typename _StrT = basic_string<_CharT, _Traits>,
4370  __detail::__parsable<_CharT, _Traits, _StrT, minutes> _Parsable>
4371  [[nodiscard]]
4372  inline auto
4373  parse(const basic_string<_CharT, _Traits, _Alloc>& __fmt, _Parsable& __tp,
4374  minutes& __offset)
4375  {
4376  return __detail::_Parse<_Parsable, _CharT, _Traits, _Alloc>(__fmt.c_str(),
4377  __tp, nullptr,
4378  &__offset);
4379  }
4380 
4381  template<typename _CharT, typename _Traits, typename _Alloc,
4382  typename _StrT = basic_string<_CharT, _Traits, _Alloc>,
4383  __detail::__parsable<_CharT, _Traits, _StrT, minutes> _Parsable>
4384  [[nodiscard, __gnu__::__access__(__read_only__, 1)]]
4385  inline auto
4386  parse(const _CharT* __fmt, _Parsable& __tp,
4387  basic_string<_CharT, _Traits, _Alloc>& __abbrev, minutes& __offset)
4388  {
4389  auto __pa = std::__addressof(__abbrev);
4390  return __detail::_Parse<_Parsable, _CharT, _Traits, _Alloc>(__fmt, __tp,
4391  __pa,
4392  &__offset);
4393  }
4394 
4395  template<typename _CharT, typename _Traits, typename _Alloc,
4396  typename _StrT = basic_string<_CharT, _Traits, _Alloc>,
4397  __detail::__parsable<_CharT, _Traits, _StrT, minutes> _Parsable>
4398  [[nodiscard]]
4399  inline auto
4400  parse(const basic_string<_CharT, _Traits, _Alloc>& __fmt, _Parsable& __tp,
4401  basic_string<_CharT, _Traits, _Alloc>& __abbrev, minutes& __offset)
4402  {
4403  auto __pa = std::__addressof(__abbrev);
4404  return __detail::_Parse<_Parsable, _CharT, _Traits, _Alloc>(__fmt.c_str(),
4405  __tp, __pa,
4406  &__offset);
4407  }
4408 
4409  /// @cond undocumented
4410  template<typename _Duration>
4411  template<typename _CharT, typename _Traits, typename _Alloc>
4412  basic_istream<_CharT, _Traits>&
4413  __detail::_Parser<_Duration>::
4414  operator()(basic_istream<_CharT, _Traits>& __is, const _CharT* __fmt,
4415  basic_string<_CharT, _Traits, _Alloc>* __abbrev,
4416  minutes* __offset)
4417  {
4418  using sentry = typename basic_istream<_CharT, _Traits>::sentry;
4419  ios_base::iostate __err = ios_base::goodbit;
4420  if (sentry __cerb(__is, true); __cerb)
4421  {
4422  locale __loc = __is.getloc();
4423  auto& __tmget = std::use_facet<std::time_get<_CharT>>(__loc);
4424  auto& __tmpunct = std::use_facet<std::__timepunct<_CharT>>(__loc);
4425 
4426  // RAII type to save and restore stream state.
4427  struct _Stream_state
4428  {
4429  explicit
4430  _Stream_state(basic_istream<_CharT, _Traits>& __i)
4431  : _M_is(__i),
4432  _M_flags(__i.flags(ios_base::skipws | ios_base::dec)),
4433  _M_w(__i.width(0))
4434  { }
4435 
4436  ~_Stream_state()
4437  {
4438  _M_is.flags(_M_flags);
4439  _M_is.width(_M_w);
4440  }
4441 
4442  _Stream_state(_Stream_state&&) = delete;
4443 
4444  basic_istream<_CharT, _Traits>& _M_is;
4445  ios_base::fmtflags _M_flags;
4446  streamsize _M_w;
4447  };
4448 
4449  auto __is_failed = [](ios_base::iostate __e) {
4450  return static_cast<bool>(__e & ios_base::failbit);
4451  };
4452 
4453  // Read an unsigned integer from the stream and return it.
4454  // Extract no more than __n digits. Set __err on error.
4455  auto __read_unsigned = [&] (int __n) {
4456  return _S_read_unsigned(__is, __err, __n);
4457  };
4458 
4459  // Read a signed integer from the stream and return it.
4460  // Extract no more than __n digits. Set __err on error.
4461  auto __read_signed = [&] (int __n) {
4462  return _S_read_signed(__is, __err, __n);
4463  };
4464 
4465  // Read an expected character from the stream.
4466  auto __read_chr = [&__is, &__err] (_CharT __c) {
4467  return _S_read_chr(__is, __err, __c);
4468  };
4469 
4470  using __format::_ChronoParts;
4471  _ChronoParts __parts{};
4472 
4473  const year __bad_y = --year::min(); // SHRT_MIN
4474  const month __bad_mon(255);
4475  const day __bad_day(255);
4476  const weekday __bad_wday(255);
4477  const hours __bad_h(-1);
4478  const minutes __bad_min(-9999);
4479  const seconds __bad_sec(-1);
4480 
4481  year __y = __bad_y, __yy = __bad_y; // %Y, %yy
4482  year __iso_y = __bad_y, __iso_yy = __bad_y; // %G, %g
4483  month __m = __bad_mon; // %m
4484  day __d = __bad_day; // %d
4485  weekday __wday = __bad_wday; // %a %A %u %w
4486  hours __h = __bad_h, __h12 = __bad_h; // %H, %I
4487  minutes __min = __bad_min; // %M
4488  _Duration __s = __bad_sec; // %S
4489  int __ampm = 0; // %p
4490  int __iso_wk = -1, __sunday_wk = -1, __monday_wk = -1; // %V, %U, %W
4491  int __century = -1; // %C
4492  int __dayofyear = -1; // %j (for non-duration)
4493 
4494  minutes __tz_offset = __bad_min;
4495  basic_string<_CharT, _Traits> __tz_abbr;
4496 
4497  if ((_M_need & _ChronoParts::_TimeOfDay) != 0
4498  && (_M_need & _ChronoParts::_Year) != 0)
4499  {
4500  // For time_points assume "00:00:00" is implicitly present,
4501  // so we don't fail to parse if it's not (PR libstdc++/114240).
4502  // We will still fail to parse if there's no year+month+day.
4503  __h = hours(0);
4504  __parts = _ChronoParts::_TimeOfDay;
4505  }
4506 
4507  // bool __is_neg = false; // TODO: how is this handled for parsing?
4508 
4509  _CharT __mod{}; // One of 'E' or 'O' or nul.
4510  unsigned __num = 0; // Non-zero for N modifier.
4511  bool __is_flag = false; // True if we're processing a % flag.
4512 
4513  constexpr bool __is_floating
4514  = treat_as_floating_point_v<typename _Duration::rep>;
4515 
4516  // If an out-of-range value is extracted (e.g. 61min for %M),
4517  // do not set failbit immediately because we might not need it
4518  // (e.g. parsing chrono::year doesn't care about invalid %M values).
4519  // Instead set the variable back to its initial 'bad' state,
4520  // and also set related variables corresponding to the same field
4521  // (e.g. a bad %M value for __min should also reset __h and __s).
4522  // If a valid value is needed later the bad value will cause failure.
4523 
4524  // For some fields we don't know the correct range when parsing and
4525  // we have to be liberal in what we accept, e.g. we allow 366 for
4526  // day-of-year because that's valid in leap years, and we allow 31
4527  // for day-of-month. If those values are needed to determine the
4528  // result then we can do a correct range check at the end when we
4529  // know the how many days the relevant year or month actually has.
4530 
4531  while (*__fmt)
4532  {
4533  _CharT __c = *__fmt++;
4534  if (!__is_flag)
4535  {
4536  if (__c == '%')
4537  __is_flag = true; // This is the start of a flag.
4538  else if (std::isspace(__c, __loc))
4539  std::ws(__is); // Match zero or more whitespace characters.
4540  else if (!__read_chr(__c)) [[unlikely]]
4541  break; // Failed to match the expected character.
4542 
4543  continue; // Process next character in the format string.
4544  }
4545 
4546  // Now processing a flag.
4547  switch (__c)
4548  {
4549  case 'a': // Locale's weekday name
4550  case 'A': // (full or abbreviated, matched case-insensitively).
4551  if (__mod || __num) [[unlikely]]
4552  __err = ios_base::failbit;
4553  else
4554  {
4555  struct tm __tm{};
4556  __tmget.get(__is, {}, __is, __err, &__tm,
4557  __fmt - 2, __fmt);
4558  if (!__is_failed(__err))
4559  __wday = weekday(__tm.tm_wday);
4560  }
4561  __parts |= _ChronoParts::_Weekday;
4562  break;
4563 
4564  case 'b': // Locale's month name
4565  case 'h': // (full or abbreviated, matched case-insensitively).
4566  case 'B':
4567  if (__mod || __num) [[unlikely]]
4568  __err = ios_base::failbit;
4569  else
4570  {
4571  // strptime behaves differently for %b and %B,
4572  // but chrono::parse says they're equivalent.
4573  // Luckily libstdc++ std::time_get works as needed.
4574  struct tm __tm{};
4575  __tmget.get(__is, {}, __is, __err, &__tm,
4576  __fmt - 2, __fmt);
4577  if (!__is_failed(__err))
4578  __m = month(__tm.tm_mon + 1);
4579  }
4580  __parts |= _ChronoParts::_Month;
4581  break;
4582 
4583  case 'c': // Locale's date and time representation.
4584  if (__mod == 'O' || __num) [[unlikely]]
4585  __err |= ios_base::failbit;
4586  else
4587  {
4588  struct tm __tm{};
4589  __tmget.get(__is, {}, __is, __err, &__tm,
4590  __fmt - 2 - (__mod == 'E'), __fmt);
4591  if (!__is_failed(__err))
4592  {
4593  __y = year(__tm.tm_year + 1900);
4594  __m = month(__tm.tm_mon + 1);
4595  __d = day(__tm.tm_mday);
4596  __h = hours(__tm.tm_hour);
4597  __min = minutes(__tm.tm_min);
4598  __s = seconds(__tm.tm_sec);
4599  }
4600  }
4601  __parts |= _ChronoParts::_DateTime;
4602  break;
4603 
4604  case 'C': // Century
4605  if (!__mod) [[likely]]
4606  {
4607  auto __v = __read_signed(__num ? __num : 2);
4608  if (!__is_failed(__err))
4609  {
4610  int __cmin = (int)year::min() / 100;
4611  int __cmax = (int)year::max() / 100;
4612  if (__cmin <= __v && __v <= __cmax)
4613  __century = __v * 100;
4614  else
4615  __century = -2; // This prevents guessing century.
4616  }
4617  }
4618  else if (__mod == 'E')
4619  {
4620  struct tm __tm{};
4621  __tmget.get(__is, {}, __is, __err, &__tm,
4622  __fmt - 3, __fmt);
4623  if (!__is_failed(__err))
4624  __century = __tm.tm_year;
4625  }
4626  else [[unlikely]]
4627  __err |= ios_base::failbit;
4628  // N.B. don't set this here: __parts |= _ChronoParts::_Year;
4629  break;
4630 
4631  case 'd': // Day of month (1-31)
4632  case 'e':
4633  if (!__mod) [[likely]]
4634  {
4635  auto __v = __read_unsigned(__num ? __num : 2);
4636  if (!__is_failed(__err))
4637  __d = day(__v);
4638  }
4639  else if (__mod == 'O')
4640  {
4641  struct tm __tm{};
4642  __tmget.get(__is, {}, __is, __err, &__tm,
4643  __fmt - 3, __fmt);
4644  if (!__is_failed(__err))
4645  __d = day(__tm.tm_mday);
4646  }
4647  else [[unlikely]]
4648  __err |= ios_base::failbit;
4649  __parts |= _ChronoParts::_Day;
4650  break;
4651 
4652  case 'D': // %m/%d/%y
4653  if (__mod || __num) [[unlikely]]
4654  __err |= ios_base::failbit;
4655  else
4656  {
4657  auto __month = __read_unsigned(2); // %m
4658  __read_chr('/');
4659  auto __day = __read_unsigned(2); // %d
4660  __read_chr('/');
4661  auto __year = __read_unsigned(2); // %y
4662  if (__is_failed(__err))
4663  break;
4664  __y = year(__year + 1900 + 100 * int(__year < 69));
4665  __m = month(__month);
4666  __d = day(__day);
4667  if (!year_month_day(__y, __m, __d).ok())
4668  {
4669  __y = __yy = __iso_y = __iso_yy = __bad_y;
4670  __m = __bad_mon;
4671  __d = __bad_day;
4672  break;
4673  }
4674  }
4675  __parts |= _ChronoParts::_Date;
4676  break;
4677 
4678  case 'F': // %Y-%m-%d - any N modifier only applies to %Y.
4679  if (__mod) [[unlikely]]
4680  __err |= ios_base::failbit;
4681  else
4682  {
4683  auto __year = __read_signed(__num ? __num : 4); // %Y
4684  __read_chr('-');
4685  auto __month = __read_unsigned(2); // %m
4686  __read_chr('-');
4687  auto __day = __read_unsigned(2); // %d
4688  if (__is_failed(__err))
4689  break;
4690  __y = year(__year);
4691  __m = month(__month);
4692  __d = day(__day);
4693  if (!year_month_day(__y, __m, __d).ok())
4694  {
4695  __y = __yy = __iso_y = __iso_yy = __bad_y;
4696  __m = __bad_mon;
4697  __d = __bad_day;
4698  break;
4699  }
4700  }
4701  __parts |= _ChronoParts::_Date;
4702  break;
4703 
4704  case 'g': // Last two digits of ISO week-based year.
4705  if (__mod) [[unlikely]]
4706  __err |= ios_base::failbit;
4707  else
4708  {
4709  auto __val = __read_unsigned(__num ? __num : 2);
4710  if (__val >= 0 && __val <= 99)
4711  {
4712  __iso_yy = year(__val);
4713  if (__century == -1) // No %C has been parsed yet.
4714  __century = 2000;
4715  }
4716  else
4717  __iso_yy = __iso_y = __y = __yy = __bad_y;
4718  }
4719  __parts |= _ChronoParts::_Year;
4720  break;
4721 
4722  case 'G': // ISO week-based year.
4723  if (__mod) [[unlikely]]
4724  __err |= ios_base::failbit;
4725  else
4726  __iso_y = year(__read_unsigned(__num ? __num : 4));
4727  __parts |= _ChronoParts::_Year;
4728  break;
4729 
4730  case 'H': // 24-hour (00-23)
4731  case 'I': // 12-hour (1-12)
4732  if (__mod == 'E') [[unlikely]]
4733  __err |= ios_base::failbit;
4734  else if (__mod == 'O')
4735  {
4736 #if 0
4737  struct tm __tm{};
4738  __tm.tm_ampm = 1;
4739  __tmget.get(__is, {}, __is, __err, &__tm,
4740  __fmt - 3, __fmt);
4741  if (!__is_failed(__err))
4742  {
4743  if (__c == 'I')
4744  {
4745  __h12 = hours(__tm.tm_hour);
4746  __h = __bad_h;
4747  }
4748  else
4749  __h = hours(__tm.tm_hour);
4750  }
4751 #else
4752  // XXX %OI seems to be unimplementable.
4753  __err |= ios_base::failbit;
4754 #endif
4755  }
4756  else
4757  {
4758  auto __val = __read_unsigned(__num ? __num : 2);
4759  if (__c == 'I' && __val >= 1 && __val <= 12)
4760  {
4761  __h12 = hours(__val);
4762  __h = __bad_h;
4763  }
4764  else if (__c == 'H' && __val >= 0 && __val <= 23)
4765  {
4766  __h = hours(__val);
4767  __h12 = __bad_h;
4768  }
4769  else
4770  {
4771  if ((_M_need & _ChronoParts::_TimeOfDay) != 0)
4772  __err |= ios_base::failbit;
4773  break;
4774  }
4775  }
4776  __parts |= _ChronoParts::_TimeOfDay;
4777  break;
4778 
4779  case 'j': // For duration, count of days, otherwise day of year
4780  if (__mod) [[unlikely]]
4781  __err |= ios_base::failbit;
4782  else if (_M_need == _ChronoParts::_TimeOfDay) // duration
4783  {
4784  auto __val = __read_signed(__num ? __num : 3);
4785  if (!__is_failed(__err))
4786  {
4787  __h = days(__val); // __h will get added to _M_time
4788  __parts |= _ChronoParts::_TimeOfDay;
4789  }
4790  }
4791  else
4792  {
4793  __dayofyear = __read_unsigned(__num ? __num : 3);
4794  // N.B. do not alter __parts here, done after loop.
4795  // No need for range checking here either.
4796  }
4797  break;
4798 
4799  case 'm': // Month (1-12)
4800  if (__mod == 'E') [[unlikely]]
4801  __err |= ios_base::failbit;
4802  else if (__mod == 'O')
4803  {
4804  struct tm __tm{};
4805  __tmget.get(__is, {}, __is, __err, &__tm,
4806  __fmt - 2, __fmt);
4807  if (!__is_failed(__err))
4808  __m = month(__tm.tm_mon + 1);
4809  }
4810  else
4811  {
4812  auto __val = __read_unsigned(__num ? __num : 2);
4813  if (__val >= 1 && __val <= 12)
4814  __m = month(__val);
4815  else
4816  __m = __bad_mon;
4817  }
4818  __parts |= _ChronoParts::_Month;
4819  break;
4820 
4821  case 'M': // Minutes
4822  if (__mod == 'E') [[unlikely]]
4823  __err |= ios_base::failbit;
4824  else if (__mod == 'O')
4825  {
4826  struct tm __tm{};
4827  __tmget.get(__is, {}, __is, __err, &__tm,
4828  __fmt - 2, __fmt);
4829  if (!__is_failed(__err))
4830  __min = minutes(__tm.tm_min);
4831  }
4832  else
4833  {
4834  auto __val = __read_unsigned(__num ? __num : 2);
4835  if (0 <= __val && __val < 60)
4836  __min = minutes(__val);
4837  else
4838  {
4839  if ((_M_need & _ChronoParts::_TimeOfDay) != 0)
4840  __err |= ios_base::failbit;
4841  break;
4842  }
4843  }
4844  __parts |= _ChronoParts::_TimeOfDay;
4845  break;
4846 
4847  case 'p': // Locale's AM/PM designation for 12-hour clock.
4848  if (__mod || __num)
4849  __err |= ios_base::failbit;
4850  else
4851  {
4852  // Can't use std::time_get here as it can't parse %p
4853  // in isolation without %I. This might be faster anyway.
4854  const _CharT* __ampms[2];
4855  __tmpunct._M_am_pm(__ampms);
4856  int __n = 0, __which = 3;
4857  while (__which != 0)
4858  {
4859  auto __i = __is.peek();
4860  if (_Traits::eq_int_type(__i, _Traits::eof()))
4861  {
4862  __err |= ios_base::eofbit | ios_base::failbit;
4863  break;
4864  }
4865  __i = std::toupper(_Traits::to_char_type(__i), __loc);
4866  if (__which & 1)
4867  {
4868  if (__i != std::toupper(__ampms[0][__n], __loc))
4869  __which ^= 1;
4870  else if (__ampms[0][__n + 1] == _CharT())
4871  {
4872  __which = 1;
4873  (void) __is.get();
4874  break;
4875  }
4876  }
4877  if (__which & 2)
4878  {
4879  if (__i != std::toupper(__ampms[1][__n], __loc))
4880  __which ^= 2;
4881  else if (__ampms[1][__n + 1] == _CharT())
4882  {
4883  __which = 2;
4884  (void) __is.get();
4885  break;
4886  }
4887  }
4888  if (__which)
4889  (void) __is.get();
4890  ++__n;
4891  }
4892  if (__which == 0 || __which == 3)
4893  __err |= ios_base::failbit;
4894  else
4895  __ampm = __which;
4896  }
4897  break;
4898 
4899  case 'r': // Locale's 12-hour time.
4900  if (__mod || __num)
4901  __err |= ios_base::failbit;
4902  else
4903  {
4904  struct tm __tm{};
4905  __tmget.get(__is, {}, __is, __err, &__tm,
4906  __fmt - 2, __fmt);
4907  if (!__is_failed(__err))
4908  {
4909  __h = hours(__tm.tm_hour);
4910  __min = minutes(__tm.tm_min);
4911  __s = seconds(__tm.tm_sec);
4912  }
4913  }
4914  __parts |= _ChronoParts::_TimeOfDay;
4915  break;
4916 
4917  case 'R': // %H:%M
4918  case 'T': // %H:%M:%S
4919  if (__mod || __num) [[unlikely]]
4920  {
4921  __err |= ios_base::failbit;
4922  break;
4923  }
4924  else
4925  {
4926  auto __val = __read_unsigned(2);
4927  if (__val == -1 || __val > 23) [[unlikely]]
4928  {
4929  if ((_M_need & _ChronoParts::_TimeOfDay) != 0)
4930  __err |= ios_base::failbit;
4931  break;
4932  }
4933  if (!__read_chr(':')) [[unlikely]]
4934  break;
4935  __h = hours(__val);
4936 
4937  __val = __read_unsigned(2);
4938  if (__val == -1 || __val > 60) [[unlikely]]
4939  {
4940  if ((_M_need & _ChronoParts::_TimeOfDay) != 0)
4941  __err |= ios_base::failbit;
4942  break;
4943  }
4944  __min = minutes(__val);
4945 
4946  if (__c == 'R')
4947  {
4948  __parts |= _ChronoParts::_TimeOfDay;
4949  break;
4950  }
4951  else if (!__read_chr(':')) [[unlikely]]
4952  break;
4953  }
4954  [[fallthrough]];
4955 
4956  case 'S': // Seconds
4957  if (__mod == 'E') [[unlikely]]
4958  __err |= ios_base::failbit;
4959  else if (__mod == 'O')
4960  {
4961  struct tm __tm{};
4962  __tmget.get(__is, {}, __is, __err, &__tm,
4963  __fmt - 3, __fmt);
4964  if (!__is_failed(__err))
4965  __s = seconds(__tm.tm_sec);
4966  }
4967  else if constexpr (_Duration::period::den == 1
4968  && !__is_floating)
4969  {
4970  auto __val = __read_unsigned(__num ? __num : 2);
4971  if (0 <= __val && __val <= 59) [[likely]]
4972  __s = seconds(__val);
4973  else
4974  {
4975  if ((_M_need & _ChronoParts::_TimeOfDay) != 0)
4976  __err |= ios_base::failbit;
4977  break;
4978  }
4979  }
4980  else // Read fractional seconds
4981  {
4982  stringstream __buf;
4983  auto __digit = _S_try_read_digit(__is, __err);
4984  if (__digit != -1)
4985  {
4986  __buf.put('0' + __digit);
4987  __digit = _S_try_read_digit(__is, __err);
4988  if (__digit != -1)
4989  __buf.put('0' + __digit);
4990  }
4991 
4992  auto __i = __is.peek();
4993  if (_Traits::eq_int_type(__i, _Traits::eof()))
4994  __err |= ios_base::eofbit;
4995  else
4996  {
4997  _CharT __dp = '.';
4998  if (__loc != locale::classic())
4999  {
5000  auto& __np = use_facet<numpunct<_CharT>>(__loc);
5001  __dp = __np.decimal_point();
5002  }
5003  _CharT __c = _Traits::to_char_type(__i);
5004  if (__c == __dp)
5005  {
5006  (void) __is.get();
5007  __buf.put('.');
5008  int __prec
5009  = hh_mm_ss<_Duration>::fractional_width;
5010  do
5011  {
5012  __digit = _S_try_read_digit(__is, __err);
5013  if (__digit != -1)
5014  __buf.put('0' + __digit);
5015  else
5016  break;
5017  }
5018  while (--__prec);
5019  }
5020  }
5021 
5022  if (!__is_failed(__err)) [[likely]]
5023  {
5024  long double __val{};
5025 #if __cpp_lib_to_chars
5026  string __str = std::move(__buf).str();
5027  auto __first = __str.data();
5028  auto __last = __first + __str.size();
5029  using enum chars_format;
5030  auto [ptr, ec] = std::from_chars(__first, __last,
5031  __val, fixed);
5032  if ((bool)ec || ptr != __last) [[unlikely]]
5033  __err |= ios_base::failbit;
5034  else
5035 #else
5036  if (__buf >> __val)
5037 #endif
5038  {
5039  duration<long double> __fs(__val);
5040  if constexpr (__is_floating)
5041  __s = __fs;
5042  else
5043  __s = chrono::round<_Duration>(__fs);
5044  }
5045  }
5046  }
5047  __parts |= _ChronoParts::_TimeOfDay;
5048  break;
5049 
5050  case 'u': // ISO weekday (1-7)
5051  case 'w': // Weekday (0-6)
5052  if (__mod == 'E') [[unlikely]]
5053  __err |= ios_base::failbit;
5054  else if (__mod == 'O')
5055  {
5056  if (__c == 'w')
5057  {
5058  struct tm __tm{};
5059  __tmget.get(__is, {}, __is, __err, &__tm,
5060  __fmt - 3, __fmt);
5061  if (!__is_failed(__err))
5062  __wday = weekday(__tm.tm_wday);
5063  }
5064  else
5065  __err |= ios_base::failbit;
5066  }
5067  else
5068  {
5069  const int __lo = __c == 'u' ? 1 : 0;
5070  const int __hi = __lo + 6;
5071  auto __val = __read_unsigned(__num ? __num : 1);
5072  if (__lo <= __val && __val <= __hi)
5073  __wday = weekday(__val);
5074  else
5075  {
5076  __wday = __bad_wday;
5077  break;
5078  }
5079  }
5080  __parts |= _ChronoParts::_Weekday;
5081  break;
5082 
5083  case 'U': // Week number of the year (from first Sunday).
5084  case 'V': // ISO week-based week number.
5085  case 'W': // Week number of the year (from first Monday).
5086  if (__mod == 'E') [[unlikely]]
5087  __err |= ios_base::failbit;
5088  else if (__mod == 'O')
5089  {
5090  if (__c == 'V') [[unlikely]]
5091  __err |= ios_base::failbit;
5092  else
5093  {
5094  // TODO nl_langinfo_l(ALT_DIGITS) ?
5095  // Not implementable using std::time_get.
5096  }
5097  }
5098  else
5099  {
5100  const int __lo = __c == 'V' ? 1 : 0;
5101  const int __hi = 53;
5102  auto __val = __read_unsigned(__num ? __num : 2);
5103  if (__lo <= __val && __val <= __hi)
5104  {
5105  switch (__c)
5106  {
5107  case 'U':
5108  __sunday_wk = __val;
5109  break;
5110  case 'V':
5111  __iso_wk = __val;
5112  break;
5113  case 'W':
5114  __monday_wk = __val;
5115  break;
5116  }
5117  }
5118  else
5119  __iso_wk = __sunday_wk = __monday_wk = -1;
5120  }
5121  // N.B. do not alter __parts here, done after loop.
5122  break;
5123 
5124  case 'x': // Locale's date representation.
5125  if (__mod == 'O' || __num) [[unlikely]]
5126  __err |= ios_base::failbit;
5127  else
5128  {
5129  struct tm __tm{};
5130  __tmget.get(__is, {}, __is, __err, &__tm,
5131  __fmt - 2 - (__mod == 'E'), __fmt);
5132  if (!__is_failed(__err))
5133  {
5134  __y = year(__tm.tm_year + 1900);
5135  __m = month(__tm.tm_mon + 1);
5136  __d = day(__tm.tm_mday);
5137  }
5138  }
5139  __parts |= _ChronoParts::_Date;
5140  break;
5141 
5142  case 'X': // Locale's time representation.
5143  if (__mod == 'O' || __num) [[unlikely]]
5144  __err |= ios_base::failbit;
5145  else
5146  {
5147  struct tm __tm{};
5148  __tmget.get(__is, {}, __is, __err, &__tm,
5149  __fmt - 2 - (__mod == 'E'), __fmt);
5150  if (!__is_failed(__err))
5151  {
5152  __h = hours(__tm.tm_hour);
5153  __min = minutes(__tm.tm_min);
5154  __s = seconds(__tm.tm_sec);
5155  }
5156  }
5157  __parts |= _ChronoParts::_TimeOfDay;
5158  break;
5159 
5160  case 'y': // Last two digits of year.
5161  if (__mod) [[unlikely]]
5162  {
5163  struct tm __tm{};
5164  __tmget.get(__is, {}, __is, __err, &__tm,
5165  __fmt - 3, __fmt);
5166  if (!__is_failed(__err))
5167  {
5168  int __cent = __tm.tm_year < 2000 ? 1900 : 2000;
5169  __yy = year(__tm.tm_year - __cent);
5170  if (__century == -1) // No %C has been parsed yet.
5171  __century = __cent;
5172  }
5173  }
5174  else
5175  {
5176  auto __val = __read_unsigned(__num ? __num : 2);
5177  if (__val >= 0 && __val <= 99)
5178  {
5179  __yy = year(__val);
5180  if (__century == -1) // No %C has been parsed yet.
5181  __century = __val < 69 ? 2000 : 1900;
5182  }
5183  else
5184  __y = __yy = __iso_yy = __iso_y = __bad_y;
5185  }
5186  __parts |= _ChronoParts::_Year;
5187  break;
5188 
5189  case 'Y': // Year
5190  if (__mod == 'O') [[unlikely]]
5191  __err |= ios_base::failbit;
5192  else if (__mod == 'E')
5193  {
5194  struct tm __tm{};
5195  __tmget.get(__is, {}, __is, __err, &__tm,
5196  __fmt - 3, __fmt);
5197  if (!__is_failed(__err))
5198  __y = year(__tm.tm_year);
5199  }
5200  else
5201  {
5202  auto __val = __read_unsigned(__num ? __num : 4);
5203  if (!__is_failed(__err))
5204  __y = year(__val);
5205  }
5206  __parts |= _ChronoParts::_Year;
5207  break;
5208 
5209  case 'z':
5210  if (__num) [[unlikely]]
5211  __err |= ios_base::failbit;
5212  else
5213  {
5214  // For %Ez and %Oz read [+|-][h]h[:mm].
5215  // For %z read [+|-]hh[mm].
5216 
5217  auto __i = __is.peek();
5218  if (_Traits::eq_int_type(__i, _Traits::eof()))
5219  {
5220  __err |= ios_base::eofbit | ios_base::failbit;
5221  break;
5222  }
5223  _CharT __ic = _Traits::to_char_type(__i);
5224  const bool __neg = __ic == _CharT('-');
5225  if (__ic == _CharT('-') || __ic == _CharT('+'))
5226  (void) __is.get();
5227 
5228  int_least32_t __hh;
5229  if (__mod)
5230  {
5231  // Read h[h]
5232  __hh = __read_unsigned(2);
5233  }
5234  else
5235  {
5236  // Read hh
5237  auto __d1 = _S_try_read_digit(__is, __err);
5238  auto __d2 = _S_try_read_digit(__is, __err);
5239  if (__d1 >= 0 && __d2 >= 0) [[likely]]
5240  __hh = 10 * __d1 + __d2;
5241  else
5242  __err |= ios_base::failbit;
5243  }
5244 
5245  if (__is_failed(__err))
5246  break;
5247 
5248  __i = __is.peek();
5249  if (_Traits::eq_int_type(__i, _Traits::eof()))
5250  {
5251  __err |= ios_base::eofbit;
5252  __tz_offset = minutes(__hh * (__neg ? -60 : 60));
5253  break;
5254  }
5255  __ic = _Traits::to_char_type(__i);
5256 
5257  bool __read_mm = false;
5258  if (__mod)
5259  {
5260  if (__ic == _GLIBCXX_WIDEN(":")[0])
5261  {
5262  // Read [:mm] part.
5263  (void) __is.get();
5264  __read_mm = true;
5265  }
5266  }
5267  else if (_CharT('0') <= __ic && __ic <= _CharT('9'))
5268  {
5269  // Read [mm] part.
5270  __read_mm = true;
5271  }
5272 
5273  int_least32_t __mm = 0;
5274  if (__read_mm)
5275  {
5276  auto __d1 = _S_try_read_digit(__is, __err);
5277  auto __d2 = _S_try_read_digit(__is, __err);
5278  if (__d1 >= 0 && __d2 >= 0) [[likely]]
5279  __mm = 10 * __d1 + __d2;
5280  else
5281  __err |= ios_base::failbit;
5282  }
5283 
5284  if (!__is_failed(__err))
5285  {
5286  auto __z = __hh * 60 + __mm;
5287  __tz_offset = minutes(__neg ? -__z : __z);
5288  }
5289  }
5290  break;
5291 
5292  case 'Z':
5293  if (__mod || __num) [[unlikely]]
5294  __err |= ios_base::failbit;
5295  else
5296  {
5297  basic_string_view<_CharT> __x = _GLIBCXX_WIDEN("_/-+");
5298  __tz_abbr.clear();
5299  while (true)
5300  {
5301  auto __i = __is.peek();
5302  if (!_Traits::eq_int_type(__i, _Traits::eof()))
5303  {
5304  _CharT __a = _Traits::to_char_type(__i);
5305  if (std::isalnum(__a, __loc)
5306  || __x.find(__a) != __x.npos)
5307  {
5308  __tz_abbr.push_back(__a);
5309  (void) __is.get();
5310  continue;
5311  }
5312  }
5313  else
5314  __err |= ios_base::eofbit;
5315  break;
5316  }
5317  if (__tz_abbr.empty())
5318  __err |= ios_base::failbit;
5319  }
5320  break;
5321 
5322  case 'n': // Exactly one whitespace character.
5323  if (__mod || __num) [[unlikely]]
5324  __err |= ios_base::failbit;
5325  else
5326  {
5327  _CharT __i = __is.peek();
5328  if (_Traits::eq_int_type(__i, _Traits::eof()))
5329  __err |= ios_base::eofbit | ios_base::failbit;
5330  else if (std::isspace(_Traits::to_char_type(__i), __loc))
5331  (void) __is.get();
5332  else
5333  __err |= ios_base::failbit;
5334  }
5335  break;
5336 
5337  case 't': // Zero or one whitespace characters.
5338  if (__mod || __num) [[unlikely]]
5339  __err |= ios_base::failbit;
5340  else
5341  {
5342  _CharT __i = __is.peek();
5343  if (_Traits::eq_int_type(__i, _Traits::eof()))
5344  __err |= ios_base::eofbit;
5345  else if (std::isspace(_Traits::to_char_type(__i), __loc))
5346  (void) __is.get();
5347  }
5348  break;
5349 
5350  case '%': // A % character.
5351  if (__mod || __num) [[unlikely]]
5352  __err |= ios_base::failbit;
5353  else
5354  __read_chr('%');
5355  break;
5356 
5357  case 'O': // Modifiers
5358  case 'E':
5359  if (__mod || __num) [[unlikely]]
5360  {
5361  __err |= ios_base::failbit;
5362  break;
5363  }
5364  __mod = __c;
5365  continue;
5366 
5367  default:
5368  if (_CharT('1') <= __c && __c <= _CharT('9'))
5369  {
5370  if (!__mod) [[likely]]
5371  {
5372  // %Nx - extract positive decimal integer N
5373  auto __end = __fmt + _Traits::length(__fmt);
5374  auto [__v, __ptr]
5375  = __format::__parse_integer(__fmt - 1, __end);
5376  if (__ptr) [[likely]]
5377  {
5378  __num = __v;
5379  __fmt = __ptr;
5380  continue;
5381  }
5382  }
5383  }
5384  __err |= ios_base::failbit;
5385  }
5386 
5387  if (__is_failed(__err)) [[unlikely]]
5388  break;
5389 
5390  __is_flag = false;
5391  __num = 0;
5392  __mod = _CharT();
5393  }
5394 
5395  if (__century >= 0)
5396  {
5397  if (__yy != __bad_y && __y == __bad_y)
5398  __y = years(__century) + __yy; // Use %y instead of %Y
5399  if (__iso_yy != __bad_y && __iso_y == __bad_y)
5400  __iso_y = years(__century) + __iso_yy; // Use %g instead of %G
5401  }
5402 
5403  bool __can_use_doy = false;
5404  bool __can_use_iso_wk = false;
5405  bool __can_use_sun_wk = false;
5406  bool __can_use_mon_wk = false;
5407 
5408  // A year + day-of-year can be converted to a full date.
5409  if (__y != __bad_y && __dayofyear >= 0)
5410  {
5411  __can_use_doy = true;
5412  __parts |= _ChronoParts::_Date;
5413  }
5414  else if (__y != __bad_y && __wday != __bad_wday && __sunday_wk >= 0)
5415  {
5416  __can_use_sun_wk = true;
5417  __parts |= _ChronoParts::_Date;
5418  }
5419  else if (__y != __bad_y && __wday != __bad_wday && __monday_wk >= 0)
5420  {
5421  __can_use_mon_wk = true;
5422  __parts |= _ChronoParts::_Date;
5423  }
5424  else if (__iso_y != __bad_y && __wday != __bad_wday && __iso_wk > 0)
5425  {
5426  // An ISO week date can be converted to a full date.
5427  __can_use_iso_wk = true;
5428  __parts |= _ChronoParts::_Date;
5429  }
5430 
5431  if (__is_failed(__err)) [[unlikely]]
5432  ; // Don't bother doing any more work.
5433  else if (__is_flag) [[unlikely]] // incomplete format flag
5434  __err |= ios_base::failbit;
5435  else if ((_M_need & __parts) == _M_need) [[likely]]
5436  {
5437  // We try to avoid calculating _M_sys_days and _M_ymd unless
5438  // necessary, because converting sys_days to year_month_day
5439  // (or vice versa) requires non-trivial calculations.
5440  // If we have y/m/d values then use them to populate _M_ymd
5441  // and only convert it to _M_sys_days if the caller needs that.
5442  // But if we don't have y/m/d and need to calculate the date
5443  // from the day-of-year or a week+weekday then we set _M_sys_days
5444  // and only convert it to _M_ymd if the caller needs that.
5445 
5446  // We do more error checking here, but only for the fields that
5447  // we actually need to use. For example, we will not diagnose
5448  // an invalid dayofyear==366 for non-leap years unless actually
5449  // using __dayofyear. This should mean we never produce invalid
5450  // results, but it means not all invalid inputs are diagnosed,
5451  // e.g. "2023-01-01 366" >> "%F %j" ignores the invalid 366.
5452  // We also do not diagnose inconsistent values for the same
5453  // field, e.g. "2021 2022 2023" >> "%C%y %Y %Y" just uses 2023.
5454 
5455  // Whether the caller wants _M_wd.
5456  // The _Weekday bit is only set for chrono::weekday.
5457  const bool __need_wday = (_M_need & _ChronoParts::_Weekday) != 0;
5458 
5459  // Whether the caller wants _M_sys_days and _M_time.
5460  // Only true for durations and time_points.
5461  const bool __need_time = (_M_need & _ChronoParts::_TimeOfDay) != 0;
5462 
5463  if (__need_wday && __wday != __bad_wday)
5464  _M_wd = __wday; // Caller only wants a weekday and we have one.
5465  else if ((_M_need & _ChronoParts::_Date) != 0) // subsumes __need_wday
5466  {
5467  // Whether the caller wants _M_ymd.
5468  // True for chrono::year etc., false for time_points.
5469  const bool __need_ymd = !__need_wday && !__need_time;
5470 
5471  if (((_M_need & _ChronoParts::_Year) != 0 && __y == __bad_y)
5472  || ((_M_need & _ChronoParts::_Month) != 0 && __m == __bad_mon)
5473  || ((_M_need & _ChronoParts::_Day) != 0 && __d == __bad_day))
5474  {
5475  // Missing at least one of y/m/d so calculate sys_days
5476  // from the other data we have available.
5477 
5478  if (__can_use_doy)
5479  {
5480  if ((0 < __dayofyear && __dayofyear <= 365)
5481  || (__dayofyear == 366 && __y.is_leap()))
5482  [[likely]]
5483  {
5484  _M_sys_days = sys_days(__y/January/1)
5485  + days(__dayofyear - 1);
5486  if (__need_ymd)
5487  _M_ymd = year_month_day(_M_sys_days);
5488  }
5489  else
5490  __err |= ios_base::failbit;
5491  }
5492  else if (__can_use_iso_wk)
5493  {
5494  // Calculate y/m/d from ISO week date.
5495 
5496  if (__iso_wk == 53)
5497  {
5498  // A year has 53 weeks iff Jan 1st is a Thursday
5499  // or Jan 1 is a Wednesday and it's a leap year.
5500  const sys_days __jan4(__iso_y/January/4);
5501  weekday __wd1(__jan4 - days(3));
5502  if (__wd1 != Thursday)
5503  if (__wd1 != Wednesday || !__iso_y.is_leap())
5504  __err |= ios_base::failbit;
5505  }
5506 
5507  if (!__is_failed(__err)) [[likely]]
5508  {
5509  // First Thursday is always in week one:
5510  sys_days __w(Thursday[1]/January/__iso_y);
5511  // First day of week-based year:
5512  __w -= Thursday - Monday;
5513  __w += days(weeks(__iso_wk - 1));
5514  __w += __wday - Monday;
5515  _M_sys_days = __w;
5516 
5517  if (__need_ymd)
5518  _M_ymd = year_month_day(_M_sys_days);
5519  }
5520  }
5521  else if (__can_use_sun_wk)
5522  {
5523  // Calculate y/m/d from week number + weekday.
5524  sys_days __wk1(__y/January/Sunday[1]);
5525  _M_sys_days = __wk1 + weeks(__sunday_wk - 1)
5526  + days(__wday.c_encoding());
5527  _M_ymd = year_month_day(_M_sys_days);
5528  if (_M_ymd.year() != __y) [[unlikely]]
5529  __err |= ios_base::failbit;
5530  }
5531  else if (__can_use_mon_wk)
5532  {
5533  // Calculate y/m/d from week number + weekday.
5534  sys_days __wk1(__y/January/Monday[1]);
5535  _M_sys_days = __wk1 + weeks(__monday_wk - 1)
5536  + days(__wday.c_encoding() - 1);
5537  _M_ymd = year_month_day(_M_sys_days);
5538  if (_M_ymd.year() != __y) [[unlikely]]
5539  __err |= ios_base::failbit;
5540  }
5541  else // Should not be able to get here.
5542  __err |= ios_base::failbit;
5543  }
5544  else
5545  {
5546  // We know that all fields the caller needs are present,
5547  // but check that their values are in range.
5548  // Make unwanted fields valid so that _M_ymd.ok() is true.
5549 
5550  if ((_M_need & _ChronoParts::_Year) != 0)
5551  {
5552  if (!__y.ok()) [[unlikely]]
5553  __err |= ios_base::failbit;
5554  }
5555  else if (__y == __bad_y)
5556  __y = 1972y; // Leap year so that Feb 29 is valid.
5557 
5558  if ((_M_need & _ChronoParts::_Month) != 0)
5559  {
5560  if (!__m.ok()) [[unlikely]]
5561  __err |= ios_base::failbit;
5562  }
5563  else if (__m == __bad_mon)
5564  __m = January;
5565 
5566  if ((_M_need & _ChronoParts::_Day) != 0)
5567  {
5568  if (__d < day(1) || __d > (__y/__m/last).day())
5569  __err |= ios_base::failbit;
5570  }
5571  else if (__d == __bad_day)
5572  __d = 1d;
5573 
5574  if (year_month_day __ymd(__y, __m, __d); __ymd.ok())
5575  {
5576  _M_ymd = __ymd;
5577  if (__need_wday || __need_time)
5578  _M_sys_days = sys_days(_M_ymd);
5579  }
5580  else [[unlikely]]
5581  __err |= ios_base::failbit;
5582  }
5583 
5584  if (__need_wday)
5585  _M_wd = weekday(_M_sys_days);
5586  }
5587 
5588  // Need to set _M_time for both durations and time_points.
5589  if (__need_time)
5590  {
5591  if (__h == __bad_h && __h12 != __bad_h)
5592  {
5593  if (__ampm == 1)
5594  __h = __h12 == hours(12) ? hours(0) : __h12;
5595  else if (__ampm == 2)
5596  __h = __h12 == hours(12) ? __h12 : __h12 + hours(12);
5597  else [[unlikely]]
5598  __err |= ios_base::failbit;
5599  }
5600 
5601  auto __t = _M_time.zero();
5602  bool __ok = false;
5603 
5604  if (__h != __bad_h)
5605  {
5606  __ok = true;
5607  __t += __h;
5608  }
5609 
5610  if (__min != __bad_min)
5611  {
5612  __ok = true;
5613  __t += __min;
5614  }
5615 
5616  if (__s != __bad_sec)
5617  {
5618  __ok = true;
5619  __t += __s;
5620  _M_is_leap_second = __s >= seconds(60);
5621  }
5622 
5623  if (__ok)
5624  _M_time = __t;
5625  else
5626  __err |= ios_base::failbit;
5627  }
5628 
5629  if (!__is_failed(__err)) [[likely]]
5630  {
5631  if (__offset && __tz_offset != __bad_min)
5632  *__offset = __tz_offset;
5633  if (__abbrev && !__tz_abbr.empty())
5634  *__abbrev = std::move(__tz_abbr);
5635  }
5636  }
5637  else
5638  __err |= ios_base::failbit;
5639  }
5640  if (__err)
5641  __is.setstate(__err);
5642  return __is;
5643  }
5644  /// @endcond
5645 #undef _GLIBCXX_WIDEN
5646 
5647  /// @} group chrono
5648 } // namespace chrono
5649 
5650 _GLIBCXX_END_NAMESPACE_VERSION
5651 } // namespace std
5652 
5653 #endif // C++20
5654 
5655 #endif //_GLIBCXX_CHRONO_IO_H
constexpr std::remove_reference< _Tp >::type && move(_Tp &&__t) noexcept
Convert a value to an rvalue.
Definition: move.h:138
constexpr const _Tp & min(const _Tp &, const _Tp &)
This does what you think it does.
Definition: stl_algobase.h:232
ISO C++ entities toplevel namespace is std.
ios_base & right(ios_base &__base)
Calls base.setf(ios_base::right, ios_base::adjustfield).
Definition: ios_base.h:1085
chrono::duration represents a distance between two points in time
Definition: chrono.h:516