20 # include <type_traits> 28 #ifndef FMT_SAFE_DURATION_CAST 29 # define FMT_SAFE_DURATION_CAST 1 31 #if FMT_SAFE_DURATION_CAST 41 template <
typename To,
typename From,
42 FMT_ENABLE_IF(!std::is_same<From, To>::value &&
43 std::numeric_limits<From>::is_signed ==
44 std::numeric_limits<To>::is_signed)>
45 FMT_CONSTEXPR
auto lossless_integral_conversion(
const From from,
int& ec)
48 using F = std::numeric_limits<From>;
49 using T = std::numeric_limits<To>;
50 static_assert(F::is_integer,
"From must be integral");
51 static_assert(T::is_integer,
"To must be integral");
54 if (detail::const_check(F::digits <= T::digits)) {
58 if (from < (T::min)() || from > (T::max)()) {
64 return static_cast<To
>(from);
69 template <
typename To,
typename From,
70 FMT_ENABLE_IF(!std::is_same<From, To>::value &&
71 std::numeric_limits<From>::is_signed !=
72 std::numeric_limits<To>::is_signed)>
73 FMT_CONSTEXPR
auto lossless_integral_conversion(
const From from,
int& ec)
76 using F = std::numeric_limits<From>;
77 using T = std::numeric_limits<To>;
78 static_assert(F::is_integer,
"From must be integral");
79 static_assert(T::is_integer,
"To must be integral");
81 if (detail::const_check(F::is_signed && !T::is_signed)) {
83 if (fmt::detail::is_negative(from)) {
88 if (detail::const_check(F::digits > T::digits) &&
89 from > static_cast<From>(detail::max_value<To>())) {
95 if (detail::const_check(!F::is_signed && T::is_signed &&
96 F::digits >= T::digits) &&
97 from > static_cast<From>(detail::max_value<To>())) {
101 return static_cast<To
>(from);
104 template <
typename To,
typename From,
105 FMT_ENABLE_IF(std::is_same<From, To>::value)>
106 FMT_CONSTEXPR
auto lossless_integral_conversion(
const From from,
int& ec)
126 template <
typename To,
typename From,
127 FMT_ENABLE_IF(!std::is_same<From, To>::value)>
128 FMT_CONSTEXPR
auto safe_float_conversion(
const From from,
int& ec) -> To {
130 using T = std::numeric_limits<To>;
131 static_assert(std::is_floating_point<From>::value,
"From must be floating");
132 static_assert(std::is_floating_point<To>::value,
"To must be floating");
135 if (std::isfinite(from)) {
136 if (from >= T::lowest() && from <= (T::max)()) {
137 return static_cast<To
>(from);
145 return static_cast<To
>(from);
148 template <
typename To,
typename From,
149 FMT_ENABLE_IF(std::is_same<From, To>::value)>
150 FMT_CONSTEXPR
auto safe_float_conversion(
const From from,
int& ec) -> To {
152 static_assert(std::is_floating_point<From>::value,
"From must be floating");
157 template <
typename To,
typename FromRep,
typename FromPeriod,
158 FMT_ENABLE_IF(std::is_floating_point<FromRep>::value),
159 FMT_ENABLE_IF(std::is_floating_point<typename To::rep>::value)>
162 using From = std::chrono::duration<FromRep, FromPeriod>;
164 if (std::isnan(from.count())) {
166 return To{std::numeric_limits<typename To::rep>::quiet_NaN()};
172 if (std::isinf(from.count())) {
173 return To{from.count()};
179 : std::ratio_divide<typename From::period, typename To::period> {};
181 static_assert(Factor::num > 0,
"num must be positive");
182 static_assert(Factor::den > 0,
"den must be positive");
188 using IntermediateRep =
189 typename std::common_type<
typename From::rep,
typename To::rep,
190 decltype(Factor::num)>::type;
194 IntermediateRep count =
195 safe_float_conversion<IntermediateRep>(from.count(), ec);
201 if (detail::const_check(Factor::num != 1)) {
202 constexpr
auto max1 = detail::max_value<IntermediateRep>() /
203 static_cast<IntermediateRep>(Factor::num);
208 constexpr
auto min1 = std::numeric_limits<IntermediateRep>::lowest() /
209 static_cast<IntermediateRep
>(Factor::num);
214 count *=
static_cast<IntermediateRep
>(Factor::num);
218 if (detail::const_check(Factor::den != 1)) {
219 using common_t =
typename std::common_type<IntermediateRep, intmax_t>::type;
220 count /=
static_cast<common_t
>(Factor::den);
224 using ToRep =
typename To::rep;
226 const ToRep tocount = safe_float_conversion<ToRep>(count, ec);
238 #ifdef FMT_USE_UTC_TIME 240 #elif defined(__cpp_lib_chrono) 241 # define FMT_USE_UTC_TIME (__cpp_lib_chrono >= 201907L) 243 # define FMT_USE_UTC_TIME 0 246 using utc_clock = std::chrono::utc_clock;
249 template <
typename T>
void to_sys(T);
254 #ifdef FMT_USE_LOCAL_TIME 256 #elif defined(__cpp_lib_chrono) 257 # define FMT_USE_LOCAL_TIME (__cpp_lib_chrono >= 201907L) 259 # define FMT_USE_LOCAL_TIME 0 261 #if FMT_USE_LOCAL_TIME 262 using local_t = std::chrono::local_t;
269 template <
typename Duration>
270 using sys_time = std::chrono::time_point<std::chrono::system_clock, Duration>;
272 template <
typename Duration>
273 using utc_time = std::chrono::time_point<detail::utc_clock, Duration>;
275 template <
class Duration>
276 using local_time = std::chrono::time_point<detail::local_t, Duration>;
284 template <
typename T =
void>
struct null {};
285 inline auto localtime_r FMT_NOMACRO(...) ->
null<> {
return null<>(); }
286 inline auto localtime_s(...) ->
null<> {
return null<>(); }
287 inline auto gmtime_r(...) ->
null<> {
return null<>(); }
288 inline auto gmtime_s(...) ->
null<> {
return null<>(); }
292 template <
typename StreamBuf>
class formatbuf :
public StreamBuf {
294 using char_type =
typename StreamBuf::char_type;
295 using streamsize = decltype(std::declval<StreamBuf>().sputn(
nullptr, 0));
296 using int_type =
typename StreamBuf::int_type;
297 using traits_type =
typename StreamBuf::traits_type;
311 auto overflow(int_type ch) -> int_type
override {
312 if (!traits_type::eq_int_type(ch, traits_type::eof()))
313 buffer_.push_back(static_cast<char_type>(ch));
317 auto xsputn(
const char_type* s, streamsize count) -> streamsize
override {
318 buffer_.
append(s, s + count);
323 inline auto get_classic_locale() ->
const std::locale& {
324 static const auto& locale = std::locale::classic();
329 static constexpr
const size_t max_size = 32;
330 CodeUnit buf[max_size];
334 template <
typename CodeUnit>
336 const std::locale& loc) {
337 FMT_PRAGMA_CLANG(diagnostic push)
338 FMT_PRAGMA_CLANG(diagnostic ignored
"-Wdeprecated")
339 auto& f = std::use_facet<std::codecvt<CodeUnit, char, std::mbstate_t>>(loc);
340 FMT_PRAGMA_CLANG(diagnostic pop)
341 auto mb = std::mbstate_t();
342 const char* from_next =
nullptr;
343 auto result = f.in(mb, in.begin(), in.end(), from_next, std::begin(out.buf),
344 std::end(out.buf), out.end);
345 if (result != std::codecvt_base::ok)
346 FMT_THROW(format_error(
"failed to format time"));
349 template <
typename OutputIt>
350 auto write_encoded_tm_str(OutputIt out,
string_view in,
const std::locale& loc)
352 if (const_check(detail::use_utf8) && loc != get_classic_locale()) {
355 #if FMT_MSC_VERSION != 0 || \ 356 (defined(__GLIBCXX__) && \ 357 (!defined(_GLIBCXX_USE_DUAL_ABI) || _GLIBCXX_USE_DUAL_ABI == 0)) 360 using code_unit = wchar_t;
362 using code_unit = char32_t;
367 write_codecvt(unit, in, loc);
371 if (!u.convert({unit.buf, to_unsigned(unit.end - unit.buf)}))
372 FMT_THROW(format_error(
"failed to format time"));
373 return copy<char>(u.c_str(), u.c_str() + u.size(), out);
375 return copy<char>(in.
data(), in.
data() + in.
size(), out);
378 template <
typename Char,
typename OutputIt,
379 FMT_ENABLE_IF(!std::is_same<Char, char>::value)>
380 auto write_tm_str(OutputIt out,
string_view sv,
const std::locale& loc)
383 write_codecvt(unit, sv, loc);
384 return copy<Char>(unit.buf, unit.end, out);
387 template <
typename Char,
typename OutputIt,
388 FMT_ENABLE_IF(std::is_same<Char, char>::value)>
389 auto write_tm_str(OutputIt out,
string_view sv,
const std::locale& loc)
391 return write_encoded_tm_str(out, sv, loc);
394 template <
typename Char>
395 inline void do_write(
buffer<Char>& buf,
const std::tm& time,
396 const std::locale& loc,
char format,
char modifier) {
398 auto&& os = std::basic_ostream<Char>(&format_buf);
400 const auto& facet = std::use_facet<std::time_put<Char>>(loc);
401 auto end = facet.put(os, os, Char(
' '), &time, format, modifier);
402 if (end.failed()) FMT_THROW(format_error(
"failed to format time"));
405 template <
typename Char,
typename OutputIt,
406 FMT_ENABLE_IF(!std::is_same<Char, char>::value)>
407 auto write(OutputIt out,
const std::tm& time,
const std::locale& loc,
408 char format,
char modifier = 0) -> OutputIt {
409 auto&& buf = get_buffer<Char>(out);
410 do_write<Char>(buf, time, loc, format, modifier);
411 return get_iterator(buf, out);
414 template <
typename Char,
typename OutputIt,
415 FMT_ENABLE_IF(std::is_same<Char, char>::value)>
416 auto write(OutputIt out,
const std::tm& time,
const std::locale& loc,
417 char format,
char modifier = 0) -> OutputIt {
419 do_write<char>(buf, time, loc, format, modifier);
423 template <
typename T,
typename U>
424 using is_similar_arithmetic_type =
425 bool_constant<(std::is_integral<T>::value && std::is_integral<U>::value) ||
426 (std::is_floating_point<T>::value &&
427 std::is_floating_point<U>::value)>;
429 FMT_NORETURN
inline void throw_duration_error() {
430 FMT_THROW(format_error(
"cannot format duration"));
434 template <
typename To,
typename FromRep,
typename FromPeriod,
435 FMT_ENABLE_IF(std::is_integral<FromRep>::value&&
436 std::is_integral<typename To::rep>::value)>
437 auto duration_cast(std::chrono::duration<FromRep, FromPeriod> from) -> To {
438 #if !FMT_SAFE_DURATION_CAST 439 return std::chrono::duration_cast<To>(from);
442 using factor = std::ratio_divide<FromPeriod, typename To::period>;
444 using common_rep =
typename std::common_type<FromRep,
typename To::rep,
445 decltype(factor::num)>::type;
448 auto count = safe_duration_cast::lossless_integral_conversion<common_rep>(
450 if (ec) throw_duration_error();
453 if (const_check(factor::num != 1)) {
454 if (count > max_value<common_rep>() / factor::num) throw_duration_error();
455 const auto min = (std::numeric_limits<common_rep>::min)() / factor::num;
456 if (const_check(!std::is_unsigned<common_rep>::value) && count < min)
457 throw_duration_error();
458 count *= factor::num;
460 if (const_check(factor::den != 1)) count /= factor::den;
462 To(safe_duration_cast::lossless_integral_conversion<typename To::rep>(
464 if (ec) throw_duration_error();
469 template <
typename To,
typename FromRep,
typename FromPeriod,
470 FMT_ENABLE_IF(std::is_floating_point<FromRep>::value&&
471 std::is_floating_point<typename To::rep>::value)>
472 auto duration_cast(std::chrono::duration<FromRep, FromPeriod> from) -> To {
473 #if FMT_SAFE_DURATION_CAST 477 To to = safe_duration_cast::safe_duration_cast<To>(from, ec);
478 if (ec) throw_duration_error();
482 return std::chrono::duration_cast<To>(from);
486 template <
typename To,
typename FromRep,
typename FromPeriod,
488 !is_similar_arithmetic_type<FromRep, typename To::rep>::value)>
489 auto duration_cast(std::chrono::duration<FromRep, FromPeriod> from) -> To {
491 return std::chrono::duration_cast<To>(from);
494 template <
typename Duration>
495 auto to_time_t(sys_time<Duration> time_point) -> std::time_t {
499 return detail::duration_cast<std::chrono::duration<std::time_t>>(
500 time_point.time_since_epoch())
508 template <
typename Duration,
typename LocalTime>
509 auto to_sys(LocalTime) -> sys_time<Duration> {
513 template <
typename... T>
auto current_zone(T...) ->
time_zone* {
517 template <
typename... T>
void _tzset(T...) {}
521 inline void tzset_once() {
522 static bool init = []() {
538 FMT_DEPRECATED
inline auto localtime(std::time_t time) -> std::tm {
543 inline dispatcher(std::time_t t) : time_(t) {}
545 inline auto run() ->
bool {
546 using namespace fmt::detail;
547 return handle(localtime_r(&time_, &tm_));
550 inline auto handle(std::tm* tm) ->
bool {
return tm !=
nullptr; }
553 using namespace fmt::detail;
554 return fallback(localtime_s(&tm_, &time_));
557 inline auto fallback(
int res) ->
bool {
return res == 0; }
561 using namespace fmt::detail;
562 std::tm* tm = std::localtime(&time_);
564 return tm !=
nullptr;
570 if (!lt.run()) FMT_THROW(format_error(
"time_t value out of range"));
574 #if FMT_USE_LOCAL_TIME 575 template <
typename Duration>
576 FMT_DEPRECATED
auto localtime(std::chrono::local_time<Duration> time)
578 using namespace std::chrono;
580 return localtime(detail::to_time_t(current_zone()->to_sys<Duration>(time)));
589 inline auto gmtime(std::time_t time) -> std::tm {
594 inline dispatcher(std::time_t t) : time_(t) {}
596 inline auto run() ->
bool {
597 using namespace fmt::detail;
598 return handle(gmtime_r(&time_, &tm_));
601 inline auto handle(std::tm* tm) ->
bool {
return tm !=
nullptr; }
604 using namespace fmt::detail;
605 return fallback(gmtime_s(&tm_, &time_));
608 inline auto fallback(
int res) ->
bool {
return res == 0; }
612 std::tm* tm = std::gmtime(&time_);
614 return tm !=
nullptr;
618 auto gt = dispatcher(time);
620 if (!gt.run()) FMT_THROW(format_error(
"time_t value out of range"));
624 template <
typename Duration>
625 inline auto gmtime(sys_time<Duration> time_point) -> std::tm {
626 return gmtime(detail::to_time_t(time_point));
634 inline void write_digit2_separated(
char* buf,
unsigned a,
unsigned b,
635 unsigned c,
char sep) {
636 unsigned long long digits =
637 a | (b << 24) | (static_cast<unsigned long long>(c) << 48);
647 digits += (((digits * 205) >> 11) & 0x000f00000f00000f) * 6;
649 digits = ((digits & 0x00f00000f00000f0) >> 4) |
650 ((digits & 0x000f00000f00000f) << 8);
651 auto usep =
static_cast<unsigned long long>(sep);
653 digits |= 0x3030003030003030 | (usep << 16) | (usep << 40);
655 constexpr
const size_t len = 8;
656 if (const_check(is_big_endian())) {
658 std::memcpy(tmp, &digits, len);
659 std::reverse_copy(tmp, tmp + len, buf);
661 std::memcpy(buf, &digits, len);
665 template <
typename Period>
666 FMT_CONSTEXPR
inline auto get_units() ->
const char* {
667 if (std::is_same<Period, std::atto>::value)
return "as";
668 if (std::is_same<Period, std::femto>::value)
return "fs";
669 if (std::is_same<Period, std::pico>::value)
return "ps";
670 if (std::is_same<Period, std::nano>::value)
return "ns";
671 if (std::is_same<Period, std::micro>::value)
672 return detail::use_utf8 ?
"µs" :
"us";
673 if (std::is_same<Period, std::milli>::value)
return "ms";
674 if (std::is_same<Period, std::centi>::value)
return "cs";
675 if (std::is_same<Period, std::deci>::value)
return "ds";
676 if (std::is_same<Period, std::ratio<1>>::
value)
return "s";
677 if (std::is_same<Period, std::deca>::value)
return "das";
678 if (std::is_same<Period, std::hecto>::value)
return "hs";
679 if (std::is_same<Period, std::kilo>::value)
return "ks";
680 if (std::is_same<Period, std::mega>::value)
return "Ms";
681 if (std::is_same<Period, std::giga>::value)
return "Gs";
682 if (std::is_same<Period, std::tera>::value)
return "Ts";
683 if (std::is_same<Period, std::peta>::value)
return "Ps";
684 if (std::is_same<Period, std::exa>::value)
return "Es";
685 if (std::is_same<Period, std::ratio<60>>::
value)
return "min";
686 if (std::is_same<Period, std::ratio<3600>>::
value)
return "h";
687 if (std::is_same<Period, std::ratio<86400>>::
value)
return "d";
691 enum class numeric_system {
698 enum class pad_type {
707 template <
typename OutputIt>
708 auto write_padding(OutputIt out, pad_type pad,
int width) -> OutputIt {
709 if (pad == pad_type::none)
return out;
710 return detail::fill_n(out, width, pad == pad_type::space ?
' ' :
'0');
713 template <
typename OutputIt>
714 auto write_padding(OutputIt out, pad_type pad) -> OutputIt {
715 if (pad != pad_type::none) *out++ = pad == pad_type::space ?
' ' :
'0';
720 template <
typename Char,
typename Handler>
721 FMT_CONSTEXPR
auto parse_chrono_format(
const Char* begin,
const Char* end,
722 Handler&& handler) ->
const Char* {
723 if (begin == end || *begin ==
'}')
return begin;
724 if (*begin !=
'%') FMT_THROW(format_error(
"invalid format"));
727 pad_type pad = pad_type::zero;
734 if (begin != ptr) handler.on_text(begin, ptr);
736 if (ptr == end) FMT_THROW(format_error(
"invalid format"));
740 pad = pad_type::space;
744 pad = pad_type::none;
748 if (ptr == end) FMT_THROW(format_error(
"invalid format"));
751 case '%': handler.on_text(ptr - 1, ptr);
break;
753 const Char newline[] = {
'\n'};
754 handler.on_text(newline, newline + 1);
758 const Char tab[] = {
'\t'};
759 handler.on_text(tab, tab + 1);
763 case 'Y': handler.on_year(numeric_system::standard, pad);
break;
764 case 'y': handler.on_short_year(numeric_system::standard);
break;
765 case 'C': handler.on_century(numeric_system::standard);
break;
766 case 'G': handler.on_iso_week_based_year();
break;
767 case 'g': handler.on_iso_week_based_short_year();
break;
769 case 'a': handler.on_abbr_weekday();
break;
770 case 'A': handler.on_full_weekday();
break;
771 case 'w': handler.on_dec0_weekday(numeric_system::standard);
break;
772 case 'u': handler.on_dec1_weekday(numeric_system::standard);
break;
775 case 'h': handler.on_abbr_month();
break;
776 case 'B': handler.on_full_month();
break;
777 case 'm': handler.on_dec_month(numeric_system::standard, pad);
break;
780 handler.on_dec0_week_of_year(numeric_system::standard, pad);
783 handler.on_dec1_week_of_year(numeric_system::standard, pad);
785 case 'V': handler.on_iso_week_of_year(numeric_system::standard, pad);
break;
786 case 'j': handler.on_day_of_year(pad);
break;
787 case 'd': handler.on_day_of_month(numeric_system::standard, pad);
break;
789 handler.on_day_of_month(numeric_system::standard, pad_type::space);
792 case 'H': handler.on_24_hour(numeric_system::standard, pad);
break;
793 case 'I': handler.on_12_hour(numeric_system::standard, pad);
break;
794 case 'M': handler.on_minute(numeric_system::standard, pad);
break;
795 case 'S': handler.on_second(numeric_system::standard, pad);
break;
797 case 'c': handler.on_datetime(numeric_system::standard);
break;
798 case 'x': handler.on_loc_date(numeric_system::standard);
break;
799 case 'X': handler.on_loc_time(numeric_system::standard);
break;
800 case 'D': handler.on_us_date();
break;
801 case 'F': handler.on_iso_date();
break;
802 case 'r': handler.on_12_hour_time();
break;
803 case 'R': handler.on_24_hour_time();
break;
804 case 'T': handler.on_iso_time();
break;
805 case 'p': handler.on_am_pm();
break;
806 case 'Q': handler.on_duration_value();
break;
807 case 'q': handler.on_duration_unit();
break;
808 case 'z': handler.on_utc_offset(numeric_system::standard);
break;
809 case 'Z': handler.on_tz_name();
break;
812 if (ptr == end) FMT_THROW(format_error(
"invalid format"));
815 case 'Y': handler.on_year(numeric_system::alternative, pad);
break;
816 case 'y': handler.on_offset_year();
break;
817 case 'C': handler.on_century(numeric_system::alternative);
break;
818 case 'c': handler.on_datetime(numeric_system::alternative);
break;
819 case 'x': handler.on_loc_date(numeric_system::alternative);
break;
820 case 'X': handler.on_loc_time(numeric_system::alternative);
break;
821 case 'z': handler.on_utc_offset(numeric_system::alternative);
break;
822 default: FMT_THROW(format_error(
"invalid format"));
827 if (ptr == end) FMT_THROW(format_error(
"invalid format"));
830 case 'y': handler.on_short_year(numeric_system::alternative);
break;
831 case 'm': handler.on_dec_month(numeric_system::alternative, pad);
break;
833 handler.on_dec0_week_of_year(numeric_system::alternative, pad);
836 handler.on_dec1_week_of_year(numeric_system::alternative, pad);
839 handler.on_iso_week_of_year(numeric_system::alternative, pad);
842 handler.on_day_of_month(numeric_system::alternative, pad);
845 handler.on_day_of_month(numeric_system::alternative, pad_type::space);
847 case 'w': handler.on_dec0_weekday(numeric_system::alternative);
break;
848 case 'u': handler.on_dec1_weekday(numeric_system::alternative);
break;
849 case 'H': handler.on_24_hour(numeric_system::alternative, pad);
break;
850 case 'I': handler.on_12_hour(numeric_system::alternative, pad);
break;
851 case 'M': handler.on_minute(numeric_system::alternative, pad);
break;
852 case 'S': handler.on_second(numeric_system::alternative, pad);
break;
853 case 'z': handler.on_utc_offset(numeric_system::alternative);
break;
854 default: FMT_THROW(format_error(
"invalid format"));
857 default: FMT_THROW(format_error(
"invalid format"));
861 if (begin != ptr) handler.on_text(begin, ptr);
866 FMT_CONSTEXPR
void unsupported() {
867 static_cast<Derived*
>(
this)->unsupported();
869 FMT_CONSTEXPR
void on_year(numeric_system, pad_type) { unsupported(); }
870 FMT_CONSTEXPR
void on_short_year(numeric_system) { unsupported(); }
871 FMT_CONSTEXPR
void on_offset_year() { unsupported(); }
872 FMT_CONSTEXPR
void on_century(numeric_system) { unsupported(); }
873 FMT_CONSTEXPR
void on_iso_week_based_year() { unsupported(); }
874 FMT_CONSTEXPR
void on_iso_week_based_short_year() { unsupported(); }
875 FMT_CONSTEXPR
void on_abbr_weekday() { unsupported(); }
876 FMT_CONSTEXPR
void on_full_weekday() { unsupported(); }
877 FMT_CONSTEXPR
void on_dec0_weekday(numeric_system) { unsupported(); }
878 FMT_CONSTEXPR
void on_dec1_weekday(numeric_system) { unsupported(); }
879 FMT_CONSTEXPR
void on_abbr_month() { unsupported(); }
880 FMT_CONSTEXPR
void on_full_month() { unsupported(); }
881 FMT_CONSTEXPR
void on_dec_month(numeric_system, pad_type) { unsupported(); }
882 FMT_CONSTEXPR
void on_dec0_week_of_year(numeric_system, pad_type) {
885 FMT_CONSTEXPR
void on_dec1_week_of_year(numeric_system, pad_type) {
888 FMT_CONSTEXPR
void on_iso_week_of_year(numeric_system, pad_type) {
891 FMT_CONSTEXPR
void on_day_of_year(pad_type) { unsupported(); }
892 FMT_CONSTEXPR
void on_day_of_month(numeric_system, pad_type) {
895 FMT_CONSTEXPR
void on_24_hour(numeric_system) { unsupported(); }
896 FMT_CONSTEXPR
void on_12_hour(numeric_system) { unsupported(); }
897 FMT_CONSTEXPR
void on_minute(numeric_system) { unsupported(); }
898 FMT_CONSTEXPR
void on_second(numeric_system) { unsupported(); }
899 FMT_CONSTEXPR
void on_datetime(numeric_system) { unsupported(); }
900 FMT_CONSTEXPR
void on_loc_date(numeric_system) { unsupported(); }
901 FMT_CONSTEXPR
void on_loc_time(numeric_system) { unsupported(); }
902 FMT_CONSTEXPR
void on_us_date() { unsupported(); }
903 FMT_CONSTEXPR
void on_iso_date() { unsupported(); }
904 FMT_CONSTEXPR
void on_12_hour_time() { unsupported(); }
905 FMT_CONSTEXPR
void on_24_hour_time() { unsupported(); }
906 FMT_CONSTEXPR
void on_iso_time() { unsupported(); }
907 FMT_CONSTEXPR
void on_am_pm() { unsupported(); }
908 FMT_CONSTEXPR
void on_duration_value() { unsupported(); }
909 FMT_CONSTEXPR
void on_duration_unit() { unsupported(); }
910 FMT_CONSTEXPR
void on_utc_offset(numeric_system) { unsupported(); }
911 FMT_CONSTEXPR
void on_tz_name() { unsupported(); }
916 bool has_timezone_ =
false;
920 : has_timezone_(has_timezone) {}
922 FMT_NORETURN
inline void unsupported() {
923 FMT_THROW(format_error(
"no format"));
926 template <
typename Char>
927 FMT_CONSTEXPR
void on_text(
const Char*,
const Char*) {}
928 FMT_CONSTEXPR
void on_year(numeric_system, pad_type) {}
929 FMT_CONSTEXPR
void on_short_year(numeric_system) {}
930 FMT_CONSTEXPR
void on_offset_year() {}
931 FMT_CONSTEXPR
void on_century(numeric_system) {}
932 FMT_CONSTEXPR
void on_iso_week_based_year() {}
933 FMT_CONSTEXPR
void on_iso_week_based_short_year() {}
934 FMT_CONSTEXPR
void on_abbr_weekday() {}
935 FMT_CONSTEXPR
void on_full_weekday() {}
936 FMT_CONSTEXPR
void on_dec0_weekday(numeric_system) {}
937 FMT_CONSTEXPR
void on_dec1_weekday(numeric_system) {}
938 FMT_CONSTEXPR
void on_abbr_month() {}
939 FMT_CONSTEXPR
void on_full_month() {}
940 FMT_CONSTEXPR
void on_dec_month(numeric_system, pad_type) {}
941 FMT_CONSTEXPR
void on_dec0_week_of_year(numeric_system, pad_type) {}
942 FMT_CONSTEXPR
void on_dec1_week_of_year(numeric_system, pad_type) {}
943 FMT_CONSTEXPR
void on_iso_week_of_year(numeric_system, pad_type) {}
944 FMT_CONSTEXPR
void on_day_of_year(pad_type) {}
945 FMT_CONSTEXPR
void on_day_of_month(numeric_system, pad_type) {}
946 FMT_CONSTEXPR
void on_24_hour(numeric_system, pad_type) {}
947 FMT_CONSTEXPR
void on_12_hour(numeric_system, pad_type) {}
948 FMT_CONSTEXPR
void on_minute(numeric_system, pad_type) {}
949 FMT_CONSTEXPR
void on_second(numeric_system, pad_type) {}
950 FMT_CONSTEXPR
void on_datetime(numeric_system) {}
951 FMT_CONSTEXPR
void on_loc_date(numeric_system) {}
952 FMT_CONSTEXPR
void on_loc_time(numeric_system) {}
953 FMT_CONSTEXPR
void on_us_date() {}
954 FMT_CONSTEXPR
void on_iso_date() {}
955 FMT_CONSTEXPR
void on_12_hour_time() {}
956 FMT_CONSTEXPR
void on_24_hour_time() {}
957 FMT_CONSTEXPR
void on_iso_time() {}
958 FMT_CONSTEXPR
void on_am_pm() {}
959 FMT_CONSTEXPR
void on_utc_offset(numeric_system) {
960 if (!has_timezone_) FMT_THROW(format_error(
"no timezone"));
962 FMT_CONSTEXPR
void on_tz_name() {
963 if (!has_timezone_) FMT_THROW(format_error(
"no timezone"));
967 inline auto tm_wday_full_name(
int wday) ->
const char* {
968 static constexpr
const char* full_name_list[] = {
969 "Sunday",
"Monday",
"Tuesday",
"Wednesday",
970 "Thursday",
"Friday",
"Saturday"};
971 return wday >= 0 && wday <= 6 ? full_name_list[wday] :
"?";
973 inline auto tm_wday_short_name(
int wday) ->
const char* {
974 static constexpr
const char* short_name_list[] = {
"Sun",
"Mon",
"Tue",
"Wed",
975 "Thu",
"Fri",
"Sat"};
976 return wday >= 0 && wday <= 6 ? short_name_list[wday] :
"???";
979 inline auto tm_mon_full_name(
int mon) ->
const char* {
980 static constexpr
const char* full_name_list[] = {
981 "January",
"February",
"March",
"April",
"May",
"June",
982 "July",
"August",
"September",
"October",
"November",
"December"};
983 return mon >= 0 && mon <= 11 ? full_name_list[mon] :
"?";
985 inline auto tm_mon_short_name(
int mon) ->
const char* {
986 static constexpr
const char* short_name_list[] = {
987 "Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
988 "Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec",
990 return mon >= 0 && mon <= 11 ? short_name_list[mon] :
"???";
993 template <
typename T,
typename =
void>
995 template <
typename T>
996 struct has_tm_gmtoff<T, void_t<decltype(T::tm_gmtoff)>> : std::true_type {};
998 template <
typename T,
typename =
void>
struct has_tm_zone : std::false_type {};
999 template <
typename T>
1000 struct has_tm_zone<T, void_t<decltype(T::tm_zone)>> : std::true_type {};
1002 template <typename T, FMT_ENABLE_IF(has_tm_zone<T>::value)>
1003 bool set_tm_zone(T& time,
char* tz) {
1007 template <typename T, FMT_ENABLE_IF(!has_tm_zone<T>::value)>
1008 bool set_tm_zone(T&,
char*) {
1012 inline char* utc() {
1013 static char tz[] =
"UTC";
1018 template <typename T, typename Int, FMT_ENABLE_IF(std::is_integral<T>::value)>
1019 inline auto to_nonnegative_int(T
value, Int upper) -> Int {
1020 if (!std::is_unsigned<Int>::value &&
1021 (value < 0 || to_unsigned(value) > to_unsigned(upper))) {
1022 FMT_THROW(format_error(
"chrono value is out of range"));
1024 return static_cast<Int
>(value);
1026 template <typename T, typename Int, FMT_ENABLE_IF(!std::is_integral<T>::value)>
1027 inline auto to_nonnegative_int(T value, Int upper) -> Int {
1028 auto int_value =
static_cast<Int
>(value);
1029 if (int_value < 0 || value > static_cast<T>(upper))
1030 FMT_THROW(format_error(
"invalid value"));
1034 constexpr
auto pow10(std::uint32_t n) ->
long long {
1035 return n == 0 ? 1 : 10 * pow10(n - 1);
1041 template <
long long Num,
long long Den,
int N = 0,
1042 bool Enabled = (N < 19) && (Num <= max_value<long long>() / 10)>
1044 static constexpr
int value =
1050 template <
long long Num,
long long Den,
int N>
1052 static constexpr
int value = (Num % Den == 0) ? N : 6;
1057 template <
typename Char,
typename OutputIt,
typename Duration>
1058 void write_fractional_seconds(OutputIt& out, Duration d,
int precision = -1) {
1059 constexpr
auto num_fractional_digits =
1061 Duration::period::den>
::value;
1063 using subsecond_precision = std::chrono::duration<
1064 typename std::common_type<
typename Duration::rep,
1065 std::chrono::seconds::rep>::type,
1066 std::ratio<1, pow10(num_fractional_digits)>>;
1068 const auto fractional = d - detail::duration_cast<std::chrono::seconds>(d);
1069 const auto subseconds =
1070 std::chrono::treat_as_floating_point<
1071 typename subsecond_precision::rep>::value
1072 ? fractional.count()
1073 : detail::duration_cast<subsecond_precision>(fractional).count();
1074 auto n =
static_cast<uint32_or_64_or_128_t<long long>
>(subseconds);
1075 const int num_digits = count_digits(n);
1077 int leading_zeroes = (std::max)(0, num_fractional_digits - num_digits);
1078 if (precision < 0) {
1079 FMT_ASSERT(!std::is_floating_point<typename Duration::rep>::value,
"");
1080 if (std::ratio_less<
typename subsecond_precision::period,
1081 std::chrono::seconds::period>::value) {
1083 out = detail::fill_n(out, leading_zeroes,
'0');
1084 out = format_decimal<Char>(out, n, num_digits);
1086 }
else if (precision > 0) {
1088 leading_zeroes = min_of(leading_zeroes, precision);
1089 int remaining = precision - leading_zeroes;
1090 out = detail::fill_n(out, leading_zeroes,
'0');
1091 if (remaining < num_digits) {
1092 int num_truncated_digits = num_digits - remaining;
1093 n /= to_unsigned(pow10(to_unsigned(num_truncated_digits)));
1094 if (n != 0) out = format_decimal<Char>(out, n, remaining);
1098 out = format_decimal<Char>(out, n, num_digits);
1099 remaining -= num_digits;
1101 out = detail::fill_n(out, remaining,
'0');
1108 template <
typename Duration>
1109 void write_floating_seconds(
memory_buffer& buf, Duration duration,
1110 int num_fractional_digits = -1) {
1111 using rep =
typename Duration::rep;
1112 FMT_ASSERT(std::is_floating_point<rep>::value,
"");
1114 auto val = duration.count();
1116 if (num_fractional_digits < 0) {
1119 using namespace std;
1120 num_fractional_digits =
1122 Duration::period::den>
::value;
1123 if (num_fractional_digits < 6 && static_cast<rep>(round(val)) != val)
1124 num_fractional_digits = 6;
1127 fmt::format_to(std::back_inserter(buf), FMT_STRING(
"{:.{}f}"),
1128 std::fmod(val * static_cast<rep>(Duration::period::num) /
1129 static_cast<rep>(Duration::period::den),
1130 static_cast<rep>(60)),
1131 num_fractional_digits);
1134 template <
typename OutputIt,
typename Char,
1135 typename Duration = std::chrono::seconds>
1138 static constexpr
int days_per_week = 7;
1140 const std::locale& loc_;
1143 const Duration* subsecs_;
1146 auto tm_sec()
const noexcept ->
int {
1147 FMT_ASSERT(tm_.tm_sec >= 0 && tm_.tm_sec <= 61,
"");
1150 auto tm_min()
const noexcept ->
int {
1151 FMT_ASSERT(tm_.tm_min >= 0 && tm_.tm_min <= 59,
"");
1154 auto tm_hour()
const noexcept ->
int {
1155 FMT_ASSERT(tm_.tm_hour >= 0 && tm_.tm_hour <= 23,
"");
1158 auto tm_mday()
const noexcept ->
int {
1159 FMT_ASSERT(tm_.tm_mday >= 1 && tm_.tm_mday <= 31,
"");
1162 auto tm_mon()
const noexcept ->
int {
1163 FMT_ASSERT(tm_.tm_mon >= 0 && tm_.tm_mon <= 11,
"");
1166 auto tm_year()
const noexcept ->
long long {
return 1900ll + tm_.tm_year; }
1167 auto tm_wday()
const noexcept ->
int {
1168 FMT_ASSERT(tm_.tm_wday >= 0 && tm_.tm_wday <= 6,
"");
1171 auto tm_yday()
const noexcept ->
int {
1172 FMT_ASSERT(tm_.tm_yday >= 0 && tm_.tm_yday <= 365,
"");
1176 auto tm_hour12()
const noexcept ->
int {
1178 auto z = h < 12 ? h : h - 12;
1179 return z == 0 ? 12 : z;
1186 auto split_year_lower(
long long year)
const noexcept ->
int {
1187 auto l = year % 100;
1189 return static_cast<int>(l);
1193 auto iso_year_weeks(
long long curr_year)
const noexcept ->
int {
1194 auto prev_year = curr_year - 1;
1196 (curr_year + curr_year / 4 - curr_year / 100 + curr_year / 400) %
1199 (prev_year + prev_year / 4 - prev_year / 100 + prev_year / 400) %
1201 return 52 + ((curr_p == 4 || prev_p == 3) ? 1 : 0);
1203 auto iso_week_num(
int tm_yday,
int tm_wday)
const noexcept ->
int {
1204 return (tm_yday + 11 - (tm_wday == 0 ? days_per_week : tm_wday)) /
1207 auto tm_iso_week_year()
const noexcept ->
long long {
1208 auto year = tm_year();
1209 auto w = iso_week_num(tm_yday(), tm_wday());
1210 if (w < 1)
return year - 1;
1211 if (w > iso_year_weeks(year))
return year + 1;
1214 auto tm_iso_week_of_year()
const noexcept ->
int {
1215 auto year = tm_year();
1216 auto w = iso_week_num(tm_yday(), tm_wday());
1217 if (w < 1)
return iso_year_weeks(year - 1);
1218 if (w > iso_year_weeks(year))
return 1;
1222 void write1(
int value) {
1223 *out_++ =
static_cast<char>(
'0' + to_unsigned(value) % 10);
1225 void write2(
int value) {
1226 const char* d = digits2(to_unsigned(value) % 100);
1230 void write2(
int value, pad_type pad) {
1231 unsigned int v = to_unsigned(value) % 100;
1233 const char* d = digits2(v);
1237 out_ = detail::write_padding(out_, pad);
1238 *out_++ =
static_cast<char>(
'0' + v);
1242 void write_year_extended(
long long year, pad_type pad) {
1245 bool negative = year < 0;
1250 uint32_or_64_or_128_t<long long> n = to_unsigned(year);
1251 const int num_digits = count_digits(n);
1252 if (negative && pad == pad_type::zero) *out_++ =
'-';
1253 if (width > num_digits)
1254 out_ = detail::write_padding(out_, pad, width - num_digits);
1255 if (negative && pad != pad_type::zero) *out_++ =
'-';
1256 out_ = format_decimal<Char>(out_, n, num_digits);
1258 void write_year(
long long year, pad_type pad) {
1259 write_year_extended(year, pad);
1262 void write_utc_offset(
long long offset, numeric_system ns) {
1270 write2(static_cast<int>(offset / 60));
1271 if (ns != numeric_system::standard) *out_++ =
':';
1272 write2(static_cast<int>(offset % 60));
1275 template <typename T, FMT_ENABLE_IF(has_tm_gmtoff<T>::value)>
1276 void format_utc_offset(
const T& tm, numeric_system ns) {
1277 write_utc_offset(tm.tm_gmtoff, ns);
1279 template <typename T, FMT_ENABLE_IF(!has_tm_gmtoff<T>::value)>
1280 void format_utc_offset(
const T&, numeric_system ns) {
1281 write_utc_offset(0, ns);
1284 template <typename T, FMT_ENABLE_IF(has_tm_zone<T>::value)>
1285 void format_tz_name(
const T& tm) {
1286 out_ = write_tm_str<Char>(out_, tm.tm_zone, loc_);
1288 template <typename T, FMT_ENABLE_IF(!has_tm_zone<T>::value)>
1289 void format_tz_name(
const T&) {
1290 out_ = std::copy_n(utc(), 3, out_);
1293 void format_localized(
char format,
char modifier = 0) {
1294 out_ = write<Char>(out_, tm_, loc_, format, modifier);
1298 tm_writer(
const std::locale& loc, OutputIt out,
const std::tm& tm,
1299 const Duration* subsecs =
nullptr)
1301 is_classic_(loc_ == get_classic_locale()),
1306 auto out()
const -> OutputIt {
return out_; }
1308 FMT_CONSTEXPR
void on_text(
const Char* begin,
const Char* end) {
1309 out_ = copy<Char>(begin, end, out_);
1312 void on_abbr_weekday() {
1314 out_ = write(out_, tm_wday_short_name(tm_wday()));
1316 format_localized(
'a');
1318 void on_full_weekday() {
1320 out_ = write(out_, tm_wday_full_name(tm_wday()));
1322 format_localized(
'A');
1324 void on_dec0_weekday(numeric_system ns) {
1325 if (is_classic_ || ns == numeric_system::standard)
return write1(tm_wday());
1326 format_localized(
'w',
'O');
1328 void on_dec1_weekday(numeric_system ns) {
1329 if (is_classic_ || ns == numeric_system::standard) {
1330 auto wday = tm_wday();
1331 write1(wday == 0 ? days_per_week : wday);
1333 format_localized(
'u',
'O');
1337 void on_abbr_month() {
1339 out_ = write(out_, tm_mon_short_name(tm_mon()));
1341 format_localized(
'b');
1343 void on_full_month() {
1345 out_ = write(out_, tm_mon_full_name(tm_mon()));
1347 format_localized(
'B');
1350 void on_datetime(numeric_system ns) {
1356 on_day_of_month(numeric_system::standard, pad_type::space);
1360 on_year(numeric_system::standard, pad_type::space);
1362 format_localized(
'c', ns == numeric_system::standard ?
'\0' :
'E');
1365 void on_loc_date(numeric_system ns) {
1369 format_localized(
'x', ns == numeric_system::standard ?
'\0' :
'E');
1371 void on_loc_time(numeric_system ns) {
1375 format_localized(
'X', ns == numeric_system::standard ?
'\0' :
'E');
1379 write_digit2_separated(buf, to_unsigned(tm_mon() + 1),
1380 to_unsigned(tm_mday()),
1381 to_unsigned(split_year_lower(tm_year())),
'/');
1382 out_ = copy<Char>(std::begin(buf), std::end(buf), out_);
1384 void on_iso_date() {
1385 auto year = tm_year();
1388 if (year >= 0 && year < 10000) {
1389 write2digits(buf, static_cast<size_t>(year / 100));
1392 write_year_extended(year, pad_type::zero);
1395 write_digit2_separated(buf + 2, static_cast<unsigned>(year % 100),
1396 to_unsigned(tm_mon() + 1), to_unsigned(tm_mday()),
1398 out_ = copy<Char>(std::begin(buf) + offset, std::end(buf), out_);
1401 void on_utc_offset(numeric_system ns) { format_utc_offset(tm_, ns); }
1402 void on_tz_name() { format_tz_name(tm_); }
1404 void on_year(numeric_system ns, pad_type pad) {
1405 if (is_classic_ || ns == numeric_system::standard)
1406 return write_year(tm_year(), pad);
1407 format_localized(
'Y',
'E');
1409 void on_short_year(numeric_system ns) {
1410 if (is_classic_ || ns == numeric_system::standard)
1411 return write2(split_year_lower(tm_year()));
1412 format_localized(
'y',
'O');
1414 void on_offset_year() {
1415 if (is_classic_)
return write2(split_year_lower(tm_year()));
1416 format_localized(
'y',
'E');
1419 void on_century(numeric_system ns) {
1420 if (is_classic_ || ns == numeric_system::standard) {
1421 auto year = tm_year();
1422 auto upper = year / 100;
1423 if (year >= -99 && year < 0) {
1427 }
else if (upper >= 0 && upper < 100) {
1428 write2(static_cast<int>(upper));
1430 out_ = write<Char>(out_, upper);
1433 format_localized(
'C',
'E');
1437 void on_dec_month(numeric_system ns, pad_type pad) {
1438 if (is_classic_ || ns == numeric_system::standard)
1439 return write2(tm_mon() + 1, pad);
1440 format_localized(
'm',
'O');
1443 void on_dec0_week_of_year(numeric_system ns, pad_type pad) {
1444 if (is_classic_ || ns == numeric_system::standard)
1445 return write2((tm_yday() + days_per_week - tm_wday()) / days_per_week,
1447 format_localized(
'U',
'O');
1449 void on_dec1_week_of_year(numeric_system ns, pad_type pad) {
1450 if (is_classic_ || ns == numeric_system::standard) {
1451 auto wday = tm_wday();
1452 write2((tm_yday() + days_per_week -
1453 (wday == 0 ? (days_per_week - 1) : (wday - 1))) /
1457 format_localized(
'W',
'O');
1460 void on_iso_week_of_year(numeric_system ns, pad_type pad) {
1461 if (is_classic_ || ns == numeric_system::standard)
1462 return write2(tm_iso_week_of_year(), pad);
1463 format_localized(
'V',
'O');
1466 void on_iso_week_based_year() {
1467 write_year(tm_iso_week_year(), pad_type::zero);
1469 void on_iso_week_based_short_year() {
1470 write2(split_year_lower(tm_iso_week_year()));
1473 void on_day_of_year(pad_type pad) {
1474 auto yday = tm_yday() + 1;
1475 auto digit1 = yday / 100;
1479 out_ = detail::write_padding(out_, pad);
1480 write2(yday % 100, pad);
1483 void on_day_of_month(numeric_system ns, pad_type pad) {
1484 if (is_classic_ || ns == numeric_system::standard)
1485 return write2(tm_mday(), pad);
1486 format_localized(
'd',
'O');
1489 void on_24_hour(numeric_system ns, pad_type pad) {
1490 if (is_classic_ || ns == numeric_system::standard)
1491 return write2(tm_hour(), pad);
1492 format_localized(
'H',
'O');
1494 void on_12_hour(numeric_system ns, pad_type pad) {
1495 if (is_classic_ || ns == numeric_system::standard)
1496 return write2(tm_hour12(), pad);
1497 format_localized(
'I',
'O');
1499 void on_minute(numeric_system ns, pad_type pad) {
1500 if (is_classic_ || ns == numeric_system::standard)
1501 return write2(tm_min(), pad);
1502 format_localized(
'M',
'O');
1505 void on_second(numeric_system ns, pad_type pad) {
1506 if (is_classic_ || ns == numeric_system::standard) {
1507 write2(tm_sec(), pad);
1509 if (std::is_floating_point<typename Duration::rep>::value) {
1511 write_floating_seconds(buf, *subsecs_);
1512 if (buf.
size() > 1) {
1514 out_ = copy<Char>(buf.begin() + 1, buf.end(), out_);
1517 write_fractional_seconds<Char>(out_, *subsecs_);
1522 format_localized(
'S',
'O');
1526 void on_12_hour_time() {
1529 write_digit2_separated(buf, to_unsigned(tm_hour12()),
1530 to_unsigned(tm_min()), to_unsigned(tm_sec()),
':');
1531 out_ = copy<Char>(std::begin(buf), std::end(buf), out_);
1535 format_localized(
'r');
1538 void on_24_hour_time() {
1543 void on_iso_time() {
1546 on_second(numeric_system::standard, pad_type::zero);
1551 *out_++ = tm_hour() < 12 ?
'A' :
'P';
1554 format_localized(
'p');
1559 void on_duration_value() {}
1560 void on_duration_unit() {}
1564 bool has_precision_integral =
false;
1566 FMT_NORETURN
inline void unsupported() { FMT_THROW(format_error(
"no date")); }
1568 template <
typename Char>
1569 FMT_CONSTEXPR
void on_text(
const Char*,
const Char*) {}
1570 FMT_CONSTEXPR
void on_day_of_year(pad_type) {}
1571 FMT_CONSTEXPR
void on_24_hour(numeric_system, pad_type) {}
1572 FMT_CONSTEXPR
void on_12_hour(numeric_system, pad_type) {}
1573 FMT_CONSTEXPR
void on_minute(numeric_system, pad_type) {}
1574 FMT_CONSTEXPR
void on_second(numeric_system, pad_type) {}
1575 FMT_CONSTEXPR
void on_12_hour_time() {}
1576 FMT_CONSTEXPR
void on_24_hour_time() {}
1577 FMT_CONSTEXPR
void on_iso_time() {}
1578 FMT_CONSTEXPR
void on_am_pm() {}
1579 FMT_CONSTEXPR
void on_duration_value()
const {
1580 if (has_precision_integral)
1581 FMT_THROW(format_error(
"precision not allowed for this argument type"));
1583 FMT_CONSTEXPR
void on_duration_unit() {}
1586 template <
typename T,
1588 inline auto isfinite(T) ->
bool {
1592 template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
1593 inline auto mod(T x,
int y) -> T {
1594 return x %
static_cast<T
>(y);
1596 template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)>
1597 inline auto mod(T x,
int y) -> T {
1598 return std::fmod(x, static_cast<T>(y));
1603 template <typename T, bool INTEGRAL = std::is_integral<T>::value>
1609 using type =
typename std::make_unsigned<T>::type;
1612 template <
typename Rep,
typename Period,
1613 FMT_ENABLE_IF(std::is_integral<Rep>::value)>
1614 inline auto get_milliseconds(std::chrono::duration<Rep, Period> d)
1615 -> std::chrono::duration<Rep, std::milli> {
1617 #if FMT_SAFE_DURATION_CAST 1618 using common_seconds_type =
1619 typename std::common_type<decltype(d), std::chrono::seconds>::type;
1620 auto d_as_common = detail::duration_cast<common_seconds_type>(d);
1621 auto d_as_whole_seconds =
1622 detail::duration_cast<std::chrono::seconds>(d_as_common);
1624 auto diff = d_as_common - d_as_whole_seconds;
1625 auto ms = detail::duration_cast<std::chrono::duration<Rep, std::milli>>(diff);
1628 auto s = detail::duration_cast<std::chrono::seconds>(d);
1629 return detail::duration_cast<std::chrono::milliseconds>(d - s);
1633 template <
typename Char,
typename Rep,
typename OutputIt,
1634 FMT_ENABLE_IF(std::is_integral<Rep>::value)>
1635 auto format_duration_value(OutputIt out, Rep val,
int) -> OutputIt {
1636 return write<Char>(out, val);
1639 template <
typename Char,
typename Rep,
typename OutputIt,
1640 FMT_ENABLE_IF(std::is_floating_point<Rep>::value)>
1641 auto format_duration_value(OutputIt out, Rep val,
int precision) -> OutputIt {
1643 specs.precision = precision;
1644 specs.set_type(precision >= 0 ? presentation_type::fixed
1645 : presentation_type::general);
1646 return write<Char>(out, val, specs);
1649 template <
typename Char,
typename OutputIt>
1650 auto copy_unit(
string_view unit, OutputIt out, Char) -> OutputIt {
1651 return copy<Char>(unit.begin(), unit.end(), out);
1654 template <
typename OutputIt>
1655 auto copy_unit(
string_view unit, OutputIt out,
wchar_t) -> OutputIt {
1659 return copy<wchar_t>(u.c_str(), u.c_str() + u.size(), out);
1662 template <
typename Char,
typename Period,
typename OutputIt>
1663 auto format_duration_unit(OutputIt out) -> OutputIt {
1664 if (
const char* unit = get_units<Period>())
1667 out = write<Char>(out, Period::num);
1668 if (const_check(Period::den != 1)) {
1670 out = write<Char>(out, Period::den);
1680 std::locale locale_;
1682 bool has_locale_ =
false;
1687 ::new (&locale_) std::locale(loc.template get<std::locale>());
1690 if (has_locale_) locale_.~locale();
1692 inline operator const std::locale&()
const {
1693 return has_locale_ ? locale_ : get_classic_locale();
1697 template <
typename Char,
typename Rep,
typename Period>
1703 conditional_t<std::is_integral<Rep>::value &&
sizeof(Rep) <
sizeof(
int),
1704 unsigned,
typename make_unsigned_or_unchanged<Rep>::type>;
1708 bool localized =
false;
1709 using seconds = std::chrono::duration<rep>;
1711 using milliseconds = std::chrono::duration<rep, std::milli>;
1718 : out(o), val(static_cast<rep>(d.count())), locale(loc), negative(
false) {
1719 if (d.count() < 0) {
1727 s = detail::duration_cast<seconds>(std::chrono::duration<rep, Period>(val));
1731 auto handle_nan_inf() ->
bool {
1732 if (isfinite(val))
return false;
1739 std::copy_n(
"inf", 3, out);
1741 std::copy_n(
"-inf", 4, out);
1745 auto days()
const -> Rep {
return static_cast<Rep
>(s.count() / 86400); }
1746 auto hour()
const -> Rep {
1747 return static_cast<Rep
>(mod((s.count() / 3600), 24));
1750 auto hour12()
const -> Rep {
1751 Rep hour =
static_cast<Rep
>(mod((s.count() / 3600), 12));
1752 return hour <= 0 ? 12 : hour;
1755 auto minute()
const -> Rep {
1756 return static_cast<Rep
>(mod((s.count() / 60), 60));
1758 auto second()
const -> Rep {
return static_cast<Rep
>(mod(s.count(), 60)); }
1760 auto time()
const -> std::tm {
1761 auto time = std::tm();
1762 time.tm_hour = to_nonnegative_int(hour(), 24);
1763 time.tm_min = to_nonnegative_int(minute(), 60);
1764 time.tm_sec = to_nonnegative_int(second(), 60);
1769 if (!negative)
return;
1774 void write(Rep value,
int width, pad_type pad = pad_type::zero) {
1776 if (isnan(value))
return write_nan();
1777 uint32_or_64_or_128_t<int> n =
1778 to_unsigned(to_nonnegative_int(value, max_value<int>()));
1779 int num_digits = detail::count_digits(n);
1780 if (width > num_digits) {
1781 out = detail::write_padding(out, pad, width - num_digits);
1783 out = format_decimal<Char>(out, n, num_digits);
1786 void write_nan() { std::copy_n(
"nan", 3, out); }
1788 template <
typename Callback,
typename... Args>
1789 void format_tm(
const tm& time, Callback cb, Args... args) {
1790 if (isnan(val))
return write_nan();
1797 void on_text(
const Char* begin,
const Char* end) {
1798 copy<Char>(begin, end, out);
1802 void on_abbr_weekday() {}
1803 void on_full_weekday() {}
1804 void on_dec0_weekday(numeric_system) {}
1805 void on_dec1_weekday(numeric_system) {}
1806 void on_abbr_month() {}
1807 void on_full_month() {}
1808 void on_datetime(numeric_system) {}
1809 void on_loc_date(numeric_system) {}
1810 void on_loc_time(numeric_system) {}
1811 void on_us_date() {}
1812 void on_iso_date() {}
1813 void on_utc_offset(numeric_system) {}
1814 void on_tz_name() {}
1815 void on_year(numeric_system, pad_type) {}
1816 void on_short_year(numeric_system) {}
1817 void on_offset_year() {}
1818 void on_century(numeric_system) {}
1819 void on_iso_week_based_year() {}
1820 void on_iso_week_based_short_year() {}
1821 void on_dec_month(numeric_system, pad_type) {}
1822 void on_dec0_week_of_year(numeric_system, pad_type) {}
1823 void on_dec1_week_of_year(numeric_system, pad_type) {}
1824 void on_iso_week_of_year(numeric_system, pad_type) {}
1825 void on_day_of_month(numeric_system, pad_type) {}
1827 void on_day_of_year(pad_type) {
1828 if (handle_nan_inf())
return;
1832 void on_24_hour(numeric_system ns, pad_type pad) {
1833 if (handle_nan_inf())
return;
1835 if (ns == numeric_system::standard)
return write(hour(), 2, pad);
1837 time.tm_hour = to_nonnegative_int(hour(), 24);
1838 format_tm(time, &tm_writer_type::on_24_hour, ns, pad);
1841 void on_12_hour(numeric_system ns, pad_type pad) {
1842 if (handle_nan_inf())
return;
1844 if (ns == numeric_system::standard)
return write(hour12(), 2, pad);
1846 time.tm_hour = to_nonnegative_int(hour12(), 12);
1847 format_tm(time, &tm_writer_type::on_12_hour, ns, pad);
1850 void on_minute(numeric_system ns, pad_type pad) {
1851 if (handle_nan_inf())
return;
1853 if (ns == numeric_system::standard)
return write(minute(), 2, pad);
1855 time.tm_min = to_nonnegative_int(minute(), 60);
1856 format_tm(time, &tm_writer_type::on_minute, ns, pad);
1859 void on_second(numeric_system ns, pad_type pad) {
1860 if (handle_nan_inf())
return;
1862 if (ns == numeric_system::standard) {
1863 if (std::is_floating_point<rep>::value) {
1865 write_floating_seconds(buf, std::chrono::duration<rep, Period>(val),
1867 if (negative) *out++ =
'-';
1868 if (buf.
size() < 2 || buf[1] ==
'.')
1869 out = detail::write_padding(out, pad);
1870 out = copy<Char>(buf.begin(), buf.end(), out);
1872 write(second(), 2, pad);
1873 write_fractional_seconds<Char>(
1874 out, std::chrono::duration<rep, Period>(val), precision);
1879 time.tm_sec = to_nonnegative_int(second(), 60);
1880 format_tm(time, &tm_writer_type::on_second, ns, pad);
1883 void on_12_hour_time() {
1884 if (handle_nan_inf())
return;
1885 format_tm(time(), &tm_writer_type::on_12_hour_time);
1888 void on_24_hour_time() {
1889 if (handle_nan_inf()) {
1900 void on_iso_time() {
1903 if (handle_nan_inf())
return;
1904 on_second(numeric_system::standard, pad_type::zero);
1908 if (handle_nan_inf())
return;
1909 format_tm(time(), &tm_writer_type::on_am_pm);
1912 void on_duration_value() {
1913 if (handle_nan_inf())
return;
1915 out = format_duration_value<Char>(out, val, precision);
1918 void on_duration_unit() { out = format_duration_unit<Char, Period>(out); }
1923 #if defined(__cpp_lib_chrono) && __cpp_lib_chrono >= 201907 1924 using weekday = std::chrono::weekday;
1925 using day = std::chrono::day;
1926 using month = std::chrono::month;
1927 using year = std::chrono::year;
1933 unsigned char value_;
1937 constexpr
explicit weekday(
unsigned wd) noexcept
1938 : value_(static_cast<unsigned char>(wd != 7 ? wd : 0)) {}
1939 constexpr
auto c_encoding()
const noexcept ->
unsigned {
return value_; }
1944 unsigned char value_;
1948 constexpr
explicit day(
unsigned d) noexcept
1949 : value_(static_cast<unsigned char>(d)) {}
1950 constexpr
explicit operator unsigned()
const noexcept {
return value_; }
1955 unsigned char value_;
1959 constexpr
explicit month(
unsigned m) noexcept
1960 : value_(static_cast<unsigned char>(m)) {}
1961 constexpr
explicit operator unsigned()
const noexcept {
return value_; }
1970 constexpr
explicit year(
int y) noexcept : value_(y) {}
1971 constexpr
explicit operator int()
const noexcept {
return value_; }
1983 : year_(y), month_(m), day_(d) {}
1984 constexpr
auto year()
const noexcept -> fmt::year {
return year_; }
1985 constexpr
auto month()
const noexcept -> fmt::month {
return month_; }
1986 constexpr
auto day()
const noexcept -> fmt::day {
return day_; }
1988 #endif // __cpp_lib_chrono >= 201907 1990 template <
typename Char>
1993 bool use_tm_formatter_ =
false;
1997 auto it = ctx.
begin(), end = ctx.
end();
1998 if (it != end && *it ==
'L') {
2000 this->set_localized();
2002 use_tm_formatter_ = it != end && *it !=
'}';
2006 template <
typename FormatContext>
2007 auto format(
weekday wd, FormatContext& ctx)
const -> decltype(ctx.out()) {
2008 auto time = std::tm();
2009 time.tm_wday =
static_cast<int>(wd.c_encoding());
2013 w.on_abbr_weekday();
2018 template <
typename Char>
2021 bool use_tm_formatter_ =
false;
2025 auto it = ctx.
begin(), end = ctx.
end();
2026 use_tm_formatter_ = it != end && *it !=
'}';
2030 template <
typename FormatContext>
2031 auto format(
day d, FormatContext& ctx)
const -> decltype(ctx.out()) {
2032 auto time = std::tm();
2033 time.tm_mday =
static_cast<int>(
static_cast<unsigned>(d));
2037 w.on_day_of_month(detail::numeric_system::standard, detail::pad_type::zero);
2042 template <
typename Char>
2045 bool use_tm_formatter_ =
false;
2049 auto it = ctx.
begin(), end = ctx.
end();
2050 if (it != end && *it ==
'L') {
2052 this->set_localized();
2054 use_tm_formatter_ = it != end && *it !=
'}';
2058 template <
typename FormatContext>
2059 auto format(
month m, FormatContext& ctx)
const -> decltype(ctx.out()) {
2060 auto time = std::tm();
2061 time.tm_mon =
static_cast<int>(
static_cast<unsigned>(m)) - 1;
2070 template <
typename Char>
2073 bool use_tm_formatter_ =
false;
2077 auto it = ctx.
begin(), end = ctx.
end();
2078 use_tm_formatter_ = it != end && *it !=
'}';
2082 template <
typename FormatContext>
2083 auto format(
year y, FormatContext& ctx)
const -> decltype(ctx.out()) {
2084 auto time = std::tm();
2085 time.tm_year =
static_cast<int>(y) - 1900;
2089 w.on_year(detail::numeric_system::standard, detail::pad_type::zero);
2094 template <
typename Char>
2097 bool use_tm_formatter_ =
false;
2101 auto it = ctx.
begin(), end = ctx.
end();
2102 use_tm_formatter_ = it != end && *it !=
'}';
2106 template <
typename FormatContext>
2108 -> decltype(ctx.out()) {
2109 auto time = std::tm();
2110 time.tm_year =
static_cast<int>(val.year()) - 1900;
2111 time.tm_mon =
static_cast<int>(
static_cast<unsigned>(val.month())) - 1;
2112 time.tm_mday =
static_cast<int>(
static_cast<unsigned>(val.day()));
2121 template <
typename Rep,
typename Period,
typename Char>
2131 auto it = ctx.
begin(), end = ctx.
end();
2132 if (it == end || *it ==
'}')
return it;
2134 it = detail::parse_align(it, end, specs_);
2135 if (it == end)
return it;
2138 if ((c >=
'0' && c <=
'9') || c ==
'{') {
2139 it = detail::parse_width(it, end, specs_, width_ref_, ctx);
2140 if (it == end)
return it;
2145 checker.has_precision_integral = !std::is_floating_point<Rep>::value;
2146 it = detail::parse_precision(it, end, specs_, precision_ref_, ctx);
2148 if (it != end && *it ==
'L') {
2149 specs_.set_localized();
2152 end = detail::parse_chrono_format(it, end, checker);
2153 fmt_ = {it, detail::to_unsigned(end - it)};
2157 template <
typename FormatContext>
2158 auto format(std::chrono::duration<Rep, Period> d, FormatContext& ctx)
const 2159 -> decltype(ctx.out()) {
2160 auto specs = specs_;
2161 auto precision = specs.precision;
2162 specs.precision = -1;
2163 auto begin = fmt_.begin(), end = fmt_.end();
2168 detail::handle_dynamic_spec(specs.dynamic_width(), specs.width, width_ref_,
2170 detail::handle_dynamic_spec(specs.dynamic_precision(), precision,
2171 precision_ref_, ctx);
2172 if (begin == end || *begin ==
'}') {
2173 out = detail::format_duration_value<Char>(out, d.count(), precision);
2174 detail::format_duration_unit<Char, Period>(out);
2178 f.precision = precision;
2179 f.localized = specs_.localized();
2180 detail::parse_chrono_format(begin, end, f);
2182 return detail::write(
2195 auto localized()
const ->
bool {
return specs_.localized(); }
2196 FMT_CONSTEXPR
void set_localized() { specs_.set_localized(); }
2200 auto it = ctx.
begin(), end = ctx.
end();
2201 if (it == end || *it ==
'}')
return it;
2203 it = detail::parse_align(it, end, specs_);
2204 if (it == end)
return it;
2207 if ((c >=
'0' && c <=
'9') || c ==
'{') {
2208 it = detail::parse_width(it, end, specs_, width_ref_, ctx);
2209 if (it == end)
return it;
2213 specs_.set_localized();
2217 end = detail::parse_chrono_format(it, end,
2220 if (end != it) fmt_ = {it, detail::to_unsigned(end - it)};
2224 template <
typename Duration,
typename FormatContext>
2225 auto do_format(
const std::tm& tm, FormatContext& ctx,
2226 const Duration* subsecs)
const -> decltype(ctx.out()) {
2227 auto specs = specs_;
2230 detail::handle_dynamic_spec(specs.dynamic_width(), specs.width, width_ref_,
2236 loc, out, tm, subsecs);
2237 detail::parse_chrono_format(fmt_.begin(), fmt_.end(), w);
2238 return detail::write(
2247 template <
typename FormatContext>
2248 auto format(
const std::tm& tm, FormatContext& ctx)
const 2249 -> decltype(ctx.out()) {
2250 return do_format<std::chrono::seconds>(tm, ctx,
nullptr);
2255 template <
typename Char,
typename Duration>
2258 return this->do_parse(ctx,
true);
2261 template <
typename FormatContext>
2262 auto format(sys_time<Duration> val, FormatContext& ctx)
const 2263 -> decltype(ctx.out()) {
2264 std::tm tm = gmtime(val);
2265 using period =
typename Duration::period;
2266 if (detail::const_check(
2267 period::num == 1 && period::den == 1 &&
2268 !std::is_floating_point<typename Duration::rep>::value)) {
2269 detail::set_tm_zone(tm, detail::utc());
2272 Duration epoch = val.time_since_epoch();
2273 Duration subsecs = detail::duration_cast<Duration>(
2274 epoch - detail::duration_cast<std::chrono::seconds>(epoch));
2275 if (subsecs.count() < 0) {
2276 auto second = detail::duration_cast<Duration>(std::chrono::seconds(1));
2277 if (tm.tm_sec != 0) {
2280 tm = gmtime(val - second);
2281 detail::set_tm_zone(tm, detail::utc());
2289 template <
typename Duration,
typename Char>
2292 template <
typename FormatContext>
2293 auto format(utc_time<Duration> val, FormatContext& ctx)
const 2294 -> decltype(ctx.out()) {
2296 detail::utc_clock::to_sys(val), ctx);
2300 template <
typename Duration,
typename Char>
2304 return this->do_parse(ctx,
false);
2307 template <
typename FormatContext>
2308 auto format(local_time<Duration> val, FormatContext& ctx)
const 2309 -> decltype(ctx.out()) {
2310 auto time_since_epoch = val.time_since_epoch();
2311 auto seconds_since_epoch =
2312 detail::duration_cast<std::chrono::seconds>(time_since_epoch);
2315 std::tm t = gmtime(seconds_since_epoch.count());
2316 using period =
typename Duration::period;
2317 if (period::num == 1 && period::den == 1 &&
2318 !std::is_floating_point<typename Duration::rep>::value) {
2322 detail::duration_cast<Duration>(time_since_epoch - seconds_since_epoch);
2330 #endif // FMT_CHRONO_H_ Definition: format.h:2469
A dynamically growing memory buffer for trivially copyable/constructible types with the first SIZE el...
Definition: format.h:778
Definition: chrono.h:1931
Definition: chrono.h:1953
Parsing context consisting of a format string range being parsed and an argument counter for automati...
Definition: base.h:640
Definition: chrono.h:1974
constexpr auto data() const noexcept -> const Char *
Returns a pointer to the string data.
Definition: base.h:561
constexpr auto size() const noexcept -> size_t
Returns the string size.
Definition: base.h:564
Definition: chrono.h:1964
constexpr auto end() const noexcept -> iterator
Returns an iterator past the end of the format string range being parsed.
Definition: base.h:889
constexpr auto size() const noexcept -> size_t
Returns the size of this buffer.
Definition: base.h:1789
Definition: chrono.h:1604
Definition: chrono.h:1942
FMT_CONSTEXPR20 void append(const U *begin, const U *end)
Appends data to the end of the buffer.
Definition: base.h:1829
Definition: format.h:1277
Definition: chrono.h:1677
FMT_CONSTEXPR auto data() noexcept -> T *
Returns a pointer to the buffer data (not null-terminated).
Definition: base.h:1795
constexpr auto begin() const noexcept -> iterator
Returns an iterator to the beginning of the format string range being parsed.
Definition: base.h:886
Definition: format.h:1260
Definition: chrono.h:1043
Definition: chrono.h:1136