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 _Runtime_format_string<_CharT>
889  _S_empty_fs()
890  { return _Runtime_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  __yi = __builtin_abs(__yi);
1317  int __ci = __yi / 100;
1318  // For floored division -123//100 is -2 and -100//100 is -1
1319  if (__conv == 'C' && __is_neg && (__ci * 100) != __yi) [[unlikely]]
1320  ++__ci;
1321 
1322  if (__conv != 'y' && __ci >= 100) [[unlikely]]
1323  {
1324  using _FmtStr = _Runtime_format_string<_CharT>;
1325  __string_view __fs = _S_minus_empty_spec + !__is_neg;
1326  __out = std::format_to(std::move(__out), _FmtStr(__fs),
1327  __conv == 'C' ? __ci : __yi);
1328  }
1329  else
1330  {
1331  _CharT __buf[5];
1332  __buf[0] = _S_plus_minus[1];
1333  __string_view __sv(__buf + 3, __buf + 3);
1334  if (__conv != 'y')
1335  {
1336  _S_fill_two_digits(__buf + 1, __ci);
1337  __sv = __string_view(__buf + !__is_neg, __buf + 3);
1338  }
1339  if (__conv != 'C')
1340  {
1341  _S_fill_two_digits(__buf + 3, __yi % 100);
1342  __sv = __string_view(__sv.data(), __buf + 5);
1343  }
1344  __out = __format::__write(std::move(__out), __sv);
1345  }
1346  return __out;
1347  }
1348 
1349  template<typename _OutIter>
1350  _OutIter
1351  _M_D_x(const _ChronoData<_CharT>& __t, _OutIter __out) const
1352  {
1353  // %D Equivalent to %m/%d/%y
1354  // %x Locale's date rep, for C-locale: %m/%d/%y
1355  // %Ex Locale's alternative date representation, for C-locale same as above
1356 
1357  auto __di = (unsigned)__t._M_day;
1358  auto __mi = (unsigned)__t._M_month;
1359  auto __yi = __builtin_abs((int)__t._M_year) % 100;
1360 
1361  if (__mi >= 100 || __di >= 100) [[unlikely]]
1362  {
1363  using _FmtStr = _Runtime_format_string<_CharT>;
1364  __string_view __fs = _GLIBCXX_WIDEN("{:02d}/{:02d}/{:02d}");
1365  __out = std::format_to(std::move(__out), _FmtStr(__fs),
1366  __mi, __di, __yi);
1367  }
1368  else
1369  {
1370  _CharT __buf[8];
1371  __buf[2] = _S_slash;
1372  __buf[5] = _S_slash;
1373  __string_view __sv(__buf, __buf + 8);
1374 
1375  _S_fill_two_digits(__buf, __mi);
1376  _S_fill_two_digits(__buf + 3, __di);
1377  _S_fill_two_digits(__buf + 6, __yi);
1378  __out = __format::__write(std::move(__out), __sv);
1379  }
1380  return std::move(__out);
1381  }
1382 
1383  template<typename _OutIter>
1384  _OutIter
1385  _M_d_e(chrono::day __d, _OutIter __out, _CharT __conv) const
1386  {
1387  // %d The day of month as a decimal number.
1388  // %Od Locale's alternative representation.
1389  // %e Day of month as decimal number, padded with space.
1390  // %Oe Locale's alternative digits.
1391 
1392  unsigned __i = (unsigned)__d;
1393 
1394  _CharT __buf[3];
1395  auto __sv = _S_str_d2(__buf, __i);
1396  if (__conv == _CharT('e') && __i < 10)
1397  {
1398  __buf[1] = __sv[1];
1399  __buf[0] = _S_space;
1400  __sv = {__buf, 2};
1401  }
1402 
1403  __out = __format::__write(std::move(__out), __sv);
1404  return std::move(__out);
1405  }
1406 
1407  template<typename _OutIter>
1408  _OutIter
1409  _M_F(const _ChronoData<_CharT>& __t, _OutIter __out) const
1410  {
1411  auto __di = (unsigned)__t._M_day;
1412  auto __mi = (unsigned)__t._M_month;
1413  auto __yi = (int)__t._M_year;
1414  const bool __is_neg = __yi < 0;
1415  __yi = __builtin_abs(__yi);
1416 
1417  if (__yi >= 10000 || __mi >= 100 || __di >= 100) [[unlikely]]
1418  {
1419  using _FmtStr = _Runtime_format_string<_CharT>;
1420  __string_view __fs
1421  = _GLIBCXX_WIDEN("-{:04d}-{:02d}-{:02d}") + !__is_neg;
1422  __out = std::format_to(std::move(__out), _FmtStr(__fs),
1423  __yi, __mi, __di);
1424  }
1425  else
1426  {
1427  _CharT __buf[11];
1428  __buf[0] = _S_plus_minus[1];
1429  __buf[5] = _S_plus_minus[1];
1430  __buf[8] = _S_plus_minus[1];
1431  __string_view __sv(__buf + !__is_neg, __buf + 11);
1432 
1433  _S_fill_two_digits(__buf + 1, __yi / 100);
1434  _S_fill_two_digits(__buf + 3, __yi % 100);
1435  _S_fill_two_digits(__buf + 6, __mi);
1436  _S_fill_two_digits(__buf + 9, __di);
1437  __out = __format::__write(std::move(__out), __sv);
1438  }
1439 
1440  return std::move(__out);
1441  }
1442 
1443  template<typename _OutIter>
1444  _OutIter
1445  _M_g_G_V(const _ChronoData<_CharT>& __t, _OutIter __out,
1446  _CharT __conv) const
1447  {
1448  // %g last two decimal digits of the ISO week-based year.
1449  // %G ISO week-based year.
1450  // %V ISO week-based week number as a decimal number.
1451  // %OV Locale's alternative numeric rep.
1452 
1453  // ISO week-based year of __t is the year that contains the nearest
1454  // Thursday. The ISO week of __t is the number of weeks since
1455  // January 1 of that year.
1456 
1457  using namespace chrono;
1458  // Offset of the nearest Thursday:
1459  const days __offset = (__t._M_weekday - Monday) - days(3);
1460  // Nearest Thursday as local days:
1461  const local_days __ild = __t._M_ldays - __offset;
1462  // Day of year of nearest Thursday:
1463  days __idoy = __t._M_day_of_year - __offset;
1464 
1465  // Year of nearest Thursday:
1466  year __iyear;
1467  if (__idoy <= days(0))
1468  __iyear = __t._M_year - years(1);
1469  else if (__idoy <= days(365))
1470  __iyear = __t._M_year;
1471  else if (__idoy == days(366) && __t._M_year.is_leap())
1472  __iyear = __t._M_year;
1473  else if (__idoy <= days(730))
1474  __iyear = __t._M_year + years(1);
1475  else [[unlikely]]
1476  __iyear = year_month_day(__ild).year();
1477 
1478  if (__conv != 'V')
1479  return _M_C_y_Y(__iyear, std::move(__out), "yY"[__conv == 'G']);
1480 
1481  if (__iyear != __t._M_year)
1482  __idoy = __ild - local_days(__iyear/January/0);
1483 
1484  const auto __wi = chrono::floor<weeks>(__idoy - days(1)).count() + 1;
1485  return __format::__write(std::move(__out), _S_two_digits(__wi));
1486  }
1487 
1488  template<typename _OutIter>
1489  _OutIter
1490  _M_H_I(chrono::hours __h, _OutIter __out, _CharT __conv) const
1491  {
1492  // %H The hour (24-hour clock) as a decimal number.
1493  // %OH Locale's alternative representation.
1494  // %I The hour (12-hour clock) as a decimal number.
1495  // %OI Locale's alternative representation.
1496 
1497  int __i = __h.count();
1498 
1499  if (__conv == _CharT('I'))
1500  {
1501  __i %= 12;
1502  if (__i == 0)
1503  __i = 12;
1504  }
1505  else if (__i >= 100) [[unlikely]]
1506  return std::format_to(std::move(__out), _S_empty_fs(), __i);
1507 
1508  return __format::__write(std::move(__out), _S_two_digits(__i));
1509  }
1510 
1511  template<typename _OutIter>
1512  _OutIter
1513  _M_j(const _ChronoData<_CharT>& __t, _OutIter __out) const
1514  {
1515  if (!_M_spec._M_needs(_ChronoParts::_DayOfYear))
1516  {
1517  // Decimal number of days, without padding.
1518  auto __d = chrono::floor<chrono::days>(__t._M_hours).count();
1519  return std::format_to(std::move(__out), _S_empty_fs(), __d);
1520  }
1521 
1522  auto __d = __t._M_day_of_year.count();
1523  if (__d >= 1000) [[unlikely]]
1524  return std::format_to(std::move(__out), _S_empty_fs(), __d);
1525 
1526  _CharT __buf[3];
1527  return __format::__write(std::move(__out), _S_str_d3(__buf, __d));
1528  }
1529 
1530  template<typename _OutIter>
1531  _OutIter
1532  _M_m(chrono::month __m, _OutIter __out) const
1533  {
1534  // %m month as a decimal number.
1535  // %Om Locale's alternative representation.
1536  auto __i = (unsigned)__m;
1537  if (__i == 0 && _M_spec._M_debug) [[unlikely]]
1538  // 0 should not be padded to two digits
1539  return __format::__write(std::move(__out), _S_digit(0));
1540 
1541  _CharT __buf[3];
1542  return __format::__write(std::move(__out), _S_str_d2(__buf, __i));
1543  }
1544 
1545  template<typename _OutIter>
1546  _OutIter
1547  _M_M(chrono::minutes __m, _OutIter __out) const
1548  {
1549  // %M The minute as a decimal number.
1550  // %OM Locale's alternative representation.
1551 
1552  auto __i = __m.count();
1553  return __format::__write(std::move(__out), _S_two_digits(__i));
1554  }
1555 
1556  template<typename _OutIter>
1557  _OutIter
1558  _M_p(chrono::hours __h, _OutIter __out) const
1559  {
1560  // %p The locale's equivalent of the AM/PM designations.
1561 
1562  _CharT __buf[2];
1563  _S_fill_ampm(__buf, __h);
1564  return __format::__write(std::move(__out), __string_view(__buf, 2));
1565  }
1566 
1567  template<typename _OutIter>
1568  _OutIter
1569  _M_q(__string_view __us, _OutIter __out) const
1570  {
1571  // %q The duration's unit suffix
1572  return __format::__write(std::move(__out), __us);
1573  }
1574 
1575  template<typename _OutIter, typename _FormatContext>
1576  _OutIter
1577  _M_Q(const _ChronoData<_CharT>& __t, _OutIter __out,
1578  _FormatContext&) const
1579  {
1580  // %Q The duration's numeric value.
1581  return std::vformat_to(std::move(__out), _S_empty_spec, __t._M_ereps);
1582  }
1583 
1584  template<typename _OutIter>
1585  _OutIter
1586  _M_r(const _ChronoData<_CharT>& __t, _OutIter __out) const
1587  {
1588  // %r Locale's 12-hour clock time, for C-locale: %I:%M:%S %p
1589  auto __hi = __t._M_hours.count() % 12;
1590  if (__hi == 0)
1591  __hi = 12;
1592 
1593  _CharT __buf[11];
1594  __buf[2] = _S_colon;
1595  __buf[5] = _S_colon;
1596  __buf[8] = _S_space;
1597  _S_fill_two_digits(__buf, __hi);
1598  _S_fill_two_digits(__buf + 3, __t._M_minutes.count());
1599  _S_fill_two_digits(__buf + 6, __t._M_seconds.count());
1600  _S_fill_ampm(__buf + 9, __t._M_hours);
1601 
1602  return __format::__write(std::move(__out), __string_view(__buf, 11));
1603  }
1604 
1605  template<typename _OutIter>
1606  _OutIter
1607  _M_R_X(const _ChronoData<_CharT>& __t, _OutIter __out,
1608  bool __secs) const
1609  {
1610  // %R Equivalent to %H:%M
1611  // %X Locale's time rep, for C-locale: %H:%M:%S (without subseconds)
1612  // %EX Locale's alternative time representation, for C-locale same as above
1613 
1614  auto __hi = __t._M_hours.count();
1615 
1616  _CharT __buf[8];
1617  __buf[2] = _S_colon;
1618  __buf[5] = _S_colon;
1619  __string_view __sv(__buf, 8);
1620 
1621  if (__hi >= 100) [[unlikely]]
1622  {
1623  __out = std::format_to(std::move(__out), _S_empty_fs(), __hi);
1624  __sv.remove_prefix(2);
1625  }
1626  else
1627  _S_fill_two_digits(__buf, __hi);
1628 
1629  _S_fill_two_digits(__buf + 3, __t._M_minutes.count());
1630  if (__secs)
1631  _S_fill_two_digits(__buf + 6, __t._M_seconds.count());
1632  else
1633  __sv.remove_suffix(3);
1634 
1635  return __format::__write(std::move(__out), __sv);
1636  }
1637 
1638  template<typename _OutIter, typename _FormatContext>
1639  _OutIter
1640  _M_S(const _ChronoData<_CharT>& __t, _OutIter __out,
1641  _FormatContext& __ctx, bool __subs = true) const
1642  {
1643  // %S Seconds as a decimal number.
1644  // %OS The locale's alternative representation.
1645  auto __s = __t._M_seconds;
1646 
1647  __out = __format::__write(std::move(__out),
1648  _S_two_digits(__s.count()));
1649  if (__subs)
1650  __out = _M_subsecs(__t, std::move(__out), __ctx);
1651  return __out;
1652  }
1653 
1654  template<typename _OutIter, typename _FormatContext>
1655  _OutIter
1656  _M_subsecs(const _ChronoData<_CharT>& __t, _OutIter __out,
1657  _FormatContext& __ctx) const
1658  {
1659  unsigned __prec = _M_spec._M_prec_kind != _WP_none
1660  ? _M_spec._M_get_precision(__ctx)
1661  : _M_spec._M_prec;
1662  if (__prec == 0)
1663  return __out;
1664 
1665  _CharT __dot = _S_dot;
1666  if (_M_spec._M_localized) [[unlikely]]
1667  {
1668  auto __loc = __ctx.locale();
1669  const auto& __np = use_facet<numpunct<_CharT>>(__loc);
1670  __dot = __np.decimal_point();
1671  }
1672  *__out = __dot;
1673  ++__out;
1674 
1675  if (_M_spec._M_floating_point_rep)
1676  {
1677  _Str_sink<_CharT> __sink;
1678  if (_M_spec._M_localized && _M_spec._M_custom_rep) [[unlikely]]
1679  std::vformat_to(__sink.out(), __ctx.locale(),
1680  _GLIBCXX_WIDEN("{1:0.{2}Lf}"), __t._M_ereps);
1681  else
1682  std::vformat_to(__sink.out(),
1683  _GLIBCXX_WIDEN("{1:0.{2}f}"), __t._M_ereps);
1684 
1685  auto __sv = __sink.view();
1686  // Skip leading zero and dot
1687  __sv.remove_prefix(2);
1688  return __format::__write(std::move(__out), __sv);
1689  }
1690 
1691  constexpr unsigned __max_prec = _ChronoData<_CharT>::_S_max_prec;
1692  constexpr typename _ChronoData<_CharT>::_Attoseconds::rep __pow10t[]
1693  {
1694  1u,
1695  10u, 100u, 1000u,
1696  10'000u, 100'000u, 1000'000u,
1697  10'000'000u, 100'000'000u, 1000'000'000u,
1698  10'000'000'000u, 100'000'000'000u, 1000'000'000'000u,
1699  10'000'000'000'000u, 100'000'000'000'000u, 1000'000'000'000'000u,
1700  10'000'000'000'000'000u, 100'000'000'000'000'000u, 1000'000'000'000'000'000u,
1701  };
1702 
1703  auto __subs = __t._M_subseconds.count();
1704  if (__prec < __max_prec)
1705  __subs /= __pow10t[__max_prec - __prec];
1706  else if (__prec > __max_prec)
1707  __prec = __max_prec;
1708 
1709  using _FmtStr = _Runtime_format_string<_CharT>;
1710  return std::format_to(__out, _FmtStr(_GLIBCXX_WIDEN("{0:0{1}}")),
1711  __subs, __prec);
1712  }
1713 
1714  // %t handled in _M_format
1715 
1716  template<typename _OutIter, typename _FormatContext>
1717  _OutIter
1718  _M_T(const _ChronoData<_CharT>& __t, _OutIter __out,
1719  _FormatContext& __ctx) const
1720  {
1721  // %T Equivalent to %H:%M:%S, with subseconds
1722  __out = _M_R_X(__t, std::move(__out), true);
1723  return _M_subsecs(__t, std::move(__out), __ctx);
1724  }
1725 
1726  template<typename _OutIter>
1727  _OutIter
1728  _M_u_w(chrono::weekday __wd, _OutIter __out, _CharT __conv) const
1729  {
1730  // %u ISO weekday as a decimal number (1-7), where Monday is 1.
1731  // %Ou Locale's alternative numeric rep.
1732  // %w Weekday as a decimal number (0-6), where Sunday is 0.
1733  // %Ow Locale's alternative numeric rep.
1734  unsigned __wdi = __conv == 'u' ? __wd.iso_encoding()
1735  : __wd.c_encoding();
1736  _CharT __buf[3];
1737  return __format::__write(std::move(__out), _S_str_d1(__buf, __wdi));
1738  }
1739 
1740  template<typename _OutIter>
1741  _OutIter
1742  _M_U_W(const _ChronoData<_CharT>& __t, _OutIter __out,
1743  _CharT __conv) const
1744  {
1745  // %U Week number of the year as a decimal number, from first Sunday.
1746  // %OU Locale's alternative numeric rep.
1747  // %W Week number of the year as a decimal number, from first Monday.
1748  // %OW Locale's alternative numeric rep.
1749 
1750  using namespace chrono;
1751  const weekday __weekstart = __conv == 'U' ? Sunday : Monday;
1752  const days __offset = __t._M_weekday - __weekstart;
1753  auto __weeks = chrono::floor<weeks>(__t._M_day_of_year - __offset - days(1));
1754  return __format::__write(std::move(__out), _S_two_digits(__weeks.count() + 1));
1755  }
1756 
1757  template<typename _OutIter>
1758  _OutIter
1759  _M_z(chrono::seconds __ts, _OutIter __out, bool __mod = false) const
1760  {
1761  if (__ts == 0s)
1762  {
1763  __string_view __zero
1764  = __mod ? _GLIBCXX_WIDEN("+00:00") : _GLIBCXX_WIDEN("+0000");
1765  return __format::__write(std::move(__out), __zero);
1766  }
1767 
1768  chrono::hh_mm_ss<chrono::seconds> __hms(__ts);
1769  unsigned __mo = 3 + __mod;
1770 
1771  _CharT __buf[6];
1772  __buf[0] = _S_plus_minus[__hms.is_negative()];
1773  __buf[3] = _S_colon;
1774  _S_fill_two_digits(__buf + 1, __hms.hours().count());
1775  _S_fill_two_digits(__buf + __mo, __hms.minutes().count());
1776 
1777  __string_view __sv(__buf, __mo + 2);
1778  return __format::__write(std::move(__out), __sv);
1779  }
1780 
1781  template<typename _OutIter>
1782  _OutIter
1783  _M_Z(__string_view __abbrev, _OutIter __out) const
1784  { return __format::__write(std::move(__out), __abbrev); }
1785 
1786  // %% handled in _M_format
1787 
1788  // A string view of single digit character, "0".."9".
1789  static basic_string_view<_CharT>
1790  _S_digit(int __n) noexcept
1791  {
1792  // Extra 9s avoid past-the-end read on bad input.
1793  return { _GLIBCXX_WIDEN("0123456789999999") + (__n & 0xf), 1 };
1794  }
1795 
1796  // A string view of two digit characters, "00".."99".
1797  static basic_string_view<_CharT>
1798  _S_two_digits(int __n) noexcept
1799  {
1800  return {
1801  _GLIBCXX_WIDEN("0001020304050607080910111213141516171819"
1802  "2021222324252627282930313233343536373839"
1803  "4041424344454647484950515253545556575859"
1804  "6061626364656667686970717273747576777879"
1805  "8081828384858687888990919293949596979899"
1806  "9999999999999999999999999999999999999999"
1807  "9999999999999999") + 2 * (__n & 0x7f),
1808  2
1809  };
1810  }
1811 
1812  // Fills __buf[0] and __buf[1] with 2 digit value of __n.
1813  [[__gnu__::__always_inline__]]
1814  static void
1815  _S_fill_two_digits(_CharT* __buf, unsigned __n)
1816  {
1817  auto __sv = _S_two_digits(__n);
1818  __buf[0] = __sv[0];
1819  __buf[1] = __sv[1];
1820  }
1821 
1822  // Fills __buf[0] and __buf[1] with "AM", "PM" depending on __h.
1823  [[__gnu__::__always_inline__]]
1824  static void
1825  _S_fill_ampm(_CharT* __buf, chrono::hours __h)
1826  {
1827  auto __hi = __h.count();
1828  if (__hi >= 24) [[unlikely]]
1829  __hi %= 24;
1830 
1831  constexpr const _CharT* __apm = _GLIBCXX_WIDEN("APM");
1832  __buf[0] = __apm[__hi >= 12];
1833  __buf[1] = __apm[2];
1834  }
1835 
1836  // Returns decimal representation of __n.
1837  // Returned string_view may point to __buf.
1838  [[__gnu__::__always_inline__]]
1839  static basic_string_view<_CharT>
1840  _S_str_d1(span<_CharT, 3> __buf, unsigned __n)
1841  {
1842  if (__n < 10) [[likely]]
1843  return _S_digit(__n);
1844  return _S_str_d2(__buf, __n);
1845  }
1846 
1847  // Returns decimal representation of __n, padded to 2 digits.
1848  // Returned string_view may point to __buf.
1849  [[__gnu__::__always_inline__]]
1850  static basic_string_view<_CharT>
1851  _S_str_d2(span<_CharT, 3> __buf, unsigned __n)
1852  {
1853  if (__n < 100) [[likely]]
1854  return _S_two_digits(__n);
1855  return _S_str_d3(__buf, __n);
1856  }
1857 
1858  // Returns decimal representation of __n, padded to 3 digits.
1859  // Returned string_view points to __buf.
1860  [[__gnu__::__always_inline__]]
1861  static basic_string_view<_CharT>
1862  _S_str_d3(span<_CharT, 3> __buf, unsigned __n)
1863  {
1864  _S_fill_two_digits(__buf.data(), __n / 10);
1865  __buf[2] = _S_chars[__n % 10];
1866  return __string_view(__buf.data(), 3);
1867  }
1868  };
1869 
1870  template<typename _CharT>
1871  struct __formatter_duration : private __formatter_chrono<_CharT>
1872  {
1873  template<typename _Rep, typename _Period>
1874  constexpr static auto
1875  _S_subseconds(const chrono::duration<_Rep, _Period>& __d)
1876  {
1877  if constexpr (chrono::treat_as_floating_point_v<_Rep>)
1878  return chrono::duration<_Rep>(__d);
1879  else if constexpr (_Period::den == 1)
1880  return chrono::seconds(0);
1881  else
1882  {
1883  using _Attoseconds = _ChronoData<_CharT>::_Attoseconds;
1884  using _CRep = common_type_t<_Rep, typename _Attoseconds::rep>;
1885  chrono::duration<_CRep, _Period> subs(__d.count());
1886  return chrono::duration_cast<_Attoseconds>(subs);
1887  }
1888  }
1889 
1890  public:
1891  template<typename _Duration>
1892  static consteval
1893  _ChronoSpec<_CharT>
1894  _S_spec_for(_ChronoParts __parts)
1895  {
1896  using _Rep = typename _Duration::rep;
1897  using enum _ChronoParts;
1898 
1899  _ChronoSpec<_CharT> __res{};
1900  __res._M_floating_point_rep = chrono::treat_as_floating_point_v<_Rep>;
1901  __res._M_custom_rep = !is_arithmetic_v<_Rep>;
1902  __res._M_prec = chrono::hh_mm_ss<_Duration>::fractional_width;
1903  if ((__parts & _TimeOfDay) != 0)
1904  __res._M_localized = __res._M_prec > 0 || __res._M_floating_point_rep;
1905 
1906  if ((__parts & _TimeOfDay) != 0)
1907  __res._M_needed |= _TimeOfDay;
1908  if ((__parts & _Date) != 0)
1909  __res._M_needed |= _YearMonthDay;
1910  if ((__parts & _ZoneAbbrev) != 0)
1911  __res._M_needed |= _ZoneAbbrev;
1912 
1913  switch (__parts)
1914  {
1915  case _ZonedDateTime:
1916  __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_ftz();
1917  break;
1918  case _DateTime:
1919  __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_ft();
1920  break;
1921  case _Date:
1922  __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_f();
1923  break;
1924  case _Time:
1925  __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_t();
1926  break;
1927  case _None:
1928  break;
1929  default:
1930  __builtin_unreachable();
1931  }
1932  return __res;
1933  };
1934 
1935  template<typename _Duration>
1936  static consteval
1937  _ChronoSpec<_CharT>
1938  _S_spec_for_tp()
1939  {
1940  using enum _ChronoParts;
1941  // streaming of local_time is defined in terms of sys_time
1942  constexpr bool __stream_insertable =
1943  requires (basic_ostream<_CharT>& __os, chrono::sys_time<_Duration> __t)
1944  { __os << __t; };
1945  if constexpr (!__stream_insertable)
1946  return _S_spec_for<_Duration>(_None);
1947  else if constexpr (is_convertible_v<_Duration, chrono::days>)
1948  return _S_spec_for<_Duration>(_Date);
1949  else
1950  return _S_spec_for<_Duration>(_DateTime);
1951  }
1952 
1953  using __formatter_chrono<_CharT>::__formatter_chrono;
1954  using __formatter_chrono<_CharT>::_M_spec;
1955 
1956  template<typename _Duration>
1957  constexpr typename basic_format_parse_context<_CharT>::iterator
1958  _M_parse(basic_format_parse_context<_CharT>& __pc, _ChronoParts __parts,
1959  const _ChronoSpec<_CharT>& __def)
1960  {
1961  using _Rep = typename _Duration::rep;
1962  using enum _ChronoParts;
1963 
1964  auto __res
1965  = __formatter_chrono<_CharT>::_M_parse(__pc, __parts, __def);
1966  // n.b. durations do not contain date parts, and for time point all
1967  // date parts are computed, and they are always ok.
1968  _M_spec._M_needs_ok_check = false;
1969 
1970  // check for custom floating point durations, if digits of output
1971  // will contain subseconds, then formatters must support specifying
1972  // precision.
1973  if constexpr (!is_floating_point_v<_Rep>)
1974  if constexpr (chrono::treat_as_floating_point_v<_Rep>)
1975  if (_M_spec._M_needs(_Subseconds|_EpochUnits)
1976  || _M_spec._M_prec_kind != _WP_none
1977  || _M_spec._M_prec_value > 0)
1978  {
1979  constexpr const _CharT* __fs = _GLIBCXX_WIDEN("#02.5Lf");
1980  basic_format_parse_context<_CharT> __npc(__fs);
1981  formatter<_Rep, _CharT> __fmtter;
1982  __fmtter.parse(__npc);
1983  }
1984  return __res;
1985  }
1986 
1987  // Return the formatting locale.
1988  template<typename _FormatContext>
1989  std::locale
1990  _M_locale(_FormatContext& __fc) const
1991  {
1992  if (!_M_spec._M_localized)
1993  return std::locale::classic();
1994  else
1995  return __fc.locale();
1996  }
1997 
1998  // Format duration for empty chrono-specs, e.g. "{}" (C++20 [time.format] p6).
1999  template<typename _Rep, typename _Period, typename _FormatContext>
2000  typename _FormatContext::iterator
2001  _M_format_to_ostream(const chrono::duration<_Rep, _Period>& __d,
2002  bool __is_neg,
2003  _FormatContext& __fc) const
2004  {
2005  basic_ostringstream<_CharT> __os;
2006  __os.imbue(this->_M_locale(__fc));
2007 
2008  if (__is_neg) [[unlikely]]
2009  __os << this->_S_plus_minus[1];
2010  __os << __d;
2011 
2012  auto __str = std::move(__os).str();
2013  return __format::__write_padded_as_spec(__str, __str.size(),
2014  __fc, _M_spec);
2015  }
2016 
2017  template<typename _Rep1, typename _Period1,
2018  typename _Rep2, typename _Period2,
2019  typename _FormatContext>
2020  typename _FormatContext::iterator
2021  _M_format_units(_ChronoData<_CharT>& __cd,
2022  const chrono::duration<_Rep1, _Period1>& __ed,
2023  const chrono::duration<_Rep2, _Period2>& __ss,
2024  _FormatContext& __fc) const
2025  {
2026  __format::_Str_sink<_CharT> __suffix_store;
2027  constexpr auto _S_unit_suffix
2028  = chrono::__detail::__units_suffix<_Period1, _CharT>();
2029  if constexpr (!_S_unit_suffix.empty())
2030  __cd._M_unit_suffix = _S_unit_suffix;
2031  else if (_M_spec._M_needs(_ChronoParts::_UnitSuffix))
2032  {
2033  chrono::__detail::
2034  __fmt_units_suffix<_Period1, _CharT>(__suffix_store.out());
2035  __cd._M_unit_suffix = __suffix_store.view();
2036  }
2037 
2038  const auto __prec = _M_spec._M_prec_kind != _WP_none
2039  ? _M_spec._M_get_precision(__fc)
2040  : _M_spec._M_prec;
2041 
2042  using _ErasedContext = typename _ChronoData<_CharT>::_FormatContext;
2043  // _GLIBCXX_RESOLVE_LIB_DEFECTS
2044  // 4118. How should duration formatters format custom rep?
2045  auto __ereps = +__ed.count();
2046  if (!_M_spec._M_needs(_ChronoParts::_Subseconds))
2047  {
2048  auto __ssreps = 0u;
2049  auto __args_store
2050  = std::make_format_args<_ErasedContext>(__ereps, __ssreps, __prec);
2051  __cd._M_ereps = __args_store;
2052  return this->_M_format(__cd, __fc);
2053  }
2054 
2055  using _Attoseconds = _ChronoData<_CharT>::_Attoseconds;
2056  auto __nss = _S_subseconds(__ss);
2057  __cd._M_subseconds = chrono::duration_cast<_Attoseconds>(__nss);
2058 
2059  auto __ssreps = __nss.count();
2060  auto __args_store
2061  = std::make_format_args<_ErasedContext>(__ereps, __ssreps, __prec);
2062  __cd._M_ereps = __args_store;
2063 
2064  return this->_M_format(__cd, __fc);
2065  }
2066 
2067  // pre: __cd._M_lseconds and __cd._M_eseconds are set.
2068  template<typename _Rep1, typename _Period1, typename _FormatContext>
2069  typename _FormatContext::iterator
2070  _M_format_time_point(_ChronoData<_CharT>& __cd,
2071  const chrono::duration<_Rep1, _Period1>& __ed,
2072  _FormatContext& __fc) const
2073  {
2074  auto __parts = _M_spec._M_needed - _ChronoParts::_TotalSeconds;
2075  if ((__parts & _ChronoParts::_DateTime) != 0)
2076  __cd._M_fill_date_time(__cd._M_lseconds, __parts);
2077  return _M_format_units(__cd, __ed, __ed - __cd._M_eseconds, __fc);
2078  }
2079  };
2080 
2081 #if _GLIBCXX_USE_CXX11_ABI || ! _GLIBCXX_USE_DUAL_ABI
2082  template<typename _CharT>
2083  struct __formatter_chrono_info
2084  {
2085  constexpr typename basic_format_parse_context<_CharT>::iterator
2086  parse(basic_format_parse_context<_CharT>& __pc)
2087  { return _M_f._M_parse(__pc, _ChronoParts(), {}); }
2088 
2089  template<typename _Info, typename _Out>
2090  typename basic_format_context<_Out, _CharT>::iterator
2091  format(const _Info& __i,
2092  basic_format_context<_Out, _CharT>& __fc) const
2093  {
2094  // n.b. only acceptable chrono-spec for info is one containing
2095  // only whitespaces and %%, that do not depend on formatted object.
2096  if (!_M_f._M_spec._M_chrono_specs.empty()) [[unlikely]]
2097  return _M_f._M_format(_ChronoData<_CharT>{}, __fc);
2098 
2099  const size_t __padwidth = _M_f._M_spec._M_get_width(__fc);
2100  if (__padwidth == 0)
2101  return _M_format_to(__fc.out(), __i);
2102 
2103  _Padding_sink<_Out, _CharT> __sink(__fc.out(), __padwidth);
2104  _M_format_to(__sink.out(), __i);
2105  return __sink._M_finish(_M_f._M_spec._M_align, _M_f._M_spec._M_fill);
2106  }
2107 
2108  private:
2109  template<typename _Out>
2110  _Out
2111  _M_format_to(_Out __out, const chrono::sys_info& __si) const
2112  {
2113  using _FmtStr = _Runtime_format_string<_CharT>;
2114  // n.b. only decimal separator is locale dependent for specifiers
2115  // used below, as sys_info uses seconds and minutes duration, the
2116  // output is locale-independent.
2117  constexpr auto* __fs
2118  = _GLIBCXX_WIDEN("[{0:%F %T},{1:%F %T},{2:%T},{3:%Q%q},{0:%Z}]");
2119  const chrono::local_seconds __lb(__si.begin.time_since_epoch());
2120  return std::format_to(std::move(__out), _FmtStr(__fs),
2121  chrono::local_time_format(__lb, &__si.abbrev),
2122  __si.end, __si.offset, __si.save);
2123  }
2124 
2125  template<typename _Out>
2126  _Out
2127  _M_format_to(_Out __out, const chrono::local_info& __li) const
2128  {
2129  *__out = _Separators<_CharT>::_S_squares()[0];
2130  ++__out;
2131  if (__li.result == chrono::local_info::unique)
2132  __out = _M_format_to(std::move(__out), __li.first);
2133  else
2134  {
2135  basic_string_view<_CharT> __sv;
2136  if (__li.result == chrono::local_info::nonexistent)
2137  __sv =_GLIBCXX_WIDEN("nonexistent");
2138  else
2139  __sv = _GLIBCXX_WIDEN("ambiguous");
2140  __out = __format::__write(std::move(__out), __sv);
2141 
2142  __sv = _GLIBCXX_WIDEN(" local time between ");
2143  __out = __format::__write(std::move(__out), __sv);
2144  __out = _M_format_to(std::move(__out), __li.first);
2145 
2146  __sv = _GLIBCXX_WIDEN(" and ");
2147  __out = __format::__write(std::move(__out), __sv);
2148  __out = _M_format_to(std::move(__out), __li.second);
2149  }
2150  *__out = _Separators<_CharT>::_S_squares()[1];
2151  ++__out;
2152  return std::move(__out);
2153  }
2154 
2155  __formatter_chrono<_CharT> _M_f;
2156  };
2157 #endif
2158 
2159 } // namespace __format
2160 /// @endcond
2161 
2162  template<typename _Rep, typename _Period, typename _CharT>
2163  requires __format::__formattable_impl<_Rep, _CharT>
2164  struct formatter<chrono::duration<_Rep, _Period>, _CharT>
2165  {
2166  constexpr typename basic_format_parse_context<_CharT>::iterator
2167  parse(basic_format_parse_context<_CharT>& __pc)
2168  {
2169  using enum __format::_ChronoParts;
2170  return _M_f.template _M_parse<_Duration>(__pc, _EpochTime, __defSpec);
2171  }
2172 
2173  template<typename _Out>
2174  typename basic_format_context<_Out, _CharT>::iterator
2175  format(const chrono::duration<_Rep, _Period>& __d,
2176  basic_format_context<_Out, _CharT>& __fc) const
2177  {
2178  if constexpr (numeric_limits<_Rep>::is_signed)
2179  if (__d < __d.zero()) [[unlikely]]
2180  {
2181  if constexpr (is_integral_v<_Rep>)
2182  {
2183  // -d is undefined for the most negative integer.
2184  // Convert duration to corresponding unsigned rep.
2185  using _URep = make_unsigned_t<_Rep>;
2186  auto __ucnt = -static_cast<_URep>(__d.count());
2187  auto __ud = chrono::duration<_URep, _Period>(__ucnt);
2188  return _M_format(__ud, true, __fc);
2189  }
2190  else
2191  return _M_format(-__d, true, __fc);
2192  }
2193  return _M_format(__d, false, __fc);
2194  }
2195 
2196  private:
2197  using _Duration = chrono::duration<_Rep, _Period>;
2198 
2199  static constexpr __format::_ChronoSpec<_CharT> __defSpec = []
2200  {
2201  using enum __format::_ChronoParts;
2202  auto __res = __format::__formatter_duration<_CharT>::
2203  template _S_spec_for<_Duration>(_None);
2204  __res._M_localized = !is_integral_v<_Rep>;
2205  // n.b. for integral format output is the same as ostream output
2206  if constexpr (is_integral_v<_Rep>)
2207  {
2208  __res._M_needed = _EpochUnits|_UnitSuffix;
2209  __res._M_chrono_specs = _GLIBCXX_WIDEN("%Q%q");
2210  }
2211  return __res;
2212  }();
2213 
2214  template<typename _Rep2, typename _Out>
2215  typename basic_format_context<_Out, _CharT>::iterator
2216  _M_format(const chrono::duration<_Rep2, _Period>& __d,
2217  bool __is_neg,
2218  basic_format_context<_Out, _CharT>& __fc) const
2219  {
2220  using namespace chrono;
2221  using enum __format::_ChronoParts;
2222  if constexpr (!is_integral_v<_Rep>)
2223  if (_M_f._M_spec._M_chrono_specs.empty())
2224  return _M_f._M_format_to_ostream(__d, __is_neg, __fc);
2225 
2226  __format::_ChronoData<_CharT> __cd;
2227  __cd._M_is_neg = __is_neg;
2228  auto __ts = chrono::floor<chrono::seconds>(__d);
2229  __cd._M_eseconds = __ts;
2230  if (_M_f._M_spec._M_needs(_HoursMinutesSeconds))
2231  __cd._M_fill_time(__ts);
2232  return _M_f._M_format_units(__cd, __d, __d - __ts, __fc);
2233  }
2234 
2235  __format::__formatter_duration<_CharT> _M_f{__defSpec};
2236  };
2237 
2238 #if __glibcxx_print >= 202406L
2239  // _GLIBCXX_RESOLVE_LIB_DEFECTS
2240  // 4400. enable_nonlocking_formatter_optimization for durations with custom rep
2241  template<typename _Rep, typename _Period>
2242  constexpr bool
2243  enable_nonlocking_formatter_optimization<chrono::duration<_Rep, _Period>>
2244  = is_arithmetic_v<_Rep>;
2245 #endif
2246 
2247  template<__format::__char _CharT>
2248  struct formatter<chrono::day, _CharT>
2249  {
2250  constexpr typename basic_format_parse_context<_CharT>::iterator
2251  parse(basic_format_parse_context<_CharT>& __pc)
2252  {
2253  using enum __format::_ChronoParts;
2254  return _M_f._M_parse(__pc, _Day|_WeekdayIndex, __defSpec);
2255  }
2256 
2257  template<typename _Out>
2258  typename basic_format_context<_Out, _CharT>::iterator
2259  format(const chrono::day& __t,
2260  basic_format_context<_Out, _CharT>& __fc) const
2261  {
2262  __format::_ChronoData<_CharT> __cd{};
2263  __cd._M_fill_day(__t, __defSpec._M_needed);
2264  return _M_f._M_format(__cd, __fc);
2265  }
2266 
2267  private:
2268  static constexpr __format::_ChronoSpec<_CharT> __defSpec = []
2269  {
2270  using __format::_ChronoFormats;
2271  using enum __format::_ChronoParts;
2272 
2273  __format::_ChronoSpec<_CharT> __res{};
2274  __res._M_debug = true;
2275  __res._M_needed = _Day;
2276  __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_d();
2277  return __res;
2278  }();
2279 
2280  __format::__formatter_chrono<_CharT> _M_f{__defSpec};
2281  };
2282 
2283 #if __glibcxx_print >= 202406L
2284  template<>
2285  inline constexpr bool
2286  enable_nonlocking_formatter_optimization<chrono::day> = true;
2287 #endif
2288 
2289  template<__format::__char _CharT>
2290  struct formatter<chrono::month, _CharT>
2291  {
2292  constexpr typename basic_format_parse_context<_CharT>::iterator
2293  parse(basic_format_parse_context<_CharT>& __pc)
2294  {
2295  using enum __format::_ChronoParts;
2296  return _M_f._M_parse(__pc, _Month, __defSpec);
2297  }
2298 
2299  template<typename _Out>
2300  typename basic_format_context<_Out, _CharT>::iterator
2301  format(const chrono::month& __t,
2302  basic_format_context<_Out, _CharT>& __fc) const
2303  {
2304  __format::_ChronoData<_CharT> __cd{};
2305  __cd._M_month = __t;
2306  return _M_f._M_format(__cd, __fc);
2307  }
2308 
2309  private:
2310  static constexpr __format::_ChronoSpec<_CharT> __defSpec = []
2311  {
2312  using __format::_ChronoFormats;
2313  using enum __format::_ChronoParts;
2314 
2315  __format::_ChronoSpec<_CharT> __res{};
2316  __res._M_debug = true;
2317  __res._M_localized = true;
2318  __res._M_locale_specific = true;
2319  __res._M_needed = _Month;
2320  __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_m();
2321  return __res;
2322  }();
2323 
2324  __format::__formatter_chrono<_CharT> _M_f{__defSpec};
2325  };
2326 
2327 #if __glibcxx_print >= 202406L
2328  template<>
2329  inline constexpr bool
2330  enable_nonlocking_formatter_optimization<chrono::month> = true;
2331 #endif
2332 
2333  template<__format::__char _CharT>
2334  struct formatter<chrono::year, _CharT>
2335  {
2336  constexpr typename basic_format_parse_context<_CharT>::iterator
2337  parse(basic_format_parse_context<_CharT>& __pc)
2338  {
2339  using enum __format::_ChronoParts;
2340  return _M_f._M_parse(__pc, _Year, __defSpec);
2341  }
2342 
2343  template<typename _Out>
2344  typename basic_format_context<_Out, _CharT>::iterator
2345  format(const chrono::year& __t,
2346  basic_format_context<_Out, _CharT>& __fc) const
2347  {
2348  __format::_ChronoData<_CharT> __cd{};
2349  __cd._M_year = __t;
2350  return _M_f._M_format(__cd, __fc);
2351  }
2352 
2353  private:
2354  static constexpr __format::_ChronoSpec<_CharT> __defSpec = []
2355  {
2356  using __format::_ChronoFormats;
2357  using enum __format::_ChronoParts;
2358 
2359  __format::_ChronoSpec<_CharT> __res{};
2360  __res._M_debug = true;
2361  __res._M_needed = _Year;
2362  __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_y();
2363  return __res;
2364  }();
2365 
2366  __format::__formatter_chrono<_CharT> _M_f{__defSpec};
2367  };
2368 
2369 #if __glibcxx_print >= 202406L
2370  template<>
2371  inline constexpr bool
2372  enable_nonlocking_formatter_optimization<chrono::year> = true;
2373 #endif
2374 
2375  template<__format::__char _CharT>
2376  struct formatter<chrono::weekday, _CharT>
2377  {
2378  constexpr typename basic_format_parse_context<_CharT>::iterator
2379  parse(basic_format_parse_context<_CharT>& __pc)
2380  {
2381  using enum __format::_ChronoParts;
2382  return _M_f._M_parse(__pc, _Weekday, __defSpec);
2383  }
2384 
2385  template<typename _Out>
2386  typename basic_format_context<_Out, _CharT>::iterator
2387  format(const chrono::weekday& __t,
2388  basic_format_context<_Out, _CharT>& __fc) const
2389  {
2390  __format::_ChronoData<_CharT> __cd{};
2391  __cd._M_weekday = __t;
2392  return _M_f._M_format(__cd, __fc);
2393  }
2394 
2395  private:
2396  static constexpr __format::_ChronoSpec<_CharT> __defSpec = []
2397  {
2398  using __format::_ChronoFormats;
2399  using enum __format::_ChronoParts;
2400 
2401  __format::_ChronoSpec<_CharT> __res{};
2402  __res._M_debug = true;
2403  __res._M_localized = true;
2404  __res._M_locale_specific = true;
2405  __res._M_needed = _Weekday;
2406  __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_w();
2407  return __res;
2408  }();
2409 
2410  __format::__formatter_chrono<_CharT> _M_f{__defSpec};
2411  };
2412 
2413 #if __glibcxx_print >= 202406L
2414  template<>
2415  inline constexpr bool
2416  enable_nonlocking_formatter_optimization<chrono::weekday> = true;
2417 #endif
2418 
2419  template<__format::__char _CharT>
2420  struct formatter<chrono::weekday_indexed, _CharT>
2421  {
2422  constexpr typename basic_format_parse_context<_CharT>::iterator
2423  parse(basic_format_parse_context<_CharT>& __pc)
2424  {
2425  using enum __format::_ChronoParts;
2426  return _M_f._M_parse(__pc, _IndexedWeekday, __defSpec);
2427  }
2428 
2429  template<typename _Out>
2430  typename basic_format_context<_Out, _CharT>::iterator
2431  format(const chrono::weekday_indexed& __t,
2432  basic_format_context<_Out, _CharT>& __fc) const
2433  {
2434  __format::_ChronoData<_CharT> __cd{};
2435  __cd._M_fill_weekday(__t, __defSpec._M_needed);
2436  return _M_f._M_format(__cd, __fc);
2437  }
2438 
2439  private:
2440  static constexpr __format::_ChronoSpec<_CharT> __defSpec = []
2441  {
2442  using __format::_ChronoFormats;
2443  using enum __format::_ChronoParts;
2444 
2445  __format::_ChronoSpec<_CharT> __res{};
2446  __res._M_debug = true;
2447  __res._M_localized = true;
2448  __res._M_locale_specific = true;
2449  __res._M_needed = _IndexedWeekday;
2450  __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_wi();
2451  return __res;
2452  }();
2453 
2454  __format::__formatter_chrono<_CharT> _M_f{__defSpec};
2455  };
2456 
2457 #if __glibcxx_print >= 202406L
2458  template<>
2459  inline constexpr bool
2460  enable_nonlocking_formatter_optimization<chrono::weekday_indexed> = true;
2461 #endif
2462 
2463  template<__format::__char _CharT>
2464  struct formatter<chrono::weekday_last, _CharT>
2465  {
2466  constexpr typename basic_format_parse_context<_CharT>::iterator
2467  parse(basic_format_parse_context<_CharT>& __pc)
2468  {
2469  using enum __format::_ChronoParts;
2470  return _M_f._M_parse(__pc, _Weekday, __defSpec);
2471  }
2472 
2473  template<typename _Out>
2474  typename basic_format_context<_Out, _CharT>::iterator
2475  format(const chrono::weekday_last& __t,
2476  basic_format_context<_Out, _CharT>& __fc) const
2477  {
2478  __format::_ChronoData<_CharT> __cd{};
2479  __cd._M_weekday = __t.weekday();
2480  return _M_f._M_format(__cd, __fc);
2481  }
2482 
2483  private:
2484  static constexpr __format::_ChronoSpec<_CharT> __defSpec = []
2485  {
2486  using __format::_ChronoFormats;
2487  using enum __format::_ChronoParts;
2488 
2489  __format::_ChronoSpec<_CharT> __res{};
2490  __res._M_debug = true;
2491  __res._M_localized = true;
2492  __res._M_locale_specific = true;
2493  __res._M_needed = _Weekday;
2494  __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_wl();
2495  return __res;
2496  }();
2497 
2498  __format::__formatter_chrono<_CharT> _M_f{__defSpec};
2499  };
2500 
2501 #if __glibcxx_print >= 202406L
2502  template<>
2503  inline constexpr bool
2504  enable_nonlocking_formatter_optimization<chrono::weekday_last> = true;
2505 #endif
2506 
2507  template<__format::__char _CharT>
2508  struct formatter<chrono::month_day, _CharT>
2509  {
2510  constexpr typename basic_format_parse_context<_CharT>::iterator
2511  parse(basic_format_parse_context<_CharT>& __pc)
2512  {
2513  using enum __format::_ChronoParts;
2514  return _M_f._M_parse(__pc, _Month|_Day|_WeekdayIndex, __defSpec);
2515  }
2516 
2517  template<typename _Out>
2518  typename basic_format_context<_Out, _CharT>::iterator
2519  format(const chrono::month_day& __t,
2520  basic_format_context<_Out, _CharT>& __fc) const
2521  {
2522  __format::_ChronoData<_CharT> __cd{};
2523  __cd._M_month = __t.month();
2524  __cd._M_fill_day(__t.day(), __defSpec._M_needed);
2525  return _M_f._M_format(__cd, __fc);
2526  }
2527 
2528  private:
2529  static constexpr __format::_ChronoSpec<_CharT> __defSpec = []
2530  {
2531  using __format::_ChronoFormats;
2532  using enum __format::_ChronoParts;
2533 
2534  __format::_ChronoSpec<_CharT> __res{};
2535  __res._M_debug = true;
2536  __res._M_localized = true;
2537  __res._M_locale_specific = true;
2538  __res._M_needed = _Month|_Day;
2539  __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_md();
2540  return __res;
2541  }();
2542 
2543  __format::__formatter_chrono<_CharT> _M_f{__defSpec};
2544  };
2545 
2546 #if __glibcxx_print >= 202406L
2547  template<>
2548  inline constexpr bool
2549  enable_nonlocking_formatter_optimization<chrono::month_day> = true;
2550 #endif
2551 
2552  template<__format::__char _CharT>
2553  struct formatter<chrono::month_day_last, _CharT>
2554  {
2555  constexpr typename basic_format_parse_context<_CharT>::iterator
2556  parse(basic_format_parse_context<_CharT>& __pc)
2557  {
2558  using enum __format::_ChronoParts;
2559  return _M_f._M_parse(__pc, _Month, __defSpec);
2560  }
2561 
2562  template<typename _Out>
2563  typename basic_format_context<_Out, _CharT>::iterator
2564  format(const chrono::month_day_last& __t,
2565  basic_format_context<_Out, _CharT>& __fc) const
2566  {
2567  __format::_ChronoData<_CharT> __cd{};
2568  __cd._M_month = __t.month();
2569  return _M_f._M_format(__cd, __fc);
2570  }
2571 
2572  private:
2573  static constexpr __format::_ChronoSpec<_CharT> __defSpec = []
2574  {
2575  using __format::_ChronoFormats;
2576  using enum __format::_ChronoParts;
2577 
2578  __format::_ChronoSpec<_CharT> __res{};
2579  __res._M_debug = true;
2580  __res._M_localized = true;
2581  __res._M_locale_specific = true;
2582  __res._M_needed = _Month;
2583  __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_ml();
2584  return __res;
2585  }();
2586 
2587  __format::__formatter_chrono<_CharT> _M_f{__defSpec};
2588  };
2589 
2590 #if __glibcxx_print >= 202406L
2591  template<>
2592  inline constexpr bool
2593  enable_nonlocking_formatter_optimization<chrono::month_day_last> = true;
2594 #endif
2595 
2596  template<__format::__char _CharT>
2597  struct formatter<chrono::month_weekday, _CharT>
2598  {
2599  constexpr typename basic_format_parse_context<_CharT>::iterator
2600  parse(basic_format_parse_context<_CharT>& __pc)
2601  {
2602  using enum __format::_ChronoParts;
2603  return _M_f._M_parse(__pc, _Month|_IndexedWeekday, __defSpec);
2604  }
2605 
2606  template<typename _Out>
2607  typename basic_format_context<_Out, _CharT>::iterator
2608  format(const chrono::month_weekday& __t,
2609  basic_format_context<_Out, _CharT>& __fc) const
2610  {
2611  __format::_ChronoData<_CharT> __cd{};
2612  __cd._M_month = __t.month();
2613  __cd._M_fill_weekday(__t.weekday_indexed(), __defSpec._M_needed);
2614  return _M_f._M_format(__cd, __fc);
2615  }
2616 
2617  private:
2618  static constexpr __format::_ChronoSpec<_CharT> __defSpec = []
2619  {
2620  using __format::_ChronoFormats;
2621  using enum __format::_ChronoParts;
2622 
2623  __format::_ChronoSpec<_CharT> __res{};
2624  __res._M_debug = true;
2625  __res._M_localized = true;
2626  __res._M_locale_specific = true;
2627  __res._M_needed = _Month|_IndexedWeekday;
2628  __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_mwi();
2629  return __res;
2630  }();
2631 
2632  __format::__formatter_chrono<_CharT> _M_f{__defSpec};
2633  };
2634 
2635 #if __glibcxx_print >= 202406L
2636  template<>
2637  inline constexpr bool
2638  enable_nonlocking_formatter_optimization<chrono::month_weekday> = true;
2639 #endif
2640 
2641  template<__format::__char _CharT>
2642  struct formatter<chrono::month_weekday_last, _CharT>
2643  {
2644  constexpr typename basic_format_parse_context<_CharT>::iterator
2645  parse(basic_format_parse_context<_CharT>& __pc)
2646  {
2647  using enum __format::_ChronoParts;
2648  return _M_f._M_parse(__pc, _Month|_Weekday, __defSpec);
2649  }
2650 
2651  template<typename _Out>
2652  typename basic_format_context<_Out, _CharT>::iterator
2653  format(const chrono::month_weekday_last& __t,
2654  basic_format_context<_Out, _CharT>& __fc) const
2655  {
2656  __format::_ChronoData<_CharT> __cd{};
2657  __cd._M_month = __t.month();
2658  __cd._M_weekday = __t.weekday_last().weekday();
2659  return _M_f._M_format(__cd, __fc);
2660  }
2661 
2662  private:
2663  static constexpr __format::_ChronoSpec<_CharT> __defSpec = []
2664  {
2665  using __format::_ChronoFormats;
2666  using enum __format::_ChronoParts;
2667 
2668  __format::_ChronoSpec<_CharT> __res{};
2669  __res._M_debug = true;
2670  __res._M_localized = true;
2671  __res._M_locale_specific = true;
2672  __res._M_needed = _Month|_Weekday;
2673  __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_mwl();
2674  return __res;
2675  }();
2676 
2677  __format::__formatter_chrono<_CharT> _M_f{__defSpec};
2678  };
2679 
2680 #if __glibcxx_print >= 202406L
2681  template<>
2682  inline constexpr bool
2683  enable_nonlocking_formatter_optimization<chrono::month_weekday_last> = true;
2684 #endif
2685 
2686  template<__format::__char _CharT>
2687  struct formatter<chrono::year_month, _CharT>
2688  {
2689  constexpr typename basic_format_parse_context<_CharT>::iterator
2690  parse(basic_format_parse_context<_CharT>& __pc)
2691  {
2692  using enum __format::_ChronoParts;
2693  return _M_f._M_parse(__pc, _Year|_Month, __defSpec);
2694  }
2695 
2696  template<typename _Out>
2697  typename basic_format_context<_Out, _CharT>::iterator
2698  format(const chrono::year_month& __t,
2699  basic_format_context<_Out, _CharT>& __fc) const
2700  {
2701  __format::_ChronoData<_CharT> __cd{};
2702  __cd._M_fill_year_month(__t, __defSpec._M_needed);
2703  return _M_f._M_format(__cd, __fc);
2704  }
2705 
2706  private:
2707  static constexpr __format::_ChronoSpec<_CharT> __defSpec = []
2708  {
2709  using __format::_ChronoFormats;
2710  using enum __format::_ChronoParts;
2711 
2712  __format::_ChronoSpec<_CharT> __res{};
2713  __res._M_debug = true;
2714  __res._M_localized = true;
2715  __res._M_locale_specific = true;
2716  __res._M_needed = _Year|_Month;
2717  __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_ym();
2718  return __res;
2719  }();
2720 
2721  __format::__formatter_chrono<_CharT> _M_f{__defSpec};
2722  };
2723 
2724 #if __glibcxx_print >= 202406L
2725  template<>
2726  inline constexpr bool
2727  enable_nonlocking_formatter_optimization<chrono::year_month> = true;
2728 #endif
2729 
2730  template<__format::__char _CharT>
2731  struct formatter<chrono::year_month_day, _CharT>
2732  {
2733  constexpr typename basic_format_parse_context<_CharT>::iterator
2734  parse(basic_format_parse_context<_CharT>& __pc)
2735  {
2736  using enum __format::_ChronoParts;
2737  return _M_f._M_parse(__pc, _Date, __defSpec);
2738  }
2739 
2740  template<typename _Out>
2741  typename basic_format_context<_Out, _CharT>::iterator
2742  format(const chrono::year_month_day& __t,
2743  basic_format_context<_Out, _CharT>& __fc) const
2744  {
2745  __format::_ChronoData<_CharT> __cd{};
2746  auto __parts = _M_f._M_spec._M_needed;
2747  __parts = __cd._M_fill_year_month(__t, __parts);
2748  __parts = __cd._M_fill_day(__t.day(), __parts);
2749  if (__parts == 0)
2750  return _M_f._M_format(__cd, __fc);
2751 
2752  __cd._M_fill_ldays(chrono::local_days(__t), __parts);
2753  return _M_f._M_format(__cd, __fc);
2754  }
2755 
2756  private:
2757  static constexpr __format::_ChronoSpec<_CharT> __defSpec = []
2758  {
2759  using __format::_ChronoFormats;
2760  using enum __format::_ChronoParts;
2761 
2762  __format::_ChronoSpec<_CharT> __res{};
2763  __res._M_debug = true;
2764  __res._M_needed = _YearMonthDay;
2765  __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_f();
2766  return __res;
2767  }();
2768 
2769  __format::__formatter_chrono<_CharT> _M_f{__defSpec};
2770  };
2771 
2772 #if __glibcxx_print >= 202406L
2773  template<>
2774  inline constexpr bool
2775  enable_nonlocking_formatter_optimization<chrono::year_month_day> = true;
2776 #endif
2777 
2778  template<__format::__char _CharT>
2779  struct formatter<chrono::year_month_day_last, _CharT>
2780  {
2781  constexpr typename basic_format_parse_context<_CharT>::iterator
2782  parse(basic_format_parse_context<_CharT>& __pc)
2783  {
2784  using enum __format::_ChronoParts;
2785  return _M_f._M_parse(__pc, _Date, __defSpec);
2786  }
2787 
2788  template<typename _Out>
2789  typename basic_format_context<_Out, _CharT>::iterator
2790  format(const chrono::year_month_day_last& __t,
2791  basic_format_context<_Out, _CharT>& __fc) const
2792  {
2793  using enum __format::_ChronoParts;
2794 
2795  __format::_ChronoData<_CharT> __cd{};
2796  auto __parts = _M_f._M_spec._M_needed;
2797  __parts = __cd._M_fill_year_month(__t, __parts);
2798  if (_M_f._M_spec._M_needs(_Day|_WeekdayIndex))
2799  __parts = __cd._M_fill_day(__t.day(), __parts);
2800  if (__parts == 0)
2801  return _M_f._M_format(__cd, __fc);
2802 
2803  __cd._M_fill_ldays(chrono::local_days(__t), __parts);
2804  return _M_f._M_format(__cd, __fc);
2805  }
2806 
2807  private:
2808  static constexpr __format::_ChronoSpec<_CharT> __defSpec = []
2809  {
2810  using __format::_ChronoFormats;
2811  using enum __format::_ChronoParts;
2812 
2813  __format::_ChronoSpec<_CharT> __res{};
2814  __res._M_debug = true;
2815  __res._M_localized = true;
2816  __res._M_locale_specific = true;
2817  __res._M_needed = _Year|_Month;
2818  __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_yml();
2819  return __res;
2820  }();
2821 
2822  __format::__formatter_chrono<_CharT> _M_f{__defSpec};
2823  };
2824 
2825 #if __glibcxx_print >= 202406L
2826  template<>
2827  inline constexpr bool
2828  enable_nonlocking_formatter_optimization<chrono::year_month_day_last> = true;
2829 #endif
2830 
2831  template<__format::__char _CharT>
2832  struct formatter<chrono::year_month_weekday, _CharT>
2833  {
2834  constexpr typename basic_format_parse_context<_CharT>::iterator
2835  parse(basic_format_parse_context<_CharT>& __pc)
2836  {
2837  using enum __format::_ChronoParts;
2838  return _M_f._M_parse(__pc, _Date, __defSpec);
2839  }
2840 
2841  template<typename _Out>
2842  typename basic_format_context<_Out, _CharT>::iterator
2843  format(const chrono::year_month_weekday& __t,
2844  basic_format_context<_Out, _CharT>& __fc) const
2845  {
2846  __format::_ChronoData<_CharT> __cd{};
2847  auto __parts = _M_f._M_spec._M_needed;
2848  __parts = __cd._M_fill_year_month(__t, __parts);
2849  __parts = __cd._M_fill_weekday(__t.weekday_indexed(), __parts);
2850  if (__t.index() == 0) [[unlikely]]
2851  // n.b. day cannot be negative, so any 0th weekday uses
2852  // value-initialized (0) day of month
2853  __parts -= __format::_ChronoParts::_Day;
2854  if (__parts == 0)
2855  return _M_f._M_format(__cd, __fc);
2856 
2857  chrono::local_days __ld(__t);
2858  __parts = __cd._M_fill_ldays(__ld, __parts);
2859  if (__parts == 0)
2860  return _M_f._M_format(__cd, __fc);
2861 
2862  auto __dom = __ld - chrono::local_days(__t.year()/__t.month()/0);
2863  // n.b. weekday index is supplied by input, do not override it
2864  __cd._M_day = chrono::day(__dom.count());
2865  return _M_f._M_format(__cd, __fc);
2866  }
2867 
2868  private:
2869  static constexpr __format::_ChronoSpec<_CharT> __defSpec = []
2870  {
2871  using __format::_ChronoFormats;
2872  using enum __format::_ChronoParts;
2873 
2874  __format::_ChronoSpec<_CharT> __res{};
2875  __res._M_debug = true;
2876  __res._M_localized = true;
2877  __res._M_locale_specific = true;
2878  __res._M_needed = _Year|_Month|_IndexedWeekday;
2879  __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_ymwi();
2880  return __res;
2881  }();
2882 
2883  __format::__formatter_chrono<_CharT> _M_f{__defSpec};
2884  };
2885 
2886 #if __glibcxx_print >= 202406L
2887  template<>
2888  inline constexpr bool
2889  enable_nonlocking_formatter_optimization<chrono::year_month_weekday> = true;
2890 #endif
2891 
2892  template<__format::__char _CharT>
2893  struct formatter<chrono::year_month_weekday_last, _CharT>
2894  {
2895  constexpr typename basic_format_parse_context<_CharT>::iterator
2896  parse(basic_format_parse_context<_CharT>& __pc)
2897  {
2898  using enum __format::_ChronoParts;
2899  return _M_f._M_parse(__pc, _Date, __defSpec);
2900  }
2901 
2902  template<typename _Out>
2903  typename basic_format_context<_Out, _CharT>::iterator
2904  format(const chrono::year_month_weekday_last& __t,
2905  basic_format_context<_Out, _CharT>& __fc) const
2906  {
2907  __format::_ChronoData<_CharT> __cd{};
2908  auto __parts = _M_f._M_spec._M_needed;
2909  __parts = __cd._M_fill_year_month(__t, __parts);
2910  __cd._M_weekday = __t.weekday_last().weekday();
2911  __parts -= __format::_ChronoParts::_Weekday;
2912  if (__parts == 0)
2913  return _M_f._M_format(__cd, __fc);
2914 
2915  chrono::local_days __ld(__t);
2916  __parts = __cd._M_fill_ldays(__ld, __parts);
2917  if (__parts == 0)
2918  return _M_f._M_format(__cd, __fc);
2919 
2920  auto __dom = __ld - chrono::local_days(__t.year()/__t.month()/0);
2921  __cd._M_fill_day(chrono::day(__dom.count()), __parts);
2922  return _M_f._M_format(__cd, __fc);
2923  }
2924 
2925  private:
2926  static constexpr __format::_ChronoSpec<_CharT> __defSpec = []
2927  {
2928  using __format::_ChronoFormats;
2929  using enum __format::_ChronoParts;
2930 
2931  __format::_ChronoSpec<_CharT> __res{};
2932  __res._M_debug = true;
2933  __res._M_localized = true;
2934  __res._M_locale_specific = true;
2935  __res._M_needed = _Year|_Month|_Weekday;
2936  __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_ymwl();
2937  return __res;
2938  }();
2939 
2940  __format::__formatter_chrono<_CharT> _M_f{__defSpec};
2941  };
2942 
2943 #if __glibcxx_print >= 202406L
2944  template<>
2945  inline constexpr bool
2946  enable_nonlocking_formatter_optimization<chrono::year_month_weekday_last> = true;
2947 #endif
2948 
2949  template<typename _Rep, typename _Period, __format::__char _CharT>
2950  struct formatter<chrono::hh_mm_ss<chrono::duration<_Rep, _Period>>, _CharT>
2951  {
2952  constexpr typename basic_format_parse_context<_CharT>::iterator
2953  parse(basic_format_parse_context<_CharT>& __pc)
2954  {
2955  using enum __format::_ChronoParts;
2956  return _M_f.template _M_parse<_Precision>(__pc, _Time, __defSpec);
2957  }
2958 
2959  template<typename _Out>
2960  typename basic_format_context<_Out, _CharT>::iterator
2961  format(const chrono::hh_mm_ss<chrono::duration<_Rep, _Period>>& __t,
2962  basic_format_context<_Out, _CharT>& __fc) const
2963  {
2964  using enum __format::_ChronoParts;
2965 
2966  __format::_ChronoData<_CharT> __cd;
2967  __cd._M_is_neg = __t.is_negative();
2968  __cd._M_hours = __t.hours();
2969  __cd._M_minutes = __t.minutes();
2970  __cd._M_seconds = __t.seconds();
2971 
2972  _Precision __d(0);
2973  // n.b. computing total duration or total seconds may overflow,
2974  // do not compute them if not requested.
2975  if (_M_f._M_spec._M_needs(_EpochUnits))
2976  __d = __t.to_duration();
2977  if (_M_f._M_spec._M_needs(_TotalSeconds))
2978  __cd._M_eseconds
2979  = __cd._M_hours + __cd._M_minutes + __cd._M_seconds;
2980  return _M_f._M_format_units(__cd, __d, __t.subseconds(), __fc);
2981  }
2982 
2983  private:
2984  using _Precision
2985  = typename chrono::hh_mm_ss<chrono::duration<_Rep, _Period>>::precision;
2986  static constexpr __format::_ChronoSpec<_CharT> __defSpec =
2987  __format::__formatter_duration<_CharT>::
2988  template _S_spec_for<_Precision>(__format::_ChronoParts::_Time);
2989 
2990  __format::__formatter_duration<_CharT> _M_f{__defSpec};
2991  };
2992 
2993 #if __glibcxx_print >= 202406L
2994  // _GLIBCXX_RESOLVE_LIB_DEFECTS
2995  // 4400. enable_nonlocking_formatter_optimization for durations with custom rep
2996  template<typename _Duration>
2997  constexpr bool
2998  enable_nonlocking_formatter_optimization<chrono::hh_mm_ss<_Duration>>
2999  = enable_nonlocking_formatter_optimization<_Duration>;
3000 #endif
3001 
3002 #if _GLIBCXX_USE_CXX11_ABI || ! _GLIBCXX_USE_DUAL_ABI
3003  template<__format::__char _CharT>
3004  struct formatter<chrono::sys_info, _CharT>
3005  {
3006  constexpr typename basic_format_parse_context<_CharT>::iterator
3007  parse(basic_format_parse_context<_CharT>& __pc)
3008  { return _M_f.parse(__pc); }
3009 
3010  template<typename _Out>
3011  typename basic_format_context<_Out, _CharT>::iterator
3012  format(const chrono::sys_info& __i,
3013  basic_format_context<_Out, _CharT>& __fc) const
3014  { return _M_f.format(__i, __fc); }
3015 
3016  private:
3017  __format::__formatter_chrono_info<_CharT> _M_f;
3018  };
3019 
3020 #if __glibcxx_print >= 202406L
3021  template<>
3022  inline constexpr bool
3023  enable_nonlocking_formatter_optimization<chrono::sys_info> = true;
3024 #endif
3025 
3026  template<__format::__char _CharT>
3027  struct formatter<chrono::local_info, _CharT>
3028  {
3029  constexpr typename basic_format_parse_context<_CharT>::iterator
3030  parse(basic_format_parse_context<_CharT>& __pc)
3031  { return _M_f.parse(__pc); }
3032 
3033  template<typename _Out>
3034  typename basic_format_context<_Out, _CharT>::iterator
3035  format(const chrono::local_info& __i,
3036  basic_format_context<_Out, _CharT>& __fc) const
3037  { return _M_f.format(__i, __fc); }
3038 
3039  private:
3040  __format::__formatter_chrono_info<_CharT> _M_f;
3041  };
3042 
3043 #if __glibcxx_print >= 202406L
3044  template<>
3045  inline constexpr bool
3046  enable_nonlocking_formatter_optimization<chrono::local_info> = true;
3047 #endif
3048 #endif
3049 
3050  template<typename _Duration, __format::__char _CharT>
3051  struct formatter<chrono::sys_time<_Duration>, _CharT>
3052  {
3053  constexpr typename basic_format_parse_context<_CharT>::iterator
3054  parse(basic_format_parse_context<_CharT>& __pc)
3055  {
3056  using enum __format::_ChronoParts;
3057  auto __res
3058  = _M_f.template _M_parse<_Duration>(__pc, _ZonedDateTime, __defSpec);
3059  if constexpr (__defSpec._M_chrono_specs.empty())
3060  if (_M_f._M_spec._M_chrono_specs.empty())
3061  __format::__invalid_chrono_spec(); // chrono-specs can't be empty
3062  return __res;
3063  }
3064 
3065  template<typename _Out>
3066  typename basic_format_context<_Out, _CharT>::iterator
3067  format(const chrono::sys_time<_Duration>& __t,
3068  basic_format_context<_Out, _CharT>& __fc) const
3069  {
3070  __format::_ChronoData<_CharT> __cd{};
3071  __cd._M_fill_utc_zone();
3072 
3073  _Duration __ed = __t.time_since_epoch();
3074  __cd._M_eseconds = chrono::floor<chrono::seconds>(__ed);
3075  __cd._M_lseconds = chrono::local_seconds(__cd._M_eseconds);
3076  return _M_f._M_format_time_point(__cd, __ed, __fc);
3077  }
3078 
3079  private:
3080  static constexpr __format::_ChronoSpec<_CharT> __defSpec =
3081  __format::__formatter_duration<_CharT>::template _S_spec_for_tp<_Duration>();
3082 
3083  __format::__formatter_duration<_CharT> _M_f{__defSpec};
3084  };
3085 
3086 #if __glibcxx_print >= 202406L
3087  // _GLIBCXX_RESOLVE_LIB_DEFECTS
3088  // 4400. enable_nonlocking_formatter_optimization for durations with custom rep
3089  template<typename _Duration>
3090  constexpr bool
3091  enable_nonlocking_formatter_optimization<chrono::sys_time<_Duration>>
3092  = enable_nonlocking_formatter_optimization<_Duration>;
3093 #endif
3094 
3095  template<typename _Duration, __format::__char _CharT>
3096  struct formatter<chrono::utc_time<_Duration>, _CharT>
3097  {
3098  constexpr typename basic_format_parse_context<_CharT>::iterator
3099  parse(basic_format_parse_context<_CharT>& __pc)
3100  {
3101  using enum __format::_ChronoParts;
3102  return _M_f.template _M_parse<_Duration>(__pc, _ZonedDateTime, __defSpec);
3103  }
3104 
3105  template<typename _Out>
3106  typename basic_format_context<_Out, _CharT>::iterator
3107  format(const chrono::utc_time<_Duration>& __t,
3108  basic_format_context<_Out, _CharT>& __fc) const
3109  {
3110  using __format::_ChronoParts;
3111  using namespace chrono;
3112  __format::_ChronoData<_CharT> __cd{};
3113  __cd._M_fill_utc_zone();
3114 
3115  _Duration __ed = __t.time_since_epoch();
3116  __cd._M_eseconds = chrono::floor<seconds>(__ed);
3117  // Adjust by removing leap seconds to get equivalent sys_time.
3118  // We can't just use clock_cast because we want to know if the time
3119  // falls within a leap second insertion, and format seconds as "60".
3120  const auto __li = chrono::get_leap_second_info(__t);
3121  __cd._M_lseconds = local_seconds(__cd._M_eseconds - __li.elapsed);
3122  auto __parts = _M_f._M_spec._M_needed - _ChronoParts::_TotalSeconds;
3123  if ((__parts & _ChronoParts::_DateTime) != 0)
3124  {
3125  __cd._M_fill_date_time(__cd._M_lseconds, __parts);
3126  __cd._M_seconds += seconds(__li.is_leap_second);
3127  }
3128  return _M_f._M_format_units(__cd, __ed, __ed - __cd._M_eseconds, __fc);
3129  }
3130 
3131  private:
3132  static constexpr __format::_ChronoSpec<_CharT> __defSpec =
3133  __format::__formatter_duration<_CharT>::
3134  template _S_spec_for<_Duration>(__format::_ChronoParts::_DateTime);
3135 
3136  __format::__formatter_duration<_CharT> _M_f{__defSpec};
3137  };
3138 
3139 #if __glibcxx_print >= 202406L
3140  // _GLIBCXX_RESOLVE_LIB_DEFECTS
3141  // 4400. enable_nonlocking_formatter_optimization for durations with custom rep
3142  template<typename _Duration>
3143  constexpr bool
3144  enable_nonlocking_formatter_optimization<chrono::utc_time<_Duration>>
3145  = enable_nonlocking_formatter_optimization<_Duration>;
3146 #endif
3147 
3148  template<typename _Duration, __format::__char _CharT>
3149  struct formatter<chrono::tai_time<_Duration>, _CharT>
3150  {
3151  constexpr typename basic_format_parse_context<_CharT>::iterator
3152  parse(basic_format_parse_context<_CharT>& __pc)
3153  {
3154  using enum __format::_ChronoParts;
3155  return _M_f.template _M_parse<_Duration>(__pc, _ZonedDateTime, __defSpec);
3156  }
3157 
3158  template<typename _Out>
3159  typename basic_format_context<_Out, _CharT>::iterator
3160  format(const chrono::tai_time<_Duration>& __t,
3161  basic_format_context<_Out, _CharT>& __fc) const
3162  {
3163  using namespace chrono;
3164  __format::_ChronoData<_CharT> __cd{};
3165  __cd._M_fill_zone("TAI", L"TAI");
3166 
3167  _Duration __ed = __t.time_since_epoch();
3168  __cd._M_eseconds = chrono::floor<seconds>(__ed);
3169  // Offset is 1970y/January/1 - 1958y/January/1
3170  constexpr chrono::days __tai_offset = chrono::days(4383);
3171  __cd._M_lseconds = local_seconds(__cd._M_eseconds - __tai_offset);
3172  return _M_f._M_format_time_point(__cd, __ed, __fc);
3173  }
3174 
3175  private:
3176  static constexpr __format::_ChronoSpec<_CharT> __defSpec =
3177  __format::__formatter_duration<_CharT>::
3178  template _S_spec_for<_Duration>(__format::_ChronoParts::_DateTime);
3179 
3180  __format::__formatter_duration<_CharT> _M_f{__defSpec};
3181  };
3182 
3183 #if __glibcxx_print >= 202406L
3184  // _GLIBCXX_RESOLVE_LIB_DEFECTS
3185  // 4400. enable_nonlocking_formatter_optimization for durations with custom rep
3186  template<typename _Duration>
3187  constexpr bool
3188  enable_nonlocking_formatter_optimization<chrono::tai_time<_Duration>>
3189  = enable_nonlocking_formatter_optimization<_Duration>;
3190 #endif
3191 
3192  template<typename _Duration, __format::__char _CharT>
3193  struct formatter<chrono::gps_time<_Duration>, _CharT>
3194  {
3195  constexpr typename basic_format_parse_context<_CharT>::iterator
3196  parse(basic_format_parse_context<_CharT>& __pc)
3197  {
3198  using enum __format::_ChronoParts;
3199  return _M_f.template _M_parse<_Duration>(__pc, _ZonedDateTime, __defSpec);
3200  }
3201 
3202  template<typename _Out>
3203  typename basic_format_context<_Out, _CharT>::iterator
3204  format(const chrono::gps_time<_Duration>& __t,
3205  basic_format_context<_Out, _CharT>& __fc) const
3206  {
3207  using namespace chrono;
3208  __format::_ChronoData<_CharT> __cd{};
3209  __cd._M_fill_zone("GPS", L"GPS");
3210 
3211  _Duration __ed = __t.time_since_epoch();
3212  __cd._M_eseconds = chrono::floor<seconds>(__ed);
3213  // Offset is 1980y/January/Sunday[1] - 1970y/January/1
3214  constexpr chrono::days __gps_offset = chrono::days(3657);
3215  __cd._M_lseconds = local_seconds(__cd._M_eseconds + __gps_offset);
3216  return _M_f._M_format_time_point(__cd, __ed, __fc);
3217  }
3218 
3219  private:
3220  static constexpr __format::_ChronoSpec<_CharT> __defSpec =
3221  __format::__formatter_duration<_CharT>::
3222  template _S_spec_for<_Duration>(__format::_ChronoParts::_DateTime);
3223 
3224  __format::__formatter_duration<_CharT> _M_f{__defSpec};
3225  };
3226 
3227 #if __glibcxx_print >= 202406L
3228  // _GLIBCXX_RESOLVE_LIB_DEFECTS
3229  // 4400. enable_nonlocking_formatter_optimization for durations with custom rep
3230  template<typename _Duration>
3231  constexpr bool
3232  enable_nonlocking_formatter_optimization<chrono::gps_time<_Duration>>
3233  = enable_nonlocking_formatter_optimization<_Duration>;
3234 #endif
3235 
3236  template<typename _Duration, __format::__char _CharT>
3237  struct formatter<chrono::file_time<_Duration>, _CharT>
3238  {
3239  constexpr typename basic_format_parse_context<_CharT>::iterator
3240  parse(basic_format_parse_context<_CharT>& __pc)
3241  {
3242  using enum __format::_ChronoParts;
3243  return _M_f.template _M_parse<_Duration>(__pc, _ZonedDateTime, __defSpec);
3244  }
3245 
3246  template<typename _Out>
3247  typename basic_format_context<_Out, _CharT>::iterator
3248  format(const chrono::file_time<_Duration>& __t,
3249  basic_format_context<_Out, _CharT>& __fc) const
3250  {
3251  using namespace chrono;
3252  __format::_ChronoData<_CharT> __cd{};
3253  __cd._M_fill_utc_zone();
3254 
3255  _Duration __ed = __t.time_since_epoch();
3256  __cd._M_eseconds = chrono::floor<seconds>(__ed);
3257  auto __st = chrono::clock_cast<system_clock>(__t);
3258  __cd._M_lseconds
3259  = local_seconds(chrono::floor<seconds>(__st.time_since_epoch()));
3260  return _M_f._M_format_time_point(__cd, __ed, __fc);
3261  }
3262 
3263  private:
3264  static constexpr __format::_ChronoSpec<_CharT> __defSpec =
3265  __format::__formatter_duration<_CharT>::
3266  template _S_spec_for<_Duration>(__format::_ChronoParts::_DateTime);
3267 
3268  __format::__formatter_duration<_CharT> _M_f{__defSpec};
3269  };
3270 
3271 #if __glibcxx_print >= 202406L
3272  // _GLIBCXX_RESOLVE_LIB_DEFECTS
3273  // 4400. enable_nonlocking_formatter_optimization for durations with custom rep
3274  template<typename _Duration>
3275  constexpr bool
3276  enable_nonlocking_formatter_optimization<chrono::file_time<_Duration>>
3277  = enable_nonlocking_formatter_optimization<_Duration>;
3278 #endif
3279 
3280  template<typename _Duration, __format::__char _CharT>
3281  struct formatter<chrono::local_time<_Duration>, _CharT>
3282  {
3283  constexpr typename basic_format_parse_context<_CharT>::iterator
3284  parse(basic_format_parse_context<_CharT>& __pc)
3285  {
3286  using enum __format::_ChronoParts;
3287  auto __res
3288  = _M_f.template _M_parse<_Duration>(__pc, _DateTime, __defSpec);
3289  if constexpr (__defSpec._M_chrono_specs.empty())
3290  if (_M_f._M_spec._M_chrono_specs.empty())
3291  __format::__invalid_chrono_spec(); // chrono-specs can't be empty
3292  return __res;
3293  }
3294 
3295  template<typename _Out>
3296  typename basic_format_context<_Out, _CharT>::iterator
3297  format(const chrono::local_time<_Duration>& __lt,
3298  basic_format_context<_Out, _CharT>& __fc) const
3299  {
3300  __format::_ChronoData<_CharT> __cd{};
3301  _Duration __ed = __lt.time_since_epoch();
3302  __cd._M_lseconds = chrono::floor<chrono::seconds>(__lt);
3303  __cd._M_eseconds = __cd._M_lseconds.time_since_epoch();
3304  return _M_f._M_format_time_point(__cd, __ed, __fc);
3305  }
3306 
3307  private:
3308  static constexpr __format::_ChronoSpec<_CharT> __defSpec =
3309  __format::__formatter_duration<_CharT>::template _S_spec_for_tp<_Duration>();
3310 
3311  __format::__formatter_duration<_CharT> _M_f{__defSpec};
3312  };
3313 
3314 #if __glibcxx_print >= 202406L
3315  // _GLIBCXX_RESOLVE_LIB_DEFECTS
3316  // 4400. enable_nonlocking_formatter_optimization for durations with custom rep
3317  template<typename _Duration>
3318  constexpr bool
3319  enable_nonlocking_formatter_optimization<chrono::local_time<_Duration>>
3320  = enable_nonlocking_formatter_optimization<_Duration>;
3321 #endif
3322 
3323  template<typename _Duration, __format::__char _CharT>
3324  struct formatter<chrono::__detail::__local_time_fmt<_Duration>, _CharT>
3325  {
3326  constexpr typename basic_format_parse_context<_CharT>::iterator
3327  parse(basic_format_parse_context<_CharT>& __pc)
3328  {
3329  using enum __format::_ChronoParts;
3330  return _M_f.template _M_parse<_Duration>(__pc, _ZonedDateTime, __defSpec);
3331  }
3332 
3333  template<typename _Out>
3334  typename basic_format_context<_Out, _CharT>::iterator
3335  format(const chrono::__detail::__local_time_fmt<_Duration>& __zt,
3336  basic_format_context<_Out, _CharT>& __fc) const
3337  {
3338  using enum __format::_ChronoParts;
3339  __format::_ChronoData<_CharT> __cd{};
3340 
3341  if (_M_f._M_spec._M_needs(_ZoneOffset))
3342  {
3343  if (!__zt._M_offset_sec)
3344  std::__throw_format_error("format error: no timezone available for %z");
3345  __cd._M_zone_offset = *__zt._M_offset_sec;
3346  }
3347 
3348  basic_string<_CharT> __zone_store;
3349  if (_M_f._M_spec._M_needs(_ZoneAbbrev))
3350  {
3351  if (!__zt._M_abbrev)
3352  std::__throw_format_error("format error: no timezone available for %Z");
3353 
3354  __cd._M_zone_cstr = __zt._M_abbrev->data();
3355  if constexpr (is_same_v<_CharT, char>)
3356  __cd._M_zone_abbrev = *__zt._M_abbrev;
3357  else
3358  {
3359  // TODO: use resize_for_override
3360  __zone_store.resize(__zt._M_abbrev->size());
3361  auto& __ct = use_facet<ctype<_CharT>>(_M_f._M_locale(__fc));
3362  __ct.widen(__zt._M_abbrev->data(),
3363  __zt._M_abbrev->data() + __zt._M_abbrev->size(),
3364  __zone_store.data());
3365  __cd._M_zone_abbrev = __zone_store;
3366  }
3367  }
3368 
3369  _Duration __ed = __zt._M_time.time_since_epoch();
3370  __cd._M_lseconds = chrono::floor<chrono::seconds>(__zt._M_time);
3371  __cd._M_eseconds = __cd._M_lseconds.time_since_epoch();
3372  return _M_f._M_format_time_point(__cd, __ed, __fc);
3373  }
3374 
3375  private:
3376  static constexpr __format::_ChronoSpec<_CharT> __defSpec =
3377  __format::__formatter_duration<_CharT>::
3378  template _S_spec_for<_Duration>(__format::_ChronoParts::_ZonedDateTime);
3379 
3380  __format::__formatter_duration<_CharT> _M_f{__defSpec};
3381  };
3382 
3383 #if __glibcxx_print >= 202406L
3384  // _GLIBCXX_RESOLVE_LIB_DEFECTS
3385  // 4400. enable_nonlocking_formatter_optimization for durations with custom rep
3386  template<typename _Duration>
3387  constexpr bool
3388  enable_nonlocking_formatter_optimization<
3389  chrono::__detail::__local_time_fmt<_Duration>>
3390  = enable_nonlocking_formatter_optimization<_Duration>;
3391 #endif
3392 
3393 #if _GLIBCXX_USE_CXX11_ABI || ! _GLIBCXX_USE_DUAL_ABI
3394  template<typename _Duration, typename _TimeZonePtr, __format::__char _CharT>
3395  struct formatter<chrono::zoned_time<_Duration, _TimeZonePtr>, _CharT>
3396  : formatter<chrono::__detail::__local_time_fmt_for<_Duration>, _CharT>
3397  {
3398  template<typename _Out>
3399  typename basic_format_context<_Out, _CharT>::iterator
3400  format(const chrono::zoned_time<_Duration, _TimeZonePtr>& __tp,
3401  basic_format_context<_Out, _CharT>& __fc) const
3402  {
3403  using _Ltf = chrono::__detail::__local_time_fmt_for<_Duration>;
3404  using _Base = formatter<_Ltf, _CharT>;
3405  const chrono::sys_info __info = __tp.get_info();
3406  const auto __lf = chrono::local_time_format(__tp.get_local_time(),
3407  &__info.abbrev,
3408  &__info.offset);
3409  return _Base::format(__lf, __fc);
3410  }
3411  };
3412 
3413 #if __glibcxx_print >= 202406L
3414  // _GLIBCXX_RESOLVE_LIB_DEFECTS
3415  // 4400. enable_nonlocking_formatter_optimization for durations with custom rep
3416  template<typename _Duration>
3417  constexpr bool
3418  enable_nonlocking_formatter_optimization<
3419  chrono::zoned_time<_Duration, const chrono::time_zone*>>
3420  = enable_nonlocking_formatter_optimization<_Duration>;
3421 #endif
3422 #endif
3423 
3424 namespace chrono
3425 {
3426 /// @addtogroup chrono
3427 /// @{
3428 
3429 /// @cond undocumented
3430 namespace __detail
3431 {
3432  template<typename _Duration = seconds>
3433  struct _Parser
3434  {
3435  static_assert(is_same_v<common_type_t<_Duration, seconds>, _Duration>);
3436 
3437  explicit
3438  _Parser(__format::_ChronoParts __need) : _M_need(__need) { }
3439 
3440  _Parser(_Parser&&) = delete;
3441  void operator=(_Parser&&) = delete;
3442 
3443  _Duration _M_time{}; // since midnight
3444  sys_days _M_sys_days{};
3445  year_month_day _M_ymd{};
3446  weekday _M_wd{};
3447  __format::_ChronoParts _M_need;
3448  unsigned _M_is_leap_second : 1 {};
3449  unsigned _M_reserved : 15 {};
3450 
3451  template<typename _CharT, typename _Traits, typename _Alloc>
3452  basic_istream<_CharT, _Traits>&
3453  operator()(basic_istream<_CharT, _Traits>& __is, const _CharT* __fmt,
3454  basic_string<_CharT, _Traits, _Alloc>* __abbrev = nullptr,
3455  minutes* __offset = nullptr);
3456 
3457  private:
3458  // Read an unsigned integer from the stream and return it.
3459  // Extract no more than __n digits. Set failbit if an integer isn't read.
3460  template<typename _CharT, typename _Traits>
3461  static int_least32_t
3462  _S_read_unsigned(basic_istream<_CharT, _Traits>& __is,
3463  ios_base::iostate& __err, int __n)
3464  {
3465  int_least32_t __val = _S_try_read_digit(__is, __err);
3466  if (__val == -1) [[unlikely]]
3467  __err |= ios_base::failbit;
3468  else
3469  {
3470  int __n1 = (std::min)(__n, 9);
3471  // Cannot overflow __val unless we read more than 9 digits
3472  for (int __i = 1; __i < __n1; ++__i)
3473  if (auto __dig = _S_try_read_digit(__is, __err); __dig != -1)
3474  {
3475  __val *= 10;
3476  __val += __dig;
3477  }
3478 
3479  while (__n1++ < __n) [[unlikely]]
3480  if (auto __dig = _S_try_read_digit(__is, __err); __dig != -1)
3481  {
3482  if (__builtin_mul_overflow(__val, 10, &__val)
3483  || __builtin_add_overflow(__val, __dig, &__val))
3484  {
3485  __err |= ios_base::failbit;
3486  return -1;
3487  }
3488  }
3489  }
3490  return __val;
3491  }
3492 
3493  // Read an unsigned integer from the stream and return it.
3494  // Extract no more than __n digits. Set failbit if an integer isn't read.
3495  template<typename _CharT, typename _Traits>
3496  static int_least32_t
3497  _S_read_signed(basic_istream<_CharT, _Traits>& __is,
3498  ios_base::iostate& __err, int __n)
3499  {
3500  auto __sign = __is.peek();
3501  if (__sign == '-' || __sign == '+')
3502  (void) __is.get();
3503  int_least32_t __val = _S_read_unsigned(__is, __err, __n);
3504  if (__err & ios_base::failbit)
3505  {
3506  if (__sign == '-') [[unlikely]]
3507  __val *= -1;
3508  }
3509  return __val;
3510  }
3511 
3512  // Read a digit from the stream and return it, or return -1.
3513  // If no digit is read eofbit will be set (but not failbit).
3514  template<typename _CharT, typename _Traits>
3515  static int_least32_t
3516  _S_try_read_digit(basic_istream<_CharT, _Traits>& __is,
3517  ios_base::iostate& __err)
3518  {
3519  int_least32_t __val = -1;
3520  auto __i = __is.peek();
3521  if (!_Traits::eq_int_type(__i, _Traits::eof())) [[likely]]
3522  {
3523  _CharT __c = _Traits::to_char_type(__i);
3524  if (_CharT('0') <= __c && __c <= _CharT('9')) [[likely]]
3525  {
3526  (void) __is.get();
3527  __val = __c - _CharT('0');
3528  }
3529  }
3530  else
3531  __err |= ios_base::eofbit;
3532  return __val;
3533  }
3534 
3535  // Read the specified character and return true.
3536  // If the character is not found, set failbit and return false.
3537  template<typename _CharT, typename _Traits>
3538  static bool
3539  _S_read_chr(basic_istream<_CharT, _Traits>& __is,
3540  ios_base::iostate& __err, _CharT __c)
3541  {
3542  auto __i = __is.peek();
3543  if (_Traits::eq_int_type(__i, _Traits::eof()))
3544  __err |= ios_base::eofbit;
3545  else if (_Traits::to_char_type(__i) == __c) [[likely]]
3546  {
3547  (void) __is.get();
3548  return true;
3549  }
3550  __err |= ios_base::failbit;
3551  return false;
3552  }
3553  };
3554 
3555  template<typename _Duration>
3556  using _Parser_t = _Parser<common_type_t<_Duration, seconds>>;
3557 
3558  template<typename _Duration>
3559  consteval bool
3560  __use_floor()
3561  {
3562  if constexpr (_Duration::period::den == 1)
3563  {
3564  switch (_Duration::period::num)
3565  {
3566  case minutes::period::num:
3567  case hours::period::num:
3568  case days::period::num:
3569  case weeks::period::num:
3570  case years::period::num:
3571  return true;
3572  }
3573  }
3574  return false;
3575  }
3576 
3577  // A "do the right thing" rounding function for duration and time_point
3578  // values extracted by from_stream. When treat_as_floating_point is true
3579  // we don't want to do anything, just a straightforward conversion.
3580  // When the destination type has a period of minutes, hours, days, weeks,
3581  // or years, we use chrono::floor to truncate towards negative infinity.
3582  // This ensures that an extracted timestamp such as 2024-09-05 13:00:00
3583  // will produce 2024-09-05 when rounded to days, rather than rounding up
3584  // to 2024-09-06 (a different day).
3585  // Otherwise, use chrono::round to get the nearest value representable
3586  // in the destination type.
3587  template<typename _ToDur, typename _Tp>
3588  constexpr auto
3589  __round(const _Tp& __t)
3590  {
3591  if constexpr (__is_duration_v<_Tp>)
3592  {
3593  if constexpr (treat_as_floating_point_v<typename _Tp::rep>)
3594  return chrono::duration_cast<_ToDur>(__t);
3595  else if constexpr (__detail::__use_floor<_ToDur>())
3596  return chrono::floor<_ToDur>(__t);
3597  else
3598  return chrono::round<_ToDur>(__t);
3599  }
3600  else
3601  {
3602  static_assert(__is_time_point_v<_Tp>);
3603  using _Tpt = time_point<typename _Tp::clock, _ToDur>;
3604  return _Tpt(__detail::__round<_ToDur>(__t.time_since_epoch()));
3605  }
3606  }
3607 
3608 } // namespace __detail
3609 /// @endcond
3610 
3611  template<typename _CharT, typename _Traits, typename _Rep, typename _Period,
3612  typename _Alloc = allocator<_CharT>>
3613  inline basic_istream<_CharT, _Traits>&
3614  from_stream(basic_istream<_CharT, _Traits>& __is, const _CharT* __fmt,
3615  duration<_Rep, _Period>& __d,
3616  basic_string<_CharT, _Traits, _Alloc>* __abbrev = nullptr,
3617  minutes* __offset = nullptr)
3618  {
3619  auto __need = __format::_ChronoParts::_TimeOfDay;
3620  __detail::_Parser_t<duration<_Rep, _Period>> __p(__need);
3621  if (__p(__is, __fmt, __abbrev, __offset))
3622  __d = __detail::__round<duration<_Rep, _Period>>(__p._M_time);
3623  return __is;
3624  }
3625 
3626  template<typename _CharT, typename _Traits>
3627  inline basic_ostream<_CharT, _Traits>&
3628  operator<<(basic_ostream<_CharT, _Traits>& __os, const day& __d)
3629  {
3630  using _Ctx = __format::__format_context<_CharT>;
3631  using _Str = basic_string_view<_CharT>;
3632  _Str __s = _GLIBCXX_WIDEN("{:02d} is not a valid day");
3633  if (__d.ok())
3634  __s = __s.substr(0, 6);
3635  auto __u = (unsigned)__d;
3636  __os << std::vformat(__s, make_format_args<_Ctx>(__u));
3637  return __os;
3638  }
3639 
3640  template<typename _CharT, typename _Traits,
3641  typename _Alloc = allocator<_CharT>>
3642  inline basic_istream<_CharT, _Traits>&
3643  from_stream(basic_istream<_CharT, _Traits>& __is, const _CharT* __fmt,
3644  day& __d,
3645  basic_string<_CharT, _Traits, _Alloc>* __abbrev = nullptr,
3646  minutes* __offset = nullptr)
3647  {
3648  __detail::_Parser<> __p(__format::_ChronoParts::_Day);
3649  if (__p(__is, __fmt, __abbrev, __offset))
3650  __d = __p._M_ymd.day();
3651  return __is;
3652  }
3653 
3654  template<typename _CharT, typename _Traits>
3655  inline basic_ostream<_CharT, _Traits>&
3656  operator<<(basic_ostream<_CharT, _Traits>& __os, const month& __m)
3657  {
3658  using _Ctx = __format::__format_context<_CharT>;
3659  using _Str = basic_string_view<_CharT>;
3660  _Str __s = _GLIBCXX_WIDEN("{:L%b}{} is not a valid month");
3661  if (__m.ok())
3662  __os << std::vformat(__os.getloc(), __s.substr(0, 6),
3663  make_format_args<_Ctx>(__m));
3664  else
3665  {
3666  auto __u = (unsigned)__m;
3667  __os << std::vformat(__s.substr(6), make_format_args<_Ctx>(__u));
3668  }
3669  return __os;
3670  }
3671 
3672  template<typename _CharT, typename _Traits,
3673  typename _Alloc = allocator<_CharT>>
3674  inline basic_istream<_CharT, _Traits>&
3675  from_stream(basic_istream<_CharT, _Traits>& __is, const _CharT* __fmt,
3676  month& __m,
3677  basic_string<_CharT, _Traits, _Alloc>* __abbrev = nullptr,
3678  minutes* __offset = nullptr)
3679  {
3680  __detail::_Parser<> __p(__format::_ChronoParts::_Month);
3681  if (__p(__is, __fmt, __abbrev, __offset))
3682  __m = __p._M_ymd.month();
3683  return __is;
3684  }
3685 
3686  template<typename _CharT, typename _Traits>
3687  inline basic_ostream<_CharT, _Traits>&
3688  operator<<(basic_ostream<_CharT, _Traits>& __os, const year& __y)
3689  {
3690  using _Ctx = __format::__format_context<_CharT>;
3691  using _Str = basic_string_view<_CharT>;
3692  _Str __s = _GLIBCXX_WIDEN("-{:04d} is not a valid year");
3693  if (__y.ok())
3694  __s = __s.substr(0, 7);
3695  int __i = (int)__y;
3696  if (__i >= 0) [[likely]]
3697  __s.remove_prefix(1);
3698  else
3699  __i = -__i;
3700  __os << std::vformat(__s, make_format_args<_Ctx>(__i));
3701  return __os;
3702  }
3703 
3704  template<typename _CharT, typename _Traits,
3705  typename _Alloc = allocator<_CharT>>
3706  inline basic_istream<_CharT, _Traits>&
3707  from_stream(basic_istream<_CharT, _Traits>& __is, const _CharT* __fmt,
3708  year& __y,
3709  basic_string<_CharT, _Traits, _Alloc>* __abbrev = nullptr,
3710  minutes* __offset = nullptr)
3711  {
3712  __detail::_Parser<> __p(__format::_ChronoParts::_Year);
3713  if (__p(__is, __fmt, __abbrev, __offset))
3714  __y = __p._M_ymd.year();
3715  return __is;
3716  }
3717 
3718  template<typename _CharT, typename _Traits>
3719  inline basic_ostream<_CharT, _Traits>&
3720  operator<<(basic_ostream<_CharT, _Traits>& __os, const weekday& __wd)
3721  {
3722  using _Ctx = __format::__format_context<_CharT>;
3723  using _Str = basic_string_view<_CharT>;
3724  _Str __s = _GLIBCXX_WIDEN("{:L%a}{} is not a valid weekday");
3725  if (__wd.ok())
3726  __os << std::vformat(__os.getloc(), __s.substr(0, 6),
3727  make_format_args<_Ctx>(__wd));
3728  else
3729  {
3730  auto __c = __wd.c_encoding();
3731  __os << std::vformat(__s.substr(6), make_format_args<_Ctx>(__c));
3732  }
3733  return __os;
3734  }
3735 
3736  template<typename _CharT, typename _Traits,
3737  typename _Alloc = allocator<_CharT>>
3738  inline basic_istream<_CharT, _Traits>&
3739  from_stream(basic_istream<_CharT, _Traits>& __is, const _CharT* __fmt,
3740  weekday& __wd,
3741  basic_string<_CharT, _Traits, _Alloc>* __abbrev = nullptr,
3742  minutes* __offset = nullptr)
3743  {
3744  __detail::_Parser<> __p(__format::_ChronoParts::_Weekday);
3745  if (__p(__is, __fmt, __abbrev, __offset))
3746  __wd = __p._M_wd;
3747  return __is;
3748  }
3749 
3750  template<typename _CharT, typename _Traits>
3751  inline basic_ostream<_CharT, _Traits>&
3752  operator<<(basic_ostream<_CharT, _Traits>& __os,
3753  const weekday_indexed& __wdi)
3754  {
3755  // The standard says to format wdi.weekday() and wdi.index() using
3756  // either "{:L}[{}]" or "{:L}[{} is not a valid index]". The {:L} spec
3757  // means to format the weekday using ostringstream, so just do that.
3758  basic_stringstream<_CharT> __os2;
3759  __os2.imbue(__os.getloc());
3760  __os2 << __wdi.weekday();
3761  const auto __i = __wdi.index();
3762  basic_string_view<_CharT> __s
3763  = _GLIBCXX_WIDEN("[ is not a valid index]");
3764  __os2 << __s[0];
3765  __os2 << std::format(_GLIBCXX_WIDEN("{}"), __i);
3766  if (__i >= 1 && __i <= 5)
3767  __os2 << __s.back();
3768  else
3769  __os2 << __s.substr(1);
3770  __os << __os2.view();
3771  return __os;
3772  }
3773 
3774  template<typename _CharT, typename _Traits>
3775  inline basic_ostream<_CharT, _Traits>&
3776  operator<<(basic_ostream<_CharT, _Traits>& __os,
3777  const weekday_last& __wdl)
3778  {
3779  // As above, just write straight to a stringstream, as if by "{:L}[last]"
3780  basic_stringstream<_CharT> __os2;
3781  __os2.imbue(__os.getloc());
3782  __os2 << __wdl.weekday() << _GLIBCXX_WIDEN("[last]");
3783  __os << __os2.view();
3784  return __os;
3785  }
3786 
3787  template<typename _CharT, typename _Traits>
3788  inline basic_ostream<_CharT, _Traits>&
3789  operator<<(basic_ostream<_CharT, _Traits>& __os, const month_day& __md)
3790  {
3791  // As above, just write straight to a stringstream, as if by "{:L}/{}"
3792  basic_stringstream<_CharT> __os2;
3793  __os2.imbue(__os.getloc());
3794  __os2 << __md.month();
3795  if constexpr (is_same_v<_CharT, char>)
3796  __os2 << '/';
3797  else
3798  __os2 << L'/';
3799  __os2 << __md.day();
3800  __os << __os2.view();
3801  return __os;
3802  }
3803 
3804  template<typename _CharT, typename _Traits,
3805  typename _Alloc = allocator<_CharT>>
3806  inline basic_istream<_CharT, _Traits>&
3807  from_stream(basic_istream<_CharT, _Traits>& __is, const _CharT* __fmt,
3808  month_day& __md,
3809  basic_string<_CharT, _Traits, _Alloc>* __abbrev = nullptr,
3810  minutes* __offset = nullptr)
3811  {
3812  using __format::_ChronoParts;
3813  auto __need = _ChronoParts::_Month | _ChronoParts::_Day;
3814  __detail::_Parser<> __p(__need);
3815  if (__p(__is, __fmt, __abbrev, __offset))
3816  __md = month_day(__p._M_ymd.month(), __p._M_ymd.day());
3817  return __is;
3818  }
3819 
3820  template<typename _CharT, typename _Traits>
3821  inline basic_ostream<_CharT, _Traits>&
3822  operator<<(basic_ostream<_CharT, _Traits>& __os,
3823  const month_day_last& __mdl)
3824  {
3825  // As above, just write straight to a stringstream, as if by "{:L}/last"
3826  basic_stringstream<_CharT> __os2;
3827  __os2.imbue(__os.getloc());
3828  __os2 << __mdl.month() << _GLIBCXX_WIDEN("/last");
3829  __os << __os2.view();
3830  return __os;
3831  }
3832 
3833  template<typename _CharT, typename _Traits>
3834  inline basic_ostream<_CharT, _Traits>&
3835  operator<<(basic_ostream<_CharT, _Traits>& __os,
3836  const month_weekday& __mwd)
3837  {
3838  // As above, just write straight to a stringstream, as if by "{:L}/{:L}"
3839  basic_stringstream<_CharT> __os2;
3840  __os2.imbue(__os.getloc());
3841  __os2 << __mwd.month();
3842  if constexpr (is_same_v<_CharT, char>)
3843  __os2 << '/';
3844  else
3845  __os2 << L'/';
3846  __os2 << __mwd.weekday_indexed();
3847  __os << __os2.view();
3848  return __os;
3849  }
3850 
3851  template<typename _CharT, typename _Traits>
3852  inline basic_ostream<_CharT, _Traits>&
3853  operator<<(basic_ostream<_CharT, _Traits>& __os,
3854  const month_weekday_last& __mwdl)
3855  {
3856  // As above, just write straight to a stringstream, as if by "{:L}/{:L}"
3857  basic_stringstream<_CharT> __os2;
3858  __os2.imbue(__os.getloc());
3859  __os2 << __mwdl.month();
3860  if constexpr (is_same_v<_CharT, char>)
3861  __os2 << '/';
3862  else
3863  __os2 << L'/';
3864  __os2 << __mwdl.weekday_last();
3865  __os << __os2.view();
3866  return __os;
3867  }
3868 
3869  template<typename _CharT, typename _Traits>
3870  inline basic_ostream<_CharT, _Traits>&
3871  operator<<(basic_ostream<_CharT, _Traits>& __os, const year_month& __ym)
3872  {
3873  // As above, just write straight to a stringstream, as if by "{}/{:L}"
3874  basic_stringstream<_CharT> __os2;
3875  __os2.imbue(__os.getloc());
3876  __os2 << __ym.year();
3877  if constexpr (is_same_v<_CharT, char>)
3878  __os2 << '/';
3879  else
3880  __os2 << L'/';
3881  __os2 << __ym.month();
3882  __os << __os2.view();
3883  return __os;
3884  }
3885 
3886  template<typename _CharT, typename _Traits,
3887  typename _Alloc = allocator<_CharT>>
3888  inline basic_istream<_CharT, _Traits>&
3889  from_stream(basic_istream<_CharT, _Traits>& __is, const _CharT* __fmt,
3890  year_month& __ym,
3891  basic_string<_CharT, _Traits, _Alloc>* __abbrev = nullptr,
3892  minutes* __offset = nullptr)
3893  {
3894  using __format::_ChronoParts;
3895  auto __need = _ChronoParts::_Year | _ChronoParts::_Month;
3896  __detail::_Parser<> __p(__need);
3897  if (__p(__is, __fmt, __abbrev, __offset))
3898  __ym = year_month(__p._M_ymd.year(), __p._M_ymd.month());
3899  return __is;
3900  }
3901 
3902  template<typename _CharT, typename _Traits>
3903  inline basic_ostream<_CharT, _Traits>&
3904  operator<<(basic_ostream<_CharT, _Traits>& __os,
3905  const year_month_day& __ymd)
3906  {
3907  using _Ctx = __format::__format_context<_CharT>;
3908  using _Str = basic_string_view<_CharT>;
3909  _Str __s = _GLIBCXX_WIDEN("{:%F} is not a valid date");
3910  __os << std::vformat(__ymd.ok() ? __s.substr(0, 5) : __s,
3911  make_format_args<_Ctx>(__ymd));
3912  return __os;
3913  }
3914 
3915  template<typename _CharT, typename _Traits,
3916  typename _Alloc = allocator<_CharT>>
3917  inline basic_istream<_CharT, _Traits>&
3918  from_stream(basic_istream<_CharT, _Traits>& __is, const _CharT* __fmt,
3919  year_month_day& __ymd,
3920  basic_string<_CharT, _Traits, _Alloc>* __abbrev = nullptr,
3921  minutes* __offset = nullptr)
3922  {
3923  using __format::_ChronoParts;
3924  auto __need = _ChronoParts::_Year | _ChronoParts::_Month
3925  | _ChronoParts::_Day;
3926  __detail::_Parser<> __p(__need);
3927  if (__p(__is, __fmt, __abbrev, __offset))
3928  __ymd = __p._M_ymd;
3929  return __is;
3930  }
3931 
3932  template<typename _CharT, typename _Traits>
3933  inline basic_ostream<_CharT, _Traits>&
3934  operator<<(basic_ostream<_CharT, _Traits>& __os,
3935  const year_month_day_last& __ymdl)
3936  {
3937  // As above, just write straight to a stringstream, as if by "{}/{:L}"
3938  basic_stringstream<_CharT> __os2;
3939  __os2.imbue(__os.getloc());
3940  __os2 << __ymdl.year();
3941  if constexpr (is_same_v<_CharT, char>)
3942  __os2 << '/';
3943  else
3944  __os2 << L'/';
3945  __os2 << __ymdl.month_day_last();
3946  __os << __os2.view();
3947  return __os;
3948  }
3949 
3950  template<typename _CharT, typename _Traits>
3951  inline basic_ostream<_CharT, _Traits>&
3952  operator<<(basic_ostream<_CharT, _Traits>& __os,
3953  const year_month_weekday& __ymwd)
3954  {
3955  // As above, just write straight to a stringstream, as if by
3956  // "{}/{:L}/{:L}"
3957  basic_stringstream<_CharT> __os2;
3958  __os2.imbue(__os.getloc());
3959  _CharT __slash;
3960  if constexpr (is_same_v<_CharT, char>)
3961  __slash = '/';
3962  else
3963  __slash = L'/';
3964  __os2 << __ymwd.year() << __slash << __ymwd.month() << __slash
3965  << __ymwd.weekday_indexed();
3966  __os << __os2.view();
3967  return __os;
3968  }
3969 
3970  template<typename _CharT, typename _Traits>
3971  inline basic_ostream<_CharT, _Traits>&
3972  operator<<(basic_ostream<_CharT, _Traits>& __os,
3973  const year_month_weekday_last& __ymwdl)
3974  {
3975  // As above, just write straight to a stringstream, as if by
3976  // "{}/{:L}/{:L}"
3977  basic_stringstream<_CharT> __os2;
3978  __os2.imbue(__os.getloc());
3979  _CharT __slash;
3980  if constexpr (is_same_v<_CharT, char>)
3981  __slash = '/';
3982  else
3983  __slash = L'/';
3984  __os2 << __ymwdl.year() << __slash << __ymwdl.month() << __slash
3985  << __ymwdl.weekday_last();
3986  __os << __os2.view();
3987  return __os;
3988  }
3989 
3990  template<typename _CharT, typename _Traits, typename _Duration>
3991  inline basic_ostream<_CharT, _Traits>&
3992  operator<<(basic_ostream<_CharT, _Traits>& __os,
3993  const hh_mm_ss<_Duration>& __hms)
3994  {
3995  return __os << format(__os.getloc(), _GLIBCXX_WIDEN("{:L%T}"), __hms);
3996  }
3997 
3998 #if _GLIBCXX_USE_CXX11_ABI || ! _GLIBCXX_USE_DUAL_ABI
3999  /// Writes a sys_info object to an ostream in an unspecified format.
4000  template<typename _CharT, typename _Traits>
4001  basic_ostream<_CharT, _Traits>&
4002  operator<<(basic_ostream<_CharT, _Traits>& __os, const sys_info& __i)
4003  {
4004  return __os << std::format(__os.getloc(), _GLIBCXX_WIDEN("{}"), __i);
4005  }
4006 
4007  /// Writes a local_info object to an ostream in an unspecified format.
4008  template<typename _CharT, typename _Traits>
4009  basic_ostream<_CharT, _Traits>&
4010  operator<<(basic_ostream<_CharT, _Traits>& __os, const local_info& __li)
4011  {
4012  __os << __format::_Separators<_CharT>::_S_squares()[0];
4013  if (__li.result == local_info::unique)
4014  __os << __li.first;
4015  else
4016  {
4017  if (__li.result == local_info::nonexistent)
4018  __os << _GLIBCXX_WIDEN("nonexistent");
4019  else
4020  __os << _GLIBCXX_WIDEN("ambiguous");
4021  __os << _GLIBCXX_WIDEN(" local time between ") << __li.first;
4022  __os << _GLIBCXX_WIDEN(" and ") << __li.second;
4023  }
4024  __os << __format::_Separators<_CharT>::_S_squares()[1];
4025  return __os;
4026  }
4027 
4028  template<typename _CharT, typename _Traits, typename _Duration,
4029  typename _TimeZonePtr>
4030  inline basic_ostream<_CharT, _Traits>&
4031  operator<<(basic_ostream<_CharT, _Traits>& __os,
4032  const zoned_time<_Duration, _TimeZonePtr>& __t)
4033  {
4034  __os << format(__os.getloc(), _GLIBCXX_WIDEN("{:L%F %T %Z}"), __t);
4035  return __os;
4036  }
4037 #endif
4038 
4039  template<typename _CharT, typename _Traits, typename _Duration>
4040  requires (!treat_as_floating_point_v<typename _Duration::rep>)
4041  && ratio_less_v<typename _Duration::period, days::period>
4042  inline basic_ostream<_CharT, _Traits>&
4043  operator<<(basic_ostream<_CharT, _Traits>& __os,
4044  const sys_time<_Duration>& __tp)
4045  {
4046  __os << std::format(__os.getloc(), _GLIBCXX_WIDEN("{:L%F %T}"), __tp);
4047  return __os;
4048  }
4049 
4050  template<typename _CharT, typename _Traits>
4051  inline basic_ostream<_CharT, _Traits>&
4052  operator<<(basic_ostream<_CharT, _Traits>& __os, const sys_days& __dp)
4053  {
4054  __os << year_month_day{__dp};
4055  return __os;
4056  }
4057 
4058  template<typename _CharT, typename _Traits, typename _Duration,
4059  typename _Alloc = allocator<_CharT>>
4060  basic_istream<_CharT, _Traits>&
4061  from_stream(basic_istream<_CharT, _Traits>& __is, const _CharT* __fmt,
4062  sys_time<_Duration>& __tp,
4063  basic_string<_CharT, _Traits, _Alloc>* __abbrev = nullptr,
4064  minutes* __offset = nullptr)
4065  {
4066  minutes __off{};
4067  if (!__offset)
4068  __offset = &__off;
4069  using __format::_ChronoParts;
4070  auto __need = _ChronoParts::_Year | _ChronoParts::_Month
4071  | _ChronoParts::_Day | _ChronoParts::_TimeOfDay;
4072  __detail::_Parser_t<_Duration> __p(__need);
4073  if (__p(__is, __fmt, __abbrev, __offset))
4074  {
4075  if (__p._M_is_leap_second)
4076  __is.setstate(ios_base::failbit);
4077  else
4078  {
4079  auto __st = __p._M_sys_days + __p._M_time - *__offset;
4080  __tp = __detail::__round<_Duration>(__st);
4081  }
4082  }
4083  return __is;
4084  }
4085 
4086  template<typename _CharT, typename _Traits, typename _Duration>
4087  inline basic_ostream<_CharT, _Traits>&
4088  operator<<(basic_ostream<_CharT, _Traits>& __os,
4089  const utc_time<_Duration>& __t)
4090  {
4091  __os << std::format(__os.getloc(), _GLIBCXX_WIDEN("{:L%F %T}"), __t);
4092  return __os;
4093  }
4094 
4095  template<typename _CharT, typename _Traits, typename _Duration,
4096  typename _Alloc = allocator<_CharT>>
4097  inline basic_istream<_CharT, _Traits>&
4098  from_stream(basic_istream<_CharT, _Traits>& __is, const _CharT* __fmt,
4099  utc_time<_Duration>& __tp,
4100  basic_string<_CharT, _Traits, _Alloc>* __abbrev = nullptr,
4101  minutes* __offset = nullptr)
4102  {
4103  minutes __off{};
4104  if (!__offset)
4105  __offset = &__off;
4106  using __format::_ChronoParts;
4107  auto __need = _ChronoParts::_Year | _ChronoParts::_Month
4108  | _ChronoParts::_Day | _ChronoParts::_TimeOfDay;
4109  __detail::_Parser_t<_Duration> __p(__need);
4110  if (__p(__is, __fmt, __abbrev, __offset))
4111  {
4112  // Converting to utc_time before adding _M_time is necessary for
4113  // "23:59:60" to correctly produce a time within a leap second.
4114  auto __ut = utc_clock::from_sys(__p._M_sys_days) + __p._M_time
4115  - *__offset;
4116  __tp = __detail::__round<_Duration>(__ut);
4117  }
4118  return __is;
4119  }
4120 
4121  template<typename _CharT, typename _Traits, typename _Duration>
4122  inline basic_ostream<_CharT, _Traits>&
4123  operator<<(basic_ostream<_CharT, _Traits>& __os,
4124  const tai_time<_Duration>& __t)
4125  {
4126  __os << std::format(__os.getloc(), _GLIBCXX_WIDEN("{:L%F %T}"), __t);
4127  return __os;
4128  }
4129 
4130  template<typename _CharT, typename _Traits, typename _Duration,
4131  typename _Alloc = allocator<_CharT>>
4132  inline basic_istream<_CharT, _Traits>&
4133  from_stream(basic_istream<_CharT, _Traits>& __is, const _CharT* __fmt,
4134  tai_time<_Duration>& __tp,
4135  basic_string<_CharT, _Traits, _Alloc>* __abbrev = nullptr,
4136  minutes* __offset = nullptr)
4137  {
4138  minutes __off{};
4139  if (!__offset)
4140  __offset = &__off;
4141  using __format::_ChronoParts;
4142  auto __need = _ChronoParts::_Year | _ChronoParts::_Month
4143  | _ChronoParts::_Day | _ChronoParts::_TimeOfDay;
4144  __detail::_Parser_t<_Duration> __p(__need);
4145  if (__p(__is, __fmt, __abbrev, __offset))
4146  {
4147  if (__p._M_is_leap_second)
4148  __is.setstate(ios_base::failbit);
4149  else
4150  {
4151  constexpr sys_days __epoch(-days(4383)); // 1958y/1/1
4152  auto __d = __p._M_sys_days - __epoch + __p._M_time - *__offset;
4153  tai_time<common_type_t<_Duration, seconds>> __tt(__d);
4154  __tp = __detail::__round<_Duration>(__tt);
4155  }
4156  }
4157  return __is;
4158  }
4159 
4160  template<typename _CharT, typename _Traits, typename _Duration>
4161  inline basic_ostream<_CharT, _Traits>&
4162  operator<<(basic_ostream<_CharT, _Traits>& __os,
4163  const gps_time<_Duration>& __t)
4164  {
4165  __os << std::format(__os.getloc(), _GLIBCXX_WIDEN("{:L%F %T}"), __t);
4166  return __os;
4167  }
4168 
4169  template<typename _CharT, typename _Traits, typename _Duration,
4170  typename _Alloc = allocator<_CharT>>
4171  inline basic_istream<_CharT, _Traits>&
4172  from_stream(basic_istream<_CharT, _Traits>& __is, const _CharT* __fmt,
4173  gps_time<_Duration>& __tp,
4174  basic_string<_CharT, _Traits, _Alloc>* __abbrev = nullptr,
4175  minutes* __offset = nullptr)
4176  {
4177  minutes __off{};
4178  if (!__offset)
4179  __offset = &__off;
4180  using __format::_ChronoParts;
4181  auto __need = _ChronoParts::_YearMonthDay | _ChronoParts::_TimeOfDay;
4182  __detail::_Parser_t<_Duration> __p(__need);
4183  if (__p(__is, __fmt, __abbrev, __offset))
4184  {
4185  if (__p._M_is_leap_second)
4186  __is.setstate(ios_base::failbit);
4187  else
4188  {
4189  constexpr sys_days __epoch(days(3657)); // 1980y/1/Sunday[1]
4190  auto __d = __p._M_sys_days - __epoch + __p._M_time - *__offset;
4191  gps_time<common_type_t<_Duration, seconds>> __gt(__d);
4192  __tp = __detail::__round<_Duration>(__gt);
4193  }
4194  }
4195  return __is;
4196  }
4197 
4198  template<typename _CharT, typename _Traits, typename _Duration>
4199  inline basic_ostream<_CharT, _Traits>&
4200  operator<<(basic_ostream<_CharT, _Traits>& __os,
4201  const file_time<_Duration>& __t)
4202  {
4203  __os << std::format(__os.getloc(), _GLIBCXX_WIDEN("{:L%F %T}"), __t);
4204  return __os;
4205  }
4206 
4207  template<typename _CharT, typename _Traits, typename _Duration,
4208  typename _Alloc = allocator<_CharT>>
4209  inline basic_istream<_CharT, _Traits>&
4210  from_stream(basic_istream<_CharT, _Traits>& __is, const _CharT* __fmt,
4211  file_time<_Duration>& __tp,
4212  basic_string<_CharT, _Traits, _Alloc>* __abbrev = nullptr,
4213  minutes* __offset = nullptr)
4214  {
4215  sys_time<_Duration> __st;
4216  if (chrono::from_stream(__is, __fmt, __st, __abbrev, __offset))
4217  __tp = __detail::__round<_Duration>(file_clock::from_sys(__st));
4218  return __is;
4219  }
4220 
4221  template<typename _CharT, typename _Traits, typename _Duration>
4222  inline basic_ostream<_CharT, _Traits>&
4223  operator<<(basic_ostream<_CharT, _Traits>& __os,
4224  const local_time<_Duration>& __lt)
4225  // _GLIBCXX_RESOLVE_LIB_DEFECTS
4226  // 4257. Stream insertion for chrono::local_time should be constrained
4227  requires requires(const sys_time<_Duration>& __st) { __os << __st; }
4228  {
4229  __os << sys_time<_Duration>{__lt.time_since_epoch()};
4230  return __os;
4231  }
4232 
4233  template<typename _CharT, typename _Traits, typename _Duration,
4234  typename _Alloc = allocator<_CharT>>
4235  basic_istream<_CharT, _Traits>&
4236  from_stream(basic_istream<_CharT, _Traits>& __is, const _CharT* __fmt,
4237  local_time<_Duration>& __tp,
4238  basic_string<_CharT, _Traits, _Alloc>* __abbrev = nullptr,
4239  minutes* __offset = nullptr)
4240  {
4241  using __format::_ChronoParts;
4242  auto __need = _ChronoParts::_YearMonthDay | _ChronoParts::_TimeOfDay;
4243  __detail::_Parser_t<_Duration> __p(__need);
4244  if (__p(__is, __fmt, __abbrev, __offset))
4245  {
4246  days __d = __p._M_sys_days.time_since_epoch();
4247  auto __t = local_days(__d) + __p._M_time; // ignore offset
4248  __tp = __detail::__round<_Duration>(__t);
4249  }
4250  return __is;
4251  }
4252 
4253  // [time.parse] parsing
4254 
4255 namespace __detail
4256 {
4257  // _GLIBCXX_RESOLVE_LIB_DEFECTS
4258  // 3956. chrono::parse uses from_stream as a customization point
4259  void from_stream() = delete;
4260 
4261  template<typename _Parsable, typename _CharT,
4262  typename _Traits = std::char_traits<_CharT>,
4263  typename... _OptArgs>
4264  concept __parsable = requires (basic_istream<_CharT, _Traits>& __is,
4265  const _CharT* __fmt, _Parsable& __tp,
4266  _OptArgs*... __args)
4267  { from_stream(__is, __fmt, __tp, __args...); };
4268 
4269  template<typename _Parsable, typename _CharT,
4270  typename _Traits = char_traits<_CharT>,
4271  typename _Alloc = allocator<_CharT>>
4272  struct _Parse
4273  {
4274  private:
4275  using __string_type = basic_string<_CharT, _Traits, _Alloc>;
4276 
4277  public:
4278  _Parse(const _CharT* __fmt, _Parsable& __tp,
4279  basic_string<_CharT, _Traits, _Alloc>* __abbrev = nullptr,
4280  minutes* __offset = nullptr)
4281  : _M_fmt(__fmt), _M_tp(std::__addressof(__tp)),
4282  _M_abbrev(__abbrev), _M_offset(__offset)
4283  { }
4284 
4285  _Parse(_Parse&&) = delete;
4286  _Parse& operator=(_Parse&&) = delete;
4287 
4288  private:
4289  using __stream_type = basic_istream<_CharT, _Traits>;
4290 
4291  const _CharT* const _M_fmt;
4292  _Parsable* const _M_tp;
4293  __string_type* const _M_abbrev;
4294  minutes* const _M_offset;
4295 
4296  friend __stream_type&
4297  operator>>(__stream_type& __is, _Parse&& __p)
4298  {
4299  if (__p._M_offset)
4300  from_stream(__is, __p._M_fmt, *__p._M_tp, __p._M_abbrev,
4301  __p._M_offset);
4302  else if (__p._M_abbrev)
4303  from_stream(__is, __p._M_fmt, *__p._M_tp, __p._M_abbrev);
4304  else
4305  from_stream(__is, __p._M_fmt, *__p._M_tp);
4306  return __is;
4307  }
4308 
4309  friend void operator>>(__stream_type&, _Parse&) = delete;
4310  friend void operator>>(__stream_type&, const _Parse&) = delete;
4311  };
4312 } // namespace __detail
4313 
4314  template<typename _CharT, __detail::__parsable<_CharT> _Parsable>
4315  [[nodiscard, __gnu__::__access__(__read_only__, 1)]]
4316  inline auto
4317  parse(const _CharT* __fmt, _Parsable& __tp)
4318  { return __detail::_Parse<_Parsable, _CharT>(__fmt, __tp); }
4319 
4320  template<typename _CharT, typename _Traits, typename _Alloc,
4321  __detail::__parsable<_CharT, _Traits> _Parsable>
4322  [[nodiscard]]
4323  inline auto
4324  parse(const basic_string<_CharT, _Traits, _Alloc>& __fmt, _Parsable& __tp)
4325  {
4326  return __detail::_Parse<_Parsable, _CharT, _Traits>(__fmt.c_str(), __tp);
4327  }
4328 
4329  template<typename _CharT, typename _Traits, typename _Alloc,
4330  typename _StrT = basic_string<_CharT, _Traits, _Alloc>,
4331  __detail::__parsable<_CharT, _Traits, _StrT> _Parsable>
4332  [[nodiscard, __gnu__::__access__(__read_only__, 1)]]
4333  inline auto
4334  parse(const _CharT* __fmt, _Parsable& __tp,
4335  basic_string<_CharT, _Traits, _Alloc>& __abbrev)
4336  {
4337  auto __pa = std::__addressof(__abbrev);
4338  return __detail::_Parse<_Parsable, _CharT, _Traits, _Alloc>(__fmt, __tp,
4339  __pa);
4340  }
4341 
4342  template<typename _CharT, typename _Traits, typename _Alloc,
4343  typename _StrT = basic_string<_CharT, _Traits, _Alloc>,
4344  __detail::__parsable<_CharT, _Traits, _StrT> _Parsable>
4345  [[nodiscard]]
4346  inline auto
4347  parse(const basic_string<_CharT, _Traits, _Alloc>& __fmt, _Parsable& __tp,
4348  basic_string<_CharT, _Traits, _Alloc>& __abbrev)
4349  {
4350  auto __pa = std::__addressof(__abbrev);
4351  return __detail::_Parse<_Parsable, _CharT, _Traits, _Alloc>(__fmt.c_str(),
4352  __tp, __pa);
4353  }
4354 
4355  template<typename _CharT, typename _Traits = char_traits<_CharT>,
4356  typename _StrT = basic_string<_CharT, _Traits>,
4357  __detail::__parsable<_CharT, _Traits, _StrT, minutes> _Parsable>
4358  [[nodiscard, __gnu__::__access__(__read_only__, 1)]]
4359  inline auto
4360  parse(const _CharT* __fmt, _Parsable& __tp, minutes& __offset)
4361  {
4362  return __detail::_Parse<_Parsable, _CharT>(__fmt, __tp, nullptr,
4363  &__offset);
4364  }
4365 
4366  template<typename _CharT, typename _Traits, typename _Alloc,
4367  typename _StrT = basic_string<_CharT, _Traits>,
4368  __detail::__parsable<_CharT, _Traits, _StrT, minutes> _Parsable>
4369  [[nodiscard]]
4370  inline auto
4371  parse(const basic_string<_CharT, _Traits, _Alloc>& __fmt, _Parsable& __tp,
4372  minutes& __offset)
4373  {
4374  return __detail::_Parse<_Parsable, _CharT, _Traits, _Alloc>(__fmt.c_str(),
4375  __tp, nullptr,
4376  &__offset);
4377  }
4378 
4379  template<typename _CharT, typename _Traits, typename _Alloc,
4380  typename _StrT = basic_string<_CharT, _Traits, _Alloc>,
4381  __detail::__parsable<_CharT, _Traits, _StrT, minutes> _Parsable>
4382  [[nodiscard, __gnu__::__access__(__read_only__, 1)]]
4383  inline auto
4384  parse(const _CharT* __fmt, _Parsable& __tp,
4385  basic_string<_CharT, _Traits, _Alloc>& __abbrev, minutes& __offset)
4386  {
4387  auto __pa = std::__addressof(__abbrev);
4388  return __detail::_Parse<_Parsable, _CharT, _Traits, _Alloc>(__fmt, __tp,
4389  __pa,
4390  &__offset);
4391  }
4392 
4393  template<typename _CharT, typename _Traits, typename _Alloc,
4394  typename _StrT = basic_string<_CharT, _Traits, _Alloc>,
4395  __detail::__parsable<_CharT, _Traits, _StrT, minutes> _Parsable>
4396  [[nodiscard]]
4397  inline auto
4398  parse(const basic_string<_CharT, _Traits, _Alloc>& __fmt, _Parsable& __tp,
4399  basic_string<_CharT, _Traits, _Alloc>& __abbrev, minutes& __offset)
4400  {
4401  auto __pa = std::__addressof(__abbrev);
4402  return __detail::_Parse<_Parsable, _CharT, _Traits, _Alloc>(__fmt.c_str(),
4403  __tp, __pa,
4404  &__offset);
4405  }
4406 
4407  /// @cond undocumented
4408  template<typename _Duration>
4409  template<typename _CharT, typename _Traits, typename _Alloc>
4410  basic_istream<_CharT, _Traits>&
4411  __detail::_Parser<_Duration>::
4412  operator()(basic_istream<_CharT, _Traits>& __is, const _CharT* __fmt,
4413  basic_string<_CharT, _Traits, _Alloc>* __abbrev,
4414  minutes* __offset)
4415  {
4416  using sentry = typename basic_istream<_CharT, _Traits>::sentry;
4417  ios_base::iostate __err = ios_base::goodbit;
4418  if (sentry __cerb(__is, true); __cerb)
4419  {
4420  locale __loc = __is.getloc();
4421  auto& __tmget = std::use_facet<std::time_get<_CharT>>(__loc);
4422  auto& __tmpunct = std::use_facet<std::__timepunct<_CharT>>(__loc);
4423 
4424  // RAII type to save and restore stream state.
4425  struct _Stream_state
4426  {
4427  explicit
4428  _Stream_state(basic_istream<_CharT, _Traits>& __i)
4429  : _M_is(__i),
4430  _M_flags(__i.flags(ios_base::skipws | ios_base::dec)),
4431  _M_w(__i.width(0))
4432  { }
4433 
4434  ~_Stream_state()
4435  {
4436  _M_is.flags(_M_flags);
4437  _M_is.width(_M_w);
4438  }
4439 
4440  _Stream_state(_Stream_state&&) = delete;
4441 
4442  basic_istream<_CharT, _Traits>& _M_is;
4443  ios_base::fmtflags _M_flags;
4444  streamsize _M_w;
4445  };
4446 
4447  auto __is_failed = [](ios_base::iostate __e) {
4448  return static_cast<bool>(__e & ios_base::failbit);
4449  };
4450 
4451  // Read an unsigned integer from the stream and return it.
4452  // Extract no more than __n digits. Set __err on error.
4453  auto __read_unsigned = [&] (int __n) {
4454  return _S_read_unsigned(__is, __err, __n);
4455  };
4456 
4457  // Read a signed integer from the stream and return it.
4458  // Extract no more than __n digits. Set __err on error.
4459  auto __read_signed = [&] (int __n) {
4460  return _S_read_signed(__is, __err, __n);
4461  };
4462 
4463  // Read an expected character from the stream.
4464  auto __read_chr = [&__is, &__err] (_CharT __c) {
4465  return _S_read_chr(__is, __err, __c);
4466  };
4467 
4468  using __format::_ChronoParts;
4469  _ChronoParts __parts{};
4470 
4471  const year __bad_y = --year::min(); // SHRT_MIN
4472  const month __bad_mon(255);
4473  const day __bad_day(255);
4474  const weekday __bad_wday(255);
4475  const hours __bad_h(-1);
4476  const minutes __bad_min(-9999);
4477  const seconds __bad_sec(-1);
4478 
4479  year __y = __bad_y, __yy = __bad_y; // %Y, %yy
4480  year __iso_y = __bad_y, __iso_yy = __bad_y; // %G, %g
4481  month __m = __bad_mon; // %m
4482  day __d = __bad_day; // %d
4483  weekday __wday = __bad_wday; // %a %A %u %w
4484  hours __h = __bad_h, __h12 = __bad_h; // %H, %I
4485  minutes __min = __bad_min; // %M
4486  _Duration __s = __bad_sec; // %S
4487  int __ampm = 0; // %p
4488  int __iso_wk = -1, __sunday_wk = -1, __monday_wk = -1; // %V, %U, %W
4489  int __century = -1; // %C
4490  int __dayofyear = -1; // %j (for non-duration)
4491 
4492  minutes __tz_offset = __bad_min;
4493  basic_string<_CharT, _Traits> __tz_abbr;
4494 
4495  if ((_M_need & _ChronoParts::_TimeOfDay) != 0
4496  && (_M_need & _ChronoParts::_Year) != 0)
4497  {
4498  // For time_points assume "00:00:00" is implicitly present,
4499  // so we don't fail to parse if it's not (PR libstdc++/114240).
4500  // We will still fail to parse if there's no year+month+day.
4501  __h = hours(0);
4502  __parts = _ChronoParts::_TimeOfDay;
4503  }
4504 
4505  // bool __is_neg = false; // TODO: how is this handled for parsing?
4506 
4507  _CharT __mod{}; // One of 'E' or 'O' or nul.
4508  unsigned __num = 0; // Non-zero for N modifier.
4509  bool __is_flag = false; // True if we're processing a % flag.
4510 
4511  constexpr bool __is_floating
4512  = treat_as_floating_point_v<typename _Duration::rep>;
4513 
4514  // If an out-of-range value is extracted (e.g. 61min for %M),
4515  // do not set failbit immediately because we might not need it
4516  // (e.g. parsing chrono::year doesn't care about invalid %M values).
4517  // Instead set the variable back to its initial 'bad' state,
4518  // and also set related variables corresponding to the same field
4519  // (e.g. a bad %M value for __min should also reset __h and __s).
4520  // If a valid value is needed later the bad value will cause failure.
4521 
4522  // For some fields we don't know the correct range when parsing and
4523  // we have to be liberal in what we accept, e.g. we allow 366 for
4524  // day-of-year because that's valid in leap years, and we allow 31
4525  // for day-of-month. If those values are needed to determine the
4526  // result then we can do a correct range check at the end when we
4527  // know the how many days the relevant year or month actually has.
4528 
4529  while (*__fmt)
4530  {
4531  _CharT __c = *__fmt++;
4532  if (!__is_flag)
4533  {
4534  if (__c == '%')
4535  __is_flag = true; // This is the start of a flag.
4536  else if (std::isspace(__c, __loc))
4537  std::ws(__is); // Match zero or more whitespace characters.
4538  else if (!__read_chr(__c)) [[unlikely]]
4539  break; // Failed to match the expected character.
4540 
4541  continue; // Process next character in the format string.
4542  }
4543 
4544  // Now processing a flag.
4545  switch (__c)
4546  {
4547  case 'a': // Locale's weekday name
4548  case 'A': // (full or abbreviated, matched case-insensitively).
4549  if (__mod || __num) [[unlikely]]
4550  __err = ios_base::failbit;
4551  else
4552  {
4553  struct tm __tm{};
4554  __tmget.get(__is, {}, __is, __err, &__tm,
4555  __fmt - 2, __fmt);
4556  if (!__is_failed(__err))
4557  __wday = weekday(__tm.tm_wday);
4558  }
4559  __parts |= _ChronoParts::_Weekday;
4560  break;
4561 
4562  case 'b': // Locale's month name
4563  case 'h': // (full or abbreviated, matched case-insensitively).
4564  case 'B':
4565  if (__mod || __num) [[unlikely]]
4566  __err = ios_base::failbit;
4567  else
4568  {
4569  // strptime behaves differently for %b and %B,
4570  // but chrono::parse says they're equivalent.
4571  // Luckily libstdc++ std::time_get works as needed.
4572  struct tm __tm{};
4573  __tmget.get(__is, {}, __is, __err, &__tm,
4574  __fmt - 2, __fmt);
4575  if (!__is_failed(__err))
4576  __m = month(__tm.tm_mon + 1);
4577  }
4578  __parts |= _ChronoParts::_Month;
4579  break;
4580 
4581  case 'c': // Locale's date and time representation.
4582  if (__mod == 'O' || __num) [[unlikely]]
4583  __err |= ios_base::failbit;
4584  else
4585  {
4586  struct tm __tm{};
4587  __tmget.get(__is, {}, __is, __err, &__tm,
4588  __fmt - 2 - (__mod == 'E'), __fmt);
4589  if (!__is_failed(__err))
4590  {
4591  __y = year(__tm.tm_year + 1900);
4592  __m = month(__tm.tm_mon + 1);
4593  __d = day(__tm.tm_mday);
4594  __h = hours(__tm.tm_hour);
4595  __min = minutes(__tm.tm_min);
4596  __s = seconds(__tm.tm_sec);
4597  }
4598  }
4599  __parts |= _ChronoParts::_DateTime;
4600  break;
4601 
4602  case 'C': // Century
4603  if (!__mod) [[likely]]
4604  {
4605  auto __v = __read_signed(__num ? __num : 2);
4606  if (!__is_failed(__err))
4607  {
4608  int __cmin = (int)year::min() / 100;
4609  int __cmax = (int)year::max() / 100;
4610  if (__cmin <= __v && __v <= __cmax)
4611  __century = __v * 100;
4612  else
4613  __century = -2; // This prevents guessing century.
4614  }
4615  }
4616  else if (__mod == 'E')
4617  {
4618  struct tm __tm{};
4619  __tmget.get(__is, {}, __is, __err, &__tm,
4620  __fmt - 3, __fmt);
4621  if (!__is_failed(__err))
4622  __century = __tm.tm_year;
4623  }
4624  else [[unlikely]]
4625  __err |= ios_base::failbit;
4626  // N.B. don't set this here: __parts |= _ChronoParts::_Year;
4627  break;
4628 
4629  case 'd': // Day of month (1-31)
4630  case 'e':
4631  if (!__mod) [[likely]]
4632  {
4633  auto __v = __read_unsigned(__num ? __num : 2);
4634  if (!__is_failed(__err))
4635  __d = day(__v);
4636  }
4637  else if (__mod == 'O')
4638  {
4639  struct tm __tm{};
4640  __tmget.get(__is, {}, __is, __err, &__tm,
4641  __fmt - 3, __fmt);
4642  if (!__is_failed(__err))
4643  __d = day(__tm.tm_mday);
4644  }
4645  else [[unlikely]]
4646  __err |= ios_base::failbit;
4647  __parts |= _ChronoParts::_Day;
4648  break;
4649 
4650  case 'D': // %m/%d/%y
4651  if (__mod || __num) [[unlikely]]
4652  __err |= ios_base::failbit;
4653  else
4654  {
4655  auto __month = __read_unsigned(2); // %m
4656  __read_chr('/');
4657  auto __day = __read_unsigned(2); // %d
4658  __read_chr('/');
4659  auto __year = __read_unsigned(2); // %y
4660  if (__is_failed(__err))
4661  break;
4662  __y = year(__year + 1900 + 100 * int(__year < 69));
4663  __m = month(__month);
4664  __d = day(__day);
4665  if (!year_month_day(__y, __m, __d).ok())
4666  {
4667  __y = __yy = __iso_y = __iso_yy = __bad_y;
4668  __m = __bad_mon;
4669  __d = __bad_day;
4670  break;
4671  }
4672  }
4673  __parts |= _ChronoParts::_Date;
4674  break;
4675 
4676  case 'F': // %Y-%m-%d - any N modifier only applies to %Y.
4677  if (__mod) [[unlikely]]
4678  __err |= ios_base::failbit;
4679  else
4680  {
4681  auto __year = __read_signed(__num ? __num : 4); // %Y
4682  __read_chr('-');
4683  auto __month = __read_unsigned(2); // %m
4684  __read_chr('-');
4685  auto __day = __read_unsigned(2); // %d
4686  if (__is_failed(__err))
4687  break;
4688  __y = year(__year);
4689  __m = month(__month);
4690  __d = day(__day);
4691  if (!year_month_day(__y, __m, __d).ok())
4692  {
4693  __y = __yy = __iso_y = __iso_yy = __bad_y;
4694  __m = __bad_mon;
4695  __d = __bad_day;
4696  break;
4697  }
4698  }
4699  __parts |= _ChronoParts::_Date;
4700  break;
4701 
4702  case 'g': // Last two digits of ISO week-based year.
4703  if (__mod) [[unlikely]]
4704  __err |= ios_base::failbit;
4705  else
4706  {
4707  auto __val = __read_unsigned(__num ? __num : 2);
4708  if (__val >= 0 && __val <= 99)
4709  {
4710  __iso_yy = year(__val);
4711  if (__century == -1) // No %C has been parsed yet.
4712  __century = 2000;
4713  }
4714  else
4715  __iso_yy = __iso_y = __y = __yy = __bad_y;
4716  }
4717  __parts |= _ChronoParts::_Year;
4718  break;
4719 
4720  case 'G': // ISO week-based year.
4721  if (__mod) [[unlikely]]
4722  __err |= ios_base::failbit;
4723  else
4724  __iso_y = year(__read_unsigned(__num ? __num : 4));
4725  __parts |= _ChronoParts::_Year;
4726  break;
4727 
4728  case 'H': // 24-hour (00-23)
4729  case 'I': // 12-hour (1-12)
4730  if (__mod == 'E') [[unlikely]]
4731  __err |= ios_base::failbit;
4732  else if (__mod == 'O')
4733  {
4734 #if 0
4735  struct tm __tm{};
4736  __tm.tm_ampm = 1;
4737  __tmget.get(__is, {}, __is, __err, &__tm,
4738  __fmt - 3, __fmt);
4739  if (!__is_failed(__err))
4740  {
4741  if (__c == 'I')
4742  {
4743  __h12 = hours(__tm.tm_hour);
4744  __h = __bad_h;
4745  }
4746  else
4747  __h = hours(__tm.tm_hour);
4748  }
4749 #else
4750  // XXX %OI seems to be unimplementable.
4751  __err |= ios_base::failbit;
4752 #endif
4753  }
4754  else
4755  {
4756  auto __val = __read_unsigned(__num ? __num : 2);
4757  if (__c == 'I' && __val >= 1 && __val <= 12)
4758  {
4759  __h12 = hours(__val);
4760  __h = __bad_h;
4761  }
4762  else if (__c == 'H' && __val >= 0 && __val <= 23)
4763  {
4764  __h = hours(__val);
4765  __h12 = __bad_h;
4766  }
4767  else
4768  {
4769  if ((_M_need & _ChronoParts::_TimeOfDay) != 0)
4770  __err |= ios_base::failbit;
4771  break;
4772  }
4773  }
4774  __parts |= _ChronoParts::_TimeOfDay;
4775  break;
4776 
4777  case 'j': // For duration, count of days, otherwise day of year
4778  if (__mod) [[unlikely]]
4779  __err |= ios_base::failbit;
4780  else if (_M_need == _ChronoParts::_TimeOfDay) // duration
4781  {
4782  auto __val = __read_signed(__num ? __num : 3);
4783  if (!__is_failed(__err))
4784  {
4785  __h = days(__val); // __h will get added to _M_time
4786  __parts |= _ChronoParts::_TimeOfDay;
4787  }
4788  }
4789  else
4790  {
4791  __dayofyear = __read_unsigned(__num ? __num : 3);
4792  // N.B. do not alter __parts here, done after loop.
4793  // No need for range checking here either.
4794  }
4795  break;
4796 
4797  case 'm': // Month (1-12)
4798  if (__mod == 'E') [[unlikely]]
4799  __err |= ios_base::failbit;
4800  else if (__mod == 'O')
4801  {
4802  struct tm __tm{};
4803  __tmget.get(__is, {}, __is, __err, &__tm,
4804  __fmt - 2, __fmt);
4805  if (!__is_failed(__err))
4806  __m = month(__tm.tm_mon + 1);
4807  }
4808  else
4809  {
4810  auto __val = __read_unsigned(__num ? __num : 2);
4811  if (__val >= 1 && __val <= 12)
4812  __m = month(__val);
4813  else
4814  __m = __bad_mon;
4815  }
4816  __parts |= _ChronoParts::_Month;
4817  break;
4818 
4819  case 'M': // Minutes
4820  if (__mod == 'E') [[unlikely]]
4821  __err |= ios_base::failbit;
4822  else if (__mod == 'O')
4823  {
4824  struct tm __tm{};
4825  __tmget.get(__is, {}, __is, __err, &__tm,
4826  __fmt - 2, __fmt);
4827  if (!__is_failed(__err))
4828  __min = minutes(__tm.tm_min);
4829  }
4830  else
4831  {
4832  auto __val = __read_unsigned(__num ? __num : 2);
4833  if (0 <= __val && __val < 60)
4834  __min = minutes(__val);
4835  else
4836  {
4837  if ((_M_need & _ChronoParts::_TimeOfDay) != 0)
4838  __err |= ios_base::failbit;
4839  break;
4840  }
4841  }
4842  __parts |= _ChronoParts::_TimeOfDay;
4843  break;
4844 
4845  case 'p': // Locale's AM/PM designation for 12-hour clock.
4846  if (__mod || __num)
4847  __err |= ios_base::failbit;
4848  else
4849  {
4850  // Can't use std::time_get here as it can't parse %p
4851  // in isolation without %I. This might be faster anyway.
4852  const _CharT* __ampms[2];
4853  __tmpunct._M_am_pm(__ampms);
4854  int __n = 0, __which = 3;
4855  while (__which != 0)
4856  {
4857  auto __i = __is.peek();
4858  if (_Traits::eq_int_type(__i, _Traits::eof()))
4859  {
4860  __err |= ios_base::eofbit | ios_base::failbit;
4861  break;
4862  }
4863  __i = std::toupper(_Traits::to_char_type(__i), __loc);
4864  if (__which & 1)
4865  {
4866  if (__i != std::toupper(__ampms[0][__n], __loc))
4867  __which ^= 1;
4868  else if (__ampms[0][__n + 1] == _CharT())
4869  {
4870  __which = 1;
4871  (void) __is.get();
4872  break;
4873  }
4874  }
4875  if (__which & 2)
4876  {
4877  if (__i != std::toupper(__ampms[1][__n], __loc))
4878  __which ^= 2;
4879  else if (__ampms[1][__n + 1] == _CharT())
4880  {
4881  __which = 2;
4882  (void) __is.get();
4883  break;
4884  }
4885  }
4886  if (__which)
4887  (void) __is.get();
4888  ++__n;
4889  }
4890  if (__which == 0 || __which == 3)
4891  __err |= ios_base::failbit;
4892  else
4893  __ampm = __which;
4894  }
4895  break;
4896 
4897  case 'r': // Locale's 12-hour time.
4898  if (__mod || __num)
4899  __err |= ios_base::failbit;
4900  else
4901  {
4902  struct tm __tm{};
4903  __tmget.get(__is, {}, __is, __err, &__tm,
4904  __fmt - 2, __fmt);
4905  if (!__is_failed(__err))
4906  {
4907  __h = hours(__tm.tm_hour);
4908  __min = minutes(__tm.tm_min);
4909  __s = seconds(__tm.tm_sec);
4910  }
4911  }
4912  __parts |= _ChronoParts::_TimeOfDay;
4913  break;
4914 
4915  case 'R': // %H:%M
4916  case 'T': // %H:%M:%S
4917  if (__mod || __num) [[unlikely]]
4918  {
4919  __err |= ios_base::failbit;
4920  break;
4921  }
4922  else
4923  {
4924  auto __val = __read_unsigned(2);
4925  if (__val == -1 || __val > 23) [[unlikely]]
4926  {
4927  if ((_M_need & _ChronoParts::_TimeOfDay) != 0)
4928  __err |= ios_base::failbit;
4929  break;
4930  }
4931  if (!__read_chr(':')) [[unlikely]]
4932  break;
4933  __h = hours(__val);
4934 
4935  __val = __read_unsigned(2);
4936  if (__val == -1 || __val > 60) [[unlikely]]
4937  {
4938  if ((_M_need & _ChronoParts::_TimeOfDay) != 0)
4939  __err |= ios_base::failbit;
4940  break;
4941  }
4942  __min = minutes(__val);
4943 
4944  if (__c == 'R')
4945  {
4946  __parts |= _ChronoParts::_TimeOfDay;
4947  break;
4948  }
4949  else if (!__read_chr(':')) [[unlikely]]
4950  break;
4951  }
4952  [[fallthrough]];
4953 
4954  case 'S': // Seconds
4955  if (__mod == 'E') [[unlikely]]
4956  __err |= ios_base::failbit;
4957  else if (__mod == 'O')
4958  {
4959  struct tm __tm{};
4960  __tmget.get(__is, {}, __is, __err, &__tm,
4961  __fmt - 3, __fmt);
4962  if (!__is_failed(__err))
4963  __s = seconds(__tm.tm_sec);
4964  }
4965  else if constexpr (_Duration::period::den == 1
4966  && !__is_floating)
4967  {
4968  auto __val = __read_unsigned(__num ? __num : 2);
4969  if (0 <= __val && __val <= 59) [[likely]]
4970  __s = seconds(__val);
4971  else
4972  {
4973  if ((_M_need & _ChronoParts::_TimeOfDay) != 0)
4974  __err |= ios_base::failbit;
4975  break;
4976  }
4977  }
4978  else // Read fractional seconds
4979  {
4980  stringstream __buf;
4981  auto __digit = _S_try_read_digit(__is, __err);
4982  if (__digit != -1)
4983  {
4984  __buf.put('0' + __digit);
4985  __digit = _S_try_read_digit(__is, __err);
4986  if (__digit != -1)
4987  __buf.put('0' + __digit);
4988  }
4989 
4990  auto __i = __is.peek();
4991  if (_Traits::eq_int_type(__i, _Traits::eof()))
4992  __err |= ios_base::eofbit;
4993  else
4994  {
4995  _CharT __dp = '.';
4996  if (__loc != locale::classic())
4997  {
4998  auto& __np = use_facet<numpunct<_CharT>>(__loc);
4999  __dp = __np.decimal_point();
5000  }
5001  _CharT __c = _Traits::to_char_type(__i);
5002  if (__c == __dp)
5003  {
5004  (void) __is.get();
5005  __buf.put('.');
5006  int __prec
5007  = hh_mm_ss<_Duration>::fractional_width;
5008  do
5009  {
5010  __digit = _S_try_read_digit(__is, __err);
5011  if (__digit != -1)
5012  __buf.put('0' + __digit);
5013  else
5014  break;
5015  }
5016  while (--__prec);
5017  }
5018  }
5019 
5020  if (!__is_failed(__err)) [[likely]]
5021  {
5022  long double __val{};
5023 #if __cpp_lib_to_chars
5024  string __str = std::move(__buf).str();
5025  auto __first = __str.data();
5026  auto __last = __first + __str.size();
5027  using enum chars_format;
5028  auto [ptr, ec] = std::from_chars(__first, __last,
5029  __val, fixed);
5030  if ((bool)ec || ptr != __last) [[unlikely]]
5031  __err |= ios_base::failbit;
5032  else
5033 #else
5034  if (__buf >> __val)
5035 #endif
5036  {
5037  duration<long double> __fs(__val);
5038  if constexpr (__is_floating)
5039  __s = __fs;
5040  else
5041  __s = chrono::round<_Duration>(__fs);
5042  }
5043  }
5044  }
5045  __parts |= _ChronoParts::_TimeOfDay;
5046  break;
5047 
5048  case 'u': // ISO weekday (1-7)
5049  case 'w': // Weekday (0-6)
5050  if (__mod == 'E') [[unlikely]]
5051  __err |= ios_base::failbit;
5052  else if (__mod == 'O')
5053  {
5054  if (__c == 'w')
5055  {
5056  struct tm __tm{};
5057  __tmget.get(__is, {}, __is, __err, &__tm,
5058  __fmt - 3, __fmt);
5059  if (!__is_failed(__err))
5060  __wday = weekday(__tm.tm_wday);
5061  }
5062  else
5063  __err |= ios_base::failbit;
5064  }
5065  else
5066  {
5067  const int __lo = __c == 'u' ? 1 : 0;
5068  const int __hi = __lo + 6;
5069  auto __val = __read_unsigned(__num ? __num : 1);
5070  if (__lo <= __val && __val <= __hi)
5071  __wday = weekday(__val);
5072  else
5073  {
5074  __wday = __bad_wday;
5075  break;
5076  }
5077  }
5078  __parts |= _ChronoParts::_Weekday;
5079  break;
5080 
5081  case 'U': // Week number of the year (from first Sunday).
5082  case 'V': // ISO week-based week number.
5083  case 'W': // Week number of the year (from first Monday).
5084  if (__mod == 'E') [[unlikely]]
5085  __err |= ios_base::failbit;
5086  else if (__mod == 'O')
5087  {
5088  if (__c == 'V') [[unlikely]]
5089  __err |= ios_base::failbit;
5090  else
5091  {
5092  // TODO nl_langinfo_l(ALT_DIGITS) ?
5093  // Not implementable using std::time_get.
5094  }
5095  }
5096  else
5097  {
5098  const int __lo = __c == 'V' ? 1 : 0;
5099  const int __hi = 53;
5100  auto __val = __read_unsigned(__num ? __num : 2);
5101  if (__lo <= __val && __val <= __hi)
5102  {
5103  switch (__c)
5104  {
5105  case 'U':
5106  __sunday_wk = __val;
5107  break;
5108  case 'V':
5109  __iso_wk = __val;
5110  break;
5111  case 'W':
5112  __monday_wk = __val;
5113  break;
5114  }
5115  }
5116  else
5117  __iso_wk = __sunday_wk = __monday_wk = -1;
5118  }
5119  // N.B. do not alter __parts here, done after loop.
5120  break;
5121 
5122  case 'x': // Locale's date representation.
5123  if (__mod == 'O' || __num) [[unlikely]]
5124  __err |= ios_base::failbit;
5125  else
5126  {
5127  struct tm __tm{};
5128  __tmget.get(__is, {}, __is, __err, &__tm,
5129  __fmt - 2 - (__mod == 'E'), __fmt);
5130  if (!__is_failed(__err))
5131  {
5132  __y = year(__tm.tm_year + 1900);
5133  __m = month(__tm.tm_mon + 1);
5134  __d = day(__tm.tm_mday);
5135  }
5136  }
5137  __parts |= _ChronoParts::_Date;
5138  break;
5139 
5140  case 'X': // Locale's time representation.
5141  if (__mod == 'O' || __num) [[unlikely]]
5142  __err |= ios_base::failbit;
5143  else
5144  {
5145  struct tm __tm{};
5146  __tmget.get(__is, {}, __is, __err, &__tm,
5147  __fmt - 2 - (__mod == 'E'), __fmt);
5148  if (!__is_failed(__err))
5149  {
5150  __h = hours(__tm.tm_hour);
5151  __min = minutes(__tm.tm_min);
5152  __s = seconds(__tm.tm_sec);
5153  }
5154  }
5155  __parts |= _ChronoParts::_TimeOfDay;
5156  break;
5157 
5158  case 'y': // Last two digits of year.
5159  if (__mod) [[unlikely]]
5160  {
5161  struct tm __tm{};
5162  __tmget.get(__is, {}, __is, __err, &__tm,
5163  __fmt - 3, __fmt);
5164  if (!__is_failed(__err))
5165  {
5166  int __cent = __tm.tm_year < 2000 ? 1900 : 2000;
5167  __yy = year(__tm.tm_year - __cent);
5168  if (__century == -1) // No %C has been parsed yet.
5169  __century = __cent;
5170  }
5171  }
5172  else
5173  {
5174  auto __val = __read_unsigned(__num ? __num : 2);
5175  if (__val >= 0 && __val <= 99)
5176  {
5177  __yy = year(__val);
5178  if (__century == -1) // No %C has been parsed yet.
5179  __century = __val < 69 ? 2000 : 1900;
5180  }
5181  else
5182  __y = __yy = __iso_yy = __iso_y = __bad_y;
5183  }
5184  __parts |= _ChronoParts::_Year;
5185  break;
5186 
5187  case 'Y': // Year
5188  if (__mod == 'O') [[unlikely]]
5189  __err |= ios_base::failbit;
5190  else if (__mod == 'E')
5191  {
5192  struct tm __tm{};
5193  __tmget.get(__is, {}, __is, __err, &__tm,
5194  __fmt - 3, __fmt);
5195  if (!__is_failed(__err))
5196  __y = year(__tm.tm_year);
5197  }
5198  else
5199  {
5200  auto __val = __read_unsigned(__num ? __num : 4);
5201  if (!__is_failed(__err))
5202  __y = year(__val);
5203  }
5204  __parts |= _ChronoParts::_Year;
5205  break;
5206 
5207  case 'z':
5208  if (__num) [[unlikely]]
5209  __err |= ios_base::failbit;
5210  else
5211  {
5212  // For %Ez and %Oz read [+|-][h]h[:mm].
5213  // For %z read [+|-]hh[mm].
5214 
5215  auto __i = __is.peek();
5216  if (_Traits::eq_int_type(__i, _Traits::eof()))
5217  {
5218  __err |= ios_base::eofbit | ios_base::failbit;
5219  break;
5220  }
5221  _CharT __ic = _Traits::to_char_type(__i);
5222  const bool __neg = __ic == _CharT('-');
5223  if (__ic == _CharT('-') || __ic == _CharT('+'))
5224  (void) __is.get();
5225 
5226  int_least32_t __hh;
5227  if (__mod)
5228  {
5229  // Read h[h]
5230  __hh = __read_unsigned(2);
5231  }
5232  else
5233  {
5234  // Read hh
5235  __hh = 10 * _S_try_read_digit(__is, __err);
5236  __hh += _S_try_read_digit(__is, __err);
5237  }
5238 
5239  if (__is_failed(__err))
5240  break;
5241 
5242  __i = __is.peek();
5243  if (_Traits::eq_int_type(__i, _Traits::eof()))
5244  {
5245  __err |= ios_base::eofbit;
5246  __tz_offset = minutes(__hh * (__neg ? -60 : 60));
5247  break;
5248  }
5249  __ic = _Traits::to_char_type(__i);
5250 
5251  bool __read_mm = false;
5252  if (__mod)
5253  {
5254  if (__ic == _GLIBCXX_WIDEN(":")[0])
5255  {
5256  // Read [:mm] part.
5257  (void) __is.get();
5258  __read_mm = true;
5259  }
5260  }
5261  else if (_CharT('0') <= __ic && __ic <= _CharT('9'))
5262  {
5263  // Read [mm] part.
5264  __read_mm = true;
5265  }
5266 
5267  int_least32_t __mm = 0;
5268  if (__read_mm)
5269  {
5270  __mm = 10 * _S_try_read_digit(__is, __err);
5271  __mm += _S_try_read_digit(__is, __err);
5272  }
5273 
5274  if (!__is_failed(__err))
5275  {
5276  auto __z = __hh * 60 + __mm;
5277  __tz_offset = minutes(__neg ? -__z : __z);
5278  }
5279  }
5280  break;
5281 
5282  case 'Z':
5283  if (__mod || __num) [[unlikely]]
5284  __err |= ios_base::failbit;
5285  else
5286  {
5287  basic_string_view<_CharT> __x = _GLIBCXX_WIDEN("_/-+");
5288  __tz_abbr.clear();
5289  while (true)
5290  {
5291  auto __i = __is.peek();
5292  if (!_Traits::eq_int_type(__i, _Traits::eof()))
5293  {
5294  _CharT __a = _Traits::to_char_type(__i);
5295  if (std::isalnum(__a, __loc)
5296  || __x.find(__a) != __x.npos)
5297  {
5298  __tz_abbr.push_back(__a);
5299  (void) __is.get();
5300  continue;
5301  }
5302  }
5303  else
5304  __err |= ios_base::eofbit;
5305  break;
5306  }
5307  if (__tz_abbr.empty())
5308  __err |= ios_base::failbit;
5309  }
5310  break;
5311 
5312  case 'n': // Exactly one whitespace character.
5313  if (__mod || __num) [[unlikely]]
5314  __err |= ios_base::failbit;
5315  else
5316  {
5317  _CharT __i = __is.peek();
5318  if (_Traits::eq_int_type(__i, _Traits::eof()))
5319  __err |= ios_base::eofbit | ios_base::failbit;
5320  else if (std::isspace(_Traits::to_char_type(__i), __loc))
5321  (void) __is.get();
5322  else
5323  __err |= ios_base::failbit;
5324  }
5325  break;
5326 
5327  case 't': // Zero or one whitespace characters.
5328  if (__mod || __num) [[unlikely]]
5329  __err |= ios_base::failbit;
5330  else
5331  {
5332  _CharT __i = __is.peek();
5333  if (_Traits::eq_int_type(__i, _Traits::eof()))
5334  __err |= ios_base::eofbit;
5335  else if (std::isspace(_Traits::to_char_type(__i), __loc))
5336  (void) __is.get();
5337  }
5338  break;
5339 
5340  case '%': // A % character.
5341  if (__mod || __num) [[unlikely]]
5342  __err |= ios_base::failbit;
5343  else
5344  __read_chr('%');
5345  break;
5346 
5347  case 'O': // Modifiers
5348  case 'E':
5349  if (__mod || __num) [[unlikely]]
5350  {
5351  __err |= ios_base::failbit;
5352  break;
5353  }
5354  __mod = __c;
5355  continue;
5356 
5357  default:
5358  if (_CharT('1') <= __c && __c <= _CharT('9'))
5359  {
5360  if (!__mod) [[likely]]
5361  {
5362  // %Nx - extract positive decimal integer N
5363  auto __end = __fmt + _Traits::length(__fmt);
5364  auto [__v, __ptr]
5365  = __format::__parse_integer(__fmt - 1, __end);
5366  if (__ptr) [[likely]]
5367  {
5368  __num = __v;
5369  __fmt = __ptr;
5370  continue;
5371  }
5372  }
5373  }
5374  __err |= ios_base::failbit;
5375  }
5376 
5377  if (__is_failed(__err)) [[unlikely]]
5378  break;
5379 
5380  __is_flag = false;
5381  __num = 0;
5382  __mod = _CharT();
5383  }
5384 
5385  if (__century >= 0)
5386  {
5387  if (__yy != __bad_y && __y == __bad_y)
5388  __y = years(__century) + __yy; // Use %y instead of %Y
5389  if (__iso_yy != __bad_y && __iso_y == __bad_y)
5390  __iso_y = years(__century) + __iso_yy; // Use %g instead of %G
5391  }
5392 
5393  bool __can_use_doy = false;
5394  bool __can_use_iso_wk = false;
5395  bool __can_use_sun_wk = false;
5396  bool __can_use_mon_wk = false;
5397 
5398  // A year + day-of-year can be converted to a full date.
5399  if (__y != __bad_y && __dayofyear >= 0)
5400  {
5401  __can_use_doy = true;
5402  __parts |= _ChronoParts::_Date;
5403  }
5404  else if (__y != __bad_y && __wday != __bad_wday && __sunday_wk >= 0)
5405  {
5406  __can_use_sun_wk = true;
5407  __parts |= _ChronoParts::_Date;
5408  }
5409  else if (__y != __bad_y && __wday != __bad_wday && __monday_wk >= 0)
5410  {
5411  __can_use_mon_wk = true;
5412  __parts |= _ChronoParts::_Date;
5413  }
5414  else if (__iso_y != __bad_y && __wday != __bad_wday && __iso_wk > 0)
5415  {
5416  // An ISO week date can be converted to a full date.
5417  __can_use_iso_wk = true;
5418  __parts |= _ChronoParts::_Date;
5419  }
5420 
5421  if (__is_failed(__err)) [[unlikely]]
5422  ; // Don't bother doing any more work.
5423  else if (__is_flag) [[unlikely]] // incomplete format flag
5424  __err |= ios_base::failbit;
5425  else if ((_M_need & __parts) == _M_need) [[likely]]
5426  {
5427  // We try to avoid calculating _M_sys_days and _M_ymd unless
5428  // necessary, because converting sys_days to year_month_day
5429  // (or vice versa) requires non-trivial calculations.
5430  // If we have y/m/d values then use them to populate _M_ymd
5431  // and only convert it to _M_sys_days if the caller needs that.
5432  // But if we don't have y/m/d and need to calculate the date
5433  // from the day-of-year or a week+weekday then we set _M_sys_days
5434  // and only convert it to _M_ymd if the caller needs that.
5435 
5436  // We do more error checking here, but only for the fields that
5437  // we actually need to use. For example, we will not diagnose
5438  // an invalid dayofyear==366 for non-leap years unless actually
5439  // using __dayofyear. This should mean we never produce invalid
5440  // results, but it means not all invalid inputs are diagnosed,
5441  // e.g. "2023-01-01 366" >> "%F %j" ignores the invalid 366.
5442  // We also do not diagnose inconsistent values for the same
5443  // field, e.g. "2021 2022 2023" >> "%C%y %Y %Y" just uses 2023.
5444 
5445  // Whether the caller wants _M_wd.
5446  // The _Weekday bit is only set for chrono::weekday.
5447  const bool __need_wday = (_M_need & _ChronoParts::_Weekday) != 0;
5448 
5449  // Whether the caller wants _M_sys_days and _M_time.
5450  // Only true for durations and time_points.
5451  const bool __need_time = (_M_need & _ChronoParts::_TimeOfDay) != 0;
5452 
5453  if (__need_wday && __wday != __bad_wday)
5454  _M_wd = __wday; // Caller only wants a weekday and we have one.
5455  else if ((_M_need & _ChronoParts::_Date) != 0) // subsumes __need_wday
5456  {
5457  // Whether the caller wants _M_ymd.
5458  // True for chrono::year etc., false for time_points.
5459  const bool __need_ymd = !__need_wday && !__need_time;
5460 
5461  if (((_M_need & _ChronoParts::_Year) != 0 && __y == __bad_y)
5462  || ((_M_need & _ChronoParts::_Month) != 0 && __m == __bad_mon)
5463  || ((_M_need & _ChronoParts::_Day) != 0 && __d == __bad_day))
5464  {
5465  // Missing at least one of y/m/d so calculate sys_days
5466  // from the other data we have available.
5467 
5468  if (__can_use_doy)
5469  {
5470  if ((0 < __dayofyear && __dayofyear <= 365)
5471  || (__dayofyear == 366 && __y.is_leap()))
5472  [[likely]]
5473  {
5474  _M_sys_days = sys_days(__y/January/1)
5475  + days(__dayofyear - 1);
5476  if (__need_ymd)
5477  _M_ymd = year_month_day(_M_sys_days);
5478  }
5479  else
5480  __err |= ios_base::failbit;
5481  }
5482  else if (__can_use_iso_wk)
5483  {
5484  // Calculate y/m/d from ISO week date.
5485 
5486  if (__iso_wk == 53)
5487  {
5488  // A year has 53 weeks iff Jan 1st is a Thursday
5489  // or Jan 1 is a Wednesday and it's a leap year.
5490  const sys_days __jan4(__iso_y/January/4);
5491  weekday __wd1(__jan4 - days(3));
5492  if (__wd1 != Thursday)
5493  if (__wd1 != Wednesday || !__iso_y.is_leap())
5494  __err |= ios_base::failbit;
5495  }
5496 
5497  if (!__is_failed(__err)) [[likely]]
5498  {
5499  // First Thursday is always in week one:
5500  sys_days __w(Thursday[1]/January/__iso_y);
5501  // First day of week-based year:
5502  __w -= Thursday - Monday;
5503  __w += days(weeks(__iso_wk - 1));
5504  __w += __wday - Monday;
5505  _M_sys_days = __w;
5506 
5507  if (__need_ymd)
5508  _M_ymd = year_month_day(_M_sys_days);
5509  }
5510  }
5511  else if (__can_use_sun_wk)
5512  {
5513  // Calculate y/m/d from week number + weekday.
5514  sys_days __wk1(__y/January/Sunday[1]);
5515  _M_sys_days = __wk1 + weeks(__sunday_wk - 1)
5516  + days(__wday.c_encoding());
5517  _M_ymd = year_month_day(_M_sys_days);
5518  if (_M_ymd.year() != __y) [[unlikely]]
5519  __err |= ios_base::failbit;
5520  }
5521  else if (__can_use_mon_wk)
5522  {
5523  // Calculate y/m/d from week number + weekday.
5524  sys_days __wk1(__y/January/Monday[1]);
5525  _M_sys_days = __wk1 + weeks(__monday_wk - 1)
5526  + days(__wday.c_encoding() - 1);
5527  _M_ymd = year_month_day(_M_sys_days);
5528  if (_M_ymd.year() != __y) [[unlikely]]
5529  __err |= ios_base::failbit;
5530  }
5531  else // Should not be able to get here.
5532  __err |= ios_base::failbit;
5533  }
5534  else
5535  {
5536  // We know that all fields the caller needs are present,
5537  // but check that their values are in range.
5538  // Make unwanted fields valid so that _M_ymd.ok() is true.
5539 
5540  if ((_M_need & _ChronoParts::_Year) != 0)
5541  {
5542  if (!__y.ok()) [[unlikely]]
5543  __err |= ios_base::failbit;
5544  }
5545  else if (__y == __bad_y)
5546  __y = 1972y; // Leap year so that Feb 29 is valid.
5547 
5548  if ((_M_need & _ChronoParts::_Month) != 0)
5549  {
5550  if (!__m.ok()) [[unlikely]]
5551  __err |= ios_base::failbit;
5552  }
5553  else if (__m == __bad_mon)
5554  __m = January;
5555 
5556  if ((_M_need & _ChronoParts::_Day) != 0)
5557  {
5558  if (__d < day(1) || __d > (__y/__m/last).day())
5559  __err |= ios_base::failbit;
5560  }
5561  else if (__d == __bad_day)
5562  __d = 1d;
5563 
5564  if (year_month_day __ymd(__y, __m, __d); __ymd.ok())
5565  {
5566  _M_ymd = __ymd;
5567  if (__need_wday || __need_time)
5568  _M_sys_days = sys_days(_M_ymd);
5569  }
5570  else [[unlikely]]
5571  __err |= ios_base::failbit;
5572  }
5573 
5574  if (__need_wday)
5575  _M_wd = weekday(_M_sys_days);
5576  }
5577 
5578  // Need to set _M_time for both durations and time_points.
5579  if (__need_time)
5580  {
5581  if (__h == __bad_h && __h12 != __bad_h)
5582  {
5583  if (__ampm == 1)
5584  __h = __h12 == hours(12) ? hours(0) : __h12;
5585  else if (__ampm == 2)
5586  __h = __h12 == hours(12) ? __h12 : __h12 + hours(12);
5587  else [[unlikely]]
5588  __err |= ios_base::failbit;
5589  }
5590 
5591  auto __t = _M_time.zero();
5592  bool __ok = false;
5593 
5594  if (__h != __bad_h)
5595  {
5596  __ok = true;
5597  __t += __h;
5598  }
5599 
5600  if (__min != __bad_min)
5601  {
5602  __ok = true;
5603  __t += __min;
5604  }
5605 
5606  if (__s != __bad_sec)
5607  {
5608  __ok = true;
5609  __t += __s;
5610  _M_is_leap_second = __s >= seconds(60);
5611  }
5612 
5613  if (__ok)
5614  _M_time = __t;
5615  else
5616  __err |= ios_base::failbit;
5617  }
5618 
5619  if (!__is_failed(__err)) [[likely]]
5620  {
5621  if (__offset && __tz_offset != __bad_min)
5622  *__offset = __tz_offset;
5623  if (__abbrev && !__tz_abbr.empty())
5624  *__abbrev = std::move(__tz_abbr);
5625  }
5626  }
5627  else
5628  __err |= ios_base::failbit;
5629  }
5630  if (__err)
5631  __is.setstate(__err);
5632  return __is;
5633  }
5634  /// @endcond
5635 #undef _GLIBCXX_WIDEN
5636 
5637  /// @} group chrono
5638 } // namespace chrono
5639 
5640 _GLIBCXX_END_NAMESPACE_VERSION
5641 } // namespace std
5642 
5643 #endif // C++20
5644 
5645 #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:233
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