1e5d2d3eaSMark de Wever // -*- C++ -*- 2e5d2d3eaSMark de Wever //===----------------------------------------------------------------------===// 3e5d2d3eaSMark de Wever // 4e5d2d3eaSMark de Wever // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 5e5d2d3eaSMark de Wever // See https://llvm.org/LICENSE.txt for license information. 6e5d2d3eaSMark de Wever // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 7e5d2d3eaSMark de Wever // 8e5d2d3eaSMark de Wever //===----------------------------------------------------------------------===// 9e5d2d3eaSMark de Wever 10e5d2d3eaSMark de Wever #ifndef _LIBCPP___CHRONO_FORMATTER_H 11e5d2d3eaSMark de Wever #define _LIBCPP___CHRONO_FORMATTER_H 12e5d2d3eaSMark de Wever 1387d56c59SLouis Dionne #include <__config> 1487d56c59SLouis Dionne 15c6f3b7bcSNikolas Klauser #if _LIBCPP_HAS_LOCALIZATION 1687d56c59SLouis Dionne 17a6fcbcceSMark de Wever # include <__algorithm/ranges_copy.h> 18105fef5dSMark de Wever # include <__chrono/calendar.h> 197f5d130aSMark de Wever # include <__chrono/concepts.h> 20e5d2d3eaSMark de Wever # include <__chrono/convert_to_tm.h> 21e5d2d3eaSMark de Wever # include <__chrono/day.h> 22719c3dc6SMark de Wever # include <__chrono/duration.h> 2396f30332SMark de Wever # include <__chrono/file_clock.h> 24719c3dc6SMark de Wever # include <__chrono/hh_mm_ss.h> 258a21d59fSMark de Wever # include <__chrono/local_info.h> 261522f190SMark de Wever # include <__chrono/month.h> 27105fef5dSMark de Wever # include <__chrono/month_weekday.h> 28105fef5dSMark de Wever # include <__chrono/monthday.h> 29719c3dc6SMark de Wever # include <__chrono/ostream.h> 30e5d2d3eaSMark de Wever # include <__chrono/parser_std_format_spec.h> 313eb4f16bSMark de Wever # include <__chrono/statically_widen.h> 326f7976c8SMark de Wever # include <__chrono/sys_info.h> 332c1d7959SMark de Wever # include <__chrono/system_clock.h> 34719c3dc6SMark de Wever # include <__chrono/time_point.h> 350cd794d4SMark de Wever # include <__chrono/utc_clock.h> 36566868cdSMark de Wever # include <__chrono/weekday.h> 373eb4f16bSMark de Wever # include <__chrono/year.h> 38105fef5dSMark de Wever # include <__chrono/year_month.h> 39105fef5dSMark de Wever # include <__chrono/year_month_day.h> 40105fef5dSMark de Wever # include <__chrono/year_month_weekday.h> 41afbfb16dSMark de Wever # include <__chrono/zoned_time.h> 42719c3dc6SMark de Wever # include <__concepts/arithmetic.h> 431522f190SMark de Wever # include <__concepts/same_as.h> 44e5d2d3eaSMark de Wever # include <__format/concepts.h> 451522f190SMark de Wever # include <__format/format_error.h> 463eb4f16bSMark de Wever # include <__format/format_functions.h> 47e5d2d3eaSMark de Wever # include <__format/format_parse_context.h> 48e5d2d3eaSMark de Wever # include <__format/formatter.h> 49e5d2d3eaSMark de Wever # include <__format/parser_std_format_spec.h> 503ab20c68SMark de Wever # include <__format/write_escaped.h> 513eb4f16bSMark de Wever # include <__memory/addressof.h> 52afbfb16dSMark de Wever # include <__type_traits/is_specialization.h> 533eb4f16bSMark de Wever # include <cmath> 54e5d2d3eaSMark de Wever # include <ctime> 556c97ad4eSMark de Wever # include <limits> 5609e3a360SLouis Dionne # include <locale> 57e5d2d3eaSMark de Wever # include <sstream> 58e5d2d3eaSMark de Wever # include <string_view> 59e5d2d3eaSMark de Wever 60e5d2d3eaSMark de Wever # if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 61e5d2d3eaSMark de Wever # pragma GCC system_header 62e5d2d3eaSMark de Wever # endif 63e5d2d3eaSMark de Wever 64e5d2d3eaSMark de Wever _LIBCPP_BEGIN_NAMESPACE_STD 65e5d2d3eaSMark de Wever 66dff62f52SMark de Wever # if _LIBCPP_STD_VER >= 20 67e5d2d3eaSMark de Wever 68e5d2d3eaSMark de Wever namespace __formatter { 69e5d2d3eaSMark de Wever 70e5d2d3eaSMark de Wever /// Formats a time based on a tm struct. 71e5d2d3eaSMark de Wever /// 72e5d2d3eaSMark de Wever /// This formatter passes the formatting to time_put which uses strftime. When 73e5d2d3eaSMark de Wever /// the value is outside the valid range it's unspecified what strftime will 74e5d2d3eaSMark de Wever /// output. For example weekday 8 can print 1 when the day is processed modulo 75e5d2d3eaSMark de Wever /// 7 since that handles the Sunday for 0-based weekday. It can also print 8 if 76e5d2d3eaSMark de Wever /// 7 is handled as a special case. 77e5d2d3eaSMark de Wever /// 78e5d2d3eaSMark de Wever /// The Standard doesn't specify what to do in this case so the result depends 79e5d2d3eaSMark de Wever /// on the result of the underlying code. 80e5d2d3eaSMark de Wever /// 81e5d2d3eaSMark de Wever /// \pre When the (abbreviated) weekday or month name are used, the caller 82e5d2d3eaSMark de Wever /// validates whether the value is valid. So the caller handles that 83e5d2d3eaSMark de Wever /// requirement of Table 97: Meaning of conversion specifiers 84e5d2d3eaSMark de Wever /// [tab:time.format.spec]. 85e5d2d3eaSMark de Wever /// 86e5d2d3eaSMark de Wever /// When no chrono-specs are provided it uses the stream formatter. 87e5d2d3eaSMark de Wever 88719c3dc6SMark de Wever // For tiny ratios it's not possible to convert a duration to a hh_mm_ss. This 89719c3dc6SMark de Wever // fails compile-time due to the limited precision of the ratio (64-bit is too 90719c3dc6SMark de Wever // small). Therefore a duration uses its own conversion. 917f5d130aSMark de Wever template <class _CharT, class _Rep, class _Period> 927f5d130aSMark de Wever _LIBCPP_HIDE_FROM_ABI void 935462b270SMark de Wever __format_sub_seconds(basic_stringstream<_CharT>& __sstr, const chrono::duration<_Rep, _Period>& __value) { 94719c3dc6SMark de Wever __sstr << std::use_facet<numpunct<_CharT>>(__sstr.getloc()).decimal_point(); 95719c3dc6SMark de Wever 967f5d130aSMark de Wever using __duration = chrono::duration<_Rep, _Period>; 977f5d130aSMark de Wever 98719c3dc6SMark de Wever auto __fraction = __value - chrono::duration_cast<chrono::seconds>(__value); 99579d3010SMark de Wever // Converts a negative fraction to its positive value. 100579d3010SMark de Wever if (__value < chrono::seconds{0} && __fraction != __duration{0}) 101579d3010SMark de Wever __fraction += chrono::seconds{1}; 1027f5d130aSMark de Wever if constexpr (chrono::treat_as_floating_point_v<_Rep>) 103719c3dc6SMark de Wever // When the floating-point value has digits itself they are ignored based 104719c3dc6SMark de Wever // on the wording in [tab:time.format.spec] 105719c3dc6SMark de Wever // If the precision of the input cannot be exactly represented with 106719c3dc6SMark de Wever // seconds, then the format is a decimal floating-point number with a 107719c3dc6SMark de Wever // fixed format and a precision matching that of the precision of the 108719c3dc6SMark de Wever // input (or to a microseconds precision if the conversion to 109719c3dc6SMark de Wever // floating-point decimal seconds cannot be made within 18 fractional 110719c3dc6SMark de Wever // digits). 111719c3dc6SMark de Wever // 112719c3dc6SMark de Wever // This matches the behaviour of MSVC STL, fmtlib interprets this 113719c3dc6SMark de Wever // differently and uses 3 decimals. 114719c3dc6SMark de Wever // https://godbolt.org/z/6dsbnW8ba 115719c3dc6SMark de Wever std::format_to(std::ostreambuf_iterator<_CharT>{__sstr}, 116719c3dc6SMark de Wever _LIBCPP_STATICALLY_WIDEN(_CharT, "{:0{}.0f}"), 11728584755SMark de Wever chrono::duration_cast<typename chrono::hh_mm_ss<__duration>::precision>(__fraction).count(), 1187f5d130aSMark de Wever chrono::hh_mm_ss<__duration>::fractional_width); 119719c3dc6SMark de Wever else 120719c3dc6SMark de Wever std::format_to(std::ostreambuf_iterator<_CharT>{__sstr}, 121719c3dc6SMark de Wever _LIBCPP_STATICALLY_WIDEN(_CharT, "{:0{}}"), 12228584755SMark de Wever chrono::duration_cast<typename chrono::hh_mm_ss<__duration>::precision>(__fraction).count(), 1237f5d130aSMark de Wever chrono::hh_mm_ss<__duration>::fractional_width); 1247f5d130aSMark de Wever } 1257f5d130aSMark de Wever 1262c1d7959SMark de Wever template <class _CharT, __is_time_point _Tp> 1275462b270SMark de Wever _LIBCPP_HIDE_FROM_ABI void __format_sub_seconds(basic_stringstream<_CharT>& __sstr, const _Tp& __value) { 1285462b270SMark de Wever __formatter::__format_sub_seconds(__sstr, __value.time_since_epoch()); 1292c1d7959SMark de Wever } 1302c1d7959SMark de Wever 1317f5d130aSMark de Wever template <class _CharT, class _Duration> 1327f5d130aSMark de Wever _LIBCPP_HIDE_FROM_ABI void 1335462b270SMark de Wever __format_sub_seconds(basic_stringstream<_CharT>& __sstr, const chrono::hh_mm_ss<_Duration>& __value) { 1347f5d130aSMark de Wever __sstr << std::use_facet<numpunct<_CharT>>(__sstr.getloc()).decimal_point(); 1357f5d130aSMark de Wever if constexpr (chrono::treat_as_floating_point_v<typename _Duration::rep>) 1367f5d130aSMark de Wever std::format_to(std::ostreambuf_iterator<_CharT>{__sstr}, 1377f5d130aSMark de Wever _LIBCPP_STATICALLY_WIDEN(_CharT, "{:0{}.0f}"), 1387f5d130aSMark de Wever __value.subseconds().count(), 1397f5d130aSMark de Wever __value.fractional_width); 1407f5d130aSMark de Wever else 1417f5d130aSMark de Wever std::format_to(std::ostreambuf_iterator<_CharT>{__sstr}, 1427f5d130aSMark de Wever _LIBCPP_STATICALLY_WIDEN(_CharT, "{:0{}}"), 1437f5d130aSMark de Wever __value.subseconds().count(), 1447f5d130aSMark de Wever __value.fractional_width); 145719c3dc6SMark de Wever } 146719c3dc6SMark de Wever 14724e70e39SNikolas Klauser # if _LIBCPP_HAS_EXPERIMENTAL_TZDB && _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM 148afbfb16dSMark de Wever template <class _CharT, class _Duration, class _TimeZonePtr> 149afbfb16dSMark de Wever _LIBCPP_HIDE_FROM_ABI void 150afbfb16dSMark de Wever __format_sub_seconds(basic_stringstream<_CharT>& __sstr, const chrono::zoned_time<_Duration, _TimeZonePtr>& __value) { 151afbfb16dSMark de Wever __formatter::__format_sub_seconds(__sstr, __value.get_local_time().time_since_epoch()); 152afbfb16dSMark de Wever } 153afbfb16dSMark de Wever # endif 154afbfb16dSMark de Wever 155719c3dc6SMark de Wever template <class _Tp> 156719c3dc6SMark de Wever consteval bool __use_fraction() { 1572c1d7959SMark de Wever if constexpr (__is_time_point<_Tp>) 1582c1d7959SMark de Wever return chrono::hh_mm_ss<typename _Tp::duration>::fractional_width; 15924e70e39SNikolas Klauser # if _LIBCPP_HAS_EXPERIMENTAL_TZDB && _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM 160afbfb16dSMark de Wever else if constexpr (__is_specialization_v<_Tp, chrono::zoned_time>) 161afbfb16dSMark de Wever return chrono::hh_mm_ss<typename _Tp::duration>::fractional_width; 162afbfb16dSMark de Wever # endif 1637c010bfdSNikolas Klauser else if constexpr (chrono::__is_duration_v<_Tp>) 164719c3dc6SMark de Wever return chrono::hh_mm_ss<_Tp>::fractional_width; 1657f5d130aSMark de Wever else if constexpr (__is_hh_mm_ss<_Tp>) 1667f5d130aSMark de Wever return _Tp::fractional_width; 167719c3dc6SMark de Wever else 168719c3dc6SMark de Wever return false; 169719c3dc6SMark de Wever } 170719c3dc6SMark de Wever 1713eb4f16bSMark de Wever template <class _CharT> 1725462b270SMark de Wever _LIBCPP_HIDE_FROM_ABI void __format_year(basic_stringstream<_CharT>& __sstr, int __year) { 1733eb4f16bSMark de Wever if (__year < 0) { 1743eb4f16bSMark de Wever __sstr << _CharT('-'); 1753eb4f16bSMark de Wever __year = -__year; 1763eb4f16bSMark de Wever } 1773eb4f16bSMark de Wever 1783eb4f16bSMark de Wever // TODO FMT Write an issue 1793eb4f16bSMark de Wever // If the result has less than four digits it is zero-padded with 0 to two digits. 1803eb4f16bSMark de Wever // is less -> has less 1813eb4f16bSMark de Wever // left-padded -> zero-padded, otherwise the proper value would be 000-0. 1823eb4f16bSMark de Wever 1833eb4f16bSMark de Wever // Note according to the wording it should be left padded, which is odd. 1843eb4f16bSMark de Wever __sstr << std::format(_LIBCPP_STATICALLY_WIDEN(_CharT, "{:04}"), __year); 1853eb4f16bSMark de Wever } 1863eb4f16bSMark de Wever 1873eb4f16bSMark de Wever template <class _CharT> 1885462b270SMark de Wever _LIBCPP_HIDE_FROM_ABI void __format_century(basic_stringstream<_CharT>& __sstr, int __year) { 1893eb4f16bSMark de Wever // TODO FMT Write an issue 1903eb4f16bSMark de Wever // [tab:time.format.spec] 1913eb4f16bSMark de Wever // %C The year divided by 100 using floored division. If the result is a 1923eb4f16bSMark de Wever // single decimal digit, it is prefixed with 0. 1933eb4f16bSMark de Wever 1943eb4f16bSMark de Wever bool __negative = __year < 0; 1953eb4f16bSMark de Wever int __century = (__year - (99 * __negative)) / 100; // floored division 1963eb4f16bSMark de Wever __sstr << std::format(_LIBCPP_STATICALLY_WIDEN(_CharT, "{:02}"), __century); 1973eb4f16bSMark de Wever } 1983eb4f16bSMark de Wever 199a6fcbcceSMark de Wever // Implements the %z format specifier according to [tab:time.format.spec], where 200a6fcbcceSMark de Wever // '__modifier' signals %Oz or %Ez were used. (Both modifiers behave the same, 201a6fcbcceSMark de Wever // so there is no need to distinguish between them.) 202a6fcbcceSMark de Wever template <class _CharT> 203a6fcbcceSMark de Wever _LIBCPP_HIDE_FROM_ABI void 204a6fcbcceSMark de Wever __format_zone_offset(basic_stringstream<_CharT>& __sstr, chrono::seconds __offset, bool __modifier) { 205a6fcbcceSMark de Wever if (__offset < 0s) { 206a6fcbcceSMark de Wever __sstr << _CharT('-'); 207a6fcbcceSMark de Wever __offset = -__offset; 208a6fcbcceSMark de Wever } else { 209a6fcbcceSMark de Wever __sstr << _CharT('+'); 210a6fcbcceSMark de Wever } 211a6fcbcceSMark de Wever 212a6fcbcceSMark de Wever chrono::hh_mm_ss __hms{__offset}; 213a6fcbcceSMark de Wever std::ostreambuf_iterator<_CharT> __out_it{__sstr}; 2146f7976c8SMark de Wever // Note HMS does not allow formatting hours > 23, but the offset is not limited to 24H. 2156f7976c8SMark de Wever std::format_to(__out_it, _LIBCPP_STATICALLY_WIDEN(_CharT, "{:02}"), __hms.hours().count()); 216a6fcbcceSMark de Wever if (__modifier) 2176f7976c8SMark de Wever __sstr << _CharT(':'); 2186f7976c8SMark de Wever std::format_to(__out_it, _LIBCPP_STATICALLY_WIDEN(_CharT, "{:02}"), __hms.minutes().count()); 219a6fcbcceSMark de Wever } 220a6fcbcceSMark de Wever 221a6fcbcceSMark de Wever // Helper to store the time zone information needed for formatting. 222a6fcbcceSMark de Wever struct _LIBCPP_HIDE_FROM_ABI __time_zone { 223a6fcbcceSMark de Wever // Typically these abbreviations are short and fit in the string's internal 224a6fcbcceSMark de Wever // buffer. 225a6fcbcceSMark de Wever string __abbrev; 226a6fcbcceSMark de Wever chrono::seconds __offset; 227a6fcbcceSMark de Wever }; 228a6fcbcceSMark de Wever 229a6fcbcceSMark de Wever template <class _Tp> 230a6fcbcceSMark de Wever _LIBCPP_HIDE_FROM_ABI __time_zone __convert_to_time_zone([[maybe_unused]] const _Tp& __value) { 23124e70e39SNikolas Klauser # if _LIBCPP_HAS_EXPERIMENTAL_TZDB 2326f7976c8SMark de Wever if constexpr (same_as<_Tp, chrono::sys_info>) 2336f7976c8SMark de Wever return {__value.abbrev, __value.offset}; 234c6f3b7bcSNikolas Klauser # if _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM 235afbfb16dSMark de Wever else if constexpr (__is_specialization_v<_Tp, chrono::zoned_time>) 236afbfb16dSMark de Wever return __formatter::__convert_to_time_zone(__value.get_info()); 2376f7976c8SMark de Wever # endif 238afbfb16dSMark de Wever else 23924e70e39SNikolas Klauser # endif // _LIBCPP_HAS_EXPERIMENTAL_TZDB 240a6fcbcceSMark de Wever return {"UTC", chrono::seconds{0}}; 241a6fcbcceSMark de Wever } 242a6fcbcceSMark de Wever 243e5d2d3eaSMark de Wever template <class _CharT, class _Tp> 244e5d2d3eaSMark de Wever _LIBCPP_HIDE_FROM_ABI void __format_chrono_using_chrono_specs( 2455462b270SMark de Wever basic_stringstream<_CharT>& __sstr, const _Tp& __value, basic_string_view<_CharT> __chrono_specs) { 246d529e811SLouis Dionne tm __t = std::__convert_to_tm<tm>(__value); 247a6fcbcceSMark de Wever __time_zone __z = __formatter::__convert_to_time_zone(__value); 248e5d2d3eaSMark de Wever const auto& __facet = std::use_facet<time_put<_CharT>>(__sstr.getloc()); 249e5d2d3eaSMark de Wever for (auto __it = __chrono_specs.begin(); __it != __chrono_specs.end(); ++__it) { 250e5d2d3eaSMark de Wever if (*__it == _CharT('%')) { 251e5d2d3eaSMark de Wever auto __s = __it; 252e5d2d3eaSMark de Wever ++__it; 253e5d2d3eaSMark de Wever // We only handle the types that can't be directly handled by time_put. 254e5d2d3eaSMark de Wever // (as an optimization n, t, and % are also handled directly.) 255e5d2d3eaSMark de Wever switch (*__it) { 256e5d2d3eaSMark de Wever case _CharT('n'): 257e5d2d3eaSMark de Wever __sstr << _CharT('\n'); 258e5d2d3eaSMark de Wever break; 259e5d2d3eaSMark de Wever case _CharT('t'): 260e5d2d3eaSMark de Wever __sstr << _CharT('\t'); 261e5d2d3eaSMark de Wever break; 262e5d2d3eaSMark de Wever case _CharT('%'): 263e5d2d3eaSMark de Wever __sstr << *__it; 264e5d2d3eaSMark de Wever break; 265e5d2d3eaSMark de Wever 2663eb4f16bSMark de Wever case _CharT('C'): { 2673eb4f16bSMark de Wever // strftime's output is only defined in the range [00, 99]. 2683eb4f16bSMark de Wever int __year = __t.tm_year + 1900; 2693eb4f16bSMark de Wever if (__year < 1000 || __year > 9999) 2705462b270SMark de Wever __formatter::__format_century(__sstr, __year); 2713eb4f16bSMark de Wever else 2729783f28cSLouis Dionne __facet.put( 2739783f28cSLouis Dionne {__sstr}, __sstr, _CharT(' '), std::addressof(__t), std::to_address(__s), std::to_address(__it + 1)); 2743eb4f16bSMark de Wever } break; 2753eb4f16bSMark de Wever 276719c3dc6SMark de Wever case _CharT('j'): 2777c010bfdSNikolas Klauser if constexpr (chrono::__is_duration_v<_Tp>) 278719c3dc6SMark de Wever // Converting a duration where the period has a small ratio to days 279719c3dc6SMark de Wever // may fail to compile. This due to loss of precision in the 280719c3dc6SMark de Wever // conversion. In order to avoid that issue convert to seconds as 281719c3dc6SMark de Wever // an intemediate step. 282719c3dc6SMark de Wever __sstr << chrono::duration_cast<chrono::days>(chrono::duration_cast<chrono::seconds>(__value)).count(); 283719c3dc6SMark de Wever else 2849783f28cSLouis Dionne __facet.put( 2859783f28cSLouis Dionne {__sstr}, __sstr, _CharT(' '), std::addressof(__t), std::to_address(__s), std::to_address(__it + 1)); 286719c3dc6SMark de Wever break; 287719c3dc6SMark de Wever 288719c3dc6SMark de Wever case _CharT('q'): 2897c010bfdSNikolas Klauser if constexpr (chrono::__is_duration_v<_Tp>) { 290719c3dc6SMark de Wever __sstr << chrono::__units_suffix<_CharT, typename _Tp::period>(); 291719c3dc6SMark de Wever break; 292719c3dc6SMark de Wever } 293719c3dc6SMark de Wever __builtin_unreachable(); 294719c3dc6SMark de Wever 295719c3dc6SMark de Wever case _CharT('Q'): 296719c3dc6SMark de Wever // TODO FMT Determine the proper ideas 297719c3dc6SMark de Wever // - Should it honour the precision? 298719c3dc6SMark de Wever // - Shoult it honour the locale setting for the separators? 299719c3dc6SMark de Wever // The wording for Q doesn't use the word locale and the effect of 300719c3dc6SMark de Wever // precision is unspecified. 301719c3dc6SMark de Wever // 302719c3dc6SMark de Wever // MSVC STL ignores precision but uses separator 303719c3dc6SMark de Wever // FMT honours precision and has a bug for separator 304719c3dc6SMark de Wever // https://godbolt.org/z/78b7sMxns 3057c010bfdSNikolas Klauser if constexpr (chrono::__is_duration_v<_Tp>) { 306841399a2SNikolas Klauser __sstr << std::format(_LIBCPP_STATICALLY_WIDEN(_CharT, "{}"), __value.count()); 307719c3dc6SMark de Wever break; 308719c3dc6SMark de Wever } 309719c3dc6SMark de Wever __builtin_unreachable(); 310719c3dc6SMark de Wever 311719c3dc6SMark de Wever case _CharT('S'): 312719c3dc6SMark de Wever case _CharT('T'): 3139783f28cSLouis Dionne __facet.put( 3149783f28cSLouis Dionne {__sstr}, __sstr, _CharT(' '), std::addressof(__t), std::to_address(__s), std::to_address(__it + 1)); 315719c3dc6SMark de Wever if constexpr (__use_fraction<_Tp>()) 3165462b270SMark de Wever __formatter::__format_sub_seconds(__sstr, __value); 317719c3dc6SMark de Wever break; 318719c3dc6SMark de Wever 3193eb4f16bSMark de Wever // Unlike time_put and strftime the formatting library requires %Y 3203eb4f16bSMark de Wever // 3213eb4f16bSMark de Wever // [tab:time.format.spec] 3223eb4f16bSMark de Wever // The year as a decimal number. If the result is less than four digits 3233eb4f16bSMark de Wever // it is left-padded with 0 to four digits. 3243eb4f16bSMark de Wever // 3253eb4f16bSMark de Wever // This means years in the range (-1000, 1000) need manual formatting. 3263eb4f16bSMark de Wever // It's unclear whether %EY needs the same treatment. For example the 3273eb4f16bSMark de Wever // Japanese EY contains the era name and year. This is zero-padded to 2 3283eb4f16bSMark de Wever // digits in time_put (note that older glibc versions didn't do 3293eb4f16bSMark de Wever // padding.) However most eras won't reach 100 years, let alone 1000. 3303eb4f16bSMark de Wever // So padding to 4 digits seems unwanted for Japanese. 3313eb4f16bSMark de Wever // 3323eb4f16bSMark de Wever // The same applies to %Ex since that too depends on the era. 3333eb4f16bSMark de Wever // 3343eb4f16bSMark de Wever // %x the locale's date representation is currently doesn't handle the 3353eb4f16bSMark de Wever // zero-padding too. 3363eb4f16bSMark de Wever // 3373eb4f16bSMark de Wever // The 4 digits can be implemented better at a later time. On POSIX 3383eb4f16bSMark de Wever // systems the required information can be extracted by nl_langinfo 3393eb4f16bSMark de Wever // https://man7.org/linux/man-pages/man3/nl_langinfo.3.html 3403eb4f16bSMark de Wever // 3413eb4f16bSMark de Wever // Note since year < -1000 is expected to be rare it uses the more 3423eb4f16bSMark de Wever // expensive year routine. 3433eb4f16bSMark de Wever // 3443eb4f16bSMark de Wever // TODO FMT evaluate the comment above. 3453eb4f16bSMark de Wever 3460ee73debSMark de Wever # if defined(__GLIBC__) || defined(_AIX) || defined(_WIN32) 3473eb4f16bSMark de Wever case _CharT('y'): 3483eb4f16bSMark de Wever // Glibc fails for negative values, AIX for positive values too. 3493eb4f16bSMark de Wever __sstr << std::format(_LIBCPP_STATICALLY_WIDEN(_CharT, "{:02}"), (std::abs(__t.tm_year + 1900)) % 100); 3503eb4f16bSMark de Wever break; 3510ee73debSMark de Wever # endif // defined(__GLIBC__) || defined(_AIX) || defined(_WIN32) 3523eb4f16bSMark de Wever 3530ee73debSMark de Wever case _CharT('Y'): 3540ee73debSMark de Wever // Depending on the platform's libc the range of supported years is 355d6fc7d3aSJay Foad // limited. Instead of of testing all conditions use the internal 3560ee73debSMark de Wever // implementation unconditionally. 3575462b270SMark de Wever __formatter::__format_year(__sstr, __t.tm_year + 1900); 3580ee73debSMark de Wever break; 3593eb4f16bSMark de Wever 360812963f6SMark de Wever case _CharT('F'): 361812963f6SMark de Wever // Depending on the platform's libc the range of supported years is 362812963f6SMark de Wever // limited. Instead of testing all conditions use the internal 363812963f6SMark de Wever // implementation unconditionally. 364812963f6SMark de Wever __formatter::__format_year(__sstr, __t.tm_year + 1900); 365105fef5dSMark de Wever __sstr << std::format(_LIBCPP_STATICALLY_WIDEN(_CharT, "-{:02}-{:02}"), __t.tm_mon + 1, __t.tm_mday); 366812963f6SMark de Wever break; 367105fef5dSMark de Wever 368a6fcbcceSMark de Wever case _CharT('z'): 369a6fcbcceSMark de Wever __formatter::__format_zone_offset(__sstr, __z.__offset, false); 370a6fcbcceSMark de Wever break; 371a6fcbcceSMark de Wever 3722c1d7959SMark de Wever case _CharT('Z'): 373a6fcbcceSMark de Wever // __abbrev is always a char so the copy may convert. 374a6fcbcceSMark de Wever ranges::copy(__z.__abbrev, std::ostreambuf_iterator<_CharT>{__sstr}); 3752c1d7959SMark de Wever break; 3762c1d7959SMark de Wever 377e5d2d3eaSMark de Wever case _CharT('O'): 378719c3dc6SMark de Wever if constexpr (__use_fraction<_Tp>()) { 379719c3dc6SMark de Wever // Handle OS using the normal representation for the non-fractional 380719c3dc6SMark de Wever // part. There seems to be no locale information regarding how the 381719c3dc6SMark de Wever // fractional part should be formatted. 382719c3dc6SMark de Wever if (*(__it + 1) == 'S') { 383719c3dc6SMark de Wever ++__it; 3849783f28cSLouis Dionne __facet.put( 3859783f28cSLouis Dionne {__sstr}, __sstr, _CharT(' '), std::addressof(__t), std::to_address(__s), std::to_address(__it + 1)); 3865462b270SMark de Wever __formatter::__format_sub_seconds(__sstr, __value); 387719c3dc6SMark de Wever break; 388719c3dc6SMark de Wever } 389719c3dc6SMark de Wever } 390a6fcbcceSMark de Wever 391a6fcbcceSMark de Wever // Oz produces the same output as Ez below. 392719c3dc6SMark de Wever [[fallthrough]]; 3933eb4f16bSMark de Wever case _CharT('E'): 394e5d2d3eaSMark de Wever ++__it; 395a6fcbcceSMark de Wever if (*__it == 'z') { 396a6fcbcceSMark de Wever __formatter::__format_zone_offset(__sstr, __z.__offset, true); 397a6fcbcceSMark de Wever break; 398a6fcbcceSMark de Wever } 399e5d2d3eaSMark de Wever [[fallthrough]]; 400e5d2d3eaSMark de Wever default: 4019783f28cSLouis Dionne __facet.put( 4029783f28cSLouis Dionne {__sstr}, __sstr, _CharT(' '), std::addressof(__t), std::to_address(__s), std::to_address(__it + 1)); 403e5d2d3eaSMark de Wever break; 404e5d2d3eaSMark de Wever } 405e5d2d3eaSMark de Wever } else { 406e5d2d3eaSMark de Wever __sstr << *__it; 407e5d2d3eaSMark de Wever } 408e5d2d3eaSMark de Wever } 409e5d2d3eaSMark de Wever } 410e5d2d3eaSMark de Wever 4111522f190SMark de Wever template <class _Tp> 412105fef5dSMark de Wever _LIBCPP_HIDE_FROM_ABI constexpr bool __weekday_ok(const _Tp& __value) { 4132c1d7959SMark de Wever if constexpr (__is_time_point<_Tp>) 4142c1d7959SMark de Wever return true; 4152c1d7959SMark de Wever else if constexpr (same_as<_Tp, chrono::day>) 4161522f190SMark de Wever return true; 4171522f190SMark de Wever else if constexpr (same_as<_Tp, chrono::month>) 4181522f190SMark de Wever return __value.ok(); 4191522f190SMark de Wever else if constexpr (same_as<_Tp, chrono::year>) 4201522f190SMark de Wever return true; 421566868cdSMark de Wever else if constexpr (same_as<_Tp, chrono::weekday>) 422566868cdSMark de Wever return true; 423105fef5dSMark de Wever else if constexpr (same_as<_Tp, chrono::weekday_indexed>) 424105fef5dSMark de Wever return true; 425105fef5dSMark de Wever else if constexpr (same_as<_Tp, chrono::weekday_last>) 426105fef5dSMark de Wever return true; 427105fef5dSMark de Wever else if constexpr (same_as<_Tp, chrono::month_day>) 428105fef5dSMark de Wever return true; 429105fef5dSMark de Wever else if constexpr (same_as<_Tp, chrono::month_day_last>) 430105fef5dSMark de Wever return true; 431105fef5dSMark de Wever else if constexpr (same_as<_Tp, chrono::month_weekday>) 432105fef5dSMark de Wever return true; 433105fef5dSMark de Wever else if constexpr (same_as<_Tp, chrono::month_weekday_last>) 434105fef5dSMark de Wever return true; 435105fef5dSMark de Wever else if constexpr (same_as<_Tp, chrono::year_month>) 436105fef5dSMark de Wever return true; 437105fef5dSMark de Wever else if constexpr (same_as<_Tp, chrono::year_month_day>) 438105fef5dSMark de Wever return __value.ok(); 439105fef5dSMark de Wever else if constexpr (same_as<_Tp, chrono::year_month_day_last>) 440105fef5dSMark de Wever return __value.ok(); 441105fef5dSMark de Wever else if constexpr (same_as<_Tp, chrono::year_month_weekday>) 442105fef5dSMark de Wever return __value.weekday().ok(); 443105fef5dSMark de Wever else if constexpr (same_as<_Tp, chrono::year_month_weekday_last>) 444105fef5dSMark de Wever return __value.weekday().ok(); 4457f5d130aSMark de Wever else if constexpr (__is_hh_mm_ss<_Tp>) 4467f5d130aSMark de Wever return true; 44724e70e39SNikolas Klauser # if _LIBCPP_HAS_EXPERIMENTAL_TZDB 4486f7976c8SMark de Wever else if constexpr (same_as<_Tp, chrono::sys_info>) 4496f7976c8SMark de Wever return true; 4508a21d59fSMark de Wever else if constexpr (same_as<_Tp, chrono::local_info>) 4518a21d59fSMark de Wever return true; 452c6f3b7bcSNikolas Klauser # if _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM 453afbfb16dSMark de Wever else if constexpr (__is_specialization_v<_Tp, chrono::zoned_time>) 454afbfb16dSMark de Wever return true; 4556f7976c8SMark de Wever # endif 45624e70e39SNikolas Klauser # endif // _LIBCPP_HAS_EXPERIMENTAL_TZDB 457566868cdSMark de Wever else 458566868cdSMark de Wever static_assert(sizeof(_Tp) == 0, "Add the missing type specialization"); 459566868cdSMark de Wever } 460566868cdSMark de Wever 461566868cdSMark de Wever template <class _Tp> 462566868cdSMark de Wever _LIBCPP_HIDE_FROM_ABI constexpr bool __weekday_name_ok(const _Tp& __value) { 4632c1d7959SMark de Wever if constexpr (__is_time_point<_Tp>) 4642c1d7959SMark de Wever return true; 4652c1d7959SMark de Wever else if constexpr (same_as<_Tp, chrono::day>) 466566868cdSMark de Wever return true; 467566868cdSMark de Wever else if constexpr (same_as<_Tp, chrono::month>) 468566868cdSMark de Wever return __value.ok(); 469566868cdSMark de Wever else if constexpr (same_as<_Tp, chrono::year>) 470566868cdSMark de Wever return true; 471566868cdSMark de Wever else if constexpr (same_as<_Tp, chrono::weekday>) 472566868cdSMark de Wever return __value.ok(); 473105fef5dSMark de Wever else if constexpr (same_as<_Tp, chrono::weekday_indexed>) 474105fef5dSMark de Wever return __value.weekday().ok(); 475105fef5dSMark de Wever else if constexpr (same_as<_Tp, chrono::weekday_last>) 476105fef5dSMark de Wever return __value.weekday().ok(); 477105fef5dSMark de Wever else if constexpr (same_as<_Tp, chrono::month_day>) 478105fef5dSMark de Wever return true; 479105fef5dSMark de Wever else if constexpr (same_as<_Tp, chrono::month_day_last>) 480105fef5dSMark de Wever return true; 481105fef5dSMark de Wever else if constexpr (same_as<_Tp, chrono::month_weekday>) 482105fef5dSMark de Wever return __value.weekday_indexed().ok(); 483105fef5dSMark de Wever else if constexpr (same_as<_Tp, chrono::month_weekday_last>) 484105fef5dSMark de Wever return __value.weekday_indexed().ok(); 485105fef5dSMark de Wever else if constexpr (same_as<_Tp, chrono::year_month>) 486105fef5dSMark de Wever return true; 487105fef5dSMark de Wever else if constexpr (same_as<_Tp, chrono::year_month_day>) 488105fef5dSMark de Wever return __value.ok(); 489105fef5dSMark de Wever else if constexpr (same_as<_Tp, chrono::year_month_day_last>) 490105fef5dSMark de Wever return __value.ok(); 491105fef5dSMark de Wever else if constexpr (same_as<_Tp, chrono::year_month_weekday>) 492105fef5dSMark de Wever return __value.weekday().ok(); 493105fef5dSMark de Wever else if constexpr (same_as<_Tp, chrono::year_month_weekday_last>) 494105fef5dSMark de Wever return __value.weekday().ok(); 4957f5d130aSMark de Wever else if constexpr (__is_hh_mm_ss<_Tp>) 4967f5d130aSMark de Wever return true; 49724e70e39SNikolas Klauser # if _LIBCPP_HAS_EXPERIMENTAL_TZDB 4986f7976c8SMark de Wever else if constexpr (same_as<_Tp, chrono::sys_info>) 4996f7976c8SMark de Wever return true; 5008a21d59fSMark de Wever else if constexpr (same_as<_Tp, chrono::local_info>) 5018a21d59fSMark de Wever return true; 502c6f3b7bcSNikolas Klauser # if _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM 503afbfb16dSMark de Wever else if constexpr (__is_specialization_v<_Tp, chrono::zoned_time>) 504afbfb16dSMark de Wever return true; 5056f7976c8SMark de Wever # endif 50624e70e39SNikolas Klauser # endif // _LIBCPP_HAS_EXPERIMENTAL_TZDB 507105fef5dSMark de Wever else 508105fef5dSMark de Wever static_assert(sizeof(_Tp) == 0, "Add the missing type specialization"); 509105fef5dSMark de Wever } 510105fef5dSMark de Wever 511105fef5dSMark de Wever template <class _Tp> 512105fef5dSMark de Wever _LIBCPP_HIDE_FROM_ABI constexpr bool __date_ok(const _Tp& __value) { 5132c1d7959SMark de Wever if constexpr (__is_time_point<_Tp>) 5142c1d7959SMark de Wever return true; 5152c1d7959SMark de Wever else if constexpr (same_as<_Tp, chrono::day>) 516105fef5dSMark de Wever return true; 517105fef5dSMark de Wever else if constexpr (same_as<_Tp, chrono::month>) 518105fef5dSMark de Wever return __value.ok(); 519105fef5dSMark de Wever else if constexpr (same_as<_Tp, chrono::year>) 520105fef5dSMark de Wever return true; 521105fef5dSMark de Wever else if constexpr (same_as<_Tp, chrono::weekday>) 522105fef5dSMark de Wever return true; 523105fef5dSMark de Wever else if constexpr (same_as<_Tp, chrono::weekday_indexed>) 524105fef5dSMark de Wever return true; 525105fef5dSMark de Wever else if constexpr (same_as<_Tp, chrono::weekday_last>) 526105fef5dSMark de Wever return true; 527105fef5dSMark de Wever else if constexpr (same_as<_Tp, chrono::month_day>) 528105fef5dSMark de Wever return true; 529105fef5dSMark de Wever else if constexpr (same_as<_Tp, chrono::month_day_last>) 530105fef5dSMark de Wever return true; 531105fef5dSMark de Wever else if constexpr (same_as<_Tp, chrono::month_weekday>) 532105fef5dSMark de Wever return true; 533105fef5dSMark de Wever else if constexpr (same_as<_Tp, chrono::month_weekday_last>) 534105fef5dSMark de Wever return true; 535105fef5dSMark de Wever else if constexpr (same_as<_Tp, chrono::year_month>) 536105fef5dSMark de Wever return true; 537105fef5dSMark de Wever else if constexpr (same_as<_Tp, chrono::year_month_day>) 538105fef5dSMark de Wever return __value.ok(); 539105fef5dSMark de Wever else if constexpr (same_as<_Tp, chrono::year_month_day_last>) 540105fef5dSMark de Wever return __value.ok(); 541105fef5dSMark de Wever else if constexpr (same_as<_Tp, chrono::year_month_weekday>) 542105fef5dSMark de Wever return __value.ok(); 543105fef5dSMark de Wever else if constexpr (same_as<_Tp, chrono::year_month_weekday_last>) 544105fef5dSMark de Wever return __value.ok(); 5457f5d130aSMark de Wever else if constexpr (__is_hh_mm_ss<_Tp>) 5467f5d130aSMark de Wever return true; 54724e70e39SNikolas Klauser # if _LIBCPP_HAS_EXPERIMENTAL_TZDB 5486f7976c8SMark de Wever else if constexpr (same_as<_Tp, chrono::sys_info>) 5496f7976c8SMark de Wever return true; 5508a21d59fSMark de Wever else if constexpr (same_as<_Tp, chrono::local_info>) 5518a21d59fSMark de Wever return true; 552c6f3b7bcSNikolas Klauser # if _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM 553afbfb16dSMark de Wever else if constexpr (__is_specialization_v<_Tp, chrono::zoned_time>) 554afbfb16dSMark de Wever return true; 5556f7976c8SMark de Wever # endif 55624e70e39SNikolas Klauser # endif // _LIBCPP_HAS_EXPERIMENTAL_TZDB 557105fef5dSMark de Wever else 558105fef5dSMark de Wever static_assert(sizeof(_Tp) == 0, "Add the missing type specialization"); 559105fef5dSMark de Wever } 560105fef5dSMark de Wever 561105fef5dSMark de Wever template <class _Tp> 562105fef5dSMark de Wever _LIBCPP_HIDE_FROM_ABI constexpr bool __month_name_ok(const _Tp& __value) { 5632c1d7959SMark de Wever if constexpr (__is_time_point<_Tp>) 5642c1d7959SMark de Wever return true; 5652c1d7959SMark de Wever else if constexpr (same_as<_Tp, chrono::day>) 566105fef5dSMark de Wever return true; 567105fef5dSMark de Wever else if constexpr (same_as<_Tp, chrono::month>) 568105fef5dSMark de Wever return __value.ok(); 569105fef5dSMark de Wever else if constexpr (same_as<_Tp, chrono::year>) 570105fef5dSMark de Wever return true; 571105fef5dSMark de Wever else if constexpr (same_as<_Tp, chrono::weekday>) 572105fef5dSMark de Wever return true; 573105fef5dSMark de Wever else if constexpr (same_as<_Tp, chrono::weekday_indexed>) 574105fef5dSMark de Wever return true; 575105fef5dSMark de Wever else if constexpr (same_as<_Tp, chrono::weekday_last>) 576105fef5dSMark de Wever return true; 577105fef5dSMark de Wever else if constexpr (same_as<_Tp, chrono::month_day>) 578105fef5dSMark de Wever return __value.month().ok(); 579105fef5dSMark de Wever else if constexpr (same_as<_Tp, chrono::month_day_last>) 580105fef5dSMark de Wever return __value.month().ok(); 581105fef5dSMark de Wever else if constexpr (same_as<_Tp, chrono::month_weekday>) 582105fef5dSMark de Wever return __value.month().ok(); 583105fef5dSMark de Wever else if constexpr (same_as<_Tp, chrono::month_weekday_last>) 584105fef5dSMark de Wever return __value.month().ok(); 585105fef5dSMark de Wever else if constexpr (same_as<_Tp, chrono::year_month>) 586105fef5dSMark de Wever return __value.month().ok(); 587105fef5dSMark de Wever else if constexpr (same_as<_Tp, chrono::year_month_day>) 588105fef5dSMark de Wever return __value.month().ok(); 589105fef5dSMark de Wever else if constexpr (same_as<_Tp, chrono::year_month_day_last>) 590105fef5dSMark de Wever return __value.month().ok(); 591105fef5dSMark de Wever else if constexpr (same_as<_Tp, chrono::year_month_weekday>) 592105fef5dSMark de Wever return __value.month().ok(); 593105fef5dSMark de Wever else if constexpr (same_as<_Tp, chrono::year_month_weekday_last>) 594105fef5dSMark de Wever return __value.month().ok(); 5957f5d130aSMark de Wever else if constexpr (__is_hh_mm_ss<_Tp>) 5967f5d130aSMark de Wever return true; 59724e70e39SNikolas Klauser # if _LIBCPP_HAS_EXPERIMENTAL_TZDB 5986f7976c8SMark de Wever else if constexpr (same_as<_Tp, chrono::sys_info>) 5996f7976c8SMark de Wever return true; 6008a21d59fSMark de Wever else if constexpr (same_as<_Tp, chrono::local_info>) 6018a21d59fSMark de Wever return true; 602c6f3b7bcSNikolas Klauser # if _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM 603afbfb16dSMark de Wever else if constexpr (__is_specialization_v<_Tp, chrono::zoned_time>) 604afbfb16dSMark de Wever return true; 6056f7976c8SMark de Wever # endif 60624e70e39SNikolas Klauser # endif // _LIBCPP_HAS_EXPERIMENTAL_TZDB 6071522f190SMark de Wever else 6081522f190SMark de Wever static_assert(sizeof(_Tp) == 0, "Add the missing type specialization"); 6091522f190SMark de Wever } 6101522f190SMark de Wever 611b51e8acdSMark de Wever template <class _CharT, class _Tp, class _FormatContext> 612e5d2d3eaSMark de Wever _LIBCPP_HIDE_FROM_ABI auto 613e5d2d3eaSMark de Wever __format_chrono(const _Tp& __value, 614b51e8acdSMark de Wever _FormatContext& __ctx, 615e5d2d3eaSMark de Wever __format_spec::__parsed_specifications<_CharT> __specs, 616b51e8acdSMark de Wever basic_string_view<_CharT> __chrono_specs) { 617e5d2d3eaSMark de Wever basic_stringstream<_CharT> __sstr; 618e5d2d3eaSMark de Wever // [time.format]/2 619e5d2d3eaSMark de Wever // 2.1 - the "C" locale if the L option is not present in chrono-format-spec, otherwise 620e5d2d3eaSMark de Wever // 2.2 - the locale passed to the formatting function if any, otherwise 621e5d2d3eaSMark de Wever // 2.3 - the global locale. 622e5d2d3eaSMark de Wever // Note that the __ctx's locale() call does 2.2 and 2.3. 623e5d2d3eaSMark de Wever if (__specs.__chrono_.__locale_specific_form_) 624e5d2d3eaSMark de Wever __sstr.imbue(__ctx.locale()); 625e5d2d3eaSMark de Wever else 626e5d2d3eaSMark de Wever __sstr.imbue(locale::classic()); 627e5d2d3eaSMark de Wever 628e5d2d3eaSMark de Wever if (__chrono_specs.empty()) 629e5d2d3eaSMark de Wever __sstr << __value; 6301522f190SMark de Wever else { 6317c010bfdSNikolas Klauser if constexpr (chrono::__is_duration_v<_Tp>) { 6326c97ad4eSMark de Wever // A duration can be a user defined arithmetic type. Users may specialize 6336c97ad4eSMark de Wever // numeric_limits, but they may not specialize is_signed. 6346c97ad4eSMark de Wever if constexpr (numeric_limits<typename _Tp::rep>::is_signed) { 6356c97ad4eSMark de Wever if (__value < __value.zero()) { 636719c3dc6SMark de Wever __sstr << _CharT('-'); 6376c97ad4eSMark de Wever __formatter::__format_chrono_using_chrono_specs(__sstr, -__value, __chrono_specs); 6386c97ad4eSMark de Wever } else 6396c97ad4eSMark de Wever __formatter::__format_chrono_using_chrono_specs(__sstr, __value, __chrono_specs); 6406c97ad4eSMark de Wever } else 6416c97ad4eSMark de Wever __formatter::__format_chrono_using_chrono_specs(__sstr, __value, __chrono_specs); 642719c3dc6SMark de Wever // TODO FMT When keeping the precision it will truncate the string. 643719c3dc6SMark de Wever // Note that the behaviour what the precision does isn't specified. 644719c3dc6SMark de Wever __specs.__precision_ = -1; 645719c3dc6SMark de Wever } else { 646105fef5dSMark de Wever // Test __weekday_name_ before __weekday_ to give a better error. 647566868cdSMark de Wever if (__specs.__chrono_.__weekday_name_ && !__formatter::__weekday_name_ok(__value)) 648402eb2efSMark de Wever std::__throw_format_error("Formatting a weekday name needs a valid weekday"); 649566868cdSMark de Wever 650105fef5dSMark de Wever if (__specs.__chrono_.__weekday_ && !__formatter::__weekday_ok(__value)) 651402eb2efSMark de Wever std::__throw_format_error("Formatting a weekday needs a valid weekday"); 652105fef5dSMark de Wever 653105fef5dSMark de Wever if (__specs.__chrono_.__day_of_year_ && !__formatter::__date_ok(__value)) 654402eb2efSMark de Wever std::__throw_format_error("Formatting a day of year needs a valid date"); 655105fef5dSMark de Wever 656105fef5dSMark de Wever if (__specs.__chrono_.__week_of_year_ && !__formatter::__date_ok(__value)) 657402eb2efSMark de Wever std::__throw_format_error("Formatting a week of year needs a valid date"); 658105fef5dSMark de Wever 6591522f190SMark de Wever if (__specs.__chrono_.__month_name_ && !__formatter::__month_name_ok(__value)) 660402eb2efSMark de Wever std::__throw_format_error("Formatting a month name from an invalid month number"); 6611522f190SMark de Wever 6627f5d130aSMark de Wever if constexpr (__is_hh_mm_ss<_Tp>) { 6637f5d130aSMark de Wever // Note this is a pedantic intepretation of the Standard. A hh_mm_ss 6647f5d130aSMark de Wever // is no longer a time_of_day and can store an arbitrary number of 6657f5d130aSMark de Wever // hours. A number of hours in a 12 or 24 hour clock can't represent 6667f5d130aSMark de Wever // 24 hours or more. The functions std::chrono::make12 and 6677f5d130aSMark de Wever // std::chrono::make24 reaffirm this view point. 6687f5d130aSMark de Wever // 6697f5d130aSMark de Wever // Interestingly this will be the only output stream function that 6707f5d130aSMark de Wever // throws. 6717f5d130aSMark de Wever // 6727f5d130aSMark de Wever // TODO FMT The wording probably needs to be adapted to 6737f5d130aSMark de Wever // - The displayed hours is hh_mm_ss.hours() % 24 6747f5d130aSMark de Wever // - It should probably allow %j in the same fashion as duration. 6757f5d130aSMark de Wever // - The stream formatter should change its output when hours >= 24 6767f5d130aSMark de Wever // - Write it as not valid, 6777f5d130aSMark de Wever // - or write the number of days. 6787f5d130aSMark de Wever if (__specs.__chrono_.__hour_ && __value.hours().count() > 23) 679402eb2efSMark de Wever std::__throw_format_error("Formatting a hour needs a valid value"); 6807f5d130aSMark de Wever 6817f5d130aSMark de Wever if (__value.is_negative()) 6827f5d130aSMark de Wever __sstr << _CharT('-'); 6837f5d130aSMark de Wever } 6847f5d130aSMark de Wever 6855462b270SMark de Wever __formatter::__format_chrono_using_chrono_specs(__sstr, __value, __chrono_specs); 6861522f190SMark de Wever } 687719c3dc6SMark de Wever } 688e5d2d3eaSMark de Wever 689ac834983SMark de Wever return __formatter::__write_string(__sstr.view(), __ctx.out(), __specs); 690e5d2d3eaSMark de Wever } 691e5d2d3eaSMark de Wever 692e5d2d3eaSMark de Wever } // namespace __formatter 693e5d2d3eaSMark de Wever 694e5d2d3eaSMark de Wever template <__fmt_char_type _CharT> 6953d334df5SLouis Dionne struct _LIBCPP_TEMPLATE_VIS __formatter_chrono { 696e5d2d3eaSMark de Wever public: 697b51e8acdSMark de Wever template <class _ParseContext> 698b51e8acdSMark de Wever _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator 699b51e8acdSMark de Wever __parse(_ParseContext& __ctx, __format_spec::__fields __fields, __format_spec::__flags __flags) { 700b51e8acdSMark de Wever return __parser_.__parse(__ctx, __fields, __flags); 701e5d2d3eaSMark de Wever } 702e5d2d3eaSMark de Wever 703b51e8acdSMark de Wever template <class _Tp, class _FormatContext> 704b51e8acdSMark de Wever _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator format(const _Tp& __value, _FormatContext& __ctx) const { 705e5d2d3eaSMark de Wever return __formatter::__format_chrono( 706e5d2d3eaSMark de Wever __value, __ctx, __parser_.__parser_.__get_parsed_chrono_specifications(__ctx), __parser_.__chrono_specs_); 707e5d2d3eaSMark de Wever } 708e5d2d3eaSMark de Wever 709e5d2d3eaSMark de Wever __format_spec::__parser_chrono<_CharT> __parser_; 710e5d2d3eaSMark de Wever }; 711e5d2d3eaSMark de Wever 7122c1d7959SMark de Wever template <class _Duration, __fmt_char_type _CharT> 7132c1d7959SMark de Wever struct _LIBCPP_TEMPLATE_VIS formatter<chrono::sys_time<_Duration>, _CharT> : public __formatter_chrono<_CharT> { 7142c1d7959SMark de Wever public: 715f6958523SNikolas Klauser using _Base _LIBCPP_NODEBUG = __formatter_chrono<_CharT>; 7162c1d7959SMark de Wever 717b51e8acdSMark de Wever template <class _ParseContext> 718b51e8acdSMark de Wever _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { 719b51e8acdSMark de Wever return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__clock); 7202c1d7959SMark de Wever } 7212c1d7959SMark de Wever }; 7222c1d7959SMark de Wever 7230cd794d4SMark de Wever # if _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM 724*3b30f20cSMark de Wever # if _LIBCPP_HAS_EXPERIMENTAL_TZDB 7250cd794d4SMark de Wever 7260cd794d4SMark de Wever template <class _Duration, __fmt_char_type _CharT> 7270cd794d4SMark de Wever struct _LIBCPP_TEMPLATE_VIS formatter<chrono::utc_time<_Duration>, _CharT> : public __formatter_chrono<_CharT> { 7280cd794d4SMark de Wever public: 7290cd794d4SMark de Wever using _Base _LIBCPP_NODEBUG = __formatter_chrono<_CharT>; 7300cd794d4SMark de Wever 7310cd794d4SMark de Wever template <class _ParseContext> 7320cd794d4SMark de Wever _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { 7330cd794d4SMark de Wever return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__clock); 7340cd794d4SMark de Wever } 7350cd794d4SMark de Wever }; 7360cd794d4SMark de Wever 737*3b30f20cSMark de Wever # endif // _LIBCPP_HAS_EXPERIMENTAL_TZDB 7380cd794d4SMark de Wever # endif // _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM 7390cd794d4SMark de Wever 74096f30332SMark de Wever template <class _Duration, __fmt_char_type _CharT> 74196f30332SMark de Wever struct _LIBCPP_TEMPLATE_VIS formatter<chrono::file_time<_Duration>, _CharT> : public __formatter_chrono<_CharT> { 74296f30332SMark de Wever public: 743f6958523SNikolas Klauser using _Base _LIBCPP_NODEBUG = __formatter_chrono<_CharT>; 74496f30332SMark de Wever 745b51e8acdSMark de Wever template <class _ParseContext> 746b51e8acdSMark de Wever _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { 747b51e8acdSMark de Wever return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__clock); 74896f30332SMark de Wever } 74996f30332SMark de Wever }; 75096f30332SMark de Wever 751bc2cf420SMark de Wever template <class _Duration, __fmt_char_type _CharT> 752bc2cf420SMark de Wever struct _LIBCPP_TEMPLATE_VIS formatter<chrono::local_time<_Duration>, _CharT> : public __formatter_chrono<_CharT> { 753bc2cf420SMark de Wever public: 754f6958523SNikolas Klauser using _Base _LIBCPP_NODEBUG = __formatter_chrono<_CharT>; 755bc2cf420SMark de Wever 756b51e8acdSMark de Wever template <class _ParseContext> 757b51e8acdSMark de Wever _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { 758bc2cf420SMark de Wever // The flags are not __clock since there is no associated time-zone. 759b51e8acdSMark de Wever return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__date_time); 760bc2cf420SMark de Wever } 761bc2cf420SMark de Wever }; 762bc2cf420SMark de Wever 763719c3dc6SMark de Wever template <class _Rep, class _Period, __fmt_char_type _CharT> 764719c3dc6SMark de Wever struct formatter<chrono::duration<_Rep, _Period>, _CharT> : public __formatter_chrono<_CharT> { 765719c3dc6SMark de Wever public: 766f6958523SNikolas Klauser using _Base _LIBCPP_NODEBUG = __formatter_chrono<_CharT>; 767719c3dc6SMark de Wever 768b51e8acdSMark de Wever template <class _ParseContext> 769b51e8acdSMark de Wever _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { 770719c3dc6SMark de Wever // [time.format]/1 771719c3dc6SMark de Wever // Giving a precision specification in the chrono-format-spec is valid only 772719c3dc6SMark de Wever // for std::chrono::duration types where the representation type Rep is a 773719c3dc6SMark de Wever // floating-point type. For all other Rep types, an exception of type 774719c3dc6SMark de Wever // format_error is thrown if the chrono-format-spec contains a precision 775719c3dc6SMark de Wever // specification. 776719c3dc6SMark de Wever // 777719c3dc6SMark de Wever // Note this doesn't refer to chrono::treat_as_floating_point_v<_Rep>. 778719c3dc6SMark de Wever if constexpr (std::floating_point<_Rep>) 779b51e8acdSMark de Wever return _Base::__parse(__ctx, __format_spec::__fields_chrono_fractional, __format_spec::__flags::__duration); 780719c3dc6SMark de Wever else 781b51e8acdSMark de Wever return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__duration); 782719c3dc6SMark de Wever } 783719c3dc6SMark de Wever }; 784719c3dc6SMark de Wever 785e5d2d3eaSMark de Wever template <__fmt_char_type _CharT> 7869783f28cSLouis Dionne struct _LIBCPP_TEMPLATE_VIS formatter<chrono::day, _CharT> : public __formatter_chrono<_CharT> { 787e5d2d3eaSMark de Wever public: 788f6958523SNikolas Klauser using _Base _LIBCPP_NODEBUG = __formatter_chrono<_CharT>; 789e5d2d3eaSMark de Wever 790b51e8acdSMark de Wever template <class _ParseContext> 791b51e8acdSMark de Wever _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { 792b51e8acdSMark de Wever return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__day); 793e5d2d3eaSMark de Wever } 794e5d2d3eaSMark de Wever }; 795e5d2d3eaSMark de Wever 7963eb4f16bSMark de Wever template <__fmt_char_type _CharT> 7979783f28cSLouis Dionne struct _LIBCPP_TEMPLATE_VIS formatter<chrono::month, _CharT> : public __formatter_chrono<_CharT> { 7981522f190SMark de Wever public: 799f6958523SNikolas Klauser using _Base _LIBCPP_NODEBUG = __formatter_chrono<_CharT>; 8001522f190SMark de Wever 801b51e8acdSMark de Wever template <class _ParseContext> 802b51e8acdSMark de Wever _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { 803b51e8acdSMark de Wever return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__month); 8041522f190SMark de Wever } 8051522f190SMark de Wever }; 8061522f190SMark de Wever 8071522f190SMark de Wever template <__fmt_char_type _CharT> 8089783f28cSLouis Dionne struct _LIBCPP_TEMPLATE_VIS formatter<chrono::year, _CharT> : public __formatter_chrono<_CharT> { 8093eb4f16bSMark de Wever public: 810f6958523SNikolas Klauser using _Base _LIBCPP_NODEBUG = __formatter_chrono<_CharT>; 8113eb4f16bSMark de Wever 812b51e8acdSMark de Wever template <class _ParseContext> 813b51e8acdSMark de Wever _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { 814b51e8acdSMark de Wever return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__year); 8153eb4f16bSMark de Wever } 8163eb4f16bSMark de Wever }; 8173eb4f16bSMark de Wever 818566868cdSMark de Wever template <__fmt_char_type _CharT> 8199783f28cSLouis Dionne struct _LIBCPP_TEMPLATE_VIS formatter<chrono::weekday, _CharT> : public __formatter_chrono<_CharT> { 820566868cdSMark de Wever public: 821f6958523SNikolas Klauser using _Base _LIBCPP_NODEBUG = __formatter_chrono<_CharT>; 822566868cdSMark de Wever 823b51e8acdSMark de Wever template <class _ParseContext> 824b51e8acdSMark de Wever _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { 825b51e8acdSMark de Wever return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__weekday); 826566868cdSMark de Wever } 827566868cdSMark de Wever }; 828566868cdSMark de Wever 829105fef5dSMark de Wever template <__fmt_char_type _CharT> 8309783f28cSLouis Dionne struct _LIBCPP_TEMPLATE_VIS formatter<chrono::weekday_indexed, _CharT> : public __formatter_chrono<_CharT> { 831105fef5dSMark de Wever public: 832f6958523SNikolas Klauser using _Base _LIBCPP_NODEBUG = __formatter_chrono<_CharT>; 833105fef5dSMark de Wever 834b51e8acdSMark de Wever template <class _ParseContext> 835b51e8acdSMark de Wever _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { 836b51e8acdSMark de Wever return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__weekday); 837105fef5dSMark de Wever } 838105fef5dSMark de Wever }; 839105fef5dSMark de Wever 840105fef5dSMark de Wever template <__fmt_char_type _CharT> 8419783f28cSLouis Dionne struct _LIBCPP_TEMPLATE_VIS formatter<chrono::weekday_last, _CharT> : public __formatter_chrono<_CharT> { 842105fef5dSMark de Wever public: 843f6958523SNikolas Klauser using _Base _LIBCPP_NODEBUG = __formatter_chrono<_CharT>; 844105fef5dSMark de Wever 845b51e8acdSMark de Wever template <class _ParseContext> 846b51e8acdSMark de Wever _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { 847b51e8acdSMark de Wever return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__weekday); 848105fef5dSMark de Wever } 849105fef5dSMark de Wever }; 850105fef5dSMark de Wever 851105fef5dSMark de Wever template <__fmt_char_type _CharT> 8529783f28cSLouis Dionne struct _LIBCPP_TEMPLATE_VIS formatter<chrono::month_day, _CharT> : public __formatter_chrono<_CharT> { 853105fef5dSMark de Wever public: 854f6958523SNikolas Klauser using _Base _LIBCPP_NODEBUG = __formatter_chrono<_CharT>; 855105fef5dSMark de Wever 856b51e8acdSMark de Wever template <class _ParseContext> 857b51e8acdSMark de Wever _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { 858b51e8acdSMark de Wever return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__month_day); 859105fef5dSMark de Wever } 860105fef5dSMark de Wever }; 861105fef5dSMark de Wever 862105fef5dSMark de Wever template <__fmt_char_type _CharT> 8639783f28cSLouis Dionne struct _LIBCPP_TEMPLATE_VIS formatter<chrono::month_day_last, _CharT> : public __formatter_chrono<_CharT> { 864105fef5dSMark de Wever public: 865f6958523SNikolas Klauser using _Base _LIBCPP_NODEBUG = __formatter_chrono<_CharT>; 866105fef5dSMark de Wever 867b51e8acdSMark de Wever template <class _ParseContext> 868b51e8acdSMark de Wever _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { 869b51e8acdSMark de Wever return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__month); 870105fef5dSMark de Wever } 871105fef5dSMark de Wever }; 872105fef5dSMark de Wever 873105fef5dSMark de Wever template <__fmt_char_type _CharT> 8749783f28cSLouis Dionne struct _LIBCPP_TEMPLATE_VIS formatter<chrono::month_weekday, _CharT> : public __formatter_chrono<_CharT> { 875105fef5dSMark de Wever public: 876f6958523SNikolas Klauser using _Base _LIBCPP_NODEBUG = __formatter_chrono<_CharT>; 877105fef5dSMark de Wever 878b51e8acdSMark de Wever template <class _ParseContext> 879b51e8acdSMark de Wever _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { 880b51e8acdSMark de Wever return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__month_weekday); 881105fef5dSMark de Wever } 882105fef5dSMark de Wever }; 883105fef5dSMark de Wever 884105fef5dSMark de Wever template <__fmt_char_type _CharT> 8859783f28cSLouis Dionne struct _LIBCPP_TEMPLATE_VIS formatter<chrono::month_weekday_last, _CharT> : public __formatter_chrono<_CharT> { 886105fef5dSMark de Wever public: 887f6958523SNikolas Klauser using _Base _LIBCPP_NODEBUG = __formatter_chrono<_CharT>; 888105fef5dSMark de Wever 889b51e8acdSMark de Wever template <class _ParseContext> 890b51e8acdSMark de Wever _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { 891b51e8acdSMark de Wever return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__month_weekday); 892105fef5dSMark de Wever } 893105fef5dSMark de Wever }; 894105fef5dSMark de Wever 895105fef5dSMark de Wever template <__fmt_char_type _CharT> 8969783f28cSLouis Dionne struct _LIBCPP_TEMPLATE_VIS formatter<chrono::year_month, _CharT> : public __formatter_chrono<_CharT> { 897105fef5dSMark de Wever public: 898f6958523SNikolas Klauser using _Base _LIBCPP_NODEBUG = __formatter_chrono<_CharT>; 899105fef5dSMark de Wever 900b51e8acdSMark de Wever template <class _ParseContext> 901b51e8acdSMark de Wever _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { 902b51e8acdSMark de Wever return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__year_month); 903105fef5dSMark de Wever } 904105fef5dSMark de Wever }; 905105fef5dSMark de Wever 906105fef5dSMark de Wever template <__fmt_char_type _CharT> 9079783f28cSLouis Dionne struct _LIBCPP_TEMPLATE_VIS formatter<chrono::year_month_day, _CharT> : public __formatter_chrono<_CharT> { 908105fef5dSMark de Wever public: 909f6958523SNikolas Klauser using _Base _LIBCPP_NODEBUG = __formatter_chrono<_CharT>; 910105fef5dSMark de Wever 911b51e8acdSMark de Wever template <class _ParseContext> 912b51e8acdSMark de Wever _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { 913b51e8acdSMark de Wever return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__date); 914105fef5dSMark de Wever } 915105fef5dSMark de Wever }; 916105fef5dSMark de Wever 917105fef5dSMark de Wever template <__fmt_char_type _CharT> 9189783f28cSLouis Dionne struct _LIBCPP_TEMPLATE_VIS formatter<chrono::year_month_day_last, _CharT> : public __formatter_chrono<_CharT> { 919105fef5dSMark de Wever public: 920f6958523SNikolas Klauser using _Base _LIBCPP_NODEBUG = __formatter_chrono<_CharT>; 921105fef5dSMark de Wever 922b51e8acdSMark de Wever template <class _ParseContext> 923b51e8acdSMark de Wever _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { 924b51e8acdSMark de Wever return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__date); 925105fef5dSMark de Wever } 926105fef5dSMark de Wever }; 927105fef5dSMark de Wever 928105fef5dSMark de Wever template <__fmt_char_type _CharT> 9299783f28cSLouis Dionne struct _LIBCPP_TEMPLATE_VIS formatter<chrono::year_month_weekday, _CharT> : public __formatter_chrono<_CharT> { 930105fef5dSMark de Wever public: 931f6958523SNikolas Klauser using _Base _LIBCPP_NODEBUG = __formatter_chrono<_CharT>; 932105fef5dSMark de Wever 933b51e8acdSMark de Wever template <class _ParseContext> 934b51e8acdSMark de Wever _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { 935b51e8acdSMark de Wever return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__date); 936105fef5dSMark de Wever } 937105fef5dSMark de Wever }; 938105fef5dSMark de Wever 939105fef5dSMark de Wever template <__fmt_char_type _CharT> 9409783f28cSLouis Dionne struct _LIBCPP_TEMPLATE_VIS formatter<chrono::year_month_weekday_last, _CharT> : public __formatter_chrono<_CharT> { 941105fef5dSMark de Wever public: 942f6958523SNikolas Klauser using _Base _LIBCPP_NODEBUG = __formatter_chrono<_CharT>; 943105fef5dSMark de Wever 944b51e8acdSMark de Wever template <class _ParseContext> 945b51e8acdSMark de Wever _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { 946b51e8acdSMark de Wever return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__date); 947105fef5dSMark de Wever } 948105fef5dSMark de Wever }; 949105fef5dSMark de Wever 9507f5d130aSMark de Wever template <class _Duration, __fmt_char_type _CharT> 9517f5d130aSMark de Wever struct formatter<chrono::hh_mm_ss<_Duration>, _CharT> : public __formatter_chrono<_CharT> { 9527f5d130aSMark de Wever public: 953f6958523SNikolas Klauser using _Base _LIBCPP_NODEBUG = __formatter_chrono<_CharT>; 9547f5d130aSMark de Wever 955b51e8acdSMark de Wever template <class _ParseContext> 956b51e8acdSMark de Wever _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { 957b51e8acdSMark de Wever return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__time); 9587f5d130aSMark de Wever } 9597f5d130aSMark de Wever }; 9606f7976c8SMark de Wever 96124e70e39SNikolas Klauser # if _LIBCPP_HAS_EXPERIMENTAL_TZDB 9626f7976c8SMark de Wever template <__fmt_char_type _CharT> 9636f7976c8SMark de Wever struct formatter<chrono::sys_info, _CharT> : public __formatter_chrono<_CharT> { 9646f7976c8SMark de Wever public: 965f6958523SNikolas Klauser using _Base _LIBCPP_NODEBUG = __formatter_chrono<_CharT>; 9666f7976c8SMark de Wever 9676f7976c8SMark de Wever template <class _ParseContext> 9686f7976c8SMark de Wever _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { 9696f7976c8SMark de Wever return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__time_zone); 9706f7976c8SMark de Wever } 9716f7976c8SMark de Wever }; 9728a21d59fSMark de Wever 9738a21d59fSMark de Wever template <__fmt_char_type _CharT> 9748a21d59fSMark de Wever struct formatter<chrono::local_info, _CharT> : public __formatter_chrono<_CharT> { 9758a21d59fSMark de Wever public: 976f6958523SNikolas Klauser using _Base _LIBCPP_NODEBUG = __formatter_chrono<_CharT>; 9778a21d59fSMark de Wever 9788a21d59fSMark de Wever template <class _ParseContext> 9798a21d59fSMark de Wever _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { 9808a21d59fSMark de Wever return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags{}); 9818a21d59fSMark de Wever } 9828a21d59fSMark de Wever }; 983c6f3b7bcSNikolas Klauser # if _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM 984afbfb16dSMark de Wever // Note due to how libc++'s formatters are implemented there is no need to add 985afbfb16dSMark de Wever // the exposition only local-time-format-t abstraction. 986afbfb16dSMark de Wever template <class _Duration, class _TimeZonePtr, __fmt_char_type _CharT> 987afbfb16dSMark de Wever struct formatter<chrono::zoned_time<_Duration, _TimeZonePtr>, _CharT> : public __formatter_chrono<_CharT> { 988afbfb16dSMark de Wever public: 989f6958523SNikolas Klauser using _Base _LIBCPP_NODEBUG = __formatter_chrono<_CharT>; 990afbfb16dSMark de Wever 991afbfb16dSMark de Wever template <class _ParseContext> 992afbfb16dSMark de Wever _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { 993afbfb16dSMark de Wever return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__clock); 994afbfb16dSMark de Wever } 995afbfb16dSMark de Wever }; 996c6f3b7bcSNikolas Klauser # endif // _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM 99724e70e39SNikolas Klauser # endif // _LIBCPP_HAS_EXPERIMENTAL_TZDB 9986f7976c8SMark de Wever 999dff62f52SMark de Wever # endif // if _LIBCPP_STD_VER >= 20 1000e5d2d3eaSMark de Wever 1001e5d2d3eaSMark de Wever _LIBCPP_END_NAMESPACE_STD 1002e5d2d3eaSMark de Wever 1003c6f3b7bcSNikolas Klauser #endif // _LIBCPP_HAS_LOCALIZATION 100487d56c59SLouis Dionne 1005e5d2d3eaSMark de Wever #endif // _LIBCPP___CHRONO_FORMATTER_H 1006