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 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> 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 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 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> 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> 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> 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 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> 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> 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> 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> 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> 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> 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 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 70106c3fb27SDimitry 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> 70606c3fb27SDimitry 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