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> 1406c3fb27SDimitry 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> 1806c3fb27SDimitry 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> 2606c3fb27SDimitry 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> 4206c3fb27SDimitry 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 5506c3fb27SDimitry 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. 8006c3fb27SDimitry Andric template <class _CharT, class _Rep, class _Period> 8106c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI void 8206c3fb27SDimitry 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 8506c3fb27SDimitry Andric using __duration = chrono::duration<_Rep, _Period>; 8606c3fb27SDimitry Andric 87bdd1243dSDimitry Andric auto __fraction = __value - chrono::duration_cast<chrono::seconds>(__value); 8806c3fb27SDimitry 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}"), 10306c3fb27SDimitry Andric chrono::duration_cast<typename chrono::hh_mm_ss<__duration>::precision>(__fraction).count(), 10406c3fb27SDimitry 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{}}"), 10806c3fb27SDimitry Andric chrono::duration_cast<typename chrono::hh_mm_ss<__duration>::precision>(__fraction).count(), 10906c3fb27SDimitry Andric chrono::hh_mm_ss<__duration>::fractional_width); 11006c3fb27SDimitry Andric } 11106c3fb27SDimitry Andric 11206c3fb27SDimitry Andric template <class _CharT, __is_time_point _Tp> 11306c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI void __format_sub_seconds(const _Tp& __value, basic_stringstream<_CharT>& __sstr) { 11406c3fb27SDimitry Andric __formatter::__format_sub_seconds(__value.time_since_epoch(), __sstr); 11506c3fb27SDimitry Andric } 11606c3fb27SDimitry Andric 11706c3fb27SDimitry Andric template <class _CharT, class _Duration> 11806c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI void 11906c3fb27SDimitry Andric __format_sub_seconds(const chrono::hh_mm_ss<_Duration>& __value, basic_stringstream<_CharT>& __sstr) { 12006c3fb27SDimitry Andric __sstr << std::use_facet<numpunct<_CharT>>(__sstr.getloc()).decimal_point(); 12106c3fb27SDimitry Andric if constexpr (chrono::treat_as_floating_point_v<typename _Duration::rep>) 12206c3fb27SDimitry Andric std::format_to(std::ostreambuf_iterator<_CharT>{__sstr}, 12306c3fb27SDimitry Andric _LIBCPP_STATICALLY_WIDEN(_CharT, "{:0{}.0f}"), 12406c3fb27SDimitry Andric __value.subseconds().count(), 12506c3fb27SDimitry Andric __value.fractional_width); 12606c3fb27SDimitry Andric else 12706c3fb27SDimitry Andric std::format_to(std::ostreambuf_iterator<_CharT>{__sstr}, 12806c3fb27SDimitry Andric _LIBCPP_STATICALLY_WIDEN(_CharT, "{:0{}}"), 12906c3fb27SDimitry Andric __value.subseconds().count(), 13006c3fb27SDimitry Andric __value.fractional_width); 131bdd1243dSDimitry Andric } 132bdd1243dSDimitry Andric 133bdd1243dSDimitry Andric template <class _Tp> 134bdd1243dSDimitry Andric consteval bool __use_fraction() { 13506c3fb27SDimitry Andric if constexpr (__is_time_point<_Tp>) 13606c3fb27SDimitry Andric return chrono::hh_mm_ss<typename _Tp::duration>::fractional_width; 13706c3fb27SDimitry Andric else if constexpr (chrono::__is_duration<_Tp>::value) 138bdd1243dSDimitry Andric return chrono::hh_mm_ss<_Tp>::fractional_width; 13906c3fb27SDimitry Andric else if constexpr (__is_hh_mm_ss<_Tp>) 14006c3fb27SDimitry 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*cb14a3feSDimitry Andric __facet.put( 202*cb14a3feSDimitry Andric {__sstr}, __sstr, _CharT(' '), std::addressof(__t), std::to_address(__s), std::to_address(__it + 1)); 203bdd1243dSDimitry Andric } break; 204bdd1243dSDimitry Andric 205bdd1243dSDimitry Andric case _CharT('j'): 206bdd1243dSDimitry Andric if constexpr (chrono::__is_duration<_Tp>::value) 207bdd1243dSDimitry Andric // Converting a duration where the period has a small ratio to days 208bdd1243dSDimitry Andric // may fail to compile. This due to loss of precision in the 209bdd1243dSDimitry Andric // conversion. In order to avoid that issue convert to seconds as 210bdd1243dSDimitry Andric // an intemediate step. 211bdd1243dSDimitry Andric __sstr << chrono::duration_cast<chrono::days>(chrono::duration_cast<chrono::seconds>(__value)).count(); 212bdd1243dSDimitry Andric else 213*cb14a3feSDimitry Andric __facet.put( 214*cb14a3feSDimitry Andric {__sstr}, __sstr, _CharT(' '), std::addressof(__t), std::to_address(__s), std::to_address(__it + 1)); 215bdd1243dSDimitry Andric break; 216bdd1243dSDimitry Andric 217bdd1243dSDimitry Andric case _CharT('q'): 218bdd1243dSDimitry Andric if constexpr (chrono::__is_duration<_Tp>::value) { 219bdd1243dSDimitry Andric __sstr << chrono::__units_suffix<_CharT, typename _Tp::period>(); 220bdd1243dSDimitry Andric break; 221bdd1243dSDimitry Andric } 222bdd1243dSDimitry Andric __builtin_unreachable(); 223bdd1243dSDimitry Andric 224bdd1243dSDimitry Andric case _CharT('Q'): 225bdd1243dSDimitry Andric // TODO FMT Determine the proper ideas 226bdd1243dSDimitry Andric // - Should it honour the precision? 227bdd1243dSDimitry Andric // - Shoult it honour the locale setting for the separators? 228bdd1243dSDimitry Andric // The wording for Q doesn't use the word locale and the effect of 229bdd1243dSDimitry Andric // precision is unspecified. 230bdd1243dSDimitry Andric // 231bdd1243dSDimitry Andric // MSVC STL ignores precision but uses separator 232bdd1243dSDimitry Andric // FMT honours precision and has a bug for separator 233bdd1243dSDimitry Andric // https://godbolt.org/z/78b7sMxns 234bdd1243dSDimitry Andric if constexpr (chrono::__is_duration<_Tp>::value) { 235bdd1243dSDimitry Andric __sstr << std::format(_LIBCPP_STATICALLY_WIDEN(_CharT, "{}"), __value.count()); 236bdd1243dSDimitry Andric break; 237bdd1243dSDimitry Andric } 238bdd1243dSDimitry Andric __builtin_unreachable(); 239bdd1243dSDimitry Andric 240bdd1243dSDimitry Andric case _CharT('S'): 241bdd1243dSDimitry Andric case _CharT('T'): 242*cb14a3feSDimitry Andric __facet.put( 243*cb14a3feSDimitry Andric {__sstr}, __sstr, _CharT(' '), std::addressof(__t), std::to_address(__s), std::to_address(__it + 1)); 244bdd1243dSDimitry Andric if constexpr (__use_fraction<_Tp>()) 245bdd1243dSDimitry Andric __formatter::__format_sub_seconds(__value, __sstr); 246bdd1243dSDimitry Andric break; 247bdd1243dSDimitry Andric 248bdd1243dSDimitry Andric // Unlike time_put and strftime the formatting library requires %Y 249bdd1243dSDimitry Andric // 250bdd1243dSDimitry Andric // [tab:time.format.spec] 251bdd1243dSDimitry Andric // The year as a decimal number. If the result is less than four digits 252bdd1243dSDimitry Andric // it is left-padded with 0 to four digits. 253bdd1243dSDimitry Andric // 254bdd1243dSDimitry Andric // This means years in the range (-1000, 1000) need manual formatting. 255bdd1243dSDimitry Andric // It's unclear whether %EY needs the same treatment. For example the 256bdd1243dSDimitry Andric // Japanese EY contains the era name and year. This is zero-padded to 2 257bdd1243dSDimitry Andric // digits in time_put (note that older glibc versions didn't do 258bdd1243dSDimitry Andric // padding.) However most eras won't reach 100 years, let alone 1000. 259bdd1243dSDimitry Andric // So padding to 4 digits seems unwanted for Japanese. 260bdd1243dSDimitry Andric // 261bdd1243dSDimitry Andric // The same applies to %Ex since that too depends on the era. 262bdd1243dSDimitry Andric // 263bdd1243dSDimitry Andric // %x the locale's date representation is currently doesn't handle the 264bdd1243dSDimitry Andric // zero-padding too. 265bdd1243dSDimitry Andric // 266bdd1243dSDimitry Andric // The 4 digits can be implemented better at a later time. On POSIX 267bdd1243dSDimitry Andric // systems the required information can be extracted by nl_langinfo 268bdd1243dSDimitry Andric // https://man7.org/linux/man-pages/man3/nl_langinfo.3.html 269bdd1243dSDimitry Andric // 270bdd1243dSDimitry Andric // Note since year < -1000 is expected to be rare it uses the more 271bdd1243dSDimitry Andric // expensive year routine. 272bdd1243dSDimitry Andric // 273bdd1243dSDimitry Andric // TODO FMT evaluate the comment above. 274bdd1243dSDimitry Andric 27506c3fb27SDimitry Andric # if defined(__GLIBC__) || defined(_AIX) || defined(_WIN32) 276bdd1243dSDimitry Andric case _CharT('y'): 277bdd1243dSDimitry Andric // Glibc fails for negative values, AIX for positive values too. 278bdd1243dSDimitry Andric __sstr << std::format(_LIBCPP_STATICALLY_WIDEN(_CharT, "{:02}"), (std::abs(__t.tm_year + 1900)) % 100); 279bdd1243dSDimitry Andric break; 28006c3fb27SDimitry Andric # endif // defined(__GLIBC__) || defined(_AIX) || defined(_WIN32) 281bdd1243dSDimitry Andric 28206c3fb27SDimitry Andric case _CharT('Y'): 28306c3fb27SDimitry Andric // Depending on the platform's libc the range of supported years is 28406c3fb27SDimitry Andric // limited. Intead of of testing all conditions use the internal 28506c3fb27SDimitry Andric // implementation unconditionally. 28606c3fb27SDimitry Andric __formatter::__format_year(__t.tm_year + 1900, __sstr); 28706c3fb27SDimitry Andric break; 288bdd1243dSDimitry Andric 289bdd1243dSDimitry Andric case _CharT('F'): { 290bdd1243dSDimitry Andric int __year = __t.tm_year + 1900; 291bdd1243dSDimitry Andric if (__year < 1000) { 292bdd1243dSDimitry Andric __formatter::__format_year(__year, __sstr); 293bdd1243dSDimitry Andric __sstr << std::format(_LIBCPP_STATICALLY_WIDEN(_CharT, "-{:02}-{:02}"), __t.tm_mon + 1, __t.tm_mday); 294bdd1243dSDimitry Andric } else 295*cb14a3feSDimitry Andric __facet.put( 296*cb14a3feSDimitry Andric {__sstr}, __sstr, _CharT(' '), std::addressof(__t), std::to_address(__s), std::to_address(__it + 1)); 297bdd1243dSDimitry Andric } break; 298bdd1243dSDimitry Andric 29906c3fb27SDimitry Andric case _CharT('Z'): 30006c3fb27SDimitry Andric // TODO FMT Add proper timezone support. 30106c3fb27SDimitry Andric __sstr << _LIBCPP_STATICALLY_WIDEN(_CharT, "UTC"); 30206c3fb27SDimitry Andric break; 30306c3fb27SDimitry Andric 304bdd1243dSDimitry Andric case _CharT('O'): 305bdd1243dSDimitry Andric if constexpr (__use_fraction<_Tp>()) { 306bdd1243dSDimitry Andric // Handle OS using the normal representation for the non-fractional 307bdd1243dSDimitry Andric // part. There seems to be no locale information regarding how the 308bdd1243dSDimitry Andric // fractional part should be formatted. 309bdd1243dSDimitry Andric if (*(__it + 1) == 'S') { 310bdd1243dSDimitry Andric ++__it; 311*cb14a3feSDimitry Andric __facet.put( 312*cb14a3feSDimitry Andric {__sstr}, __sstr, _CharT(' '), std::addressof(__t), std::to_address(__s), std::to_address(__it + 1)); 313bdd1243dSDimitry Andric __formatter::__format_sub_seconds(__value, __sstr); 314bdd1243dSDimitry Andric break; 315bdd1243dSDimitry Andric } 316bdd1243dSDimitry Andric } 317bdd1243dSDimitry Andric [[fallthrough]]; 318bdd1243dSDimitry Andric case _CharT('E'): 319bdd1243dSDimitry Andric ++__it; 320bdd1243dSDimitry Andric [[fallthrough]]; 321bdd1243dSDimitry Andric default: 322*cb14a3feSDimitry Andric __facet.put( 323*cb14a3feSDimitry Andric {__sstr}, __sstr, _CharT(' '), std::addressof(__t), std::to_address(__s), std::to_address(__it + 1)); 324bdd1243dSDimitry Andric break; 325bdd1243dSDimitry Andric } 326bdd1243dSDimitry Andric } else { 327bdd1243dSDimitry Andric __sstr << *__it; 328bdd1243dSDimitry Andric } 329bdd1243dSDimitry Andric } 330bdd1243dSDimitry Andric } 331bdd1243dSDimitry Andric 332bdd1243dSDimitry Andric template <class _Tp> 333bdd1243dSDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr bool __weekday_ok(const _Tp& __value) { 33406c3fb27SDimitry Andric if constexpr (__is_time_point<_Tp>) 33506c3fb27SDimitry Andric return true; 33606c3fb27SDimitry Andric else if constexpr (same_as<_Tp, chrono::day>) 337bdd1243dSDimitry Andric return true; 338bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::month>) 339bdd1243dSDimitry Andric return __value.ok(); 340bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::year>) 341bdd1243dSDimitry Andric return true; 342bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::weekday>) 343bdd1243dSDimitry Andric return true; 344bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::weekday_indexed>) 345bdd1243dSDimitry Andric return true; 346bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::weekday_last>) 347bdd1243dSDimitry Andric return true; 348bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::month_day>) 349bdd1243dSDimitry Andric return true; 350bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::month_day_last>) 351bdd1243dSDimitry Andric return true; 352bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::month_weekday>) 353bdd1243dSDimitry Andric return true; 354bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::month_weekday_last>) 355bdd1243dSDimitry Andric return true; 356bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::year_month>) 357bdd1243dSDimitry Andric return true; 358bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::year_month_day>) 359bdd1243dSDimitry Andric return __value.ok(); 360bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::year_month_day_last>) 361bdd1243dSDimitry Andric return __value.ok(); 362bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::year_month_weekday>) 363bdd1243dSDimitry Andric return __value.weekday().ok(); 364bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::year_month_weekday_last>) 365bdd1243dSDimitry Andric return __value.weekday().ok(); 36606c3fb27SDimitry Andric else if constexpr (__is_hh_mm_ss<_Tp>) 36706c3fb27SDimitry Andric return true; 368bdd1243dSDimitry Andric else 369bdd1243dSDimitry Andric static_assert(sizeof(_Tp) == 0, "Add the missing type specialization"); 370bdd1243dSDimitry Andric } 371bdd1243dSDimitry Andric 372bdd1243dSDimitry Andric template <class _Tp> 373bdd1243dSDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr bool __weekday_name_ok(const _Tp& __value) { 37406c3fb27SDimitry Andric if constexpr (__is_time_point<_Tp>) 37506c3fb27SDimitry Andric return true; 37606c3fb27SDimitry Andric else if constexpr (same_as<_Tp, chrono::day>) 377bdd1243dSDimitry Andric return true; 378bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::month>) 379bdd1243dSDimitry Andric return __value.ok(); 380bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::year>) 381bdd1243dSDimitry Andric return true; 382bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::weekday>) 383bdd1243dSDimitry Andric return __value.ok(); 384bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::weekday_indexed>) 385bdd1243dSDimitry Andric return __value.weekday().ok(); 386bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::weekday_last>) 387bdd1243dSDimitry Andric return __value.weekday().ok(); 388bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::month_day>) 389bdd1243dSDimitry Andric return true; 390bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::month_day_last>) 391bdd1243dSDimitry Andric return true; 392bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::month_weekday>) 393bdd1243dSDimitry Andric return __value.weekday_indexed().ok(); 394bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::month_weekday_last>) 395bdd1243dSDimitry Andric return __value.weekday_indexed().ok(); 396bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::year_month>) 397bdd1243dSDimitry Andric return true; 398bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::year_month_day>) 399bdd1243dSDimitry Andric return __value.ok(); 400bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::year_month_day_last>) 401bdd1243dSDimitry Andric return __value.ok(); 402bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::year_month_weekday>) 403bdd1243dSDimitry Andric return __value.weekday().ok(); 404bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::year_month_weekday_last>) 405bdd1243dSDimitry Andric return __value.weekday().ok(); 40606c3fb27SDimitry Andric else if constexpr (__is_hh_mm_ss<_Tp>) 40706c3fb27SDimitry Andric return true; 408bdd1243dSDimitry Andric else 409bdd1243dSDimitry Andric static_assert(sizeof(_Tp) == 0, "Add the missing type specialization"); 410bdd1243dSDimitry Andric } 411bdd1243dSDimitry Andric 412bdd1243dSDimitry Andric template <class _Tp> 413bdd1243dSDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr bool __date_ok(const _Tp& __value) { 41406c3fb27SDimitry Andric if constexpr (__is_time_point<_Tp>) 41506c3fb27SDimitry Andric return true; 41606c3fb27SDimitry Andric else if constexpr (same_as<_Tp, chrono::day>) 417bdd1243dSDimitry Andric return true; 418bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::month>) 419bdd1243dSDimitry Andric return __value.ok(); 420bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::year>) 421bdd1243dSDimitry Andric return true; 422bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::weekday>) 423bdd1243dSDimitry Andric return true; 424bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::weekday_indexed>) 425bdd1243dSDimitry Andric return true; 426bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::weekday_last>) 427bdd1243dSDimitry Andric return true; 428bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::month_day>) 429bdd1243dSDimitry Andric return true; 430bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::month_day_last>) 431bdd1243dSDimitry Andric return true; 432bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::month_weekday>) 433bdd1243dSDimitry Andric return true; 434bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::month_weekday_last>) 435bdd1243dSDimitry Andric return true; 436bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::year_month>) 437bdd1243dSDimitry Andric return true; 438bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::year_month_day>) 439bdd1243dSDimitry Andric return __value.ok(); 440bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::year_month_day_last>) 441bdd1243dSDimitry Andric return __value.ok(); 442bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::year_month_weekday>) 443bdd1243dSDimitry Andric return __value.ok(); 444bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::year_month_weekday_last>) 445bdd1243dSDimitry Andric return __value.ok(); 44606c3fb27SDimitry Andric else if constexpr (__is_hh_mm_ss<_Tp>) 44706c3fb27SDimitry Andric return true; 448bdd1243dSDimitry Andric else 449bdd1243dSDimitry Andric static_assert(sizeof(_Tp) == 0, "Add the missing type specialization"); 450bdd1243dSDimitry Andric } 451bdd1243dSDimitry Andric 452bdd1243dSDimitry Andric template <class _Tp> 453bdd1243dSDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr bool __month_name_ok(const _Tp& __value) { 45406c3fb27SDimitry Andric if constexpr (__is_time_point<_Tp>) 45506c3fb27SDimitry Andric return true; 45606c3fb27SDimitry Andric else if constexpr (same_as<_Tp, chrono::day>) 457bdd1243dSDimitry Andric return true; 458bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::month>) 459bdd1243dSDimitry Andric return __value.ok(); 460bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::year>) 461bdd1243dSDimitry Andric return true; 462bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::weekday>) 463bdd1243dSDimitry Andric return true; 464bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::weekday_indexed>) 465bdd1243dSDimitry Andric return true; 466bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::weekday_last>) 467bdd1243dSDimitry Andric return true; 468bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::month_day>) 469bdd1243dSDimitry Andric return __value.month().ok(); 470bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::month_day_last>) 471bdd1243dSDimitry Andric return __value.month().ok(); 472bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::month_weekday>) 473bdd1243dSDimitry Andric return __value.month().ok(); 474bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::month_weekday_last>) 475bdd1243dSDimitry Andric return __value.month().ok(); 476bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::year_month>) 477bdd1243dSDimitry Andric return __value.month().ok(); 478bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::year_month_day>) 479bdd1243dSDimitry Andric return __value.month().ok(); 480bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::year_month_day_last>) 481bdd1243dSDimitry Andric return __value.month().ok(); 482bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::year_month_weekday>) 483bdd1243dSDimitry Andric return __value.month().ok(); 484bdd1243dSDimitry Andric else if constexpr (same_as<_Tp, chrono::year_month_weekday_last>) 485bdd1243dSDimitry Andric return __value.month().ok(); 48606c3fb27SDimitry Andric else if constexpr (__is_hh_mm_ss<_Tp>) 48706c3fb27SDimitry Andric return true; 488bdd1243dSDimitry Andric else 489bdd1243dSDimitry Andric static_assert(sizeof(_Tp) == 0, "Add the missing type specialization"); 490bdd1243dSDimitry Andric } 491bdd1243dSDimitry Andric 49206c3fb27SDimitry Andric template <class _CharT, class _Tp, class _FormatContext> 493bdd1243dSDimitry Andric _LIBCPP_HIDE_FROM_ABI auto 494bdd1243dSDimitry Andric __format_chrono(const _Tp& __value, 49506c3fb27SDimitry Andric _FormatContext& __ctx, 496bdd1243dSDimitry Andric __format_spec::__parsed_specifications<_CharT> __specs, 49706c3fb27SDimitry Andric basic_string_view<_CharT> __chrono_specs) { 498bdd1243dSDimitry Andric basic_stringstream<_CharT> __sstr; 499bdd1243dSDimitry Andric // [time.format]/2 500bdd1243dSDimitry Andric // 2.1 - the "C" locale if the L option is not present in chrono-format-spec, otherwise 501bdd1243dSDimitry Andric // 2.2 - the locale passed to the formatting function if any, otherwise 502bdd1243dSDimitry Andric // 2.3 - the global locale. 503bdd1243dSDimitry Andric // Note that the __ctx's locale() call does 2.2 and 2.3. 504bdd1243dSDimitry Andric if (__specs.__chrono_.__locale_specific_form_) 505bdd1243dSDimitry Andric __sstr.imbue(__ctx.locale()); 506bdd1243dSDimitry Andric else 507bdd1243dSDimitry Andric __sstr.imbue(locale::classic()); 508bdd1243dSDimitry Andric 509bdd1243dSDimitry Andric if (__chrono_specs.empty()) 510bdd1243dSDimitry Andric __sstr << __value; 511bdd1243dSDimitry Andric else { 512bdd1243dSDimitry Andric if constexpr (chrono::__is_duration<_Tp>::value) { 513bdd1243dSDimitry Andric if (__value < __value.zero()) 514bdd1243dSDimitry Andric __sstr << _CharT('-'); 515bdd1243dSDimitry Andric __formatter::__format_chrono_using_chrono_specs(chrono::abs(__value), __sstr, __chrono_specs); 516bdd1243dSDimitry Andric // TODO FMT When keeping the precision it will truncate the string. 517bdd1243dSDimitry Andric // Note that the behaviour what the precision does isn't specified. 518bdd1243dSDimitry Andric __specs.__precision_ = -1; 519bdd1243dSDimitry Andric } else { 520bdd1243dSDimitry Andric // Test __weekday_name_ before __weekday_ to give a better error. 521bdd1243dSDimitry Andric if (__specs.__chrono_.__weekday_name_ && !__formatter::__weekday_name_ok(__value)) 52206c3fb27SDimitry Andric std::__throw_format_error("Formatting a weekday name needs a valid weekday"); 523bdd1243dSDimitry Andric 524bdd1243dSDimitry Andric if (__specs.__chrono_.__weekday_ && !__formatter::__weekday_ok(__value)) 52506c3fb27SDimitry Andric std::__throw_format_error("Formatting a weekday needs a valid weekday"); 526bdd1243dSDimitry Andric 527bdd1243dSDimitry Andric if (__specs.__chrono_.__day_of_year_ && !__formatter::__date_ok(__value)) 52806c3fb27SDimitry Andric std::__throw_format_error("Formatting a day of year needs a valid date"); 529bdd1243dSDimitry Andric 530bdd1243dSDimitry Andric if (__specs.__chrono_.__week_of_year_ && !__formatter::__date_ok(__value)) 53106c3fb27SDimitry Andric std::__throw_format_error("Formatting a week of year needs a valid date"); 532bdd1243dSDimitry Andric 533bdd1243dSDimitry Andric if (__specs.__chrono_.__month_name_ && !__formatter::__month_name_ok(__value)) 53406c3fb27SDimitry Andric std::__throw_format_error("Formatting a month name from an invalid month number"); 53506c3fb27SDimitry Andric 53606c3fb27SDimitry Andric if constexpr (__is_hh_mm_ss<_Tp>) { 53706c3fb27SDimitry Andric // Note this is a pedantic intepretation of the Standard. A hh_mm_ss 53806c3fb27SDimitry Andric // is no longer a time_of_day and can store an arbitrary number of 53906c3fb27SDimitry Andric // hours. A number of hours in a 12 or 24 hour clock can't represent 54006c3fb27SDimitry Andric // 24 hours or more. The functions std::chrono::make12 and 54106c3fb27SDimitry Andric // std::chrono::make24 reaffirm this view point. 54206c3fb27SDimitry Andric // 54306c3fb27SDimitry Andric // Interestingly this will be the only output stream function that 54406c3fb27SDimitry Andric // throws. 54506c3fb27SDimitry Andric // 54606c3fb27SDimitry Andric // TODO FMT The wording probably needs to be adapted to 54706c3fb27SDimitry Andric // - The displayed hours is hh_mm_ss.hours() % 24 54806c3fb27SDimitry Andric // - It should probably allow %j in the same fashion as duration. 54906c3fb27SDimitry Andric // - The stream formatter should change its output when hours >= 24 55006c3fb27SDimitry Andric // - Write it as not valid, 55106c3fb27SDimitry Andric // - or write the number of days. 55206c3fb27SDimitry Andric if (__specs.__chrono_.__hour_ && __value.hours().count() > 23) 55306c3fb27SDimitry Andric std::__throw_format_error("Formatting a hour needs a valid value"); 55406c3fb27SDimitry Andric 55506c3fb27SDimitry Andric if (__value.is_negative()) 55606c3fb27SDimitry Andric __sstr << _CharT('-'); 55706c3fb27SDimitry Andric } 558bdd1243dSDimitry Andric 559bdd1243dSDimitry Andric __formatter::__format_chrono_using_chrono_specs(__value, __sstr, __chrono_specs); 560bdd1243dSDimitry Andric } 561bdd1243dSDimitry Andric } 562bdd1243dSDimitry Andric 56306c3fb27SDimitry Andric return __formatter::__write_string(__sstr.view(), __ctx.out(), __specs); 564bdd1243dSDimitry Andric } 565bdd1243dSDimitry Andric 566bdd1243dSDimitry Andric } // namespace __formatter 567bdd1243dSDimitry Andric 568bdd1243dSDimitry Andric template <__fmt_char_type _CharT> 56906c3fb27SDimitry Andric struct _LIBCPP_TEMPLATE_VIS __formatter_chrono { 570bdd1243dSDimitry Andric public: 57106c3fb27SDimitry Andric template <class _ParseContext> 57206c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator 57306c3fb27SDimitry Andric __parse(_ParseContext& __ctx, __format_spec::__fields __fields, __format_spec::__flags __flags) { 57406c3fb27SDimitry Andric return __parser_.__parse(__ctx, __fields, __flags); 575bdd1243dSDimitry Andric } 576bdd1243dSDimitry Andric 57706c3fb27SDimitry Andric template <class _Tp, class _FormatContext> 57806c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator format(const _Tp& __value, _FormatContext& __ctx) const { 579bdd1243dSDimitry Andric return __formatter::__format_chrono( 580bdd1243dSDimitry Andric __value, __ctx, __parser_.__parser_.__get_parsed_chrono_specifications(__ctx), __parser_.__chrono_specs_); 581bdd1243dSDimitry Andric } 582bdd1243dSDimitry Andric 583bdd1243dSDimitry Andric __format_spec::__parser_chrono<_CharT> __parser_; 584bdd1243dSDimitry Andric }; 585bdd1243dSDimitry Andric 58606c3fb27SDimitry Andric template <class _Duration, __fmt_char_type _CharT> 58706c3fb27SDimitry Andric struct _LIBCPP_TEMPLATE_VIS formatter<chrono::sys_time<_Duration>, _CharT> : public __formatter_chrono<_CharT> { 58806c3fb27SDimitry Andric public: 58906c3fb27SDimitry Andric using _Base = __formatter_chrono<_CharT>; 59006c3fb27SDimitry Andric 59106c3fb27SDimitry Andric template <class _ParseContext> 59206c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { 59306c3fb27SDimitry Andric return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__clock); 59406c3fb27SDimitry Andric } 59506c3fb27SDimitry Andric }; 59606c3fb27SDimitry Andric 59706c3fb27SDimitry Andric template <class _Duration, __fmt_char_type _CharT> 59806c3fb27SDimitry Andric struct _LIBCPP_TEMPLATE_VIS formatter<chrono::file_time<_Duration>, _CharT> : public __formatter_chrono<_CharT> { 59906c3fb27SDimitry Andric public: 60006c3fb27SDimitry Andric using _Base = __formatter_chrono<_CharT>; 60106c3fb27SDimitry Andric 60206c3fb27SDimitry Andric template <class _ParseContext> 60306c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { 60406c3fb27SDimitry Andric return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__clock); 60506c3fb27SDimitry Andric } 60606c3fb27SDimitry Andric }; 60706c3fb27SDimitry Andric 60806c3fb27SDimitry Andric template <class _Duration, __fmt_char_type _CharT> 60906c3fb27SDimitry Andric struct _LIBCPP_TEMPLATE_VIS formatter<chrono::local_time<_Duration>, _CharT> : public __formatter_chrono<_CharT> { 61006c3fb27SDimitry Andric public: 61106c3fb27SDimitry Andric using _Base = __formatter_chrono<_CharT>; 61206c3fb27SDimitry Andric 61306c3fb27SDimitry Andric template <class _ParseContext> 61406c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { 61506c3fb27SDimitry Andric // The flags are not __clock since there is no associated time-zone. 61606c3fb27SDimitry Andric return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__date_time); 61706c3fb27SDimitry Andric } 61806c3fb27SDimitry Andric }; 61906c3fb27SDimitry Andric 620bdd1243dSDimitry Andric template <class _Rep, class _Period, __fmt_char_type _CharT> 621bdd1243dSDimitry Andric struct formatter<chrono::duration<_Rep, _Period>, _CharT> : public __formatter_chrono<_CharT> { 622bdd1243dSDimitry Andric public: 623bdd1243dSDimitry Andric using _Base = __formatter_chrono<_CharT>; 624bdd1243dSDimitry Andric 62506c3fb27SDimitry Andric template <class _ParseContext> 62606c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { 627bdd1243dSDimitry Andric // [time.format]/1 628bdd1243dSDimitry Andric // Giving a precision specification in the chrono-format-spec is valid only 629bdd1243dSDimitry Andric // for std::chrono::duration types where the representation type Rep is a 630bdd1243dSDimitry Andric // floating-point type. For all other Rep types, an exception of type 631bdd1243dSDimitry Andric // format_error is thrown if the chrono-format-spec contains a precision 632bdd1243dSDimitry Andric // specification. 633bdd1243dSDimitry Andric // 634bdd1243dSDimitry Andric // Note this doesn't refer to chrono::treat_as_floating_point_v<_Rep>. 635bdd1243dSDimitry Andric if constexpr (std::floating_point<_Rep>) 63606c3fb27SDimitry Andric return _Base::__parse(__ctx, __format_spec::__fields_chrono_fractional, __format_spec::__flags::__duration); 637bdd1243dSDimitry Andric else 63806c3fb27SDimitry Andric return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__duration); 639bdd1243dSDimitry Andric } 640bdd1243dSDimitry Andric }; 641bdd1243dSDimitry Andric 642bdd1243dSDimitry Andric template <__fmt_char_type _CharT> 643*cb14a3feSDimitry Andric struct _LIBCPP_TEMPLATE_VIS formatter<chrono::day, _CharT> : public __formatter_chrono<_CharT> { 644bdd1243dSDimitry Andric public: 645bdd1243dSDimitry Andric using _Base = __formatter_chrono<_CharT>; 646bdd1243dSDimitry Andric 64706c3fb27SDimitry Andric template <class _ParseContext> 64806c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { 64906c3fb27SDimitry Andric return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__day); 650bdd1243dSDimitry Andric } 651bdd1243dSDimitry Andric }; 652bdd1243dSDimitry Andric 653bdd1243dSDimitry Andric template <__fmt_char_type _CharT> 654*cb14a3feSDimitry Andric struct _LIBCPP_TEMPLATE_VIS formatter<chrono::month, _CharT> : public __formatter_chrono<_CharT> { 655bdd1243dSDimitry Andric public: 656bdd1243dSDimitry Andric using _Base = __formatter_chrono<_CharT>; 657bdd1243dSDimitry Andric 65806c3fb27SDimitry Andric template <class _ParseContext> 65906c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { 66006c3fb27SDimitry Andric return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__month); 661bdd1243dSDimitry Andric } 662bdd1243dSDimitry Andric }; 663bdd1243dSDimitry Andric 664bdd1243dSDimitry Andric template <__fmt_char_type _CharT> 665*cb14a3feSDimitry Andric struct _LIBCPP_TEMPLATE_VIS formatter<chrono::year, _CharT> : public __formatter_chrono<_CharT> { 666bdd1243dSDimitry Andric public: 667bdd1243dSDimitry Andric using _Base = __formatter_chrono<_CharT>; 668bdd1243dSDimitry Andric 66906c3fb27SDimitry Andric template <class _ParseContext> 67006c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { 67106c3fb27SDimitry Andric return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__year); 672bdd1243dSDimitry Andric } 673bdd1243dSDimitry Andric }; 674bdd1243dSDimitry Andric 675bdd1243dSDimitry Andric template <__fmt_char_type _CharT> 676*cb14a3feSDimitry Andric struct _LIBCPP_TEMPLATE_VIS formatter<chrono::weekday, _CharT> : public __formatter_chrono<_CharT> { 677bdd1243dSDimitry Andric public: 678bdd1243dSDimitry Andric using _Base = __formatter_chrono<_CharT>; 679bdd1243dSDimitry Andric 68006c3fb27SDimitry Andric template <class _ParseContext> 68106c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { 68206c3fb27SDimitry Andric return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__weekday); 683bdd1243dSDimitry Andric } 684bdd1243dSDimitry Andric }; 685bdd1243dSDimitry Andric 686bdd1243dSDimitry Andric template <__fmt_char_type _CharT> 687*cb14a3feSDimitry Andric struct _LIBCPP_TEMPLATE_VIS formatter<chrono::weekday_indexed, _CharT> : public __formatter_chrono<_CharT> { 688bdd1243dSDimitry Andric public: 689bdd1243dSDimitry Andric using _Base = __formatter_chrono<_CharT>; 690bdd1243dSDimitry Andric 69106c3fb27SDimitry Andric template <class _ParseContext> 69206c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { 69306c3fb27SDimitry Andric return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__weekday); 694bdd1243dSDimitry Andric } 695bdd1243dSDimitry Andric }; 696bdd1243dSDimitry Andric 697bdd1243dSDimitry Andric template <__fmt_char_type _CharT> 698*cb14a3feSDimitry Andric struct _LIBCPP_TEMPLATE_VIS formatter<chrono::weekday_last, _CharT> : public __formatter_chrono<_CharT> { 699bdd1243dSDimitry Andric public: 700bdd1243dSDimitry Andric using _Base = __formatter_chrono<_CharT>; 701bdd1243dSDimitry Andric 70206c3fb27SDimitry Andric template <class _ParseContext> 70306c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { 70406c3fb27SDimitry 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*cb14a3feSDimitry Andric struct _LIBCPP_TEMPLATE_VIS formatter<chrono::month_day, _CharT> : public __formatter_chrono<_CharT> { 710bdd1243dSDimitry Andric public: 711bdd1243dSDimitry Andric using _Base = __formatter_chrono<_CharT>; 712bdd1243dSDimitry Andric 71306c3fb27SDimitry Andric template <class _ParseContext> 71406c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { 71506c3fb27SDimitry Andric return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__month_day); 716bdd1243dSDimitry Andric } 717bdd1243dSDimitry Andric }; 718bdd1243dSDimitry Andric 719bdd1243dSDimitry Andric template <__fmt_char_type _CharT> 720*cb14a3feSDimitry Andric struct _LIBCPP_TEMPLATE_VIS formatter<chrono::month_day_last, _CharT> : public __formatter_chrono<_CharT> { 721bdd1243dSDimitry Andric public: 722bdd1243dSDimitry Andric using _Base = __formatter_chrono<_CharT>; 723bdd1243dSDimitry Andric 72406c3fb27SDimitry Andric template <class _ParseContext> 72506c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { 72606c3fb27SDimitry Andric return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__month); 727bdd1243dSDimitry Andric } 728bdd1243dSDimitry Andric }; 729bdd1243dSDimitry Andric 730bdd1243dSDimitry Andric template <__fmt_char_type _CharT> 731*cb14a3feSDimitry Andric struct _LIBCPP_TEMPLATE_VIS formatter<chrono::month_weekday, _CharT> : public __formatter_chrono<_CharT> { 732bdd1243dSDimitry Andric public: 733bdd1243dSDimitry Andric using _Base = __formatter_chrono<_CharT>; 734bdd1243dSDimitry Andric 73506c3fb27SDimitry Andric template <class _ParseContext> 73606c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { 73706c3fb27SDimitry Andric return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__month_weekday); 738bdd1243dSDimitry Andric } 739bdd1243dSDimitry Andric }; 740bdd1243dSDimitry Andric 741bdd1243dSDimitry Andric template <__fmt_char_type _CharT> 742*cb14a3feSDimitry Andric struct _LIBCPP_TEMPLATE_VIS formatter<chrono::month_weekday_last, _CharT> : public __formatter_chrono<_CharT> { 743bdd1243dSDimitry Andric public: 744bdd1243dSDimitry Andric using _Base = __formatter_chrono<_CharT>; 745bdd1243dSDimitry Andric 74606c3fb27SDimitry Andric template <class _ParseContext> 74706c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { 74806c3fb27SDimitry Andric return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__month_weekday); 749bdd1243dSDimitry Andric } 750bdd1243dSDimitry Andric }; 751bdd1243dSDimitry Andric 752bdd1243dSDimitry Andric template <__fmt_char_type _CharT> 753*cb14a3feSDimitry Andric struct _LIBCPP_TEMPLATE_VIS formatter<chrono::year_month, _CharT> : public __formatter_chrono<_CharT> { 754bdd1243dSDimitry Andric public: 755bdd1243dSDimitry Andric using _Base = __formatter_chrono<_CharT>; 756bdd1243dSDimitry Andric 75706c3fb27SDimitry Andric template <class _ParseContext> 75806c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { 75906c3fb27SDimitry Andric return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__year_month); 760bdd1243dSDimitry Andric } 761bdd1243dSDimitry Andric }; 762bdd1243dSDimitry Andric 763bdd1243dSDimitry Andric template <__fmt_char_type _CharT> 764*cb14a3feSDimitry Andric struct _LIBCPP_TEMPLATE_VIS formatter<chrono::year_month_day, _CharT> : public __formatter_chrono<_CharT> { 765bdd1243dSDimitry Andric public: 766bdd1243dSDimitry Andric using _Base = __formatter_chrono<_CharT>; 767bdd1243dSDimitry Andric 76806c3fb27SDimitry Andric template <class _ParseContext> 76906c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { 77006c3fb27SDimitry Andric return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__date); 771bdd1243dSDimitry Andric } 772bdd1243dSDimitry Andric }; 773bdd1243dSDimitry Andric 774bdd1243dSDimitry Andric template <__fmt_char_type _CharT> 775*cb14a3feSDimitry Andric struct _LIBCPP_TEMPLATE_VIS formatter<chrono::year_month_day_last, _CharT> : public __formatter_chrono<_CharT> { 776bdd1243dSDimitry Andric public: 777bdd1243dSDimitry Andric using _Base = __formatter_chrono<_CharT>; 778bdd1243dSDimitry Andric 77906c3fb27SDimitry Andric template <class _ParseContext> 78006c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { 78106c3fb27SDimitry Andric return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__date); 782bdd1243dSDimitry Andric } 783bdd1243dSDimitry Andric }; 784bdd1243dSDimitry Andric 785bdd1243dSDimitry Andric template <__fmt_char_type _CharT> 786*cb14a3feSDimitry Andric struct _LIBCPP_TEMPLATE_VIS formatter<chrono::year_month_weekday, _CharT> : public __formatter_chrono<_CharT> { 787bdd1243dSDimitry Andric public: 788bdd1243dSDimitry Andric using _Base = __formatter_chrono<_CharT>; 789bdd1243dSDimitry Andric 79006c3fb27SDimitry Andric template <class _ParseContext> 79106c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { 79206c3fb27SDimitry Andric return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__date); 793bdd1243dSDimitry Andric } 794bdd1243dSDimitry Andric }; 795bdd1243dSDimitry Andric 796bdd1243dSDimitry Andric template <__fmt_char_type _CharT> 797*cb14a3feSDimitry Andric struct _LIBCPP_TEMPLATE_VIS formatter<chrono::year_month_weekday_last, _CharT> : public __formatter_chrono<_CharT> { 798bdd1243dSDimitry Andric public: 799bdd1243dSDimitry Andric using _Base = __formatter_chrono<_CharT>; 800bdd1243dSDimitry Andric 80106c3fb27SDimitry Andric template <class _ParseContext> 80206c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { 80306c3fb27SDimitry Andric return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__date); 804bdd1243dSDimitry Andric } 805bdd1243dSDimitry Andric }; 806bdd1243dSDimitry Andric 80706c3fb27SDimitry Andric template <class _Duration, __fmt_char_type _CharT> 80806c3fb27SDimitry Andric struct formatter<chrono::hh_mm_ss<_Duration>, _CharT> : public __formatter_chrono<_CharT> { 80906c3fb27SDimitry Andric public: 81006c3fb27SDimitry Andric using _Base = __formatter_chrono<_CharT>; 81106c3fb27SDimitry Andric 81206c3fb27SDimitry Andric template <class _ParseContext> 81306c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { 81406c3fb27SDimitry Andric return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__time); 81506c3fb27SDimitry Andric } 81606c3fb27SDimitry Andric }; 81706c3fb27SDimitry Andric #endif // if _LIBCPP_STD_VER >= 20 818bdd1243dSDimitry Andric 819bdd1243dSDimitry Andric _LIBCPP_END_NAMESPACE_STD 820bdd1243dSDimitry Andric 821bdd1243dSDimitry Andric #endif // _LIBCPP___CHRONO_FORMATTER_H 822