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