xref: /openbsd-src/gnu/llvm/libcxx/include/__chrono/formatter.h (revision 4bdff4bed0e3d54e55670334c7d0077db4170f86)
1*4bdff4beSrobert // -*- C++ -*-
2*4bdff4beSrobert //===----------------------------------------------------------------------===//
3*4bdff4beSrobert //
4*4bdff4beSrobert // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5*4bdff4beSrobert // See https://llvm.org/LICENSE.txt for license information.
6*4bdff4beSrobert // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7*4bdff4beSrobert //
8*4bdff4beSrobert //===----------------------------------------------------------------------===//
9*4bdff4beSrobert 
10*4bdff4beSrobert #ifndef _LIBCPP___CHRONO_FORMATTER_H
11*4bdff4beSrobert #define _LIBCPP___CHRONO_FORMATTER_H
12*4bdff4beSrobert 
13*4bdff4beSrobert #include <__chrono/calendar.h>
14*4bdff4beSrobert #include <__chrono/convert_to_tm.h>
15*4bdff4beSrobert #include <__chrono/day.h>
16*4bdff4beSrobert #include <__chrono/duration.h>
17*4bdff4beSrobert #include <__chrono/hh_mm_ss.h>
18*4bdff4beSrobert #include <__chrono/month.h>
19*4bdff4beSrobert #include <__chrono/month_weekday.h>
20*4bdff4beSrobert #include <__chrono/monthday.h>
21*4bdff4beSrobert #include <__chrono/ostream.h>
22*4bdff4beSrobert #include <__chrono/parser_std_format_spec.h>
23*4bdff4beSrobert #include <__chrono/statically_widen.h>
24*4bdff4beSrobert #include <__chrono/time_point.h>
25*4bdff4beSrobert #include <__chrono/weekday.h>
26*4bdff4beSrobert #include <__chrono/year.h>
27*4bdff4beSrobert #include <__chrono/year_month.h>
28*4bdff4beSrobert #include <__chrono/year_month_day.h>
29*4bdff4beSrobert #include <__chrono/year_month_weekday.h>
30*4bdff4beSrobert #include <__concepts/arithmetic.h>
31*4bdff4beSrobert #include <__concepts/same_as.h>
32*4bdff4beSrobert #include <__config>
33*4bdff4beSrobert #include <__format/concepts.h>
34*4bdff4beSrobert #include <__format/format_error.h>
35*4bdff4beSrobert #include <__format/format_functions.h>
36*4bdff4beSrobert #include <__format/format_parse_context.h>
37*4bdff4beSrobert #include <__format/formatter.h>
38*4bdff4beSrobert #include <__format/formatter_output.h>
39*4bdff4beSrobert #include <__format/parser_std_format_spec.h>
40*4bdff4beSrobert #include <__memory/addressof.h>
41*4bdff4beSrobert #include <cmath>
42*4bdff4beSrobert #include <ctime>
43*4bdff4beSrobert #include <sstream>
44*4bdff4beSrobert #include <string>
45*4bdff4beSrobert #include <string_view>
46*4bdff4beSrobert 
47*4bdff4beSrobert #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
48*4bdff4beSrobert #  pragma GCC system_header
49*4bdff4beSrobert #endif
50*4bdff4beSrobert 
51*4bdff4beSrobert _LIBCPP_BEGIN_NAMESPACE_STD
52*4bdff4beSrobert 
53*4bdff4beSrobert #if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_FORMAT)
54*4bdff4beSrobert 
55*4bdff4beSrobert namespace __formatter {
56*4bdff4beSrobert 
57*4bdff4beSrobert /// Formats a time based on a tm struct.
58*4bdff4beSrobert ///
59*4bdff4beSrobert /// This formatter passes the formatting to time_put which uses strftime. When
60*4bdff4beSrobert /// the value is outside the valid range it's unspecified what strftime will
61*4bdff4beSrobert /// output. For example weekday 8 can print 1 when the day is processed modulo
62*4bdff4beSrobert /// 7 since that handles the Sunday for 0-based weekday. It can also print 8 if
63*4bdff4beSrobert /// 7 is handled as a special case.
64*4bdff4beSrobert ///
65*4bdff4beSrobert /// The Standard doesn't specify what to do in this case so the result depends
66*4bdff4beSrobert /// on the result of the underlying code.
67*4bdff4beSrobert ///
68*4bdff4beSrobert /// \pre When the (abbreviated) weekday or month name are used, the caller
69*4bdff4beSrobert ///      validates whether the value is valid. So the caller handles that
70*4bdff4beSrobert ///      requirement of Table 97: Meaning of conversion specifiers
71*4bdff4beSrobert ///      [tab:time.format.spec].
72*4bdff4beSrobert ///
73*4bdff4beSrobert /// When no chrono-specs are provided it uses the stream formatter.
74*4bdff4beSrobert 
75*4bdff4beSrobert // For tiny ratios it's not possible to convert a duration to a hh_mm_ss. This
76*4bdff4beSrobert // fails compile-time due to the limited precision of the ratio (64-bit is too
77*4bdff4beSrobert // small). Therefore a duration uses its own conversion.
78*4bdff4beSrobert template <class _CharT, class _Tp>
requires(chrono::__is_duration<_Tp>::value)79*4bdff4beSrobert   requires(chrono::__is_duration<_Tp>::value)
80*4bdff4beSrobert _LIBCPP_HIDE_FROM_ABI void __format_sub_seconds(const _Tp& __value, basic_stringstream<_CharT>& __sstr) {
81*4bdff4beSrobert   __sstr << std::use_facet<numpunct<_CharT>>(__sstr.getloc()).decimal_point();
82*4bdff4beSrobert 
83*4bdff4beSrobert   auto __fraction = __value - chrono::duration_cast<chrono::seconds>(__value);
84*4bdff4beSrobert   if constexpr (chrono::treat_as_floating_point_v<typename _Tp::rep>)
85*4bdff4beSrobert     // When the floating-point value has digits itself they are ignored based
86*4bdff4beSrobert     // on the wording in [tab:time.format.spec]
87*4bdff4beSrobert     //   If the precision of the input cannot be exactly represented with
88*4bdff4beSrobert     //   seconds, then the format is a decimal floating-point number with a
89*4bdff4beSrobert     //   fixed format and a precision matching that of the precision of the
90*4bdff4beSrobert     //   input (or to a microseconds precision if the conversion to
91*4bdff4beSrobert     //   floating-point decimal seconds cannot be made within 18 fractional
92*4bdff4beSrobert     //   digits).
93*4bdff4beSrobert     //
94*4bdff4beSrobert     // This matches the behaviour of MSVC STL, fmtlib interprets this
95*4bdff4beSrobert     // differently and uses 3 decimals.
96*4bdff4beSrobert     // https://godbolt.org/z/6dsbnW8ba
97*4bdff4beSrobert     std::format_to(std::ostreambuf_iterator<_CharT>{__sstr},
98*4bdff4beSrobert                    _LIBCPP_STATICALLY_WIDEN(_CharT, "{:0{}.0f}"),
99*4bdff4beSrobert                    __fraction.count(),
100*4bdff4beSrobert                    chrono::hh_mm_ss<_Tp>::fractional_width);
101*4bdff4beSrobert   else
102*4bdff4beSrobert     std::format_to(std::ostreambuf_iterator<_CharT>{__sstr},
103*4bdff4beSrobert                    _LIBCPP_STATICALLY_WIDEN(_CharT, "{:0{}}"),
104*4bdff4beSrobert                    __fraction.count(),
105*4bdff4beSrobert                    chrono::hh_mm_ss<_Tp>::fractional_width);
106*4bdff4beSrobert }
107*4bdff4beSrobert 
108*4bdff4beSrobert template <class _Tp>
__use_fraction()109*4bdff4beSrobert consteval bool __use_fraction() {
110*4bdff4beSrobert   if constexpr (chrono::__is_duration<_Tp>::value)
111*4bdff4beSrobert     return chrono::hh_mm_ss<_Tp>::fractional_width;
112*4bdff4beSrobert   else
113*4bdff4beSrobert     return false;
114*4bdff4beSrobert }
115*4bdff4beSrobert 
116*4bdff4beSrobert template <class _CharT>
__format_year(int __year,basic_stringstream<_CharT> & __sstr)117*4bdff4beSrobert _LIBCPP_HIDE_FROM_ABI void __format_year(int __year, basic_stringstream<_CharT>& __sstr) {
118*4bdff4beSrobert   if (__year < 0) {
119*4bdff4beSrobert     __sstr << _CharT('-');
120*4bdff4beSrobert     __year = -__year;
121*4bdff4beSrobert   }
122*4bdff4beSrobert 
123*4bdff4beSrobert   // TODO FMT Write an issue
124*4bdff4beSrobert   //   If the result has less than four digits it is zero-padded with 0 to two digits.
125*4bdff4beSrobert   // is less -> has less
126*4bdff4beSrobert   // left-padded -> zero-padded, otherwise the proper value would be 000-0.
127*4bdff4beSrobert 
128*4bdff4beSrobert   // Note according to the wording it should be left padded, which is odd.
129*4bdff4beSrobert   __sstr << std::format(_LIBCPP_STATICALLY_WIDEN(_CharT, "{:04}"), __year);
130*4bdff4beSrobert }
131*4bdff4beSrobert 
132*4bdff4beSrobert template <class _CharT>
__format_century(int __year,basic_stringstream<_CharT> & __sstr)133*4bdff4beSrobert _LIBCPP_HIDE_FROM_ABI void __format_century(int __year, basic_stringstream<_CharT>& __sstr) {
134*4bdff4beSrobert   // TODO FMT Write an issue
135*4bdff4beSrobert   // [tab:time.format.spec]
136*4bdff4beSrobert   //   %C The year divided by 100 using floored division. If the result is a
137*4bdff4beSrobert   //   single decimal digit, it is prefixed with 0.
138*4bdff4beSrobert 
139*4bdff4beSrobert   bool __negative = __year < 0;
140*4bdff4beSrobert   int __century   = (__year - (99 * __negative)) / 100; // floored division
141*4bdff4beSrobert   __sstr << std::format(_LIBCPP_STATICALLY_WIDEN(_CharT, "{:02}"), __century);
142*4bdff4beSrobert }
143*4bdff4beSrobert 
144*4bdff4beSrobert template <class _CharT, class _Tp>
__format_chrono_using_chrono_specs(const _Tp & __value,basic_stringstream<_CharT> & __sstr,basic_string_view<_CharT> __chrono_specs)145*4bdff4beSrobert _LIBCPP_HIDE_FROM_ABI void __format_chrono_using_chrono_specs(
146*4bdff4beSrobert     const _Tp& __value, basic_stringstream<_CharT>& __sstr, basic_string_view<_CharT> __chrono_specs) {
147*4bdff4beSrobert   tm __t              = std::__convert_to_tm<tm>(__value);
148*4bdff4beSrobert   const auto& __facet = std::use_facet<time_put<_CharT>>(__sstr.getloc());
149*4bdff4beSrobert   for (auto __it = __chrono_specs.begin(); __it != __chrono_specs.end(); ++__it) {
150*4bdff4beSrobert     if (*__it == _CharT('%')) {
151*4bdff4beSrobert       auto __s = __it;
152*4bdff4beSrobert       ++__it;
153*4bdff4beSrobert       // We only handle the types that can't be directly handled by time_put.
154*4bdff4beSrobert       // (as an optimization n, t, and % are also handled directly.)
155*4bdff4beSrobert       switch (*__it) {
156*4bdff4beSrobert       case _CharT('n'):
157*4bdff4beSrobert         __sstr << _CharT('\n');
158*4bdff4beSrobert         break;
159*4bdff4beSrobert       case _CharT('t'):
160*4bdff4beSrobert         __sstr << _CharT('\t');
161*4bdff4beSrobert         break;
162*4bdff4beSrobert       case _CharT('%'):
163*4bdff4beSrobert         __sstr << *__it;
164*4bdff4beSrobert         break;
165*4bdff4beSrobert 
166*4bdff4beSrobert       case _CharT('C'): {
167*4bdff4beSrobert         // strftime's output is only defined in the range [00, 99].
168*4bdff4beSrobert         int __year = __t.tm_year + 1900;
169*4bdff4beSrobert         if (__year < 1000 || __year > 9999)
170*4bdff4beSrobert           __formatter::__format_century(__year, __sstr);
171*4bdff4beSrobert         else
172*4bdff4beSrobert           __facet.put({__sstr}, __sstr, _CharT(' '), std::addressof(__t), __s, __it + 1);
173*4bdff4beSrobert       } break;
174*4bdff4beSrobert 
175*4bdff4beSrobert       case _CharT('j'):
176*4bdff4beSrobert         if constexpr (chrono::__is_duration<_Tp>::value)
177*4bdff4beSrobert           // Converting a duration where the period has a small ratio to days
178*4bdff4beSrobert           // may fail to compile. This due to loss of precision in the
179*4bdff4beSrobert           // conversion. In order to avoid that issue convert to seconds as
180*4bdff4beSrobert           // an intemediate step.
181*4bdff4beSrobert           __sstr << chrono::duration_cast<chrono::days>(chrono::duration_cast<chrono::seconds>(__value)).count();
182*4bdff4beSrobert         else
183*4bdff4beSrobert           __facet.put({__sstr}, __sstr, _CharT(' '), std::addressof(__t), __s, __it + 1);
184*4bdff4beSrobert         break;
185*4bdff4beSrobert 
186*4bdff4beSrobert       case _CharT('q'):
187*4bdff4beSrobert         if constexpr (chrono::__is_duration<_Tp>::value) {
188*4bdff4beSrobert           __sstr << chrono::__units_suffix<_CharT, typename _Tp::period>();
189*4bdff4beSrobert           break;
190*4bdff4beSrobert         }
191*4bdff4beSrobert         __builtin_unreachable();
192*4bdff4beSrobert 
193*4bdff4beSrobert       case _CharT('Q'):
194*4bdff4beSrobert         // TODO FMT Determine the proper ideas
195*4bdff4beSrobert         // - Should it honour the precision?
196*4bdff4beSrobert         // - Shoult it honour the locale setting for the separators?
197*4bdff4beSrobert         // The wording for Q doesn't use the word locale and the effect of
198*4bdff4beSrobert         // precision is unspecified.
199*4bdff4beSrobert         //
200*4bdff4beSrobert         // MSVC STL ignores precision but uses separator
201*4bdff4beSrobert         // FMT honours precision and has a bug for separator
202*4bdff4beSrobert         // https://godbolt.org/z/78b7sMxns
203*4bdff4beSrobert         if constexpr (chrono::__is_duration<_Tp>::value) {
204*4bdff4beSrobert           __sstr << std::format(_LIBCPP_STATICALLY_WIDEN(_CharT, "{}"), __value.count());
205*4bdff4beSrobert           break;
206*4bdff4beSrobert         }
207*4bdff4beSrobert         __builtin_unreachable();
208*4bdff4beSrobert 
209*4bdff4beSrobert       case _CharT('S'):
210*4bdff4beSrobert       case _CharT('T'):
211*4bdff4beSrobert         __facet.put({__sstr}, __sstr, _CharT(' '), std::addressof(__t), __s, __it + 1);
212*4bdff4beSrobert         if constexpr (__use_fraction<_Tp>())
213*4bdff4beSrobert           __formatter::__format_sub_seconds(__value, __sstr);
214*4bdff4beSrobert         break;
215*4bdff4beSrobert 
216*4bdff4beSrobert         // Unlike time_put and strftime the formatting library requires %Y
217*4bdff4beSrobert         //
218*4bdff4beSrobert         // [tab:time.format.spec]
219*4bdff4beSrobert         //   The year as a decimal number. If the result is less than four digits
220*4bdff4beSrobert         //   it is left-padded with 0 to four digits.
221*4bdff4beSrobert         //
222*4bdff4beSrobert         // This means years in the range (-1000, 1000) need manual formatting.
223*4bdff4beSrobert         // It's unclear whether %EY needs the same treatment. For example the
224*4bdff4beSrobert         // Japanese EY contains the era name and year. This is zero-padded to 2
225*4bdff4beSrobert         // digits in time_put (note that older glibc versions didn't do
226*4bdff4beSrobert         // padding.) However most eras won't reach 100 years, let alone 1000.
227*4bdff4beSrobert         // So padding to 4 digits seems unwanted for Japanese.
228*4bdff4beSrobert         //
229*4bdff4beSrobert         // The same applies to %Ex since that too depends on the era.
230*4bdff4beSrobert         //
231*4bdff4beSrobert         // %x the locale's date representation is currently doesn't handle the
232*4bdff4beSrobert         // zero-padding too.
233*4bdff4beSrobert         //
234*4bdff4beSrobert         // The 4 digits can be implemented better at a later time. On POSIX
235*4bdff4beSrobert         // systems the required information can be extracted by nl_langinfo
236*4bdff4beSrobert         // https://man7.org/linux/man-pages/man3/nl_langinfo.3.html
237*4bdff4beSrobert         //
238*4bdff4beSrobert         // Note since year < -1000 is expected to be rare it uses the more
239*4bdff4beSrobert         // expensive year routine.
240*4bdff4beSrobert         //
241*4bdff4beSrobert         // TODO FMT evaluate the comment above.
242*4bdff4beSrobert 
243*4bdff4beSrobert #  if defined(__GLIBC__) || defined(_AIX)
244*4bdff4beSrobert       case _CharT('y'):
245*4bdff4beSrobert         // Glibc fails for negative values, AIX for positive values too.
246*4bdff4beSrobert         __sstr << std::format(_LIBCPP_STATICALLY_WIDEN(_CharT, "{:02}"), (std::abs(__t.tm_year + 1900)) % 100);
247*4bdff4beSrobert         break;
248*4bdff4beSrobert #  endif // defined(__GLIBC__) || defined(_AIX)
249*4bdff4beSrobert 
250*4bdff4beSrobert       case _CharT('Y'): {
251*4bdff4beSrobert         int __year = __t.tm_year + 1900;
252*4bdff4beSrobert         if (__year < 1000)
253*4bdff4beSrobert           __formatter::__format_year(__year, __sstr);
254*4bdff4beSrobert         else
255*4bdff4beSrobert           __facet.put({__sstr}, __sstr, _CharT(' '), std::addressof(__t), __s, __it + 1);
256*4bdff4beSrobert       } break;
257*4bdff4beSrobert 
258*4bdff4beSrobert       case _CharT('F'): {
259*4bdff4beSrobert         int __year = __t.tm_year + 1900;
260*4bdff4beSrobert         if (__year < 1000) {
261*4bdff4beSrobert           __formatter::__format_year(__year, __sstr);
262*4bdff4beSrobert           __sstr << std::format(_LIBCPP_STATICALLY_WIDEN(_CharT, "-{:02}-{:02}"), __t.tm_mon + 1, __t.tm_mday);
263*4bdff4beSrobert         } else
264*4bdff4beSrobert           __facet.put({__sstr}, __sstr, _CharT(' '), std::addressof(__t), __s, __it + 1);
265*4bdff4beSrobert       } break;
266*4bdff4beSrobert 
267*4bdff4beSrobert       case _CharT('O'):
268*4bdff4beSrobert         if constexpr (__use_fraction<_Tp>()) {
269*4bdff4beSrobert           // Handle OS using the normal representation for the non-fractional
270*4bdff4beSrobert           // part. There seems to be no locale information regarding how the
271*4bdff4beSrobert           // fractional part should be formatted.
272*4bdff4beSrobert           if (*(__it + 1) == 'S') {
273*4bdff4beSrobert             ++__it;
274*4bdff4beSrobert             __facet.put({__sstr}, __sstr, _CharT(' '), std::addressof(__t), __s, __it + 1);
275*4bdff4beSrobert             __formatter::__format_sub_seconds(__value, __sstr);
276*4bdff4beSrobert             break;
277*4bdff4beSrobert           }
278*4bdff4beSrobert         }
279*4bdff4beSrobert         [[fallthrough]];
280*4bdff4beSrobert       case _CharT('E'):
281*4bdff4beSrobert         ++__it;
282*4bdff4beSrobert         [[fallthrough]];
283*4bdff4beSrobert       default:
284*4bdff4beSrobert         __facet.put({__sstr}, __sstr, _CharT(' '), std::addressof(__t), __s, __it + 1);
285*4bdff4beSrobert         break;
286*4bdff4beSrobert       }
287*4bdff4beSrobert     } else {
288*4bdff4beSrobert       __sstr << *__it;
289*4bdff4beSrobert     }
290*4bdff4beSrobert   }
291*4bdff4beSrobert }
292*4bdff4beSrobert 
293*4bdff4beSrobert template <class _Tp>
__weekday_ok(const _Tp & __value)294*4bdff4beSrobert _LIBCPP_HIDE_FROM_ABI constexpr bool __weekday_ok(const _Tp& __value) {
295*4bdff4beSrobert   if constexpr (same_as<_Tp, chrono::day>)
296*4bdff4beSrobert     return true;
297*4bdff4beSrobert   else if constexpr (same_as<_Tp, chrono::month>)
298*4bdff4beSrobert     return __value.ok();
299*4bdff4beSrobert   else if constexpr (same_as<_Tp, chrono::year>)
300*4bdff4beSrobert     return true;
301*4bdff4beSrobert   else if constexpr (same_as<_Tp, chrono::weekday>)
302*4bdff4beSrobert     return true;
303*4bdff4beSrobert   else if constexpr (same_as<_Tp, chrono::weekday_indexed>)
304*4bdff4beSrobert     return true;
305*4bdff4beSrobert   else if constexpr (same_as<_Tp, chrono::weekday_last>)
306*4bdff4beSrobert     return true;
307*4bdff4beSrobert   else if constexpr (same_as<_Tp, chrono::month_day>)
308*4bdff4beSrobert     return true;
309*4bdff4beSrobert   else if constexpr (same_as<_Tp, chrono::month_day_last>)
310*4bdff4beSrobert     return true;
311*4bdff4beSrobert   else if constexpr (same_as<_Tp, chrono::month_weekday>)
312*4bdff4beSrobert     return true;
313*4bdff4beSrobert   else if constexpr (same_as<_Tp, chrono::month_weekday_last>)
314*4bdff4beSrobert     return true;
315*4bdff4beSrobert   else if constexpr (same_as<_Tp, chrono::year_month>)
316*4bdff4beSrobert     return true;
317*4bdff4beSrobert   else if constexpr (same_as<_Tp, chrono::year_month_day>)
318*4bdff4beSrobert     return __value.ok();
319*4bdff4beSrobert   else if constexpr (same_as<_Tp, chrono::year_month_day_last>)
320*4bdff4beSrobert     return __value.ok();
321*4bdff4beSrobert   else if constexpr (same_as<_Tp, chrono::year_month_weekday>)
322*4bdff4beSrobert     return __value.weekday().ok();
323*4bdff4beSrobert   else if constexpr (same_as<_Tp, chrono::year_month_weekday_last>)
324*4bdff4beSrobert     return __value.weekday().ok();
325*4bdff4beSrobert   else
326*4bdff4beSrobert     static_assert(sizeof(_Tp) == 0, "Add the missing type specialization");
327*4bdff4beSrobert }
328*4bdff4beSrobert 
329*4bdff4beSrobert template <class _Tp>
__weekday_name_ok(const _Tp & __value)330*4bdff4beSrobert _LIBCPP_HIDE_FROM_ABI constexpr bool __weekday_name_ok(const _Tp& __value) {
331*4bdff4beSrobert   if constexpr (same_as<_Tp, chrono::day>)
332*4bdff4beSrobert     return true;
333*4bdff4beSrobert   else if constexpr (same_as<_Tp, chrono::month>)
334*4bdff4beSrobert     return __value.ok();
335*4bdff4beSrobert   else if constexpr (same_as<_Tp, chrono::year>)
336*4bdff4beSrobert     return true;
337*4bdff4beSrobert   else if constexpr (same_as<_Tp, chrono::weekday>)
338*4bdff4beSrobert     return __value.ok();
339*4bdff4beSrobert   else if constexpr (same_as<_Tp, chrono::weekday_indexed>)
340*4bdff4beSrobert     return __value.weekday().ok();
341*4bdff4beSrobert   else if constexpr (same_as<_Tp, chrono::weekday_last>)
342*4bdff4beSrobert     return __value.weekday().ok();
343*4bdff4beSrobert   else if constexpr (same_as<_Tp, chrono::month_day>)
344*4bdff4beSrobert     return true;
345*4bdff4beSrobert   else if constexpr (same_as<_Tp, chrono::month_day_last>)
346*4bdff4beSrobert     return true;
347*4bdff4beSrobert   else if constexpr (same_as<_Tp, chrono::month_weekday>)
348*4bdff4beSrobert     return __value.weekday_indexed().ok();
349*4bdff4beSrobert   else if constexpr (same_as<_Tp, chrono::month_weekday_last>)
350*4bdff4beSrobert     return __value.weekday_indexed().ok();
351*4bdff4beSrobert   else if constexpr (same_as<_Tp, chrono::year_month>)
352*4bdff4beSrobert     return true;
353*4bdff4beSrobert   else if constexpr (same_as<_Tp, chrono::year_month_day>)
354*4bdff4beSrobert     return __value.ok();
355*4bdff4beSrobert   else if constexpr (same_as<_Tp, chrono::year_month_day_last>)
356*4bdff4beSrobert     return __value.ok();
357*4bdff4beSrobert   else if constexpr (same_as<_Tp, chrono::year_month_weekday>)
358*4bdff4beSrobert     return __value.weekday().ok();
359*4bdff4beSrobert   else if constexpr (same_as<_Tp, chrono::year_month_weekday_last>)
360*4bdff4beSrobert     return __value.weekday().ok();
361*4bdff4beSrobert   else
362*4bdff4beSrobert     static_assert(sizeof(_Tp) == 0, "Add the missing type specialization");
363*4bdff4beSrobert }
364*4bdff4beSrobert 
365*4bdff4beSrobert template <class _Tp>
__date_ok(const _Tp & __value)366*4bdff4beSrobert _LIBCPP_HIDE_FROM_ABI constexpr bool __date_ok(const _Tp& __value) {
367*4bdff4beSrobert   if constexpr (same_as<_Tp, chrono::day>)
368*4bdff4beSrobert     return true;
369*4bdff4beSrobert   else if constexpr (same_as<_Tp, chrono::month>)
370*4bdff4beSrobert     return __value.ok();
371*4bdff4beSrobert   else if constexpr (same_as<_Tp, chrono::year>)
372*4bdff4beSrobert     return true;
373*4bdff4beSrobert   else if constexpr (same_as<_Tp, chrono::weekday>)
374*4bdff4beSrobert     return true;
375*4bdff4beSrobert   else if constexpr (same_as<_Tp, chrono::weekday_indexed>)
376*4bdff4beSrobert     return true;
377*4bdff4beSrobert   else if constexpr (same_as<_Tp, chrono::weekday_last>)
378*4bdff4beSrobert     return true;
379*4bdff4beSrobert   else if constexpr (same_as<_Tp, chrono::month_day>)
380*4bdff4beSrobert     return true;
381*4bdff4beSrobert   else if constexpr (same_as<_Tp, chrono::month_day_last>)
382*4bdff4beSrobert     return true;
383*4bdff4beSrobert   else if constexpr (same_as<_Tp, chrono::month_weekday>)
384*4bdff4beSrobert     return true;
385*4bdff4beSrobert   else if constexpr (same_as<_Tp, chrono::month_weekday_last>)
386*4bdff4beSrobert     return true;
387*4bdff4beSrobert   else if constexpr (same_as<_Tp, chrono::year_month>)
388*4bdff4beSrobert     return true;
389*4bdff4beSrobert   else if constexpr (same_as<_Tp, chrono::year_month_day>)
390*4bdff4beSrobert     return __value.ok();
391*4bdff4beSrobert   else if constexpr (same_as<_Tp, chrono::year_month_day_last>)
392*4bdff4beSrobert     return __value.ok();
393*4bdff4beSrobert   else if constexpr (same_as<_Tp, chrono::year_month_weekday>)
394*4bdff4beSrobert     return __value.ok();
395*4bdff4beSrobert   else if constexpr (same_as<_Tp, chrono::year_month_weekday_last>)
396*4bdff4beSrobert     return __value.ok();
397*4bdff4beSrobert   else
398*4bdff4beSrobert     static_assert(sizeof(_Tp) == 0, "Add the missing type specialization");
399*4bdff4beSrobert }
400*4bdff4beSrobert 
401*4bdff4beSrobert template <class _Tp>
__month_name_ok(const _Tp & __value)402*4bdff4beSrobert _LIBCPP_HIDE_FROM_ABI constexpr bool __month_name_ok(const _Tp& __value) {
403*4bdff4beSrobert   if constexpr (same_as<_Tp, chrono::day>)
404*4bdff4beSrobert     return true;
405*4bdff4beSrobert   else if constexpr (same_as<_Tp, chrono::month>)
406*4bdff4beSrobert     return __value.ok();
407*4bdff4beSrobert   else if constexpr (same_as<_Tp, chrono::year>)
408*4bdff4beSrobert     return true;
409*4bdff4beSrobert   else if constexpr (same_as<_Tp, chrono::weekday>)
410*4bdff4beSrobert     return true;
411*4bdff4beSrobert   else if constexpr (same_as<_Tp, chrono::weekday_indexed>)
412*4bdff4beSrobert     return true;
413*4bdff4beSrobert   else if constexpr (same_as<_Tp, chrono::weekday_last>)
414*4bdff4beSrobert     return true;
415*4bdff4beSrobert   else if constexpr (same_as<_Tp, chrono::month_day>)
416*4bdff4beSrobert     return __value.month().ok();
417*4bdff4beSrobert   else if constexpr (same_as<_Tp, chrono::month_day_last>)
418*4bdff4beSrobert     return __value.month().ok();
419*4bdff4beSrobert   else if constexpr (same_as<_Tp, chrono::month_weekday>)
420*4bdff4beSrobert     return __value.month().ok();
421*4bdff4beSrobert   else if constexpr (same_as<_Tp, chrono::month_weekday_last>)
422*4bdff4beSrobert     return __value.month().ok();
423*4bdff4beSrobert   else if constexpr (same_as<_Tp, chrono::year_month>)
424*4bdff4beSrobert     return __value.month().ok();
425*4bdff4beSrobert   else if constexpr (same_as<_Tp, chrono::year_month_day>)
426*4bdff4beSrobert     return __value.month().ok();
427*4bdff4beSrobert   else if constexpr (same_as<_Tp, chrono::year_month_day_last>)
428*4bdff4beSrobert     return __value.month().ok();
429*4bdff4beSrobert   else if constexpr (same_as<_Tp, chrono::year_month_weekday>)
430*4bdff4beSrobert     return __value.month().ok();
431*4bdff4beSrobert   else if constexpr (same_as<_Tp, chrono::year_month_weekday_last>)
432*4bdff4beSrobert     return __value.month().ok();
433*4bdff4beSrobert   else
434*4bdff4beSrobert     static_assert(sizeof(_Tp) == 0, "Add the missing type specialization");
435*4bdff4beSrobert }
436*4bdff4beSrobert 
437*4bdff4beSrobert template <class _CharT, class _Tp>
438*4bdff4beSrobert _LIBCPP_HIDE_FROM_ABI auto
439*4bdff4beSrobert __format_chrono(const _Tp& __value,
440*4bdff4beSrobert                 auto& __ctx,
441*4bdff4beSrobert                 __format_spec::__parsed_specifications<_CharT> __specs,
442*4bdff4beSrobert                 basic_string_view<_CharT> __chrono_specs) -> decltype(__ctx.out()) {
443*4bdff4beSrobert   basic_stringstream<_CharT> __sstr;
444*4bdff4beSrobert   // [time.format]/2
445*4bdff4beSrobert   // 2.1 - the "C" locale if the L option is not present in chrono-format-spec, otherwise
446*4bdff4beSrobert   // 2.2 - the locale passed to the formatting function if any, otherwise
447*4bdff4beSrobert   // 2.3 - the global locale.
448*4bdff4beSrobert   // Note that the __ctx's locale() call does 2.2 and 2.3.
449*4bdff4beSrobert   if (__specs.__chrono_.__locale_specific_form_)
450*4bdff4beSrobert     __sstr.imbue(__ctx.locale());
451*4bdff4beSrobert   else
452*4bdff4beSrobert     __sstr.imbue(locale::classic());
453*4bdff4beSrobert 
454*4bdff4beSrobert   if (__chrono_specs.empty())
455*4bdff4beSrobert     __sstr << __value;
456*4bdff4beSrobert   else {
457*4bdff4beSrobert     if constexpr (chrono::__is_duration<_Tp>::value) {
458*4bdff4beSrobert       if (__value < __value.zero())
459*4bdff4beSrobert         __sstr << _CharT('-');
460*4bdff4beSrobert       __formatter::__format_chrono_using_chrono_specs(chrono::abs(__value), __sstr, __chrono_specs);
461*4bdff4beSrobert       // TODO FMT When keeping the precision it will truncate the string.
462*4bdff4beSrobert       // Note that the behaviour what the precision does isn't specified.
463*4bdff4beSrobert       __specs.__precision_ = -1;
464*4bdff4beSrobert     } else {
465*4bdff4beSrobert       // Test __weekday_name_ before __weekday_ to give a better error.
466*4bdff4beSrobert       if (__specs.__chrono_.__weekday_name_ && !__formatter::__weekday_name_ok(__value))
467*4bdff4beSrobert         std::__throw_format_error("formatting a weekday name needs a valid weekday");
468*4bdff4beSrobert 
469*4bdff4beSrobert       if (__specs.__chrono_.__weekday_ && !__formatter::__weekday_ok(__value))
470*4bdff4beSrobert         std::__throw_format_error("formatting a weekday needs a valid weekday");
471*4bdff4beSrobert 
472*4bdff4beSrobert       if (__specs.__chrono_.__day_of_year_ && !__formatter::__date_ok(__value))
473*4bdff4beSrobert         std::__throw_format_error("formatting a day of year needs a valid date");
474*4bdff4beSrobert 
475*4bdff4beSrobert       if (__specs.__chrono_.__week_of_year_ && !__formatter::__date_ok(__value))
476*4bdff4beSrobert         std::__throw_format_error("formatting a week of year needs a valid date");
477*4bdff4beSrobert 
478*4bdff4beSrobert       if (__specs.__chrono_.__month_name_ && !__formatter::__month_name_ok(__value))
479*4bdff4beSrobert         std::__throw_format_error("formatting a month name from an invalid month number");
480*4bdff4beSrobert 
481*4bdff4beSrobert       __formatter::__format_chrono_using_chrono_specs(__value, __sstr, __chrono_specs);
482*4bdff4beSrobert     }
483*4bdff4beSrobert   }
484*4bdff4beSrobert 
485*4bdff4beSrobert   // TODO FMT Use the stringstream's view after P0408R7 has been implemented.
486*4bdff4beSrobert   basic_string<_CharT> __str = __sstr.str();
487*4bdff4beSrobert   return __formatter::__write_string(basic_string_view<_CharT>{__str}, __ctx.out(), __specs);
488*4bdff4beSrobert }
489*4bdff4beSrobert 
490*4bdff4beSrobert } // namespace __formatter
491*4bdff4beSrobert 
492*4bdff4beSrobert template <__fmt_char_type _CharT>
493*4bdff4beSrobert struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT __formatter_chrono {
494*4bdff4beSrobert public:
495*4bdff4beSrobert   _LIBCPP_HIDE_FROM_ABI constexpr auto __parse(
496*4bdff4beSrobert       basic_format_parse_context<_CharT>& __parse_ctx, __format_spec::__fields __fields, __format_spec::__flags __flags)
497*4bdff4beSrobert       -> decltype(__parse_ctx.begin()) {
498*4bdff4beSrobert     return __parser_.__parse(__parse_ctx, __fields, __flags);
499*4bdff4beSrobert   }
500*4bdff4beSrobert 
501*4bdff4beSrobert   template <class _Tp>
502*4bdff4beSrobert   _LIBCPP_HIDE_FROM_ABI auto format(const _Tp& __value, auto& __ctx) const -> decltype(__ctx.out()) const {
503*4bdff4beSrobert     return __formatter::__format_chrono(
504*4bdff4beSrobert         __value, __ctx, __parser_.__parser_.__get_parsed_chrono_specifications(__ctx), __parser_.__chrono_specs_);
505*4bdff4beSrobert   }
506*4bdff4beSrobert 
507*4bdff4beSrobert   __format_spec::__parser_chrono<_CharT> __parser_;
508*4bdff4beSrobert };
509*4bdff4beSrobert 
510*4bdff4beSrobert template <class _Rep, class _Period, __fmt_char_type _CharT>
511*4bdff4beSrobert struct formatter<chrono::duration<_Rep, _Period>, _CharT> : public __formatter_chrono<_CharT> {
512*4bdff4beSrobert public:
513*4bdff4beSrobert   using _Base = __formatter_chrono<_CharT>;
514*4bdff4beSrobert 
515*4bdff4beSrobert   _LIBCPP_HIDE_FROM_ABI constexpr auto parse(basic_format_parse_context<_CharT>& __parse_ctx)
516*4bdff4beSrobert       -> decltype(__parse_ctx.begin()) {
517*4bdff4beSrobert     // [time.format]/1
518*4bdff4beSrobert     // Giving a precision specification in the chrono-format-spec is valid only
519*4bdff4beSrobert     // for std::chrono::duration types where the representation type Rep is a
520*4bdff4beSrobert     // floating-point type. For all other Rep types, an exception of type
521*4bdff4beSrobert     // format_error is thrown if the chrono-format-spec contains a precision
522*4bdff4beSrobert     // specification.
523*4bdff4beSrobert     //
524*4bdff4beSrobert     // Note this doesn't refer to chrono::treat_as_floating_point_v<_Rep>.
525*4bdff4beSrobert     if constexpr (std::floating_point<_Rep>)
526*4bdff4beSrobert       return _Base::__parse(__parse_ctx, __format_spec::__fields_chrono_fractional, __format_spec::__flags::__duration);
527*4bdff4beSrobert     else
528*4bdff4beSrobert       return _Base::__parse(__parse_ctx, __format_spec::__fields_chrono, __format_spec::__flags::__duration);
529*4bdff4beSrobert   }
530*4bdff4beSrobert };
531*4bdff4beSrobert 
532*4bdff4beSrobert template <__fmt_char_type _CharT>
533*4bdff4beSrobert struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter<chrono::day, _CharT>
534*4bdff4beSrobert     : public __formatter_chrono<_CharT> {
535*4bdff4beSrobert public:
536*4bdff4beSrobert   using _Base = __formatter_chrono<_CharT>;
537*4bdff4beSrobert 
538*4bdff4beSrobert   _LIBCPP_HIDE_FROM_ABI constexpr auto parse(basic_format_parse_context<_CharT>& __parse_ctx)
539*4bdff4beSrobert       -> decltype(__parse_ctx.begin()) {
540*4bdff4beSrobert     return _Base::__parse(__parse_ctx, __format_spec::__fields_chrono, __format_spec::__flags::__day);
541*4bdff4beSrobert   }
542*4bdff4beSrobert };
543*4bdff4beSrobert 
544*4bdff4beSrobert template <__fmt_char_type _CharT>
545*4bdff4beSrobert struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter<chrono::month, _CharT>
546*4bdff4beSrobert     : public __formatter_chrono<_CharT> {
547*4bdff4beSrobert public:
548*4bdff4beSrobert   using _Base = __formatter_chrono<_CharT>;
549*4bdff4beSrobert 
550*4bdff4beSrobert   _LIBCPP_HIDE_FROM_ABI constexpr auto parse(basic_format_parse_context<_CharT>& __parse_ctx)
551*4bdff4beSrobert       -> decltype(__parse_ctx.begin()) {
552*4bdff4beSrobert     return _Base::__parse(__parse_ctx, __format_spec::__fields_chrono, __format_spec::__flags::__month);
553*4bdff4beSrobert   }
554*4bdff4beSrobert };
555*4bdff4beSrobert 
556*4bdff4beSrobert template <__fmt_char_type _CharT>
557*4bdff4beSrobert struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter<chrono::year, _CharT>
558*4bdff4beSrobert     : public __formatter_chrono<_CharT> {
559*4bdff4beSrobert public:
560*4bdff4beSrobert   using _Base = __formatter_chrono<_CharT>;
561*4bdff4beSrobert 
562*4bdff4beSrobert   _LIBCPP_HIDE_FROM_ABI constexpr auto parse(basic_format_parse_context<_CharT>& __parse_ctx)
563*4bdff4beSrobert       -> decltype(__parse_ctx.begin()) {
564*4bdff4beSrobert     return _Base::__parse(__parse_ctx, __format_spec::__fields_chrono, __format_spec::__flags::__year);
565*4bdff4beSrobert   }
566*4bdff4beSrobert };
567*4bdff4beSrobert 
568*4bdff4beSrobert template <__fmt_char_type _CharT>
569*4bdff4beSrobert struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter<chrono::weekday, _CharT>
570*4bdff4beSrobert     : public __formatter_chrono<_CharT> {
571*4bdff4beSrobert public:
572*4bdff4beSrobert   using _Base = __formatter_chrono<_CharT>;
573*4bdff4beSrobert 
574*4bdff4beSrobert   _LIBCPP_HIDE_FROM_ABI constexpr auto parse(basic_format_parse_context<_CharT>& __parse_ctx)
575*4bdff4beSrobert       -> decltype(__parse_ctx.begin()) {
576*4bdff4beSrobert     return _Base::__parse(__parse_ctx, __format_spec::__fields_chrono, __format_spec::__flags::__weekday);
577*4bdff4beSrobert   }
578*4bdff4beSrobert };
579*4bdff4beSrobert 
580*4bdff4beSrobert template <__fmt_char_type _CharT>
581*4bdff4beSrobert struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter<chrono::weekday_indexed, _CharT>
582*4bdff4beSrobert     : public __formatter_chrono<_CharT> {
583*4bdff4beSrobert public:
584*4bdff4beSrobert   using _Base = __formatter_chrono<_CharT>;
585*4bdff4beSrobert 
586*4bdff4beSrobert   _LIBCPP_HIDE_FROM_ABI constexpr auto parse(basic_format_parse_context<_CharT>& __parse_ctx)
587*4bdff4beSrobert       -> decltype(__parse_ctx.begin()) {
588*4bdff4beSrobert     return _Base::__parse(__parse_ctx, __format_spec::__fields_chrono, __format_spec::__flags::__weekday);
589*4bdff4beSrobert   }
590*4bdff4beSrobert };
591*4bdff4beSrobert 
592*4bdff4beSrobert template <__fmt_char_type _CharT>
593*4bdff4beSrobert struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter<chrono::weekday_last, _CharT>
594*4bdff4beSrobert     : public __formatter_chrono<_CharT> {
595*4bdff4beSrobert public:
596*4bdff4beSrobert   using _Base = __formatter_chrono<_CharT>;
597*4bdff4beSrobert 
598*4bdff4beSrobert   _LIBCPP_HIDE_FROM_ABI constexpr auto parse(basic_format_parse_context<_CharT>& __parse_ctx)
599*4bdff4beSrobert       -> decltype(__parse_ctx.begin()) {
600*4bdff4beSrobert     return _Base::__parse(__parse_ctx, __format_spec::__fields_chrono, __format_spec::__flags::__weekday);
601*4bdff4beSrobert   }
602*4bdff4beSrobert };
603*4bdff4beSrobert 
604*4bdff4beSrobert template <__fmt_char_type _CharT>
605*4bdff4beSrobert struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter<chrono::month_day, _CharT>
606*4bdff4beSrobert     : public __formatter_chrono<_CharT> {
607*4bdff4beSrobert public:
608*4bdff4beSrobert   using _Base = __formatter_chrono<_CharT>;
609*4bdff4beSrobert 
610*4bdff4beSrobert   _LIBCPP_HIDE_FROM_ABI constexpr auto parse(basic_format_parse_context<_CharT>& __parse_ctx)
611*4bdff4beSrobert       -> decltype(__parse_ctx.begin()) {
612*4bdff4beSrobert     return _Base::__parse(__parse_ctx, __format_spec::__fields_chrono, __format_spec::__flags::__month_day);
613*4bdff4beSrobert   }
614*4bdff4beSrobert };
615*4bdff4beSrobert 
616*4bdff4beSrobert template <__fmt_char_type _CharT>
617*4bdff4beSrobert struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter<chrono::month_day_last, _CharT>
618*4bdff4beSrobert     : public __formatter_chrono<_CharT> {
619*4bdff4beSrobert public:
620*4bdff4beSrobert   using _Base = __formatter_chrono<_CharT>;
621*4bdff4beSrobert 
622*4bdff4beSrobert   _LIBCPP_HIDE_FROM_ABI constexpr auto parse(basic_format_parse_context<_CharT>& __parse_ctx)
623*4bdff4beSrobert       -> decltype(__parse_ctx.begin()) {
624*4bdff4beSrobert     return _Base::__parse(__parse_ctx, __format_spec::__fields_chrono, __format_spec::__flags::__month);
625*4bdff4beSrobert   }
626*4bdff4beSrobert };
627*4bdff4beSrobert 
628*4bdff4beSrobert template <__fmt_char_type _CharT>
629*4bdff4beSrobert struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter<chrono::month_weekday, _CharT>
630*4bdff4beSrobert     : public __formatter_chrono<_CharT> {
631*4bdff4beSrobert public:
632*4bdff4beSrobert   using _Base = __formatter_chrono<_CharT>;
633*4bdff4beSrobert 
634*4bdff4beSrobert   _LIBCPP_HIDE_FROM_ABI constexpr auto parse(basic_format_parse_context<_CharT>& __parse_ctx)
635*4bdff4beSrobert       -> decltype(__parse_ctx.begin()) {
636*4bdff4beSrobert     return _Base::__parse(__parse_ctx, __format_spec::__fields_chrono, __format_spec::__flags::__month_weekday);
637*4bdff4beSrobert   }
638*4bdff4beSrobert };
639*4bdff4beSrobert 
640*4bdff4beSrobert template <__fmt_char_type _CharT>
641*4bdff4beSrobert struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter<chrono::month_weekday_last, _CharT>
642*4bdff4beSrobert     : public __formatter_chrono<_CharT> {
643*4bdff4beSrobert public:
644*4bdff4beSrobert   using _Base = __formatter_chrono<_CharT>;
645*4bdff4beSrobert 
646*4bdff4beSrobert   _LIBCPP_HIDE_FROM_ABI constexpr auto parse(basic_format_parse_context<_CharT>& __parse_ctx)
647*4bdff4beSrobert       -> decltype(__parse_ctx.begin()) {
648*4bdff4beSrobert     return _Base::__parse(__parse_ctx, __format_spec::__fields_chrono, __format_spec::__flags::__month_weekday);
649*4bdff4beSrobert   }
650*4bdff4beSrobert };
651*4bdff4beSrobert 
652*4bdff4beSrobert template <__fmt_char_type _CharT>
653*4bdff4beSrobert struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter<chrono::year_month, _CharT>
654*4bdff4beSrobert     : public __formatter_chrono<_CharT> {
655*4bdff4beSrobert public:
656*4bdff4beSrobert   using _Base = __formatter_chrono<_CharT>;
657*4bdff4beSrobert 
658*4bdff4beSrobert   _LIBCPP_HIDE_FROM_ABI constexpr auto parse(basic_format_parse_context<_CharT>& __parse_ctx)
659*4bdff4beSrobert       -> decltype(__parse_ctx.begin()) {
660*4bdff4beSrobert     return _Base::__parse(__parse_ctx, __format_spec::__fields_chrono, __format_spec::__flags::__year_month);
661*4bdff4beSrobert   }
662*4bdff4beSrobert };
663*4bdff4beSrobert 
664*4bdff4beSrobert template <__fmt_char_type _CharT>
665*4bdff4beSrobert struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter<chrono::year_month_day, _CharT>
666*4bdff4beSrobert     : public __formatter_chrono<_CharT> {
667*4bdff4beSrobert public:
668*4bdff4beSrobert   using _Base = __formatter_chrono<_CharT>;
669*4bdff4beSrobert 
670*4bdff4beSrobert   _LIBCPP_HIDE_FROM_ABI constexpr auto parse(basic_format_parse_context<_CharT>& __parse_ctx)
671*4bdff4beSrobert       -> decltype(__parse_ctx.begin()) {
672*4bdff4beSrobert     return _Base::__parse(__parse_ctx, __format_spec::__fields_chrono, __format_spec::__flags::__date);
673*4bdff4beSrobert   }
674*4bdff4beSrobert };
675*4bdff4beSrobert 
676*4bdff4beSrobert template <__fmt_char_type _CharT>
677*4bdff4beSrobert struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter<chrono::year_month_day_last, _CharT>
678*4bdff4beSrobert     : public __formatter_chrono<_CharT> {
679*4bdff4beSrobert public:
680*4bdff4beSrobert   using _Base = __formatter_chrono<_CharT>;
681*4bdff4beSrobert 
682*4bdff4beSrobert   _LIBCPP_HIDE_FROM_ABI constexpr auto parse(basic_format_parse_context<_CharT>& __parse_ctx)
683*4bdff4beSrobert       -> decltype(__parse_ctx.begin()) {
684*4bdff4beSrobert     return _Base::__parse(__parse_ctx, __format_spec::__fields_chrono, __format_spec::__flags::__date);
685*4bdff4beSrobert   }
686*4bdff4beSrobert };
687*4bdff4beSrobert 
688*4bdff4beSrobert template <__fmt_char_type _CharT>
689*4bdff4beSrobert struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter<chrono::year_month_weekday, _CharT>
690*4bdff4beSrobert     : public __formatter_chrono<_CharT> {
691*4bdff4beSrobert public:
692*4bdff4beSrobert   using _Base = __formatter_chrono<_CharT>;
693*4bdff4beSrobert 
694*4bdff4beSrobert   _LIBCPP_HIDE_FROM_ABI constexpr auto parse(basic_format_parse_context<_CharT>& __parse_ctx)
695*4bdff4beSrobert       -> decltype(__parse_ctx.begin()) {
696*4bdff4beSrobert     return _Base::__parse(__parse_ctx, __format_spec::__fields_chrono, __format_spec::__flags::__date);
697*4bdff4beSrobert   }
698*4bdff4beSrobert };
699*4bdff4beSrobert 
700*4bdff4beSrobert template <__fmt_char_type _CharT>
701*4bdff4beSrobert struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter<chrono::year_month_weekday_last, _CharT>
702*4bdff4beSrobert     : public __formatter_chrono<_CharT> {
703*4bdff4beSrobert public:
704*4bdff4beSrobert   using _Base = __formatter_chrono<_CharT>;
705*4bdff4beSrobert 
706*4bdff4beSrobert   _LIBCPP_HIDE_FROM_ABI constexpr auto parse(basic_format_parse_context<_CharT>& __parse_ctx)
707*4bdff4beSrobert       -> decltype(__parse_ctx.begin()) {
708*4bdff4beSrobert     return _Base::__parse(__parse_ctx, __format_spec::__fields_chrono, __format_spec::__flags::__date);
709*4bdff4beSrobert   }
710*4bdff4beSrobert };
711*4bdff4beSrobert 
712*4bdff4beSrobert #endif // if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_FORMAT)
713*4bdff4beSrobert 
714*4bdff4beSrobert _LIBCPP_END_NAMESPACE_STD
715*4bdff4beSrobert 
716*4bdff4beSrobert #endif //  _LIBCPP___CHRONO_FORMATTER_H
717