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