20# include <type_traits>
28#ifndef FMT_USE_LOCAL_TIME
29# ifdef __cpp_lib_chrono
30# define FMT_USE_LOCAL_TIME (__cpp_lib_chrono >= 201907L)
32# define FMT_USE_LOCAL_TIME 0
37#ifndef FMT_USE_UTC_TIME
38# ifdef __cpp_lib_chrono
39# define FMT_USE_UTC_TIME (__cpp_lib_chrono >= 201907L)
41# define FMT_USE_UTC_TIME 0
48# if FMT_HAS_INCLUDE("winapifamily.h")
49# include <winapifamily.h>
51# if defined(_WIN32) && (!defined(WINAPI_FAMILY) || \
52 (WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP))
53# define FMT_USE_TZSET 1
55# define FMT_USE_TZSET 0
60#ifndef FMT_SAFE_DURATION_CAST
61# define FMT_SAFE_DURATION_CAST 1
63#if FMT_SAFE_DURATION_CAST
71namespace safe_duration_cast {
73template <
typename To,
typename From,
74 FMT_ENABLE_IF(!std::is_same<From, To>::value &&
75 std::numeric_limits<From>::is_signed ==
76 std::numeric_limits<To>::is_signed)>
77FMT_CONSTEXPR
auto lossless_integral_conversion(
const From from,
int& ec)
80 using F = std::numeric_limits<From>;
81 using T = std::numeric_limits<To>;
82 static_assert(F::is_integer,
"From must be integral");
83 static_assert(T::is_integer,
"To must be integral");
86 if (detail::const_check(F::digits <= T::digits)) {
90 if (from < (T::min)() || from > (T::max)()) {
96 return static_cast<To
>(from);
101template <
typename To,
typename From,
102 FMT_ENABLE_IF(!std::is_same<From, To>::value &&
103 std::numeric_limits<From>::is_signed !=
104 std::numeric_limits<To>::is_signed)>
105FMT_CONSTEXPR
auto lossless_integral_conversion(
const From from,
int& ec)
108 using F = std::numeric_limits<From>;
109 using T = std::numeric_limits<To>;
110 static_assert(F::is_integer,
"From must be integral");
111 static_assert(T::is_integer,
"To must be integral");
113 if (detail::const_check(F::is_signed && !T::is_signed)) {
115 if (fmt::detail::is_negative(from)) {
120 if (detail::const_check(F::digits > T::digits) &&
121 from >
static_cast<From
>(detail::max_value<To>())) {
127 if (detail::const_check(!F::is_signed && T::is_signed &&
128 F::digits >= T::digits) &&
129 from >
static_cast<From
>(detail::max_value<To>())) {
133 return static_cast<To
>(from);
136template <
typename To,
typename From,
137 FMT_ENABLE_IF(std::is_same<From, To>::value)>
138FMT_CONSTEXPR
auto lossless_integral_conversion(
const From from,
int& ec)
158template <
typename To,
typename From,
159 FMT_ENABLE_IF(!std::is_same<From, To>::value)>
160FMT_CONSTEXPR
auto safe_float_conversion(
const From from,
int& ec) -> To {
162 using T = std::numeric_limits<To>;
163 static_assert(std::is_floating_point<From>::value,
"From must be floating");
164 static_assert(std::is_floating_point<To>::value,
"To must be floating");
167 if (std::isfinite(from)) {
168 if (from >= T::lowest() && from <= (T::max)()) {
169 return static_cast<To
>(from);
177 return static_cast<To
>(from);
180template <
typename To,
typename From,
181 FMT_ENABLE_IF(std::is_same<From, To>::value)>
182FMT_CONSTEXPR
auto safe_float_conversion(
const From from,
int& ec) -> To {
184 static_assert(std::is_floating_point<From>::value,
"From must be floating");
189template <
typename To,
typename FromRep,
typename FromPeriod,
190 FMT_ENABLE_IF(std::is_integral<FromRep>::value),
191 FMT_ENABLE_IF(std::is_integral<typename To::rep>::value)>
192auto safe_duration_cast(std::chrono::duration<FromRep, FromPeriod> from,
194 using From = std::chrono::duration<FromRep, FromPeriod>;
199 : std::ratio_divide<typename From::period, typename To::period> {};
201 static_assert(Factor::num > 0,
"num must be positive");
202 static_assert(Factor::den > 0,
"den must be positive");
208 using IntermediateRep =
209 typename std::common_type<
typename From::rep,
typename To::rep,
210 decltype(Factor::num)>::type;
213 IntermediateRep count =
214 lossless_integral_conversion<IntermediateRep>(from.count(), ec);
217 if (detail::const_check(Factor::num != 1)) {
218 const auto max1 = detail::max_value<IntermediateRep>() / Factor::num;
224 (std::numeric_limits<IntermediateRep>::min)() / Factor::num;
225 if (detail::const_check(!std::is_unsigned<IntermediateRep>::value) &&
230 count *= Factor::num;
233 if (detail::const_check(Factor::den != 1)) count /= Factor::den;
234 auto tocount = lossless_integral_conversion<typename To::rep>(count, ec);
235 return ec ? To() : To(tocount);
239template <
typename To,
typename FromRep,
typename FromPeriod,
240 FMT_ENABLE_IF(std::is_floating_point<FromRep>::value),
241 FMT_ENABLE_IF(std::is_floating_point<typename To::rep>::value)>
242auto safe_duration_cast(std::chrono::duration<FromRep, FromPeriod> from,
244 using From = std::chrono::duration<FromRep, FromPeriod>;
246 if (std::isnan(from.count())) {
248 return To{std::numeric_limits<typename To::rep>::quiet_NaN()};
254 if (std::isinf(from.count())) {
255 return To{from.count()};
261 : std::ratio_divide<typename From::period, typename To::period> {};
263 static_assert(Factor::num > 0,
"num must be positive");
264 static_assert(Factor::den > 0,
"den must be positive");
270 using IntermediateRep =
271 typename std::common_type<
typename From::rep,
typename To::rep,
272 decltype(Factor::num)>::type;
276 IntermediateRep count =
277 safe_float_conversion<IntermediateRep>(from.count(), ec);
283 if (detail::const_check(Factor::num != 1)) {
284 constexpr auto max1 = detail::max_value<IntermediateRep>() /
285 static_cast<IntermediateRep
>(Factor::num);
290 constexpr auto min1 = std::numeric_limits<IntermediateRep>::lowest() /
291 static_cast<IntermediateRep
>(Factor::num);
296 count *=
static_cast<IntermediateRep
>(Factor::num);
300 if (detail::const_check(Factor::den != 1)) {
301 using common_t =
typename std::common_type<IntermediateRep, intmax_t>::type;
302 count /=
static_cast<common_t
>(Factor::den);
306 using ToRep =
typename To::rep;
308 const ToRep tocount = safe_float_conversion<ToRep>(count, ec);
322template <
typename T =
void>
struct null {};
323inline auto localtime_r FMT_NOMACRO(...) ->
null<> {
return null<>(); }
324inline auto localtime_s(...) -> null<> {
return null<>(); }
330template <
typename Streambuf>
class formatbuf :
public Streambuf {
332 using char_type =
typename Streambuf::char_type;
333 using streamsize =
decltype(std::declval<Streambuf>().sputn(
nullptr, 0));
334 using int_type =
typename Streambuf::int_type;
335 using traits_type =
typename Streambuf::traits_type;
349 auto overflow(int_type ch) -> int_type
override {
350 if (!traits_type::eq_int_type(ch, traits_type::eof()))
351 buffer_.push_back(
static_cast<char_type
>(ch));
355 auto xsputn(
const char_type* s, streamsize count) -> streamsize
override {
356 buffer_.append(s, s + count);
361inline auto get_classic_locale() ->
const std::locale& {
362 static const auto& locale = std::locale::classic();
367 static constexpr const size_t max_size = 32;
368 CodeUnit buf[max_size];
372template <
typename CodeUnit>
374 const std::locale& loc) {
376# pragma clang diagnostic push
377# pragma clang diagnostic ignored "-Wdeprecated"
378 auto& f = std::use_facet<std::codecvt<CodeUnit, char, std::mbstate_t>>(loc);
379# pragma clang diagnostic pop
381 auto& f = std::use_facet<std::codecvt<CodeUnit, char, std::mbstate_t>>(loc);
383 auto mb = std::mbstate_t();
384 const char* from_next =
nullptr;
385 auto result = f.in(mb, in_buf.begin(), in_buf.end(), from_next,
386 std::begin(out.buf), std::end(out.buf), out.end);
387 if (result != std::codecvt_base::ok)
388 FMT_THROW(format_error(
"failed to format time"));
391template <
typename OutputIt>
392auto write_encoded_tm_str(OutputIt out, string_view in,
const std::locale& loc)
394 if (detail::use_utf8() && loc != get_classic_locale()) {
397#if FMT_MSC_VERSION != 0 || \
398 (defined(__GLIBCXX__) && \
399 (!defined(_GLIBCXX_USE_DUAL_ABI) || _GLIBCXX_USE_DUAL_ABI == 0))
402 using code_unit = wchar_t;
404 using code_unit = char32_t;
407 using unit_t = codecvt_result<code_unit>;
409 write_codecvt(unit, in, loc);
412 to_utf8<code_unit, basic_memory_buffer<char, unit_t::max_size * 4>>();
413 if (!u.convert({unit.buf, to_unsigned(unit.end - unit.buf)}))
414 FMT_THROW(format_error(
"failed to format time"));
415 return copy<char>(u.c_str(), u.c_str() + u.size(), out);
417 return copy<char>(in.data(), in.data() + in.size(), out);
420template <
typename Char,
typename OutputIt,
421 FMT_ENABLE_IF(!std::is_same<Char, char>::value)>
422auto write_tm_str(OutputIt out, string_view sv,
const std::locale& loc)
425 write_codecvt(unit, sv, loc);
426 return copy<Char>(unit.buf, unit.end, out);
429template <
typename Char,
typename OutputIt,
430 FMT_ENABLE_IF(std::is_same<Char, char>::value)>
431auto write_tm_str(OutputIt out, string_view sv,
const std::locale& loc)
433 return write_encoded_tm_str(out, sv, loc);
436template <
typename Char>
437inline void do_write(
buffer<Char>& buf,
const std::tm& time,
438 const std::locale& loc,
char format,
char modifier) {
440 auto&& os = std::basic_ostream<Char>(&format_buf);
442 const auto& facet = std::use_facet<std::time_put<Char>>(loc);
443 auto end = facet.put(os, os, Char(
' '), &time, format, modifier);
444 if (end.failed()) FMT_THROW(format_error(
"failed to format time"));
447template <
typename Char,
typename OutputIt,
448 FMT_ENABLE_IF(!std::is_same<Char, char>::value)>
449auto write(OutputIt out,
const std::tm& time,
const std::locale& loc,
450 char format,
char modifier = 0) -> OutputIt {
451 auto&& buf = get_buffer<Char>(out);
452 do_write<Char>(buf, time, loc, format, modifier);
453 return get_iterator(buf, out);
456template <
typename Char,
typename OutputIt,
457 FMT_ENABLE_IF(std::is_same<Char, char>::value)>
458auto write(OutputIt out,
const std::tm& time,
const std::locale& loc,
459 char format,
char modifier = 0) -> OutputIt {
460 auto&& buf = basic_memory_buffer<Char>();
461 do_write<char>(buf, time, loc, format, modifier);
462 return write_encoded_tm_str(out, string_view(buf.data(), buf.size()), loc);
465template <
typename Rep1,
typename Rep2>
467 :
public std::integral_constant<bool,
468 (std::is_integral<Rep1>::value &&
469 std::is_integral<Rep2>::value) ||
470 (std::is_floating_point<Rep1>::value &&
471 std::is_floating_point<Rep2>::value)> {
475 typename To,
typename FromRep,
typename FromPeriod,
477auto fmt_duration_cast(std::chrono::duration<FromRep, FromPeriod> from) -> To {
478#if FMT_SAFE_DURATION_CAST
482 To to = safe_duration_cast::safe_duration_cast<To>(from, ec);
483 if (ec) FMT_THROW(format_error(
"cannot format duration"));
487 return std::chrono::duration_cast<To>(from);
492 typename To,
typename FromRep,
typename FromPeriod,
493 FMT_ENABLE_IF(!is_same_arithmetic_type<FromRep, typename To::rep>::value)>
494auto fmt_duration_cast(std::chrono::duration<FromRep, FromPeriod> from) -> To {
496 return std::chrono::duration_cast<To>(from);
499template <
typename Duration>
501 std::chrono::time_point<std::chrono::system_clock, Duration> time_point)
506 return fmt_duration_cast<std::chrono::duration<std::time_t>>(
507 time_point.time_since_epoch())
519inline auto localtime(std::time_t time) -> std::tm {
524 dispatcher(std::time_t t) : time_(t) {}
527 using namespace fmt::detail;
528 return handle(localtime_r(&time_, &tm_));
531 auto handle(std::tm* tm) ->
bool {
return tm !=
nullptr; }
533 auto handle(detail::null<>) ->
bool {
534 using namespace fmt::detail;
535 return fallback(localtime_s(&tm_, &time_));
538 auto fallback(
int res) ->
bool {
return res == 0; }
541 auto fallback(detail::null<>) ->
bool {
542 using namespace fmt::detail;
543 std::tm* tm = std::localtime(&time_);
545 return tm !=
nullptr;
551 if (!lt.run()) FMT_THROW(format_error(
"time_t value out of range"));
555#if FMT_USE_LOCAL_TIME
556template <
typename Duration>
557inline auto localtime(std::chrono::local_time<Duration> time) -> std::tm {
559 detail::to_time_t(std::chrono::current_zone()->to_sys(time)));
568inline auto gmtime(std::time_t time) -> std::tm {
573 dispatcher(std::time_t t) : time_(t) {}
576 using namespace fmt::detail;
577 return handle(gmtime_r(&time_, &tm_));
580 auto handle(std::tm* tm) ->
bool {
return tm !=
nullptr; }
582 auto handle(detail::null<>) ->
bool {
583 using namespace fmt::detail;
584 return fallback(gmtime_s(&tm_, &time_));
587 auto fallback(
int res) ->
bool {
return res == 0; }
590 auto fallback(detail::null<>) ->
bool {
591 std::tm* tm = std::gmtime(&time_);
593 return tm !=
nullptr;
597 auto gt = dispatcher(time);
599 if (!gt.run()) FMT_THROW(format_error(
"time_t value out of range"));
603template <
typename Duration>
605 std::chrono::time_point<std::chrono::system_clock, Duration> time_point)
607 return gmtime(detail::to_time_t(time_point));
615inline void write_digit2_separated(
char* buf,
unsigned a,
unsigned b,
616 unsigned c,
char sep) {
617 unsigned long long digits =
618 a | (b << 24) | (static_cast<unsigned long long>(c) << 48);
628 digits += (((digits * 205) >> 11) & 0x000f00000f00000f) * 6;
630 digits = ((digits & 0x00f00000f00000f0) >> 4) |
631 ((digits & 0x000f00000f00000f) << 8);
632 auto usep =
static_cast<unsigned long long>(sep);
634 digits |= 0x3030003030003030 | (usep << 16) | (usep << 40);
636 constexpr const size_t len = 8;
637 if (const_check(is_big_endian())) {
639 std::memcpy(tmp, &digits, len);
640 std::reverse_copy(tmp, tmp + len, buf);
642 std::memcpy(buf, &digits, len);
646template <
typename Period>
647FMT_CONSTEXPR
inline auto get_units() ->
const char* {
648 if (std::is_same<Period, std::atto>::value)
return "as";
649 if (std::is_same<Period, std::femto>::value)
return "fs";
650 if (std::is_same<Period, std::pico>::value)
return "ps";
651 if (std::is_same<Period, std::nano>::value)
return "ns";
652 if (std::is_same<Period, std::micro>::value)
return "µs";
653 if (std::is_same<Period, std::milli>::value)
return "ms";
654 if (std::is_same<Period, std::centi>::value)
return "cs";
655 if (std::is_same<Period, std::deci>::value)
return "ds";
656 if (std::is_same<Period, std::ratio<1>>::value)
return "s";
657 if (std::is_same<Period, std::deca>::value)
return "das";
658 if (std::is_same<Period, std::hecto>::value)
return "hs";
659 if (std::is_same<Period, std::kilo>::value)
return "ks";
660 if (std::is_same<Period, std::mega>::value)
return "Ms";
661 if (std::is_same<Period, std::giga>::value)
return "Gs";
662 if (std::is_same<Period, std::tera>::value)
return "Ts";
663 if (std::is_same<Period, std::peta>::value)
return "Ps";
664 if (std::is_same<Period, std::exa>::value)
return "Es";
665 if (std::is_same<Period, std::ratio<60>>::value)
return "min";
666 if (std::is_same<Period, std::ratio<3600>>::value)
return "h";
667 if (std::is_same<Period, std::ratio<86400>>::value)
return "d";
671enum class numeric_system {
687template <
typename OutputIt>
688auto write_padding(OutputIt out, pad_type pad,
int width) -> OutputIt {
689 if (pad == pad_type::none)
return out;
690 return detail::fill_n(out, width, pad == pad_type::space ?
' ' :
'0');
693template <
typename OutputIt>
694auto write_padding(OutputIt out, pad_type pad) -> OutputIt {
695 if (pad != pad_type::none) *out++ = pad == pad_type::space ?
' ' :
'0';
700template <
typename Char,
typename Handler>
701FMT_CONSTEXPR
auto parse_chrono_format(
const Char* begin,
const Char* end,
702 Handler&& handler) ->
const Char* {
703 if (begin == end || *begin ==
'}')
return begin;
704 if (*begin !=
'%') FMT_THROW(format_error(
"invalid format"));
707 pad_type pad = pad_type::zero;
714 if (begin != ptr) handler.on_text(begin, ptr);
716 if (ptr == end) FMT_THROW(format_error(
"invalid format"));
720 pad = pad_type::space;
724 pad = pad_type::none;
728 if (ptr == end) FMT_THROW(format_error(
"invalid format"));
732 handler.on_text(ptr - 1, ptr);
735 const Char newline[] = {
'\n'};
736 handler.on_text(newline, newline + 1);
740 const Char tab[] = {
'\t'};
741 handler.on_text(tab, tab + 1);
746 handler.on_year(numeric_system::standard);
749 handler.on_short_year(numeric_system::standard);
752 handler.on_century(numeric_system::standard);
755 handler.on_iso_week_based_year();
758 handler.on_iso_week_based_short_year();
762 handler.on_abbr_weekday();
765 handler.on_full_weekday();
768 handler.on_dec0_weekday(numeric_system::standard);
771 handler.on_dec1_weekday(numeric_system::standard);
776 handler.on_abbr_month();
779 handler.on_full_month();
782 handler.on_dec_month(numeric_system::standard);
786 handler.on_dec0_week_of_year(numeric_system::standard, pad);
789 handler.on_dec1_week_of_year(numeric_system::standard, pad);
792 handler.on_iso_week_of_year(numeric_system::standard, pad);
795 handler.on_day_of_year();
798 handler.on_day_of_month(numeric_system::standard, pad);
801 handler.on_day_of_month(numeric_system::standard, pad_type::space);
805 handler.on_24_hour(numeric_system::standard, pad);
808 handler.on_12_hour(numeric_system::standard, pad);
811 handler.on_minute(numeric_system::standard, pad);
814 handler.on_second(numeric_system::standard, pad);
818 handler.on_datetime(numeric_system::standard);
821 handler.on_loc_date(numeric_system::standard);
824 handler.on_loc_time(numeric_system::standard);
827 handler.on_us_date();
830 handler.on_iso_date();
833 handler.on_12_hour_time();
836 handler.on_24_hour_time();
839 handler.on_iso_time();
845 handler.on_duration_value();
848 handler.on_duration_unit();
851 handler.on_utc_offset(numeric_system::standard);
854 handler.on_tz_name();
858 if (ptr == end) FMT_THROW(format_error(
"invalid format"));
862 handler.on_year(numeric_system::alternative);
865 handler.on_offset_year();
868 handler.on_century(numeric_system::alternative);
871 handler.on_datetime(numeric_system::alternative);
874 handler.on_loc_date(numeric_system::alternative);
877 handler.on_loc_time(numeric_system::alternative);
880 handler.on_utc_offset(numeric_system::alternative);
883 FMT_THROW(format_error(
"invalid format"));
888 if (ptr == end) FMT_THROW(format_error(
"invalid format"));
892 handler.on_short_year(numeric_system::alternative);
895 handler.on_dec_month(numeric_system::alternative);
898 handler.on_dec0_week_of_year(numeric_system::alternative, pad);
901 handler.on_dec1_week_of_year(numeric_system::alternative, pad);
904 handler.on_iso_week_of_year(numeric_system::alternative, pad);
907 handler.on_day_of_month(numeric_system::alternative, pad);
910 handler.on_day_of_month(numeric_system::alternative, pad_type::space);
913 handler.on_dec0_weekday(numeric_system::alternative);
916 handler.on_dec1_weekday(numeric_system::alternative);
919 handler.on_24_hour(numeric_system::alternative, pad);
922 handler.on_12_hour(numeric_system::alternative, pad);
925 handler.on_minute(numeric_system::alternative, pad);
928 handler.on_second(numeric_system::alternative, pad);
931 handler.on_utc_offset(numeric_system::alternative);
934 FMT_THROW(format_error(
"invalid format"));
938 FMT_THROW(format_error(
"invalid format"));
942 if (begin != ptr) handler.on_text(begin, ptr);
947 FMT_CONSTEXPR
void unsupported() {
948 static_cast<Derived*
>(
this)->unsupported();
950 FMT_CONSTEXPR
void on_year(numeric_system) { unsupported(); }
951 FMT_CONSTEXPR
void on_short_year(numeric_system) { unsupported(); }
952 FMT_CONSTEXPR
void on_offset_year() { unsupported(); }
953 FMT_CONSTEXPR
void on_century(numeric_system) { unsupported(); }
954 FMT_CONSTEXPR
void on_iso_week_based_year() { unsupported(); }
955 FMT_CONSTEXPR
void on_iso_week_based_short_year() { unsupported(); }
956 FMT_CONSTEXPR
void on_abbr_weekday() { unsupported(); }
957 FMT_CONSTEXPR
void on_full_weekday() { unsupported(); }
958 FMT_CONSTEXPR
void on_dec0_weekday(numeric_system) { unsupported(); }
959 FMT_CONSTEXPR
void on_dec1_weekday(numeric_system) { unsupported(); }
960 FMT_CONSTEXPR
void on_abbr_month() { unsupported(); }
961 FMT_CONSTEXPR
void on_full_month() { unsupported(); }
962 FMT_CONSTEXPR
void on_dec_month(numeric_system) { unsupported(); }
963 FMT_CONSTEXPR
void on_dec0_week_of_year(numeric_system, pad_type) {
966 FMT_CONSTEXPR
void on_dec1_week_of_year(numeric_system, pad_type) {
969 FMT_CONSTEXPR
void on_iso_week_of_year(numeric_system, pad_type) {
972 FMT_CONSTEXPR
void on_day_of_year() { unsupported(); }
973 FMT_CONSTEXPR
void on_day_of_month(numeric_system, pad_type) {
976 FMT_CONSTEXPR
void on_24_hour(numeric_system) { unsupported(); }
977 FMT_CONSTEXPR
void on_12_hour(numeric_system) { unsupported(); }
978 FMT_CONSTEXPR
void on_minute(numeric_system) { unsupported(); }
979 FMT_CONSTEXPR
void on_second(numeric_system) { unsupported(); }
980 FMT_CONSTEXPR
void on_datetime(numeric_system) { unsupported(); }
981 FMT_CONSTEXPR
void on_loc_date(numeric_system) { unsupported(); }
982 FMT_CONSTEXPR
void on_loc_time(numeric_system) { unsupported(); }
983 FMT_CONSTEXPR
void on_us_date() { unsupported(); }
984 FMT_CONSTEXPR
void on_iso_date() { unsupported(); }
985 FMT_CONSTEXPR
void on_12_hour_time() { unsupported(); }
986 FMT_CONSTEXPR
void on_24_hour_time() { unsupported(); }
987 FMT_CONSTEXPR
void on_iso_time() { unsupported(); }
988 FMT_CONSTEXPR
void on_am_pm() { unsupported(); }
989 FMT_CONSTEXPR
void on_duration_value() { unsupported(); }
990 FMT_CONSTEXPR
void on_duration_unit() { unsupported(); }
991 FMT_CONSTEXPR
void on_utc_offset(numeric_system) { unsupported(); }
992 FMT_CONSTEXPR
void on_tz_name() { unsupported(); }
996 FMT_NORETURN
void unsupported() { FMT_THROW(format_error(
"no format")); }
998 template <
typename Char>
999 FMT_CONSTEXPR
void on_text(
const Char*,
const Char*) {}
1000 FMT_CONSTEXPR
void on_year(numeric_system) {}
1001 FMT_CONSTEXPR
void on_short_year(numeric_system) {}
1002 FMT_CONSTEXPR
void on_offset_year() {}
1003 FMT_CONSTEXPR
void on_century(numeric_system) {}
1004 FMT_CONSTEXPR
void on_iso_week_based_year() {}
1005 FMT_CONSTEXPR
void on_iso_week_based_short_year() {}
1006 FMT_CONSTEXPR
void on_abbr_weekday() {}
1007 FMT_CONSTEXPR
void on_full_weekday() {}
1008 FMT_CONSTEXPR
void on_dec0_weekday(numeric_system) {}
1009 FMT_CONSTEXPR
void on_dec1_weekday(numeric_system) {}
1010 FMT_CONSTEXPR
void on_abbr_month() {}
1011 FMT_CONSTEXPR
void on_full_month() {}
1012 FMT_CONSTEXPR
void on_dec_month(numeric_system) {}
1013 FMT_CONSTEXPR
void on_dec0_week_of_year(numeric_system, pad_type) {}
1014 FMT_CONSTEXPR
void on_dec1_week_of_year(numeric_system, pad_type) {}
1015 FMT_CONSTEXPR
void on_iso_week_of_year(numeric_system, pad_type) {}
1016 FMT_CONSTEXPR
void on_day_of_year() {}
1017 FMT_CONSTEXPR
void on_day_of_month(numeric_system, pad_type) {}
1018 FMT_CONSTEXPR
void on_24_hour(numeric_system, pad_type) {}
1019 FMT_CONSTEXPR
void on_12_hour(numeric_system, pad_type) {}
1020 FMT_CONSTEXPR
void on_minute(numeric_system, pad_type) {}
1021 FMT_CONSTEXPR
void on_second(numeric_system, pad_type) {}
1022 FMT_CONSTEXPR
void on_datetime(numeric_system) {}
1023 FMT_CONSTEXPR
void on_loc_date(numeric_system) {}
1024 FMT_CONSTEXPR
void on_loc_time(numeric_system) {}
1025 FMT_CONSTEXPR
void on_us_date() {}
1026 FMT_CONSTEXPR
void on_iso_date() {}
1027 FMT_CONSTEXPR
void on_12_hour_time() {}
1028 FMT_CONSTEXPR
void on_24_hour_time() {}
1029 FMT_CONSTEXPR
void on_iso_time() {}
1030 FMT_CONSTEXPR
void on_am_pm() {}
1031 FMT_CONSTEXPR
void on_utc_offset(numeric_system) {}
1032 FMT_CONSTEXPR
void on_tz_name() {}
1035inline auto tm_wday_full_name(
int wday) ->
const char* {
1036 static constexpr const char* full_name_list[] = {
1037 "Sunday",
"Monday",
"Tuesday",
"Wednesday",
1038 "Thursday",
"Friday",
"Saturday"};
1039 return wday >= 0 && wday <= 6 ? full_name_list[wday] :
"?";
1041inline auto tm_wday_short_name(
int wday) ->
const char* {
1042 static constexpr const char* short_name_list[] = {
"Sun",
"Mon",
"Tue",
"Wed",
1043 "Thu",
"Fri",
"Sat"};
1044 return wday >= 0 && wday <= 6 ? short_name_list[wday] :
"???";
1047inline auto tm_mon_full_name(
int mon) ->
const char* {
1048 static constexpr const char* full_name_list[] = {
1049 "January",
"February",
"March",
"April",
"May",
"June",
1050 "July",
"August",
"September",
"October",
"November",
"December"};
1051 return mon >= 0 && mon <= 11 ? full_name_list[mon] :
"?";
1053inline auto tm_mon_short_name(
int mon) ->
const char* {
1054 static constexpr const char* short_name_list[] = {
1055 "Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
1056 "Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec",
1058 return mon >= 0 && mon <= 11 ? short_name_list[mon] :
"???";
1061template <
typename T,
typename =
void>
1063template <
typename T>
1065 : std::true_type {};
1067template <
typename T,
typename =
void>
1069template <
typename T>
1071 : std::true_type {};
1074inline void tzset_once() {
1075 static bool init = []() ->
bool {
1079 ignore_unused(init);
1084template <
typename T,
typename Int, FMT_ENABLE_IF(std::is_
integral<T>::value)>
1085inline auto to_nonnegative_int(T
value, Int upper) -> Int {
1086 if (!std::is_unsigned<Int>::value &&
1087 (
value < 0 || to_unsigned(
value) > to_unsigned(upper))) {
1088 FMT_THROW(fmt::format_error(
"chrono value is out of range"));
1090 return static_cast<Int
>(
value);
1092template <
typename T,
typename Int, FMT_ENABLE_IF(!std::is_
integral<T>::value)>
1093inline auto to_nonnegative_int(T
value, Int upper) -> Int {
1094 auto int_value =
static_cast<Int
>(
value);
1095 if (int_value < 0 || value >
static_cast<T
>(upper))
1096 FMT_THROW(format_error(
"invalid value"));
1100constexpr auto pow10(std::uint32_t n) ->
long long {
1101 return n == 0 ? 1 : 10 * pow10(n - 1);
1107template <
long long Num,
long long Den,
int N = 0,
1108 bool Enabled = (N < 19) && (Num <= max_value<long long>() / 10)>
1110 static constexpr int value =
1111 Num % Den == 0 ? N : count_fractional_digits<Num * 10, Den, N + 1>::value;
1116template <
long long Num,
long long Den,
int N>
1118 static constexpr int value = (Num % Den == 0) ? N : 6;
1123template <
typename Char,
typename OutputIt,
typename Duration>
1124void write_fractional_seconds(OutputIt& out, Duration d,
int precision = -1) {
1125 constexpr auto num_fractional_digits =
1127 Duration::period::den>
::value;
1129 using subsecond_precision = std::chrono::duration<
1130 typename std::common_type<
typename Duration::rep,
1131 std::chrono::seconds::rep>::type,
1132 std::ratio<1, detail::pow10(num_fractional_digits)>>;
1134 const auto fractional = d - fmt_duration_cast<std::chrono::seconds>(d);
1135 const auto subseconds =
1136 std::chrono::treat_as_floating_point<
1137 typename subsecond_precision::rep>
::value
1138 ? fractional.count()
1139 : fmt_duration_cast<subsecond_precision>(fractional).count();
1140 auto n =
static_cast<uint32_or_64_or_128_t<long long>
>(subseconds);
1141 const int num_digits = detail::count_digits(n);
1143 int leading_zeroes = (std::max)(0, num_fractional_digits - num_digits);
1144 if (precision < 0) {
1145 FMT_ASSERT(!std::is_floating_point<typename Duration::rep>::value,
"");
1146 if (std::ratio_less<
typename subsecond_precision::period,
1147 std::chrono::seconds::period>
::value) {
1149 out = detail::fill_n(out, leading_zeroes,
'0');
1150 out = format_decimal<Char>(out, n, num_digits).end;
1152 }
else if (precision > 0) {
1154 leading_zeroes = (std::min)(leading_zeroes, precision);
1155 int remaining = precision - leading_zeroes;
1156 out = detail::fill_n(out, leading_zeroes,
'0');
1157 if (remaining < num_digits) {
1158 int num_truncated_digits = num_digits - remaining;
1159 n /= to_unsigned(detail::pow10(to_unsigned(num_truncated_digits)));
1161 out = format_decimal<Char>(out, n, remaining).end;
1166 out = format_decimal<Char>(out, n, num_digits).end;
1167 remaining -= num_digits;
1169 out = detail::fill_n(out, remaining,
'0');
1176template <
typename Duration>
1177void write_floating_seconds(memory_buffer& buf, Duration duration,
1178 int num_fractional_digits = -1) {
1179 using rep =
typename Duration::rep;
1180 FMT_ASSERT(std::is_floating_point<rep>::value,
"");
1182 auto val = duration.count();
1184 if (num_fractional_digits < 0) {
1187 using namespace std;
1188 num_fractional_digits =
1190 Duration::period::den>::value;
1191 if (num_fractional_digits < 6 &&
static_cast<rep
>(round(val)) != val)
1192 num_fractional_digits = 6;
1195 fmt::format_to(std::back_inserter(buf), FMT_STRING(
"{:.{}f}"),
1196 std::fmod(val *
static_cast<rep
>(Duration::period::num) /
1197 static_cast<rep
>(Duration::period::den),
1198 static_cast<rep
>(60)),
1199 num_fractional_digits);
1202template <
typename OutputIt,
typename Char,
1203 typename Duration = std::chrono::seconds>
1206 static constexpr int days_per_week = 7;
1208 const std::locale& loc_;
1209 const bool is_classic_;
1211 const Duration* subsecs_;
1214 auto tm_sec()
const noexcept ->
int {
1215 FMT_ASSERT(tm_.tm_sec >= 0 && tm_.tm_sec <= 61,
"");
1218 auto tm_min()
const noexcept ->
int {
1219 FMT_ASSERT(tm_.tm_min >= 0 && tm_.tm_min <= 59,
"");
1222 auto tm_hour()
const noexcept ->
int {
1223 FMT_ASSERT(tm_.tm_hour >= 0 && tm_.tm_hour <= 23,
"");
1226 auto tm_mday()
const noexcept ->
int {
1227 FMT_ASSERT(tm_.tm_mday >= 1 && tm_.tm_mday <= 31,
"");
1230 auto tm_mon()
const noexcept ->
int {
1231 FMT_ASSERT(tm_.tm_mon >= 0 && tm_.tm_mon <= 11,
"");
1234 auto tm_year()
const noexcept ->
long long {
return 1900ll + tm_.tm_year; }
1235 auto tm_wday()
const noexcept ->
int {
1236 FMT_ASSERT(tm_.tm_wday >= 0 && tm_.tm_wday <= 6,
"");
1239 auto tm_yday()
const noexcept ->
int {
1240 FMT_ASSERT(tm_.tm_yday >= 0 && tm_.tm_yday <= 365,
"");
1244 auto tm_hour12()
const noexcept ->
int {
1245 const auto h = tm_hour();
1246 const auto z = h < 12 ? h : h - 12;
1247 return z == 0 ? 12 : z;
1254 auto split_year_lower(
long long year)
const noexcept ->
int {
1255 auto l =
year % 100;
1257 return static_cast<int>(l);
1261 auto iso_year_weeks(
long long curr_year)
const noexcept ->
int {
1262 const auto prev_year = curr_year - 1;
1264 (curr_year + curr_year / 4 - curr_year / 100 + curr_year / 400) %
1267 (prev_year + prev_year / 4 - prev_year / 100 + prev_year / 400) %
1269 return 52 + ((curr_p == 4 || prev_p == 3) ? 1 : 0);
1271 auto iso_week_num(
int tm_yday,
int tm_wday)
const noexcept ->
int {
1272 return (tm_yday + 11 - (tm_wday == 0 ? days_per_week : tm_wday)) /
1275 auto tm_iso_week_year()
const noexcept ->
long long {
1276 const auto year = tm_year();
1277 const auto w = iso_week_num(tm_yday(), tm_wday());
1278 if (w < 1)
return year - 1;
1279 if (w > iso_year_weeks(
year))
return year + 1;
1282 auto tm_iso_week_of_year()
const noexcept ->
int {
1283 const auto year = tm_year();
1284 const auto w = iso_week_num(tm_yday(), tm_wday());
1285 if (w < 1)
return iso_year_weeks(
year - 1);
1286 if (w > iso_year_weeks(
year))
return 1;
1290 void write1(
int value) {
1291 *out_++ =
static_cast<char>(
'0' + to_unsigned(
value) % 10);
1293 void write2(
int value) {
1294 const char* d = digits2(to_unsigned(
value) % 100);
1298 void write2(
int value, pad_type pad) {
1299 unsigned int v = to_unsigned(
value) % 100;
1301 const char* d = digits2(v);
1305 out_ = detail::write_padding(out_, pad);
1306 *out_++ =
static_cast<char>(
'0' + v);
1310 void write_year_extended(
long long year) {
1318 uint32_or_64_or_128_t<long long> n = to_unsigned(
year);
1319 const int num_digits = count_digits(n);
1320 if (width > num_digits)
1321 out_ = detail::fill_n(out_, width - num_digits,
'0');
1322 out_ = format_decimal<Char>(out_, n, num_digits).end;
1324 void write_year(
long long year) {
1326 write2(
static_cast<int>(
year / 100));
1327 write2(
static_cast<int>(
year % 100));
1329 write_year_extended(
year);
1333 void write_utc_offset(
long offset, numeric_system ns) {
1341 write2(
static_cast<int>(offset / 60));
1342 if (ns != numeric_system::standard) *out_++ =
':';
1343 write2(
static_cast<int>(offset % 60));
1345 template <
typename T, FMT_ENABLE_IF(has_member_data_tm_gmtoff<T>::value)>
1346 void format_utc_offset_impl(
const T& tm, numeric_system ns) {
1347 write_utc_offset(tm.tm_gmtoff, ns);
1349 template <
typename T, FMT_ENABLE_IF(!has_member_data_tm_gmtoff<T>::value)>
1350 void format_utc_offset_impl(
const T& tm, numeric_system ns) {
1351#if defined(_WIN32) && defined(_UCRT)
1356 _get_timezone(&offset);
1359 _get_dstbias(&dstbias);
1362 write_utc_offset(-offset, ns);
1364 if (ns == numeric_system::standard)
return format_localized(
'z');
1368 std::time_t gt = std::mktime(>m);
1369 std::tm ltm = gmtime(gt);
1370 std::time_t lt = std::mktime(<m);
1371 long offset = gt - lt;
1372 write_utc_offset(offset, ns);
1376 template <
typename T, FMT_ENABLE_IF(has_member_data_tm_zone<T>::value)>
1377 void format_tz_name_impl(
const T& tm) {
1379 out_ = write_tm_str<Char>(out_, tm.tm_zone, loc_);
1381 format_localized(
'Z');
1383 template <
typename T, FMT_ENABLE_IF(!has_member_data_tm_zone<T>::value)>
1384 void format_tz_name_impl(
const T&) {
1385 format_localized(
'Z');
1388 void format_localized(
char format,
char modifier = 0) {
1389 out_ = write<Char>(out_, tm_, loc_, format, modifier);
1393 tm_writer(
const std::locale& loc, OutputIt out,
const std::tm& tm,
1394 const Duration* subsecs =
nullptr)
1396 is_classic_(loc_ == get_classic_locale()),
1401 auto out()
const -> OutputIt {
return out_; }
1403 FMT_CONSTEXPR
void on_text(
const Char* begin,
const Char* end) {
1404 out_ = copy<Char>(begin, end, out_);
1407 void on_abbr_weekday() {
1409 out_ = write(out_, tm_wday_short_name(tm_wday()));
1411 format_localized(
'a');
1413 void on_full_weekday() {
1415 out_ = write(out_, tm_wday_full_name(tm_wday()));
1417 format_localized(
'A');
1419 void on_dec0_weekday(numeric_system ns) {
1420 if (is_classic_ || ns == numeric_system::standard)
return write1(tm_wday());
1421 format_localized(
'w',
'O');
1423 void on_dec1_weekday(numeric_system ns) {
1424 if (is_classic_ || ns == numeric_system::standard) {
1425 auto wday = tm_wday();
1426 write1(wday == 0 ? days_per_week : wday);
1428 format_localized(
'u',
'O');
1432 void on_abbr_month() {
1434 out_ = write(out_, tm_mon_short_name(tm_mon()));
1436 format_localized(
'b');
1438 void on_full_month() {
1440 out_ = write(out_, tm_mon_full_name(tm_mon()));
1442 format_localized(
'B');
1445 void on_datetime(numeric_system ns) {
1451 on_day_of_month(numeric_system::standard, pad_type::space);
1455 on_year(numeric_system::standard);
1457 format_localized(
'c', ns == numeric_system::standard ?
'\0' :
'E');
1460 void on_loc_date(numeric_system ns) {
1464 format_localized(
'x', ns == numeric_system::standard ?
'\0' :
'E');
1466 void on_loc_time(numeric_system ns) {
1470 format_localized(
'X', ns == numeric_system::standard ?
'\0' :
'E');
1474 write_digit2_separated(buf, to_unsigned(tm_mon() + 1),
1475 to_unsigned(tm_mday()),
1476 to_unsigned(split_year_lower(tm_year())),
'/');
1477 out_ = copy<Char>(std::begin(buf), std::end(buf), out_);
1479 void on_iso_date() {
1480 auto year = tm_year();
1484 copy2(buf, digits2(
static_cast<size_t>(
year / 100)));
1487 write_year_extended(
year);
1490 write_digit2_separated(buf + 2,
static_cast<unsigned>(
year % 100),
1491 to_unsigned(tm_mon() + 1), to_unsigned(tm_mday()),
1493 out_ = copy<Char>(std::begin(buf) + offset, std::end(buf), out_);
1496 void on_utc_offset(numeric_system ns) { format_utc_offset_impl(tm_, ns); }
1497 void on_tz_name() { format_tz_name_impl(tm_); }
1499 void on_year(numeric_system ns) {
1500 if (is_classic_ || ns == numeric_system::standard)
1501 return write_year(tm_year());
1502 format_localized(
'Y',
'E');
1504 void on_short_year(numeric_system ns) {
1505 if (is_classic_ || ns == numeric_system::standard)
1506 return write2(split_year_lower(tm_year()));
1507 format_localized(
'y',
'O');
1509 void on_offset_year() {
1510 if (is_classic_)
return write2(split_year_lower(tm_year()));
1511 format_localized(
'y',
'E');
1514 void on_century(numeric_system ns) {
1515 if (is_classic_ || ns == numeric_system::standard) {
1516 auto year = tm_year();
1517 auto upper =
year / 100;
1522 }
else if (upper >= 0 && upper < 100) {
1523 write2(
static_cast<int>(upper));
1525 out_ = write<Char>(out_, upper);
1528 format_localized(
'C',
'E');
1532 void on_dec_month(numeric_system ns) {
1533 if (is_classic_ || ns == numeric_system::standard)
1534 return write2(tm_mon() + 1);
1535 format_localized(
'm',
'O');
1538 void on_dec0_week_of_year(numeric_system ns, pad_type pad) {
1539 if (is_classic_ || ns == numeric_system::standard)
1540 return write2((tm_yday() + days_per_week - tm_wday()) / days_per_week,
1542 format_localized(
'U',
'O');
1544 void on_dec1_week_of_year(numeric_system ns, pad_type pad) {
1545 if (is_classic_ || ns == numeric_system::standard) {
1546 auto wday = tm_wday();
1547 write2((tm_yday() + days_per_week -
1548 (wday == 0 ? (days_per_week - 1) : (wday - 1))) /
1552 format_localized(
'W',
'O');
1555 void on_iso_week_of_year(numeric_system ns, pad_type pad) {
1556 if (is_classic_ || ns == numeric_system::standard)
1557 return write2(tm_iso_week_of_year(), pad);
1558 format_localized(
'V',
'O');
1561 void on_iso_week_based_year() { write_year(tm_iso_week_year()); }
1562 void on_iso_week_based_short_year() {
1563 write2(split_year_lower(tm_iso_week_year()));
1566 void on_day_of_year() {
1567 auto yday = tm_yday() + 1;
1571 void on_day_of_month(numeric_system ns, pad_type pad) {
1572 if (is_classic_ || ns == numeric_system::standard)
1573 return write2(tm_mday(), pad);
1574 format_localized(
'd',
'O');
1577 void on_24_hour(numeric_system ns, pad_type pad) {
1578 if (is_classic_ || ns == numeric_system::standard)
1579 return write2(tm_hour(), pad);
1580 format_localized(
'H',
'O');
1582 void on_12_hour(numeric_system ns, pad_type pad) {
1583 if (is_classic_ || ns == numeric_system::standard)
1584 return write2(tm_hour12(), pad);
1585 format_localized(
'I',
'O');
1587 void on_minute(numeric_system ns, pad_type pad) {
1588 if (is_classic_ || ns == numeric_system::standard)
1589 return write2(tm_min(), pad);
1590 format_localized(
'M',
'O');
1593 void on_second(numeric_system ns, pad_type pad) {
1594 if (is_classic_ || ns == numeric_system::standard) {
1595 write2(tm_sec(), pad);
1597 if (std::is_floating_point<typename Duration::rep>::value) {
1598 auto buf = memory_buffer();
1599 write_floating_seconds(buf, *subsecs_);
1600 if (buf.
size() > 1) {
1602 out_ = std::copy(buf.begin() + 1, buf.end(), out_);
1605 write_fractional_seconds<Char>(out_, *subsecs_);
1610 format_localized(
'S',
'O');
1614 void on_12_hour_time() {
1617 write_digit2_separated(buf, to_unsigned(tm_hour12()),
1618 to_unsigned(tm_min()), to_unsigned(tm_sec()),
':');
1619 out_ = copy<Char>(std::begin(buf), std::end(buf), out_);
1623 format_localized(
'r');
1626 void on_24_hour_time() {
1631 void on_iso_time() {
1634 on_second(numeric_system::standard, pad_type::zero);
1639 *out_++ = tm_hour() < 12 ?
'A' :
'P';
1642 format_localized(
'p');
1647 void on_duration_value() {}
1648 void on_duration_unit() {}
1652 bool has_precision_integral =
false;
1654 FMT_NORETURN
void unsupported() { FMT_THROW(format_error(
"no date")); }
1656 template <
typename Char>
1657 FMT_CONSTEXPR
void on_text(
const Char*,
const Char*) {}
1658 FMT_CONSTEXPR
void on_day_of_year() {}
1659 FMT_CONSTEXPR
void on_24_hour(numeric_system, pad_type) {}
1660 FMT_CONSTEXPR
void on_12_hour(numeric_system, pad_type) {}
1661 FMT_CONSTEXPR
void on_minute(numeric_system, pad_type) {}
1662 FMT_CONSTEXPR
void on_second(numeric_system, pad_type) {}
1663 FMT_CONSTEXPR
void on_12_hour_time() {}
1664 FMT_CONSTEXPR
void on_24_hour_time() {}
1665 FMT_CONSTEXPR
void on_iso_time() {}
1666 FMT_CONSTEXPR
void on_am_pm() {}
1667 FMT_CONSTEXPR
void on_duration_value()
const {
1668 if (has_precision_integral) {
1669 FMT_THROW(format_error(
"precision not allowed for this argument type"));
1672 FMT_CONSTEXPR
void on_duration_unit() {}
1675template <
typename T,
1677inline auto isfinite(T) ->
bool {
1681template <
typename T, FMT_ENABLE_IF(std::is_
integral<T>::value)>
1682inline auto mod(T x,
int y) -> T {
1683 return x %
static_cast<T
>(y);
1685template <
typename T, FMT_ENABLE_IF(std::is_
floating_po
int<T>::value)>
1686inline auto mod(T x,
int y) -> T {
1687 return std::fmod(x,
static_cast<T
>(y));
1692template <typename T, bool INTEGRAL = std::is_integral<T>::value>
1698 using type =
typename std::make_unsigned<T>::type;
1701template <
typename Rep,
typename Period,
1702 FMT_ENABLE_IF(std::is_integral<Rep>::value)>
1703inline auto get_milliseconds(std::chrono::duration<Rep, Period> d)
1704 -> std::chrono::duration<Rep, std::milli> {
1707#if FMT_SAFE_DURATION_CAST
1708 using CommonSecondsType =
1709 typename std::common_type<
decltype(d), std::chrono::seconds>::type;
1710 const auto d_as_common = fmt_duration_cast<CommonSecondsType>(d);
1711 const auto d_as_whole_seconds =
1712 fmt_duration_cast<std::chrono::seconds>(d_as_common);
1714 const auto diff = d_as_common - d_as_whole_seconds;
1716 fmt_duration_cast<std::chrono::duration<Rep, std::milli>>(diff);
1719 auto s = fmt_duration_cast<std::chrono::seconds>(d);
1720 return fmt_duration_cast<std::chrono::milliseconds>(d - s);
1724template <
typename Char,
typename Rep,
typename OutputIt,
1725 FMT_ENABLE_IF(std::is_integral<Rep>::value)>
1726auto format_duration_value(OutputIt out, Rep val,
int) -> OutputIt {
1727 return write<Char>(out, val);
1730template <
typename Char,
typename Rep,
typename OutputIt,
1731 FMT_ENABLE_IF(std::is_floating_point<Rep>::value)>
1732auto format_duration_value(OutputIt out, Rep val,
int precision) -> OutputIt {
1733 auto specs = format_specs();
1734 specs.precision = precision;
1736 precision >= 0 ? presentation_type::fixed : presentation_type::general;
1737 return write<Char>(out, val, specs);
1740template <
typename Char,
typename OutputIt>
1741auto copy_unit(string_view unit, OutputIt out, Char) -> OutputIt {
1742 return std::copy(unit.begin(), unit.end(), out);
1745template <
typename OutputIt>
1746auto copy_unit(string_view unit, OutputIt out,
wchar_t) -> OutputIt {
1750 return std::copy(u.c_str(), u.c_str() + u.size(), out);
1753template <
typename Char,
typename Period,
typename OutputIt>
1754auto format_duration_unit(OutputIt out) -> OutputIt {
1755 if (
const char* unit = get_units<Period>())
1756 return copy_unit(string_view(unit), out, Char());
1758 out = write<Char>(out, Period::num);
1759 if (const_check(Period::den != 1)) {
1761 out = write<Char>(out, Period::den);
1771 std::locale locale_;
1773 bool has_locale_ =
false;
1776 get_locale(
bool localized,
locale_ref loc) : has_locale_(localized) {
1777#ifndef FMT_STATIC_THOUSANDS_SEPARATOR
1779 ::new (&locale_) std::locale(loc.template get<std::locale>());
1783 if (has_locale_) locale_.~locale();
1785 operator const std::locale&()
const {
1786 return has_locale_ ? locale_ : get_classic_locale();
1790template <
typename FormatContext,
typename OutputIt,
typename Rep,
1792struct chrono_formatter {
1793 FormatContext& context;
1796 bool localized =
false;
1799 conditional_t<std::is_integral<Rep>::value &&
sizeof(Rep) <
sizeof(
int),
1800 unsigned,
typename make_unsigned_or_unchanged<Rep>::type>;
1802 using seconds = std::chrono::duration<rep>;
1804 using milliseconds = std::chrono::duration<rep, std::milli>;
1807 using char_type =
typename FormatContext::char_type;
1810 chrono_formatter(FormatContext& ctx, OutputIt o,
1811 std::chrono::duration<Rep, Period> d)
1814 val(
static_cast<rep
>(d.count())),
1816 if (d.count() < 0) {
1824 s = fmt_duration_cast<seconds>(std::chrono::duration<rep, Period>(val));
1828 auto handle_nan_inf() ->
bool {
1829 if (isfinite(val)) {
1845 auto days()
const -> Rep {
return static_cast<Rep
>(s.count() / 86400); }
1846 auto hour()
const -> Rep {
1847 return static_cast<Rep
>(mod((s.count() / 3600), 24));
1850 auto hour12()
const -> Rep {
1851 Rep hour =
static_cast<Rep
>(mod((s.count() / 3600), 12));
1852 return hour <= 0 ? 12 : hour;
1855 auto minute()
const -> Rep {
1856 return static_cast<Rep
>(mod((s.count() / 60), 60));
1858 auto second()
const -> Rep {
return static_cast<Rep
>(mod(s.count(), 60)); }
1860 auto time()
const -> std::tm {
1861 auto time = std::tm();
1862 time.tm_hour = to_nonnegative_int(hour(), 24);
1863 time.tm_min = to_nonnegative_int(minute(), 60);
1864 time.tm_sec = to_nonnegative_int(second(), 60);
1875 void write(Rep
value,
int width, pad_type pad = pad_type::zero) {
1877 if (isnan(
value))
return write_nan();
1878 uint32_or_64_or_128_t<int> n =
1879 to_unsigned(to_nonnegative_int(
value, max_value<int>()));
1880 int num_digits = detail::count_digits(n);
1881 if (width > num_digits) {
1882 out = detail::write_padding(out, pad, width - num_digits);
1884 out = format_decimal<char_type>(out, n, num_digits).end;
1887 void write_nan() { std::copy_n(
"nan", 3, out); }
1888 void write_pinf() { std::copy_n(
"inf", 3, out); }
1889 void write_ninf() { std::copy_n(
"-inf", 4, out); }
1891 template <
typename Callback,
typename... Args>
1892 void format_tm(
const tm& time, Callback cb, Args... args) {
1893 if (isnan(val))
return write_nan();
1895 auto w = tm_writer_type(loc, out, time);
1900 void on_text(
const char_type* begin,
const char_type* end) {
1901 std::copy(begin, end, out);
1905 void on_abbr_weekday() {}
1906 void on_full_weekday() {}
1907 void on_dec0_weekday(numeric_system) {}
1908 void on_dec1_weekday(numeric_system) {}
1909 void on_abbr_month() {}
1910 void on_full_month() {}
1911 void on_datetime(numeric_system) {}
1912 void on_loc_date(numeric_system) {}
1913 void on_loc_time(numeric_system) {}
1914 void on_us_date() {}
1915 void on_iso_date() {}
1916 void on_utc_offset(numeric_system) {}
1917 void on_tz_name() {}
1918 void on_year(numeric_system) {}
1919 void on_short_year(numeric_system) {}
1920 void on_offset_year() {}
1921 void on_century(numeric_system) {}
1922 void on_iso_week_based_year() {}
1923 void on_iso_week_based_short_year() {}
1924 void on_dec_month(numeric_system) {}
1925 void on_dec0_week_of_year(numeric_system, pad_type) {}
1926 void on_dec1_week_of_year(numeric_system, pad_type) {}
1927 void on_iso_week_of_year(numeric_system, pad_type) {}
1928 void on_day_of_month(numeric_system, pad_type) {}
1930 void on_day_of_year() {
1931 if (handle_nan_inf())
return;
1935 void on_24_hour(numeric_system ns, pad_type pad) {
1936 if (handle_nan_inf())
return;
1938 if (ns == numeric_system::standard)
return write(hour(), 2, pad);
1940 time.tm_hour = to_nonnegative_int(hour(), 24);
1941 format_tm(time, &tm_writer_type::on_24_hour, ns, pad);
1944 void on_12_hour(numeric_system ns, pad_type pad) {
1945 if (handle_nan_inf())
return;
1947 if (ns == numeric_system::standard)
return write(hour12(), 2, pad);
1949 time.tm_hour = to_nonnegative_int(hour12(), 12);
1950 format_tm(time, &tm_writer_type::on_12_hour, ns, pad);
1953 void on_minute(numeric_system ns, pad_type pad) {
1954 if (handle_nan_inf())
return;
1956 if (ns == numeric_system::standard)
return write(minute(), 2, pad);
1958 time.tm_min = to_nonnegative_int(minute(), 60);
1959 format_tm(time, &tm_writer_type::on_minute, ns, pad);
1962 void on_second(numeric_system ns, pad_type pad) {
1963 if (handle_nan_inf())
return;
1965 if (ns == numeric_system::standard) {
1966 if (std::is_floating_point<rep>::value) {
1967 auto buf = memory_buffer();
1968 write_floating_seconds(buf, std::chrono::duration<rep, Period>(val),
1970 if (negative) *out++ =
'-';
1971 if (buf.
size() < 2 || buf[1] ==
'.') {
1972 out = detail::write_padding(out, pad);
1974 out = std::copy(buf.begin(), buf.end(), out);
1976 write(second(), 2, pad);
1977 write_fractional_seconds<char_type>(
1978 out, std::chrono::duration<rep, Period>(val), precision);
1983 time.tm_sec = to_nonnegative_int(second(), 60);
1984 format_tm(time, &tm_writer_type::on_second, ns, pad);
1987 void on_12_hour_time() {
1988 if (handle_nan_inf())
return;
1989 format_tm(time(), &tm_writer_type::on_12_hour_time);
1992 void on_24_hour_time() {
1993 if (handle_nan_inf()) {
2004 void on_iso_time() {
2007 if (handle_nan_inf())
return;
2008 on_second(numeric_system::standard, pad_type::zero);
2012 if (handle_nan_inf())
return;
2013 format_tm(time(), &tm_writer_type::on_am_pm);
2016 void on_duration_value() {
2017 if (handle_nan_inf())
return;
2019 out = format_duration_value<char_type>(out, val, precision);
2022 void on_duration_unit() {
2023 out = format_duration_unit<char_type, Period>(out);
2029#if defined(__cpp_lib_chrono) && __cpp_lib_chrono >= 201907
2030using weekday = std::chrono::weekday;
2031using day = std::chrono::day;
2032using month = std::chrono::month;
2033using year = std::chrono::year;
2039 unsigned char value_;
2042 weekday() =
default;
2043 constexpr explicit weekday(
unsigned wd) noexcept
2044 : value_(
static_cast<unsigned char>(wd != 7 ? wd : 0)) {}
2045 constexpr auto c_encoding()
const noexcept ->
unsigned {
return value_; }
2050 unsigned char value_;
2054 constexpr explicit day(
unsigned d) noexcept
2055 : value_(
static_cast<unsigned char>(d)) {}
2056 constexpr explicit operator unsigned()
const noexcept {
return value_; }
2061 unsigned char value_;
2065 constexpr explicit month(
unsigned m) noexcept
2066 : value_(
static_cast<unsigned char>(m)) {}
2067 constexpr explicit operator unsigned()
const noexcept {
return value_; }
2076 constexpr explicit year(
int y) noexcept : value_(y) {}
2077 constexpr explicit operator int()
const noexcept {
return value_; }
2080class year_month_day {
2087 year_month_day() =
default;
2088 constexpr year_month_day(
const year& y,
const month& m,
const day& d) noexcept
2089 : year_(y), month_(m), day_(d) {}
2090 constexpr auto year()
const noexcept -> fmt::year {
return year_; }
2091 constexpr auto month()
const noexcept -> fmt::month {
return month_; }
2092 constexpr auto day()
const noexcept -> fmt::day {
return day_; }
2096template <
typename Char>
2097struct formatter<
weekday, Char> :
private formatter<std::tm, Char> {
2099 bool localized_ =
false;
2100 bool use_tm_formatter_ =
false;
2104 ->
decltype(ctx.
begin()) {
2105 auto it = ctx.
begin(), end = ctx.
end();
2106 if (it != end && *it ==
'L') {
2111 use_tm_formatter_ = it != end && *it !=
'}';
2112 return use_tm_formatter_ ? formatter<std::tm, Char>::parse(ctx) : it;
2115 template <
typename FormatContext>
2116 auto format(
weekday wd, FormatContext& ctx)
const ->
decltype(ctx.out()) {
2117 auto time = std::tm();
2118 time.tm_wday =
static_cast<int>(wd.c_encoding());
2119 if (use_tm_formatter_)
return formatter<std::tm, Char>::format(time, ctx);
2122 w.on_abbr_weekday();
2127template <
typename Char>
2128struct formatter<
day, Char> :
private formatter<std::tm, Char> {
2130 bool use_tm_formatter_ =
false;
2134 ->
decltype(ctx.
begin()) {
2135 auto it = ctx.
begin(), end = ctx.
end();
2136 use_tm_formatter_ = it != end && *it !=
'}';
2137 return use_tm_formatter_ ? formatter<std::tm, Char>::parse(ctx) : it;
2140 template <
typename FormatContext>
2141 auto format(
day d, FormatContext& ctx)
const ->
decltype(ctx.out()) {
2142 auto time = std::tm();
2143 time.tm_mday =
static_cast<int>(
static_cast<unsigned>(d));
2144 if (use_tm_formatter_)
return formatter<std::tm, Char>::format(time, ctx);
2147 w.on_day_of_month(detail::numeric_system::standard, detail::pad_type::zero);
2152template <
typename Char>
2153struct formatter<
month, Char> :
private formatter<std::tm, Char> {
2155 bool localized_ =
false;
2156 bool use_tm_formatter_ =
false;
2160 ->
decltype(ctx.
begin()) {
2161 auto it = ctx.
begin(), end = ctx.
end();
2162 if (it != end && *it ==
'L') {
2167 use_tm_formatter_ = it != end && *it !=
'}';
2168 return use_tm_formatter_ ? formatter<std::tm, Char>::parse(ctx) : it;
2171 template <
typename FormatContext>
2172 auto format(
month m, FormatContext& ctx)
const ->
decltype(ctx.out()) {
2173 auto time = std::tm();
2174 time.tm_mon =
static_cast<int>(
static_cast<unsigned>(m)) - 1;
2175 if (use_tm_formatter_)
return formatter<std::tm, Char>::format(time, ctx);
2183template <
typename Char>
2184struct formatter<
year, Char> :
private formatter<std::tm, Char> {
2186 bool use_tm_formatter_ =
false;
2190 ->
decltype(ctx.
begin()) {
2191 auto it = ctx.
begin(), end = ctx.
end();
2192 use_tm_formatter_ = it != end && *it !=
'}';
2193 return use_tm_formatter_ ? formatter<std::tm, Char>::parse(ctx) : it;
2196 template <
typename FormatContext>
2197 auto format(
year y, FormatContext& ctx)
const ->
decltype(ctx.out()) {
2198 auto time = std::tm();
2199 time.tm_year =
static_cast<int>(y) - 1900;
2200 if (use_tm_formatter_)
return formatter<std::tm, Char>::format(time, ctx);
2203 w.on_year(detail::numeric_system::standard);
2208template <
typename Char>
2211 bool use_tm_formatter_ =
false;
2215 ->
decltype(ctx.
begin()) {
2216 auto it = ctx.
begin(), end = ctx.
end();
2217 use_tm_formatter_ = it != end && *it !=
'}';
2218 return use_tm_formatter_ ? formatter<std::tm, Char>::parse(ctx) : it;
2221 template <
typename FormatContext>
2223 ->
decltype(ctx.out()) {
2224 auto time = std::tm();
2225 time.tm_year =
static_cast<int>(val.year()) - 1900;
2226 time.tm_mon =
static_cast<int>(
static_cast<unsigned>(val.month())) - 1;
2227 time.tm_mday =
static_cast<int>(
static_cast<unsigned>(val.day()));
2228 if (use_tm_formatter_)
return formatter<std::tm, Char>::format(time, ctx);
2236template <
typename Rep,
typename Period,
typename Char>
2237struct formatter<std::chrono::duration<Rep, Period>, Char> {
2242 bool localized_ =
false;
2247 ->
decltype(ctx.
begin()) {
2248 auto it = ctx.
begin(), end = ctx.
end();
2249 if (it == end || *it ==
'}')
return it;
2251 it = detail::parse_align(it, end, specs_);
2252 if (it == end)
return it;
2254 it = detail::parse_dynamic_spec(it, end, specs_.width, width_ref_, ctx);
2255 if (it == end)
return it;
2259 checker.has_precision_integral = !std::is_floating_point<Rep>::value;
2260 it = detail::parse_precision(it, end, specs_.precision, precision_ref_,
2263 if (it != end && *it ==
'L') {
2267 end = detail::parse_chrono_format(it, end, checker);
2268 format_str_ = {it, detail::to_unsigned(end - it)};
2272 template <
typename FormatContext>
2273 auto format(std::chrono::duration<Rep, Period> d, FormatContext& ctx)
const
2274 ->
decltype(ctx.out()) {
2275 auto specs = specs_;
2276 auto precision = specs.precision;
2277 specs.precision = -1;
2278 auto begin = format_str_.begin(), end = format_str_.end();
2282 auto out = std::back_inserter(buf);
2283 detail::handle_dynamic_spec<detail::width_checker>(specs.width, width_ref_,
2285 detail::handle_dynamic_spec<detail::precision_checker>(precision,
2286 precision_ref_, ctx);
2287 if (begin == end || *begin ==
'}') {
2288 out = detail::format_duration_value<Char>(out, d.count(), precision);
2289 detail::format_duration_unit<Char, Period>(out);
2291 using chrono_formatter =
2293 auto f = chrono_formatter(ctx, out, d);
2294 f.precision = precision;
2295 f.localized = localized_;
2296 detail::parse_chrono_format(begin, end, f);
2298 return detail::write(
2303template <
typename Char,
typename Duration>
2304struct formatter<std::chrono::time_point<std::chrono::system_clock, Duration>,
2305 Char> : formatter<std::tm, Char> {
2306 FMT_CONSTEXPR formatter() {
2310 template <
typename FormatContext>
2311 auto format(std::chrono::time_point<std::chrono::system_clock, Duration> val,
2312 FormatContext& ctx)
const ->
decltype(ctx.out()) {
2313 std::tm tm = gmtime(val);
2314 using period =
typename Duration::period;
2315 if (detail::const_check(
2316 period::num == 1 && period::den == 1 &&
2317 !std::is_floating_point<typename Duration::rep>::value)) {
2318 return formatter<std::tm, Char>::format(tm, ctx);
2320 Duration epoch = val.time_since_epoch();
2321 Duration subsecs = detail::fmt_duration_cast<Duration>(
2322 epoch - detail::fmt_duration_cast<std::chrono::seconds>(epoch));
2323 if (subsecs.count() < 0) {
2325 detail::fmt_duration_cast<Duration>(std::chrono::seconds(1));
2329 tm = gmtime(val - second);
2330 subsecs += detail::fmt_duration_cast<Duration>(std::chrono::seconds(1));
2332 return formatter<std::tm, Char>::do_format(tm, ctx, &subsecs);
2336#if FMT_USE_LOCAL_TIME
2337template <
typename Char,
typename Duration>
2338struct formatter<std::chrono::local_time<Duration>, Char>
2344 template <
typename FormatContext>
2345 auto format(std::chrono::local_time<Duration> val, FormatContext& ctx)
const
2346 ->
decltype(ctx.out()) {
2347 using period =
typename Duration::period;
2348 if (period::num != 1 || period::den != 1 ||
2349 std::is_floating_point<typename Duration::rep>::value) {
2350 const auto epoch = val.time_since_epoch();
2351 const auto subsecs = detail::fmt_duration_cast<Duration>(
2352 epoch - detail::fmt_duration_cast<std::chrono::seconds>(epoch));
2354 return formatter<std::tm, Char>::do_format(localtime(val), ctx, &subsecs);
2357 return formatter<std::tm, Char>::format(localtime(val), ctx);
2363template <
typename Char,
typename Duration>
2364struct formatter<std::chrono::time_point<std::chrono::utc_clock, Duration>,
2366 :
formatter<std::chrono::time_point<std::chrono::system_clock, Duration>,
2368 template <
typename FormatContext>
2369 auto format(std::chrono::time_point<std::chrono::utc_clock, Duration> val,
2370 FormatContext& ctx)
const ->
decltype(ctx.out()) {
2372 std::chrono::time_point<std::chrono::system_clock, Duration>,
2373 Char>::format(std::chrono::utc_clock::to_sys(val), ctx);
2378template <
typename Char>
struct formatter<std::tm, Char> {
2386 template <
typename FormatContext,
typename Duration>
2387 auto do_format(
const std::tm& tm, FormatContext& ctx,
2388 const Duration* subsecs)
const ->
decltype(ctx.out()) {
2389 auto specs = specs_;
2391 auto out = std::back_inserter(buf);
2392 detail::handle_dynamic_spec<detail::width_checker>(specs.width, width_ref_,
2395 auto loc_ref = ctx.locale();
2399 detail::parse_chrono_format(format_str_.begin(), format_str_.end(), w);
2400 return detail::write(
2406 ->
decltype(ctx.begin()) {
2407 auto it = ctx.begin(), end = ctx.end();
2408 if (it == end || *it ==
'}')
return it;
2410 it = detail::parse_align(it, end, specs_);
2411 if (it == end)
return it;
2413 it = detail::parse_dynamic_spec(it, end, specs_.width, width_ref_, ctx);
2414 if (it == end)
return it;
2418 if (end != it) format_str_ = {it, detail::to_unsigned(end - it)};
2422 template <
typename FormatContext>
2423 auto format(
const std::tm& tm, FormatContext& ctx)
const
2424 ->
decltype(ctx.out()) {
2425 return do_format<FormatContext, std::chrono::seconds>(tm, ctx,
nullptr);
constexpr auto end() const noexcept -> iterator
Returns an iterator past the end of the format string range being parsed.
Definition base.h:775
constexpr auto begin() const noexcept -> iterator
Definition base.h:770
constexpr auto size() const noexcept -> size_t
Returns the size of this buffer.
Definition base.h:894
FMT_CONSTEXPR auto data() noexcept -> T *
Returns a pointer to the buffer data (not null-terminated).
Definition base.h:900