1bdd1243dSDimitry Andric // -*- C++ -*-
2bdd1243dSDimitry Andric //===----------------------------------------------------------------------===//
3bdd1243dSDimitry Andric //
4bdd1243dSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5bdd1243dSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
6bdd1243dSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7bdd1243dSDimitry Andric //
8bdd1243dSDimitry Andric //===----------------------------------------------------------------------===//
9bdd1243dSDimitry Andric
10bdd1243dSDimitry Andric #ifndef _LIBCPP___CHRONO_FORMATTER_H
11bdd1243dSDimitry Andric #define _LIBCPP___CHRONO_FORMATTER_H
12bdd1243dSDimitry Andric
13*0fca6ea1SDimitry Andric #include <__algorithm/ranges_copy.h>
14bdd1243dSDimitry Andric #include <__chrono/calendar.h>
1506c3fb27SDimitry Andric #include <__chrono/concepts.h>
16bdd1243dSDimitry Andric #include <__chrono/convert_to_tm.h>
17bdd1243dSDimitry Andric #include <__chrono/day.h>
18bdd1243dSDimitry Andric #include <__chrono/duration.h>
1906c3fb27SDimitry Andric #include <__chrono/file_clock.h>
20bdd1243dSDimitry Andric #include <__chrono/hh_mm_ss.h>
21*0fca6ea1SDimitry Andric #include <__chrono/local_info.h>
22bdd1243dSDimitry Andric #include <__chrono/month.h>
23bdd1243dSDimitry Andric #include <__chrono/month_weekday.h>
24bdd1243dSDimitry Andric #include <__chrono/monthday.h>
25bdd1243dSDimitry Andric #include <__chrono/ostream.h>
26bdd1243dSDimitry Andric #include <__chrono/parser_std_format_spec.h>
27bdd1243dSDimitry Andric #include <__chrono/statically_widen.h>
28*0fca6ea1SDimitry Andric #include <__chrono/sys_info.h>
2906c3fb27SDimitry Andric #include <__chrono/system_clock.h>
30bdd1243dSDimitry Andric #include <__chrono/time_point.h>
31bdd1243dSDimitry Andric #include <__chrono/weekday.h>
32bdd1243dSDimitry Andric #include <__chrono/year.h>
33bdd1243dSDimitry Andric #include <__chrono/year_month.h>
34bdd1243dSDimitry Andric #include <__chrono/year_month_day.h>
35bdd1243dSDimitry Andric #include <__chrono/year_month_weekday.h>
36*0fca6ea1SDimitry Andric #include <__chrono/zoned_time.h>
37bdd1243dSDimitry Andric #include <__concepts/arithmetic.h>
38bdd1243dSDimitry Andric #include <__concepts/same_as.h>
39bdd1243dSDimitry Andric #include <__config>
40bdd1243dSDimitry Andric #include <__format/concepts.h>
41bdd1243dSDimitry Andric #include <__format/format_error.h>
42bdd1243dSDimitry Andric #include <__format/format_functions.h>
43bdd1243dSDimitry Andric #include <__format/format_parse_context.h>
44bdd1243dSDimitry Andric #include <__format/formatter.h>
45bdd1243dSDimitry Andric #include <__format/parser_std_format_spec.h>
4606c3fb27SDimitry Andric #include <__format/write_escaped.h>
47bdd1243dSDimitry Andric #include <__memory/addressof.h>
48*0fca6ea1SDimitry Andric #include <__type_traits/is_specialization.h>
49bdd1243dSDimitry Andric #include <cmath>
50bdd1243dSDimitry Andric #include <ctime>
51*0fca6ea1SDimitry Andric #include <limits>
52bdd1243dSDimitry Andric #include <sstream>
53bdd1243dSDimitry Andric #include <string_view>
54bdd1243dSDimitry Andric
55bdd1243dSDimitry Andric #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
56bdd1243dSDimitry Andric # pragma GCC system_header
57bdd1243dSDimitry Andric #endif
58bdd1243dSDimitry Andric
59bdd1243dSDimitry Andric _LIBCPP_BEGIN_NAMESPACE_STD
60bdd1243dSDimitry Andric
6106c3fb27SDimitry Andric #if _LIBCPP_STD_VER >= 20
62bdd1243dSDimitry Andric
63bdd1243dSDimitry Andric namespace __formatter {
64bdd1243dSDimitry Andric
65bdd1243dSDimitry Andric /// Formats a time based on a tm struct.
66bdd1243dSDimitry Andric ///
67bdd1243dSDimitry Andric /// This formatter passes the formatting to time_put which uses strftime. When
68bdd1243dSDimitry Andric /// the value is outside the valid range it's unspecified what strftime will
69bdd1243dSDimitry Andric /// output. For example weekday 8 can print 1 when the day is processed modulo
70bdd1243dSDimitry Andric /// 7 since that handles the Sunday for 0-based weekday. It can also print 8 if
71bdd1243dSDimitry Andric /// 7 is handled as a special case.
72bdd1243dSDimitry Andric ///
73bdd1243dSDimitry Andric /// The Standard doesn't specify what to do in this case so the result depends
74bdd1243dSDimitry Andric /// on the result of the underlying code.
75bdd1243dSDimitry Andric ///
76bdd1243dSDimitry Andric /// \pre When the (abbreviated) weekday or month name are used, the caller
77bdd1243dSDimitry Andric /// validates whether the value is valid. So the caller handles that
78bdd1243dSDimitry Andric /// requirement of Table 97: Meaning of conversion specifiers
79bdd1243dSDimitry Andric /// [tab:time.format.spec].
80bdd1243dSDimitry Andric ///
81bdd1243dSDimitry Andric /// When no chrono-specs are provided it uses the stream formatter.
82bdd1243dSDimitry Andric
83bdd1243dSDimitry Andric // For tiny ratios it's not possible to convert a duration to a hh_mm_ss. This
84bdd1243dSDimitry Andric // fails compile-time due to the limited precision of the ratio (64-bit is too
85bdd1243dSDimitry Andric // small). Therefore a duration uses its own conversion.
8606c3fb27SDimitry Andric template <class _CharT, class _Rep, class _Period>
8706c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI void
__format_sub_seconds(basic_stringstream<_CharT> & __sstr,const chrono::duration<_Rep,_Period> & __value)88*0fca6ea1SDimitry Andric __format_sub_seconds(basic_stringstream<_CharT>& __sstr, const chrono::duration<_Rep, _Period>& __value) {
89bdd1243dSDimitry Andric __sstr << std::use_facet<numpunct<_CharT>>(__sstr.getloc()).decimal_point();
90bdd1243dSDimitry Andric
9106c3fb27SDimitry Andric using __duration = chrono::duration<_Rep, _Period>;
9206c3fb27SDimitry Andric
93bdd1243dSDimitry Andric auto __fraction = __value - chrono::duration_cast<chrono::seconds>(__value);
94*0fca6ea1SDimitry Andric // Converts a negative fraction to its positive value.
95*0fca6ea1SDimitry Andric if (__value < chrono::seconds{0} && __fraction != __duration{0})
96*0fca6ea1SDimitry Andric __fraction += chrono::seconds{1};
9706c3fb27SDimitry Andric if constexpr (chrono::treat_as_floating_point_v<_Rep>)
98bdd1243dSDimitry Andric // When the floating-point value has digits itself they are ignored based
99bdd1243dSDimitry Andric // on the wording in [tab:time.format.spec]
100bdd1243dSDimitry Andric // If the precision of the input cannot be exactly represented with
101bdd1243dSDimitry Andric // seconds, then the format is a decimal floating-point number with a
102bdd1243dSDimitry Andric // fixed format and a precision matching that of the precision of the
103bdd1243dSDimitry Andric // input (or to a microseconds precision if the conversion to
104bdd1243dSDimitry Andric // floating-point decimal seconds cannot be made within 18 fractional
105bdd1243dSDimitry Andric // digits).
106bdd1243dSDimitry Andric //
107bdd1243dSDimitry Andric // This matches the behaviour of MSVC STL, fmtlib interprets this
108bdd1243dSDimitry Andric // differently and uses 3 decimals.
109bdd1243dSDimitry Andric // https://godbolt.org/z/6dsbnW8ba
110bdd1243dSDimitry Andric std::format_to(std::ostreambuf_iterator<_CharT>{__sstr},
111bdd1243dSDimitry Andric _LIBCPP_STATICALLY_WIDEN(_CharT, "{:0{}.0f}"),
11206c3fb27SDimitry Andric chrono::duration_cast<typename chrono::hh_mm_ss<__duration>::precision>(__fraction).count(),
11306c3fb27SDimitry Andric chrono::hh_mm_ss<__duration>::fractional_width);
114bdd1243dSDimitry Andric else
115bdd1243dSDimitry Andric std::format_to(std::ostreambuf_iterator<_CharT>{__sstr},
116bdd1243dSDimitry Andric _LIBCPP_STATICALLY_WIDEN(_CharT, "{:0{}}"),
11706c3fb27SDimitry Andric chrono::duration_cast<typename chrono::hh_mm_ss<__duration>::precision>(__fraction).count(),
11806c3fb27SDimitry Andric chrono::hh_mm_ss<__duration>::fractional_width);
11906c3fb27SDimitry Andric }
12006c3fb27SDimitry Andric
12106c3fb27SDimitry Andric template <class _CharT, __is_time_point _Tp>
__format_sub_seconds(basic_stringstream<_CharT> & __sstr,const _Tp & __value)122*0fca6ea1SDimitry Andric _LIBCPP_HIDE_FROM_ABI void __format_sub_seconds(basic_stringstream<_CharT>& __sstr, const _Tp& __value) {
123*0fca6ea1SDimitry Andric __formatter::__format_sub_seconds(__sstr, __value.time_since_epoch());
12406c3fb27SDimitry Andric }
12506c3fb27SDimitry Andric
12606c3fb27SDimitry Andric template <class _CharT, class _Duration>
12706c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI void
__format_sub_seconds(basic_stringstream<_CharT> & __sstr,const chrono::hh_mm_ss<_Duration> & __value)128*0fca6ea1SDimitry Andric __format_sub_seconds(basic_stringstream<_CharT>& __sstr, const chrono::hh_mm_ss<_Duration>& __value) {
12906c3fb27SDimitry Andric __sstr << std::use_facet<numpunct<_CharT>>(__sstr.getloc()).decimal_point();
13006c3fb27SDimitry Andric if constexpr (chrono::treat_as_floating_point_v<typename _Duration::rep>)
13106c3fb27SDimitry Andric std::format_to(std::ostreambuf_iterator<_CharT>{__sstr},
13206c3fb27SDimitry Andric _LIBCPP_STATICALLY_WIDEN(_CharT, "{:0{}.0f}"),
13306c3fb27SDimitry Andric __value.subseconds().count(),
13406c3fb27SDimitry Andric __value.fractional_width);
13506c3fb27SDimitry Andric else
13606c3fb27SDimitry Andric std::format_to(std::ostreambuf_iterator<_CharT>{__sstr},
13706c3fb27SDimitry Andric _LIBCPP_STATICALLY_WIDEN(_CharT, "{:0{}}"),
13806c3fb27SDimitry Andric __value.subseconds().count(),
13906c3fb27SDimitry Andric __value.fractional_width);
140bdd1243dSDimitry Andric }
141bdd1243dSDimitry Andric
142*0fca6ea1SDimitry Andric # if !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_TZDB) && !defined(_LIBCPP_HAS_NO_TIME_ZONE_DATABASE) && \
143*0fca6ea1SDimitry Andric !defined(_LIBCPP_HAS_NO_FILESYSTEM) && !defined(_LIBCPP_HAS_NO_LOCALIZATION)
144*0fca6ea1SDimitry Andric template <class _CharT, class _Duration, class _TimeZonePtr>
145*0fca6ea1SDimitry Andric _LIBCPP_HIDE_FROM_ABI void
__format_sub_seconds(basic_stringstream<_CharT> & __sstr,const chrono::zoned_time<_Duration,_TimeZonePtr> & __value)146*0fca6ea1SDimitry Andric __format_sub_seconds(basic_stringstream<_CharT>& __sstr, const chrono::zoned_time<_Duration, _TimeZonePtr>& __value) {
147*0fca6ea1SDimitry Andric __formatter::__format_sub_seconds(__sstr, __value.get_local_time().time_since_epoch());
148*0fca6ea1SDimitry Andric }
149*0fca6ea1SDimitry Andric # endif
150*0fca6ea1SDimitry Andric
151bdd1243dSDimitry Andric template <class _Tp>
__use_fraction()152bdd1243dSDimitry Andric consteval bool __use_fraction() {
15306c3fb27SDimitry Andric if constexpr (__is_time_point<_Tp>)
15406c3fb27SDimitry Andric return chrono::hh_mm_ss<typename _Tp::duration>::fractional_width;
155*0fca6ea1SDimitry Andric # if !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_TZDB) && !defined(_LIBCPP_HAS_NO_TIME_ZONE_DATABASE) && \
156*0fca6ea1SDimitry Andric !defined(_LIBCPP_HAS_NO_FILESYSTEM) && !defined(_LIBCPP_HAS_NO_LOCALIZATION)
157*0fca6ea1SDimitry Andric else if constexpr (__is_specialization_v<_Tp, chrono::zoned_time>)
158*0fca6ea1SDimitry Andric return chrono::hh_mm_ss<typename _Tp::duration>::fractional_width;
159*0fca6ea1SDimitry Andric # endif
16006c3fb27SDimitry Andric else if constexpr (chrono::__is_duration<_Tp>::value)
161bdd1243dSDimitry Andric return chrono::hh_mm_ss<_Tp>::fractional_width;
16206c3fb27SDimitry Andric else if constexpr (__is_hh_mm_ss<_Tp>)
16306c3fb27SDimitry Andric return _Tp::fractional_width;
164bdd1243dSDimitry Andric else
165bdd1243dSDimitry Andric return false;
166bdd1243dSDimitry Andric }
167bdd1243dSDimitry Andric
168bdd1243dSDimitry Andric template <class _CharT>
__format_year(basic_stringstream<_CharT> & __sstr,int __year)169*0fca6ea1SDimitry Andric _LIBCPP_HIDE_FROM_ABI void __format_year(basic_stringstream<_CharT>& __sstr, int __year) {
170bdd1243dSDimitry Andric if (__year < 0) {
171bdd1243dSDimitry Andric __sstr << _CharT('-');
172bdd1243dSDimitry Andric __year = -__year;
173bdd1243dSDimitry Andric }
174bdd1243dSDimitry Andric
175bdd1243dSDimitry Andric // TODO FMT Write an issue
176bdd1243dSDimitry Andric // If the result has less than four digits it is zero-padded with 0 to two digits.
177bdd1243dSDimitry Andric // is less -> has less
178bdd1243dSDimitry Andric // left-padded -> zero-padded, otherwise the proper value would be 000-0.
179bdd1243dSDimitry Andric
180bdd1243dSDimitry Andric // Note according to the wording it should be left padded, which is odd.
181bdd1243dSDimitry Andric __sstr << std::format(_LIBCPP_STATICALLY_WIDEN(_CharT, "{:04}"), __year);
182bdd1243dSDimitry Andric }
183bdd1243dSDimitry Andric
184bdd1243dSDimitry Andric template <class _CharT>
__format_century(basic_stringstream<_CharT> & __sstr,int __year)185*0fca6ea1SDimitry Andric _LIBCPP_HIDE_FROM_ABI void __format_century(basic_stringstream<_CharT>& __sstr, int __year) {
186bdd1243dSDimitry Andric // TODO FMT Write an issue
187bdd1243dSDimitry Andric // [tab:time.format.spec]
188bdd1243dSDimitry Andric // %C The year divided by 100 using floored division. If the result is a
189bdd1243dSDimitry Andric // single decimal digit, it is prefixed with 0.
190bdd1243dSDimitry Andric
191bdd1243dSDimitry Andric bool __negative = __year < 0;
192bdd1243dSDimitry Andric int __century = (__year - (99 * __negative)) / 100; // floored division
193bdd1243dSDimitry Andric __sstr << std::format(_LIBCPP_STATICALLY_WIDEN(_CharT, "{:02}"), __century);
194bdd1243dSDimitry Andric }
195bdd1243dSDimitry Andric
196*0fca6ea1SDimitry Andric // Implements the %z format specifier according to [tab:time.format.spec], where
197*0fca6ea1SDimitry Andric // '__modifier' signals %Oz or %Ez were used. (Both modifiers behave the same,
198*0fca6ea1SDimitry Andric // so there is no need to distinguish between them.)
199*0fca6ea1SDimitry Andric template <class _CharT>
200*0fca6ea1SDimitry Andric _LIBCPP_HIDE_FROM_ABI void
__format_zone_offset(basic_stringstream<_CharT> & __sstr,chrono::seconds __offset,bool __modifier)201*0fca6ea1SDimitry Andric __format_zone_offset(basic_stringstream<_CharT>& __sstr, chrono::seconds __offset, bool __modifier) {
202*0fca6ea1SDimitry Andric if (__offset < 0s) {
203*0fca6ea1SDimitry Andric __sstr << _CharT('-');
204*0fca6ea1SDimitry Andric __offset = -__offset;
205*0fca6ea1SDimitry Andric } else {
206*0fca6ea1SDimitry Andric __sstr << _CharT('+');
207*0fca6ea1SDimitry Andric }
208*0fca6ea1SDimitry Andric
209*0fca6ea1SDimitry Andric chrono::hh_mm_ss __hms{__offset};
210*0fca6ea1SDimitry Andric std::ostreambuf_iterator<_CharT> __out_it{__sstr};
211*0fca6ea1SDimitry Andric // Note HMS does not allow formatting hours > 23, but the offset is not limited to 24H.
212*0fca6ea1SDimitry Andric std::format_to(__out_it, _LIBCPP_STATICALLY_WIDEN(_CharT, "{:02}"), __hms.hours().count());
213*0fca6ea1SDimitry Andric if (__modifier)
214*0fca6ea1SDimitry Andric __sstr << _CharT(':');
215*0fca6ea1SDimitry Andric std::format_to(__out_it, _LIBCPP_STATICALLY_WIDEN(_CharT, "{:02}"), __hms.minutes().count());
216*0fca6ea1SDimitry Andric }
217*0fca6ea1SDimitry Andric
218*0fca6ea1SDimitry Andric // Helper to store the time zone information needed for formatting.
219*0fca6ea1SDimitry Andric struct _LIBCPP_HIDE_FROM_ABI __time_zone {
220*0fca6ea1SDimitry Andric // Typically these abbreviations are short and fit in the string's internal
221*0fca6ea1SDimitry Andric // buffer.
222*0fca6ea1SDimitry Andric string __abbrev;
223*0fca6ea1SDimitry Andric chrono::seconds __offset;
224*0fca6ea1SDimitry Andric };
225*0fca6ea1SDimitry Andric
226*0fca6ea1SDimitry Andric template <class _Tp>
__convert_to_time_zone(const _Tp & __value)227*0fca6ea1SDimitry Andric _LIBCPP_HIDE_FROM_ABI __time_zone __convert_to_time_zone([[maybe_unused]] const _Tp& __value) {
228*0fca6ea1SDimitry Andric # if !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_TZDB)
229*0fca6ea1SDimitry Andric if constexpr (same_as<_Tp, chrono::sys_info>)
230*0fca6ea1SDimitry Andric return {__value.abbrev, __value.offset};
231*0fca6ea1SDimitry Andric # if !defined(_LIBCPP_HAS_NO_TIME_ZONE_DATABASE) && !defined(_LIBCPP_HAS_NO_FILESYSTEM) && \
232*0fca6ea1SDimitry Andric !defined(_LIBCPP_HAS_NO_LOCALIZATION)
233*0fca6ea1SDimitry Andric else if constexpr (__is_specialization_v<_Tp, chrono::zoned_time>)
234*0fca6ea1SDimitry Andric return __formatter::__convert_to_time_zone(__value.get_info());
235*0fca6ea1SDimitry Andric # endif
236*0fca6ea1SDimitry Andric else
237*0fca6ea1SDimitry Andric # endif // !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_TZDB)
238*0fca6ea1SDimitry Andric return {"UTC", chrono::seconds{0}};
239*0fca6ea1SDimitry Andric }
240*0fca6ea1SDimitry Andric
241bdd1243dSDimitry Andric template <class _CharT, class _Tp>
__format_chrono_using_chrono_specs(basic_stringstream<_CharT> & __sstr,const _Tp & __value,basic_string_view<_CharT> __chrono_specs)242bdd1243dSDimitry Andric _LIBCPP_HIDE_FROM_ABI void __format_chrono_using_chrono_specs(
243*0fca6ea1SDimitry Andric basic_stringstream<_CharT>& __sstr, const _Tp& __value, basic_string_view<_CharT> __chrono_specs) {
244bdd1243dSDimitry Andric tm __t = std::__convert_to_tm<tm>(__value);
245*0fca6ea1SDimitry Andric __time_zone __z = __formatter::__convert_to_time_zone(__value);
246bdd1243dSDimitry Andric const auto& __facet = std::use_facet<time_put<_CharT>>(__sstr.getloc());
247bdd1243dSDimitry Andric for (auto __it = __chrono_specs.begin(); __it != __chrono_specs.end(); ++__it) {
248bdd1243dSDimitry Andric if (*__it == _CharT('%')) {
249bdd1243dSDimitry Andric auto __s = __it;
250bdd1243dSDimitry Andric ++__it;
251bdd1243dSDimitry Andric // We only handle the types that can't be directly handled by time_put.
252bdd1243dSDimitry Andric // (as an optimization n, t, and % are also handled directly.)
253bdd1243dSDimitry Andric switch (*__it) {
254bdd1243dSDimitry Andric case _CharT('n'):
255bdd1243dSDimitry Andric __sstr << _CharT('\n');
256bdd1243dSDimitry Andric break;
257bdd1243dSDimitry Andric case _CharT('t'):
258bdd1243dSDimitry Andric __sstr << _CharT('\t');
259bdd1243dSDimitry Andric break;
260bdd1243dSDimitry Andric case _CharT('%'):
261bdd1243dSDimitry Andric __sstr << *__it;
262bdd1243dSDimitry Andric break;
263bdd1243dSDimitry Andric
264bdd1243dSDimitry Andric case _CharT('C'): {
265bdd1243dSDimitry Andric // strftime's output is only defined in the range [00, 99].
266bdd1243dSDimitry Andric int __year = __t.tm_year + 1900;
267bdd1243dSDimitry Andric if (__year < 1000 || __year > 9999)
268*0fca6ea1SDimitry Andric __formatter::__format_century(__sstr, __year);
269bdd1243dSDimitry Andric else
270cb14a3feSDimitry Andric __facet.put(
271cb14a3feSDimitry Andric {__sstr}, __sstr, _CharT(' '), std::addressof(__t), std::to_address(__s), std::to_address(__it + 1));
272bdd1243dSDimitry Andric } break;
273bdd1243dSDimitry Andric
274bdd1243dSDimitry Andric case _CharT('j'):
275bdd1243dSDimitry Andric if constexpr (chrono::__is_duration<_Tp>::value)
276bdd1243dSDimitry Andric // Converting a duration where the period has a small ratio to days
277bdd1243dSDimitry Andric // may fail to compile. This due to loss of precision in the
278bdd1243dSDimitry Andric // conversion. In order to avoid that issue convert to seconds as
279bdd1243dSDimitry Andric // an intemediate step.
280bdd1243dSDimitry Andric __sstr << chrono::duration_cast<chrono::days>(chrono::duration_cast<chrono::seconds>(__value)).count();
281bdd1243dSDimitry Andric else
282cb14a3feSDimitry Andric __facet.put(
283cb14a3feSDimitry Andric {__sstr}, __sstr, _CharT(' '), std::addressof(__t), std::to_address(__s), std::to_address(__it + 1));
284bdd1243dSDimitry Andric break;
285bdd1243dSDimitry Andric
286bdd1243dSDimitry Andric case _CharT('q'):
287bdd1243dSDimitry Andric if constexpr (chrono::__is_duration<_Tp>::value) {
288bdd1243dSDimitry Andric __sstr << chrono::__units_suffix<_CharT, typename _Tp::period>();
289bdd1243dSDimitry Andric break;
290bdd1243dSDimitry Andric }
291bdd1243dSDimitry Andric __builtin_unreachable();
292bdd1243dSDimitry Andric
293bdd1243dSDimitry Andric case _CharT('Q'):
294bdd1243dSDimitry Andric // TODO FMT Determine the proper ideas
295bdd1243dSDimitry Andric // - Should it honour the precision?
296bdd1243dSDimitry Andric // - Shoult it honour the locale setting for the separators?
297bdd1243dSDimitry Andric // The wording for Q doesn't use the word locale and the effect of
298bdd1243dSDimitry Andric // precision is unspecified.
299bdd1243dSDimitry Andric //
300bdd1243dSDimitry Andric // MSVC STL ignores precision but uses separator
301bdd1243dSDimitry Andric // FMT honours precision and has a bug for separator
302bdd1243dSDimitry Andric // https://godbolt.org/z/78b7sMxns
303bdd1243dSDimitry Andric if constexpr (chrono::__is_duration<_Tp>::value) {
304bdd1243dSDimitry Andric __sstr << std::format(_LIBCPP_STATICALLY_WIDEN(_CharT, "{}"), __value.count());
305bdd1243dSDimitry Andric break;
306bdd1243dSDimitry Andric }
307bdd1243dSDimitry Andric __builtin_unreachable();
308bdd1243dSDimitry Andric
309bdd1243dSDimitry Andric case _CharT('S'):
310bdd1243dSDimitry Andric case _CharT('T'):
311cb14a3feSDimitry Andric __facet.put(
312cb14a3feSDimitry Andric {__sstr}, __sstr, _CharT(' '), std::addressof(__t), std::to_address(__s), std::to_address(__it + 1));
313bdd1243dSDimitry Andric if constexpr (__use_fraction<_Tp>())
314*0fca6ea1SDimitry Andric __formatter::__format_sub_seconds(__sstr, __value);
315bdd1243dSDimitry Andric break;
316bdd1243dSDimitry Andric
317bdd1243dSDimitry Andric // Unlike time_put and strftime the formatting library requires %Y
318bdd1243dSDimitry Andric //
319bdd1243dSDimitry Andric // [tab:time.format.spec]
320bdd1243dSDimitry Andric // The year as a decimal number. If the result is less than four digits
321bdd1243dSDimitry Andric // it is left-padded with 0 to four digits.
322bdd1243dSDimitry Andric //
323bdd1243dSDimitry Andric // This means years in the range (-1000, 1000) need manual formatting.
324bdd1243dSDimitry Andric // It's unclear whether %EY needs the same treatment. For example the
325bdd1243dSDimitry Andric // Japanese EY contains the era name and year. This is zero-padded to 2
326bdd1243dSDimitry Andric // digits in time_put (note that older glibc versions didn't do
327bdd1243dSDimitry Andric // padding.) However most eras won't reach 100 years, let alone 1000.
328bdd1243dSDimitry Andric // So padding to 4 digits seems unwanted for Japanese.
329bdd1243dSDimitry Andric //
330bdd1243dSDimitry Andric // The same applies to %Ex since that too depends on the era.
331bdd1243dSDimitry Andric //
332bdd1243dSDimitry Andric // %x the locale's date representation is currently doesn't handle the
333bdd1243dSDimitry Andric // zero-padding too.
334bdd1243dSDimitry Andric //
335bdd1243dSDimitry Andric // The 4 digits can be implemented better at a later time. On POSIX
336bdd1243dSDimitry Andric // systems the required information can be extracted by nl_langinfo
337bdd1243dSDimitry Andric // https://man7.org/linux/man-pages/man3/nl_langinfo.3.html
338bdd1243dSDimitry Andric //
339bdd1243dSDimitry Andric // Note since year < -1000 is expected to be rare it uses the more
340bdd1243dSDimitry Andric // expensive year routine.
341bdd1243dSDimitry Andric //
342bdd1243dSDimitry Andric // TODO FMT evaluate the comment above.
343bdd1243dSDimitry Andric
34406c3fb27SDimitry Andric # if defined(__GLIBC__) || defined(_AIX) || defined(_WIN32)
345bdd1243dSDimitry Andric case _CharT('y'):
346bdd1243dSDimitry Andric // Glibc fails for negative values, AIX for positive values too.
347bdd1243dSDimitry Andric __sstr << std::format(_LIBCPP_STATICALLY_WIDEN(_CharT, "{:02}"), (std::abs(__t.tm_year + 1900)) % 100);
348bdd1243dSDimitry Andric break;
34906c3fb27SDimitry Andric # endif // defined(__GLIBC__) || defined(_AIX) || defined(_WIN32)
350bdd1243dSDimitry Andric
35106c3fb27SDimitry Andric case _CharT('Y'):
35206c3fb27SDimitry Andric // Depending on the platform's libc the range of supported years is
35306c3fb27SDimitry Andric // limited. Intead of of testing all conditions use the internal
35406c3fb27SDimitry Andric // implementation unconditionally.
355*0fca6ea1SDimitry Andric __formatter::__format_year(__sstr, __t.tm_year + 1900);
35606c3fb27SDimitry Andric break;
357bdd1243dSDimitry Andric
358*0fca6ea1SDimitry Andric case _CharT('F'):
359*0fca6ea1SDimitry Andric // Depending on the platform's libc the range of supported years is
360*0fca6ea1SDimitry Andric // limited. Instead of testing all conditions use the internal
361*0fca6ea1SDimitry Andric // implementation unconditionally.
362*0fca6ea1SDimitry Andric __formatter::__format_year(__sstr, __t.tm_year + 1900);
363bdd1243dSDimitry Andric __sstr << std::format(_LIBCPP_STATICALLY_WIDEN(_CharT, "-{:02}-{:02}"), __t.tm_mon + 1, __t.tm_mday);
364*0fca6ea1SDimitry Andric break;
365*0fca6ea1SDimitry Andric
366*0fca6ea1SDimitry Andric case _CharT('z'):
367*0fca6ea1SDimitry Andric __formatter::__format_zone_offset(__sstr, __z.__offset, false);
368*0fca6ea1SDimitry Andric break;
369bdd1243dSDimitry Andric
37006c3fb27SDimitry Andric case _CharT('Z'):
371*0fca6ea1SDimitry Andric // __abbrev is always a char so the copy may convert.
372*0fca6ea1SDimitry Andric ranges::copy(__z.__abbrev, std::ostreambuf_iterator<_CharT>{__sstr});
37306c3fb27SDimitry Andric break;
37406c3fb27SDimitry Andric
375bdd1243dSDimitry Andric case _CharT('O'):
376bdd1243dSDimitry Andric if constexpr (__use_fraction<_Tp>()) {
377bdd1243dSDimitry Andric // Handle OS using the normal representation for the non-fractional
378bdd1243dSDimitry Andric // part. There seems to be no locale information regarding how the
379bdd1243dSDimitry Andric // fractional part should be formatted.
380bdd1243dSDimitry Andric if (*(__it + 1) == 'S') {
381bdd1243dSDimitry Andric ++__it;
382cb14a3feSDimitry Andric __facet.put(
383cb14a3feSDimitry Andric {__sstr}, __sstr, _CharT(' '), std::addressof(__t), std::to_address(__s), std::to_address(__it + 1));
384*0fca6ea1SDimitry Andric __formatter::__format_sub_seconds(__sstr, __value);
385bdd1243dSDimitry Andric break;
386bdd1243dSDimitry Andric }
387bdd1243dSDimitry Andric }
388*0fca6ea1SDimitry Andric
389*0fca6ea1SDimitry Andric // Oz produces the same output as Ez below.
390bdd1243dSDimitry Andric [[fallthrough]];
391bdd1243dSDimitry Andric case _CharT('E'):
392bdd1243dSDimitry Andric ++__it;
393*0fca6ea1SDimitry Andric if (*__it == 'z') {
394*0fca6ea1SDimitry Andric __formatter::__format_zone_offset(__sstr, __z.__offset, true);
395*0fca6ea1SDimitry Andric break;
396*0fca6ea1SDimitry Andric }
397bdd1243dSDimitry Andric [[fallthrough]];
398bdd1243dSDimitry Andric default:
399cb14a3feSDimitry Andric __facet.put(
400cb14a3feSDimitry Andric {__sstr}, __sstr, _CharT(' '), std::addressof(__t), std::to_address(__s), std::to_address(__it + 1));
401bdd1243dSDimitry Andric break;
402bdd1243dSDimitry Andric }
403bdd1243dSDimitry Andric } else {
404bdd1243dSDimitry Andric __sstr << *__it;
405bdd1243dSDimitry Andric }
406bdd1243dSDimitry Andric }
407bdd1243dSDimitry Andric }
408bdd1243dSDimitry Andric
409bdd1243dSDimitry Andric template <class _Tp>
__weekday_ok(const _Tp & __value)410bdd1243dSDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr bool __weekday_ok(const _Tp& __value) {
41106c3fb27SDimitry Andric if constexpr (__is_time_point<_Tp>)
41206c3fb27SDimitry Andric return true;
41306c3fb27SDimitry Andric else if constexpr (same_as<_Tp, chrono::day>)
414bdd1243dSDimitry Andric return true;
415bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::month>)
416bdd1243dSDimitry Andric return __value.ok();
417bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::year>)
418bdd1243dSDimitry Andric return true;
419bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::weekday>)
420bdd1243dSDimitry Andric return true;
421bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::weekday_indexed>)
422bdd1243dSDimitry Andric return true;
423bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::weekday_last>)
424bdd1243dSDimitry Andric return true;
425bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::month_day>)
426bdd1243dSDimitry Andric return true;
427bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::month_day_last>)
428bdd1243dSDimitry Andric return true;
429bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::month_weekday>)
430bdd1243dSDimitry Andric return true;
431bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::month_weekday_last>)
432bdd1243dSDimitry Andric return true;
433bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::year_month>)
434bdd1243dSDimitry Andric return true;
435bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::year_month_day>)
436bdd1243dSDimitry Andric return __value.ok();
437bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::year_month_day_last>)
438bdd1243dSDimitry Andric return __value.ok();
439bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::year_month_weekday>)
440bdd1243dSDimitry Andric return __value.weekday().ok();
441bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::year_month_weekday_last>)
442bdd1243dSDimitry Andric return __value.weekday().ok();
44306c3fb27SDimitry Andric else if constexpr (__is_hh_mm_ss<_Tp>)
44406c3fb27SDimitry Andric return true;
445*0fca6ea1SDimitry Andric # if !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_TZDB)
446*0fca6ea1SDimitry Andric else if constexpr (same_as<_Tp, chrono::sys_info>)
447*0fca6ea1SDimitry Andric return true;
448*0fca6ea1SDimitry Andric else if constexpr (same_as<_Tp, chrono::local_info>)
449*0fca6ea1SDimitry Andric return true;
450*0fca6ea1SDimitry Andric # if !defined(_LIBCPP_HAS_NO_TIME_ZONE_DATABASE) && !defined(_LIBCPP_HAS_NO_FILESYSTEM) && \
451*0fca6ea1SDimitry Andric !defined(_LIBCPP_HAS_NO_LOCALIZATION)
452*0fca6ea1SDimitry Andric else if constexpr (__is_specialization_v<_Tp, chrono::zoned_time>)
453*0fca6ea1SDimitry Andric return true;
454*0fca6ea1SDimitry Andric # endif
455*0fca6ea1SDimitry Andric # endif // !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_TZDB)
456bdd1243dSDimitry Andric else
457bdd1243dSDimitry Andric static_assert(sizeof(_Tp) == 0, "Add the missing type specialization");
458bdd1243dSDimitry Andric }
459bdd1243dSDimitry Andric
460bdd1243dSDimitry Andric template <class _Tp>
__weekday_name_ok(const _Tp & __value)461bdd1243dSDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr bool __weekday_name_ok(const _Tp& __value) {
46206c3fb27SDimitry Andric if constexpr (__is_time_point<_Tp>)
46306c3fb27SDimitry Andric return true;
46406c3fb27SDimitry Andric else if constexpr (same_as<_Tp, chrono::day>)
465bdd1243dSDimitry Andric return true;
466bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::month>)
467bdd1243dSDimitry Andric return __value.ok();
468bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::year>)
469bdd1243dSDimitry Andric return true;
470bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::weekday>)
471bdd1243dSDimitry Andric return __value.ok();
472bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::weekday_indexed>)
473bdd1243dSDimitry Andric return __value.weekday().ok();
474bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::weekday_last>)
475bdd1243dSDimitry Andric return __value.weekday().ok();
476bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::month_day>)
477bdd1243dSDimitry Andric return true;
478bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::month_day_last>)
479bdd1243dSDimitry Andric return true;
480bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::month_weekday>)
481bdd1243dSDimitry Andric return __value.weekday_indexed().ok();
482bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::month_weekday_last>)
483bdd1243dSDimitry Andric return __value.weekday_indexed().ok();
484bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::year_month>)
485bdd1243dSDimitry Andric return true;
486bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::year_month_day>)
487bdd1243dSDimitry Andric return __value.ok();
488bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::year_month_day_last>)
489bdd1243dSDimitry Andric return __value.ok();
490bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::year_month_weekday>)
491bdd1243dSDimitry Andric return __value.weekday().ok();
492bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::year_month_weekday_last>)
493bdd1243dSDimitry Andric return __value.weekday().ok();
49406c3fb27SDimitry Andric else if constexpr (__is_hh_mm_ss<_Tp>)
49506c3fb27SDimitry Andric return true;
496*0fca6ea1SDimitry Andric # if !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_TZDB)
497*0fca6ea1SDimitry Andric else if constexpr (same_as<_Tp, chrono::sys_info>)
498*0fca6ea1SDimitry Andric return true;
499*0fca6ea1SDimitry Andric else if constexpr (same_as<_Tp, chrono::local_info>)
500*0fca6ea1SDimitry Andric return true;
501*0fca6ea1SDimitry Andric # if !defined(_LIBCPP_HAS_NO_TIME_ZONE_DATABASE) && !defined(_LIBCPP_HAS_NO_FILESYSTEM) && \
502*0fca6ea1SDimitry Andric !defined(_LIBCPP_HAS_NO_LOCALIZATION)
503*0fca6ea1SDimitry Andric else if constexpr (__is_specialization_v<_Tp, chrono::zoned_time>)
504*0fca6ea1SDimitry Andric return true;
505*0fca6ea1SDimitry Andric # endif
506*0fca6ea1SDimitry Andric # endif // !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_TZDB)
507bdd1243dSDimitry Andric else
508bdd1243dSDimitry Andric static_assert(sizeof(_Tp) == 0, "Add the missing type specialization");
509bdd1243dSDimitry Andric }
510bdd1243dSDimitry Andric
511bdd1243dSDimitry Andric template <class _Tp>
__date_ok(const _Tp & __value)512bdd1243dSDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr bool __date_ok(const _Tp& __value) {
51306c3fb27SDimitry Andric if constexpr (__is_time_point<_Tp>)
51406c3fb27SDimitry Andric return true;
51506c3fb27SDimitry Andric else if constexpr (same_as<_Tp, chrono::day>)
516bdd1243dSDimitry Andric return true;
517bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::month>)
518bdd1243dSDimitry Andric return __value.ok();
519bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::year>)
520bdd1243dSDimitry Andric return true;
521bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::weekday>)
522bdd1243dSDimitry Andric return true;
523bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::weekday_indexed>)
524bdd1243dSDimitry Andric return true;
525bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::weekday_last>)
526bdd1243dSDimitry Andric return true;
527bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::month_day>)
528bdd1243dSDimitry Andric return true;
529bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::month_day_last>)
530bdd1243dSDimitry Andric return true;
531bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::month_weekday>)
532bdd1243dSDimitry Andric return true;
533bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::month_weekday_last>)
534bdd1243dSDimitry Andric return true;
535bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::year_month>)
536bdd1243dSDimitry Andric return true;
537bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::year_month_day>)
538bdd1243dSDimitry Andric return __value.ok();
539bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::year_month_day_last>)
540bdd1243dSDimitry Andric return __value.ok();
541bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::year_month_weekday>)
542bdd1243dSDimitry Andric return __value.ok();
543bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::year_month_weekday_last>)
544bdd1243dSDimitry Andric return __value.ok();
54506c3fb27SDimitry Andric else if constexpr (__is_hh_mm_ss<_Tp>)
54606c3fb27SDimitry Andric return true;
547*0fca6ea1SDimitry Andric # if !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_TZDB)
548*0fca6ea1SDimitry Andric else if constexpr (same_as<_Tp, chrono::sys_info>)
549*0fca6ea1SDimitry Andric return true;
550*0fca6ea1SDimitry Andric else if constexpr (same_as<_Tp, chrono::local_info>)
551*0fca6ea1SDimitry Andric return true;
552*0fca6ea1SDimitry Andric # if !defined(_LIBCPP_HAS_NO_TIME_ZONE_DATABASE) && !defined(_LIBCPP_HAS_NO_FILESYSTEM) && \
553*0fca6ea1SDimitry Andric !defined(_LIBCPP_HAS_NO_LOCALIZATION)
554*0fca6ea1SDimitry Andric else if constexpr (__is_specialization_v<_Tp, chrono::zoned_time>)
555*0fca6ea1SDimitry Andric return true;
556*0fca6ea1SDimitry Andric # endif
557*0fca6ea1SDimitry Andric # endif // !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_TZDB)
558bdd1243dSDimitry Andric else
559bdd1243dSDimitry Andric static_assert(sizeof(_Tp) == 0, "Add the missing type specialization");
560bdd1243dSDimitry Andric }
561bdd1243dSDimitry Andric
562bdd1243dSDimitry Andric template <class _Tp>
__month_name_ok(const _Tp & __value)563bdd1243dSDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr bool __month_name_ok(const _Tp& __value) {
56406c3fb27SDimitry Andric if constexpr (__is_time_point<_Tp>)
56506c3fb27SDimitry Andric return true;
56606c3fb27SDimitry Andric else if constexpr (same_as<_Tp, chrono::day>)
567bdd1243dSDimitry Andric return true;
568bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::month>)
569bdd1243dSDimitry Andric return __value.ok();
570bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::year>)
571bdd1243dSDimitry Andric return true;
572bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::weekday>)
573bdd1243dSDimitry Andric return true;
574bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::weekday_indexed>)
575bdd1243dSDimitry Andric return true;
576bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::weekday_last>)
577bdd1243dSDimitry Andric return true;
578bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::month_day>)
579bdd1243dSDimitry Andric return __value.month().ok();
580bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::month_day_last>)
581bdd1243dSDimitry Andric return __value.month().ok();
582bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::month_weekday>)
583bdd1243dSDimitry Andric return __value.month().ok();
584bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::month_weekday_last>)
585bdd1243dSDimitry Andric return __value.month().ok();
586bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::year_month>)
587bdd1243dSDimitry Andric return __value.month().ok();
588bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::year_month_day>)
589bdd1243dSDimitry Andric return __value.month().ok();
590bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::year_month_day_last>)
591bdd1243dSDimitry Andric return __value.month().ok();
592bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::year_month_weekday>)
593bdd1243dSDimitry Andric return __value.month().ok();
594bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::year_month_weekday_last>)
595bdd1243dSDimitry Andric return __value.month().ok();
59606c3fb27SDimitry Andric else if constexpr (__is_hh_mm_ss<_Tp>)
59706c3fb27SDimitry Andric return true;
598*0fca6ea1SDimitry Andric # if !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_TZDB)
599*0fca6ea1SDimitry Andric else if constexpr (same_as<_Tp, chrono::sys_info>)
600*0fca6ea1SDimitry Andric return true;
601*0fca6ea1SDimitry Andric else if constexpr (same_as<_Tp, chrono::local_info>)
602*0fca6ea1SDimitry Andric return true;
603*0fca6ea1SDimitry Andric # if !defined(_LIBCPP_HAS_NO_TIME_ZONE_DATABASE) && !defined(_LIBCPP_HAS_NO_FILESYSTEM) && \
604*0fca6ea1SDimitry Andric !defined(_LIBCPP_HAS_NO_LOCALIZATION)
605*0fca6ea1SDimitry Andric else if constexpr (__is_specialization_v<_Tp, chrono::zoned_time>)
606*0fca6ea1SDimitry Andric return true;
607*0fca6ea1SDimitry Andric # endif
608*0fca6ea1SDimitry Andric # endif // !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_TZDB)
609bdd1243dSDimitry Andric else
610bdd1243dSDimitry Andric static_assert(sizeof(_Tp) == 0, "Add the missing type specialization");
611bdd1243dSDimitry Andric }
612bdd1243dSDimitry Andric
61306c3fb27SDimitry Andric template <class _CharT, class _Tp, class _FormatContext>
614bdd1243dSDimitry Andric _LIBCPP_HIDE_FROM_ABI auto
__format_chrono(const _Tp & __value,_FormatContext & __ctx,__format_spec::__parsed_specifications<_CharT> __specs,basic_string_view<_CharT> __chrono_specs)615bdd1243dSDimitry Andric __format_chrono(const _Tp& __value,
61606c3fb27SDimitry Andric _FormatContext& __ctx,
617bdd1243dSDimitry Andric __format_spec::__parsed_specifications<_CharT> __specs,
61806c3fb27SDimitry Andric basic_string_view<_CharT> __chrono_specs) {
619bdd1243dSDimitry Andric basic_stringstream<_CharT> __sstr;
620bdd1243dSDimitry Andric // [time.format]/2
621bdd1243dSDimitry Andric // 2.1 - the "C" locale if the L option is not present in chrono-format-spec, otherwise
622bdd1243dSDimitry Andric // 2.2 - the locale passed to the formatting function if any, otherwise
623bdd1243dSDimitry Andric // 2.3 - the global locale.
624bdd1243dSDimitry Andric // Note that the __ctx's locale() call does 2.2 and 2.3.
625bdd1243dSDimitry Andric if (__specs.__chrono_.__locale_specific_form_)
626bdd1243dSDimitry Andric __sstr.imbue(__ctx.locale());
627bdd1243dSDimitry Andric else
628bdd1243dSDimitry Andric __sstr.imbue(locale::classic());
629bdd1243dSDimitry Andric
630bdd1243dSDimitry Andric if (__chrono_specs.empty())
631bdd1243dSDimitry Andric __sstr << __value;
632bdd1243dSDimitry Andric else {
633bdd1243dSDimitry Andric if constexpr (chrono::__is_duration<_Tp>::value) {
634*0fca6ea1SDimitry Andric // A duration can be a user defined arithmetic type. Users may specialize
635*0fca6ea1SDimitry Andric // numeric_limits, but they may not specialize is_signed.
636*0fca6ea1SDimitry Andric if constexpr (numeric_limits<typename _Tp::rep>::is_signed) {
637*0fca6ea1SDimitry Andric if (__value < __value.zero()) {
638bdd1243dSDimitry Andric __sstr << _CharT('-');
639*0fca6ea1SDimitry Andric __formatter::__format_chrono_using_chrono_specs(__sstr, -__value, __chrono_specs);
640*0fca6ea1SDimitry Andric } else
641*0fca6ea1SDimitry Andric __formatter::__format_chrono_using_chrono_specs(__sstr, __value, __chrono_specs);
642*0fca6ea1SDimitry Andric } else
643*0fca6ea1SDimitry Andric __formatter::__format_chrono_using_chrono_specs(__sstr, __value, __chrono_specs);
644bdd1243dSDimitry Andric // TODO FMT When keeping the precision it will truncate the string.
645bdd1243dSDimitry Andric // Note that the behaviour what the precision does isn't specified.
646bdd1243dSDimitry Andric __specs.__precision_ = -1;
647bdd1243dSDimitry Andric } else {
648bdd1243dSDimitry Andric // Test __weekday_name_ before __weekday_ to give a better error.
649bdd1243dSDimitry Andric if (__specs.__chrono_.__weekday_name_ && !__formatter::__weekday_name_ok(__value))
65006c3fb27SDimitry Andric std::__throw_format_error("Formatting a weekday name needs a valid weekday");
651bdd1243dSDimitry Andric
652bdd1243dSDimitry Andric if (__specs.__chrono_.__weekday_ && !__formatter::__weekday_ok(__value))
65306c3fb27SDimitry Andric std::__throw_format_error("Formatting a weekday needs a valid weekday");
654bdd1243dSDimitry Andric
655bdd1243dSDimitry Andric if (__specs.__chrono_.__day_of_year_ && !__formatter::__date_ok(__value))
65606c3fb27SDimitry Andric std::__throw_format_error("Formatting a day of year needs a valid date");
657bdd1243dSDimitry Andric
658bdd1243dSDimitry Andric if (__specs.__chrono_.__week_of_year_ && !__formatter::__date_ok(__value))
65906c3fb27SDimitry Andric std::__throw_format_error("Formatting a week of year needs a valid date");
660bdd1243dSDimitry Andric
661bdd1243dSDimitry Andric if (__specs.__chrono_.__month_name_ && !__formatter::__month_name_ok(__value))
66206c3fb27SDimitry Andric std::__throw_format_error("Formatting a month name from an invalid month number");
66306c3fb27SDimitry Andric
66406c3fb27SDimitry Andric if constexpr (__is_hh_mm_ss<_Tp>) {
66506c3fb27SDimitry Andric // Note this is a pedantic intepretation of the Standard. A hh_mm_ss
66606c3fb27SDimitry Andric // is no longer a time_of_day and can store an arbitrary number of
66706c3fb27SDimitry Andric // hours. A number of hours in a 12 or 24 hour clock can't represent
66806c3fb27SDimitry Andric // 24 hours or more. The functions std::chrono::make12 and
66906c3fb27SDimitry Andric // std::chrono::make24 reaffirm this view point.
67006c3fb27SDimitry Andric //
67106c3fb27SDimitry Andric // Interestingly this will be the only output stream function that
67206c3fb27SDimitry Andric // throws.
67306c3fb27SDimitry Andric //
67406c3fb27SDimitry Andric // TODO FMT The wording probably needs to be adapted to
67506c3fb27SDimitry Andric // - The displayed hours is hh_mm_ss.hours() % 24
67606c3fb27SDimitry Andric // - It should probably allow %j in the same fashion as duration.
67706c3fb27SDimitry Andric // - The stream formatter should change its output when hours >= 24
67806c3fb27SDimitry Andric // - Write it as not valid,
67906c3fb27SDimitry Andric // - or write the number of days.
68006c3fb27SDimitry Andric if (__specs.__chrono_.__hour_ && __value.hours().count() > 23)
68106c3fb27SDimitry Andric std::__throw_format_error("Formatting a hour needs a valid value");
68206c3fb27SDimitry Andric
68306c3fb27SDimitry Andric if (__value.is_negative())
68406c3fb27SDimitry Andric __sstr << _CharT('-');
68506c3fb27SDimitry Andric }
686bdd1243dSDimitry Andric
687*0fca6ea1SDimitry Andric __formatter::__format_chrono_using_chrono_specs(__sstr, __value, __chrono_specs);
688bdd1243dSDimitry Andric }
689bdd1243dSDimitry Andric }
690bdd1243dSDimitry Andric
69106c3fb27SDimitry Andric return __formatter::__write_string(__sstr.view(), __ctx.out(), __specs);
692bdd1243dSDimitry Andric }
693bdd1243dSDimitry Andric
694bdd1243dSDimitry Andric } // namespace __formatter
695bdd1243dSDimitry Andric
696bdd1243dSDimitry Andric template <__fmt_char_type _CharT>
69706c3fb27SDimitry Andric struct _LIBCPP_TEMPLATE_VIS __formatter_chrono {
698bdd1243dSDimitry Andric public:
69906c3fb27SDimitry Andric template <class _ParseContext>
70006c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator
__parse__formatter_chrono70106c3fb27SDimitry Andric __parse(_ParseContext& __ctx, __format_spec::__fields __fields, __format_spec::__flags __flags) {
70206c3fb27SDimitry Andric return __parser_.__parse(__ctx, __fields, __flags);
703bdd1243dSDimitry Andric }
704bdd1243dSDimitry Andric
70506c3fb27SDimitry Andric template <class _Tp, class _FormatContext>
format__formatter_chrono70606c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator format(const _Tp& __value, _FormatContext& __ctx) const {
707bdd1243dSDimitry Andric return __formatter::__format_chrono(
708bdd1243dSDimitry Andric __value, __ctx, __parser_.__parser_.__get_parsed_chrono_specifications(__ctx), __parser_.__chrono_specs_);
709bdd1243dSDimitry Andric }
710bdd1243dSDimitry Andric
711bdd1243dSDimitry Andric __format_spec::__parser_chrono<_CharT> __parser_;
712bdd1243dSDimitry Andric };
713bdd1243dSDimitry Andric
71406c3fb27SDimitry Andric template <class _Duration, __fmt_char_type _CharT>
71506c3fb27SDimitry Andric struct _LIBCPP_TEMPLATE_VIS formatter<chrono::sys_time<_Duration>, _CharT> : public __formatter_chrono<_CharT> {
71606c3fb27SDimitry Andric public:
71706c3fb27SDimitry Andric using _Base = __formatter_chrono<_CharT>;
71806c3fb27SDimitry Andric
71906c3fb27SDimitry Andric template <class _ParseContext>
72006c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) {
72106c3fb27SDimitry Andric return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__clock);
72206c3fb27SDimitry Andric }
72306c3fb27SDimitry Andric };
72406c3fb27SDimitry Andric
72506c3fb27SDimitry Andric template <class _Duration, __fmt_char_type _CharT>
72606c3fb27SDimitry Andric struct _LIBCPP_TEMPLATE_VIS formatter<chrono::file_time<_Duration>, _CharT> : public __formatter_chrono<_CharT> {
72706c3fb27SDimitry Andric public:
72806c3fb27SDimitry Andric using _Base = __formatter_chrono<_CharT>;
72906c3fb27SDimitry Andric
73006c3fb27SDimitry Andric template <class _ParseContext>
73106c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) {
73206c3fb27SDimitry Andric return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__clock);
73306c3fb27SDimitry Andric }
73406c3fb27SDimitry Andric };
73506c3fb27SDimitry Andric
73606c3fb27SDimitry Andric template <class _Duration, __fmt_char_type _CharT>
73706c3fb27SDimitry Andric struct _LIBCPP_TEMPLATE_VIS formatter<chrono::local_time<_Duration>, _CharT> : public __formatter_chrono<_CharT> {
73806c3fb27SDimitry Andric public:
73906c3fb27SDimitry Andric using _Base = __formatter_chrono<_CharT>;
74006c3fb27SDimitry Andric
74106c3fb27SDimitry Andric template <class _ParseContext>
74206c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) {
74306c3fb27SDimitry Andric // The flags are not __clock since there is no associated time-zone.
74406c3fb27SDimitry Andric return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__date_time);
74506c3fb27SDimitry Andric }
74606c3fb27SDimitry Andric };
74706c3fb27SDimitry Andric
748bdd1243dSDimitry Andric template <class _Rep, class _Period, __fmt_char_type _CharT>
749bdd1243dSDimitry Andric struct formatter<chrono::duration<_Rep, _Period>, _CharT> : public __formatter_chrono<_CharT> {
750bdd1243dSDimitry Andric public:
751bdd1243dSDimitry Andric using _Base = __formatter_chrono<_CharT>;
752bdd1243dSDimitry Andric
75306c3fb27SDimitry Andric template <class _ParseContext>
75406c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) {
755bdd1243dSDimitry Andric // [time.format]/1
756bdd1243dSDimitry Andric // Giving a precision specification in the chrono-format-spec is valid only
757bdd1243dSDimitry Andric // for std::chrono::duration types where the representation type Rep is a
758bdd1243dSDimitry Andric // floating-point type. For all other Rep types, an exception of type
759bdd1243dSDimitry Andric // format_error is thrown if the chrono-format-spec contains a precision
760bdd1243dSDimitry Andric // specification.
761bdd1243dSDimitry Andric //
762bdd1243dSDimitry Andric // Note this doesn't refer to chrono::treat_as_floating_point_v<_Rep>.
763bdd1243dSDimitry Andric if constexpr (std::floating_point<_Rep>)
76406c3fb27SDimitry Andric return _Base::__parse(__ctx, __format_spec::__fields_chrono_fractional, __format_spec::__flags::__duration);
765bdd1243dSDimitry Andric else
76606c3fb27SDimitry Andric return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__duration);
767bdd1243dSDimitry Andric }
768bdd1243dSDimitry Andric };
769bdd1243dSDimitry Andric
770bdd1243dSDimitry Andric template <__fmt_char_type _CharT>
771cb14a3feSDimitry Andric struct _LIBCPP_TEMPLATE_VIS formatter<chrono::day, _CharT> : public __formatter_chrono<_CharT> {
772bdd1243dSDimitry Andric public:
773bdd1243dSDimitry Andric using _Base = __formatter_chrono<_CharT>;
774bdd1243dSDimitry Andric
77506c3fb27SDimitry Andric template <class _ParseContext>
77606c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) {
77706c3fb27SDimitry Andric return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__day);
778bdd1243dSDimitry Andric }
779bdd1243dSDimitry Andric };
780bdd1243dSDimitry Andric
781bdd1243dSDimitry Andric template <__fmt_char_type _CharT>
782cb14a3feSDimitry Andric struct _LIBCPP_TEMPLATE_VIS formatter<chrono::month, _CharT> : public __formatter_chrono<_CharT> {
783bdd1243dSDimitry Andric public:
784bdd1243dSDimitry Andric using _Base = __formatter_chrono<_CharT>;
785bdd1243dSDimitry Andric
78606c3fb27SDimitry Andric template <class _ParseContext>
78706c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) {
78806c3fb27SDimitry Andric return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__month);
789bdd1243dSDimitry Andric }
790bdd1243dSDimitry Andric };
791bdd1243dSDimitry Andric
792bdd1243dSDimitry Andric template <__fmt_char_type _CharT>
793cb14a3feSDimitry Andric struct _LIBCPP_TEMPLATE_VIS formatter<chrono::year, _CharT> : public __formatter_chrono<_CharT> {
794bdd1243dSDimitry Andric public:
795bdd1243dSDimitry Andric using _Base = __formatter_chrono<_CharT>;
796bdd1243dSDimitry Andric
79706c3fb27SDimitry Andric template <class _ParseContext>
79806c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) {
79906c3fb27SDimitry Andric return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__year);
800bdd1243dSDimitry Andric }
801bdd1243dSDimitry Andric };
802bdd1243dSDimitry Andric
803bdd1243dSDimitry Andric template <__fmt_char_type _CharT>
804cb14a3feSDimitry Andric struct _LIBCPP_TEMPLATE_VIS formatter<chrono::weekday, _CharT> : public __formatter_chrono<_CharT> {
805bdd1243dSDimitry Andric public:
806bdd1243dSDimitry Andric using _Base = __formatter_chrono<_CharT>;
807bdd1243dSDimitry Andric
80806c3fb27SDimitry Andric template <class _ParseContext>
80906c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) {
81006c3fb27SDimitry Andric return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__weekday);
811bdd1243dSDimitry Andric }
812bdd1243dSDimitry Andric };
813bdd1243dSDimitry Andric
814bdd1243dSDimitry Andric template <__fmt_char_type _CharT>
815cb14a3feSDimitry Andric struct _LIBCPP_TEMPLATE_VIS formatter<chrono::weekday_indexed, _CharT> : public __formatter_chrono<_CharT> {
816bdd1243dSDimitry Andric public:
817bdd1243dSDimitry Andric using _Base = __formatter_chrono<_CharT>;
818bdd1243dSDimitry Andric
81906c3fb27SDimitry Andric template <class _ParseContext>
82006c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) {
82106c3fb27SDimitry Andric return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__weekday);
822bdd1243dSDimitry Andric }
823bdd1243dSDimitry Andric };
824bdd1243dSDimitry Andric
825bdd1243dSDimitry Andric template <__fmt_char_type _CharT>
826cb14a3feSDimitry Andric struct _LIBCPP_TEMPLATE_VIS formatter<chrono::weekday_last, _CharT> : public __formatter_chrono<_CharT> {
827bdd1243dSDimitry Andric public:
828bdd1243dSDimitry Andric using _Base = __formatter_chrono<_CharT>;
829bdd1243dSDimitry Andric
83006c3fb27SDimitry Andric template <class _ParseContext>
83106c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) {
83206c3fb27SDimitry Andric return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__weekday);
833bdd1243dSDimitry Andric }
834bdd1243dSDimitry Andric };
835bdd1243dSDimitry Andric
836bdd1243dSDimitry Andric template <__fmt_char_type _CharT>
837cb14a3feSDimitry Andric struct _LIBCPP_TEMPLATE_VIS formatter<chrono::month_day, _CharT> : public __formatter_chrono<_CharT> {
838bdd1243dSDimitry Andric public:
839bdd1243dSDimitry Andric using _Base = __formatter_chrono<_CharT>;
840bdd1243dSDimitry Andric
84106c3fb27SDimitry Andric template <class _ParseContext>
84206c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) {
84306c3fb27SDimitry Andric return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__month_day);
844bdd1243dSDimitry Andric }
845bdd1243dSDimitry Andric };
846bdd1243dSDimitry Andric
847bdd1243dSDimitry Andric template <__fmt_char_type _CharT>
848cb14a3feSDimitry Andric struct _LIBCPP_TEMPLATE_VIS formatter<chrono::month_day_last, _CharT> : public __formatter_chrono<_CharT> {
849bdd1243dSDimitry Andric public:
850bdd1243dSDimitry Andric using _Base = __formatter_chrono<_CharT>;
851bdd1243dSDimitry Andric
85206c3fb27SDimitry Andric template <class _ParseContext>
85306c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) {
85406c3fb27SDimitry Andric return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__month);
855bdd1243dSDimitry Andric }
856bdd1243dSDimitry Andric };
857bdd1243dSDimitry Andric
858bdd1243dSDimitry Andric template <__fmt_char_type _CharT>
859cb14a3feSDimitry Andric struct _LIBCPP_TEMPLATE_VIS formatter<chrono::month_weekday, _CharT> : public __formatter_chrono<_CharT> {
860bdd1243dSDimitry Andric public:
861bdd1243dSDimitry Andric using _Base = __formatter_chrono<_CharT>;
862bdd1243dSDimitry Andric
86306c3fb27SDimitry Andric template <class _ParseContext>
86406c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) {
86506c3fb27SDimitry Andric return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__month_weekday);
866bdd1243dSDimitry Andric }
867bdd1243dSDimitry Andric };
868bdd1243dSDimitry Andric
869bdd1243dSDimitry Andric template <__fmt_char_type _CharT>
870cb14a3feSDimitry Andric struct _LIBCPP_TEMPLATE_VIS formatter<chrono::month_weekday_last, _CharT> : public __formatter_chrono<_CharT> {
871bdd1243dSDimitry Andric public:
872bdd1243dSDimitry Andric using _Base = __formatter_chrono<_CharT>;
873bdd1243dSDimitry Andric
87406c3fb27SDimitry Andric template <class _ParseContext>
87506c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) {
87606c3fb27SDimitry Andric return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__month_weekday);
877bdd1243dSDimitry Andric }
878bdd1243dSDimitry Andric };
879bdd1243dSDimitry Andric
880bdd1243dSDimitry Andric template <__fmt_char_type _CharT>
881cb14a3feSDimitry Andric struct _LIBCPP_TEMPLATE_VIS formatter<chrono::year_month, _CharT> : public __formatter_chrono<_CharT> {
882bdd1243dSDimitry Andric public:
883bdd1243dSDimitry Andric using _Base = __formatter_chrono<_CharT>;
884bdd1243dSDimitry Andric
88506c3fb27SDimitry Andric template <class _ParseContext>
88606c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) {
88706c3fb27SDimitry Andric return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__year_month);
888bdd1243dSDimitry Andric }
889bdd1243dSDimitry Andric };
890bdd1243dSDimitry Andric
891bdd1243dSDimitry Andric template <__fmt_char_type _CharT>
892cb14a3feSDimitry Andric struct _LIBCPP_TEMPLATE_VIS formatter<chrono::year_month_day, _CharT> : public __formatter_chrono<_CharT> {
893bdd1243dSDimitry Andric public:
894bdd1243dSDimitry Andric using _Base = __formatter_chrono<_CharT>;
895bdd1243dSDimitry Andric
89606c3fb27SDimitry Andric template <class _ParseContext>
89706c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) {
89806c3fb27SDimitry Andric return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__date);
899bdd1243dSDimitry Andric }
900bdd1243dSDimitry Andric };
901bdd1243dSDimitry Andric
902bdd1243dSDimitry Andric template <__fmt_char_type _CharT>
903cb14a3feSDimitry Andric struct _LIBCPP_TEMPLATE_VIS formatter<chrono::year_month_day_last, _CharT> : public __formatter_chrono<_CharT> {
904bdd1243dSDimitry Andric public:
905bdd1243dSDimitry Andric using _Base = __formatter_chrono<_CharT>;
906bdd1243dSDimitry Andric
90706c3fb27SDimitry Andric template <class _ParseContext>
90806c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) {
90906c3fb27SDimitry Andric return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__date);
910bdd1243dSDimitry Andric }
911bdd1243dSDimitry Andric };
912bdd1243dSDimitry Andric
913bdd1243dSDimitry Andric template <__fmt_char_type _CharT>
914cb14a3feSDimitry Andric struct _LIBCPP_TEMPLATE_VIS formatter<chrono::year_month_weekday, _CharT> : public __formatter_chrono<_CharT> {
915bdd1243dSDimitry Andric public:
916bdd1243dSDimitry Andric using _Base = __formatter_chrono<_CharT>;
917bdd1243dSDimitry Andric
91806c3fb27SDimitry Andric template <class _ParseContext>
91906c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) {
92006c3fb27SDimitry Andric return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__date);
921bdd1243dSDimitry Andric }
922bdd1243dSDimitry Andric };
923bdd1243dSDimitry Andric
924bdd1243dSDimitry Andric template <__fmt_char_type _CharT>
925cb14a3feSDimitry Andric struct _LIBCPP_TEMPLATE_VIS formatter<chrono::year_month_weekday_last, _CharT> : public __formatter_chrono<_CharT> {
926bdd1243dSDimitry Andric public:
927bdd1243dSDimitry Andric using _Base = __formatter_chrono<_CharT>;
928bdd1243dSDimitry Andric
92906c3fb27SDimitry Andric template <class _ParseContext>
93006c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) {
93106c3fb27SDimitry Andric return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__date);
932bdd1243dSDimitry Andric }
933bdd1243dSDimitry Andric };
934bdd1243dSDimitry Andric
93506c3fb27SDimitry Andric template <class _Duration, __fmt_char_type _CharT>
93606c3fb27SDimitry Andric struct formatter<chrono::hh_mm_ss<_Duration>, _CharT> : public __formatter_chrono<_CharT> {
93706c3fb27SDimitry Andric public:
93806c3fb27SDimitry Andric using _Base = __formatter_chrono<_CharT>;
93906c3fb27SDimitry Andric
94006c3fb27SDimitry Andric template <class _ParseContext>
94106c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) {
94206c3fb27SDimitry Andric return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__time);
94306c3fb27SDimitry Andric }
94406c3fb27SDimitry Andric };
945*0fca6ea1SDimitry Andric
946*0fca6ea1SDimitry Andric # if !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_TZDB)
947*0fca6ea1SDimitry Andric template <__fmt_char_type _CharT>
948*0fca6ea1SDimitry Andric struct formatter<chrono::sys_info, _CharT> : public __formatter_chrono<_CharT> {
949*0fca6ea1SDimitry Andric public:
950*0fca6ea1SDimitry Andric using _Base = __formatter_chrono<_CharT>;
951*0fca6ea1SDimitry Andric
952*0fca6ea1SDimitry Andric template <class _ParseContext>
953*0fca6ea1SDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) {
954*0fca6ea1SDimitry Andric return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__time_zone);
955*0fca6ea1SDimitry Andric }
956*0fca6ea1SDimitry Andric };
957*0fca6ea1SDimitry Andric
958*0fca6ea1SDimitry Andric template <__fmt_char_type _CharT>
959*0fca6ea1SDimitry Andric struct formatter<chrono::local_info, _CharT> : public __formatter_chrono<_CharT> {
960*0fca6ea1SDimitry Andric public:
961*0fca6ea1SDimitry Andric using _Base = __formatter_chrono<_CharT>;
962*0fca6ea1SDimitry Andric
963*0fca6ea1SDimitry Andric template <class _ParseContext>
964*0fca6ea1SDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) {
965*0fca6ea1SDimitry Andric return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags{});
966*0fca6ea1SDimitry Andric }
967*0fca6ea1SDimitry Andric };
968*0fca6ea1SDimitry Andric # if !defined(_LIBCPP_HAS_NO_TIME_ZONE_DATABASE) && !defined(_LIBCPP_HAS_NO_FILESYSTEM) && \
969*0fca6ea1SDimitry Andric !defined(_LIBCPP_HAS_NO_LOCALIZATION)
970*0fca6ea1SDimitry Andric // Note due to how libc++'s formatters are implemented there is no need to add
971*0fca6ea1SDimitry Andric // the exposition only local-time-format-t abstraction.
972*0fca6ea1SDimitry Andric template <class _Duration, class _TimeZonePtr, __fmt_char_type _CharT>
973*0fca6ea1SDimitry Andric struct formatter<chrono::zoned_time<_Duration, _TimeZonePtr>, _CharT> : public __formatter_chrono<_CharT> {
974*0fca6ea1SDimitry Andric public:
975*0fca6ea1SDimitry Andric using _Base = __formatter_chrono<_CharT>;
976*0fca6ea1SDimitry Andric
977*0fca6ea1SDimitry Andric template <class _ParseContext>
978*0fca6ea1SDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) {
979*0fca6ea1SDimitry Andric return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__clock);
980*0fca6ea1SDimitry Andric }
981*0fca6ea1SDimitry Andric };
982*0fca6ea1SDimitry Andric # endif // !defined(_LIBCPP_HAS_NO_TIME_ZONE_DATABASE) && !defined(_LIBCPP_HAS_NO_FILESYSTEM) &&
983*0fca6ea1SDimitry Andric // !defined(_LIBCPP_HAS_NO_LOCALIZATION)
984*0fca6ea1SDimitry Andric # endif // !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_TZDB)
985*0fca6ea1SDimitry Andric
98606c3fb27SDimitry Andric #endif // if _LIBCPP_STD_VER >= 20
987bdd1243dSDimitry Andric
988bdd1243dSDimitry Andric _LIBCPP_END_NAMESPACE_STD
989bdd1243dSDimitry Andric
990bdd1243dSDimitry Andric #endif // _LIBCPP___CHRONO_FORMATTER_H
991