19 #include <type_traits>
26 #ifndef FMT_USE_LOCAL_TIME
27 # ifdef __cpp_lib_chrono
28 # define FMT_USE_LOCAL_TIME (__cpp_lib_chrono >= 201907L)
30 # define FMT_USE_LOCAL_TIME 0
35 #ifndef FMT_USE_UTC_TIME
36 # ifdef __cpp_lib_chrono
37 # define FMT_USE_UTC_TIME (__cpp_lib_chrono >= 201907L)
39 # define FMT_USE_UTC_TIME 0
46 # if FMT_HAS_INCLUDE("winapifamily.h")
47 # include <winapifamily.h>
49 # if defined(_WIN32) && (!defined(WINAPI_FAMILY) || \
50 (WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP))
51 # define FMT_USE_TZSET 1
53 # define FMT_USE_TZSET 0
58 #ifndef FMT_SAFE_DURATION_CAST
59 # define FMT_SAFE_DURATION_CAST 1
61 #if FMT_SAFE_DURATION_CAST
71 template <
typename To,
typename From,
78 using F = std::numeric_limits<From>;
79 using T = std::numeric_limits<To>;
88 if (from < (T::min)() || from > (T::max)()) {
94 return static_cast<To
>(from);
101 template <
typename To,
typename From,
108 using F = std::numeric_limits<From>;
109 using T = std::numeric_limits<To>;
121 from >
static_cast<From
>(detail::max_value<To>())) {
128 F::digits >= T::digits) &&
129 from >
static_cast<From
>(detail::max_value<To>())) {
133 return static_cast<To
>(from);
136 template <
typename To,
typename From,
158 template <
typename To,
typename From,
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");
168 if (from >= T::lowest() && from <= (T::max)()) {
169 return static_cast<To
>(from);
177 return static_cast<To
>(from);
180 template <
typename To,
typename From,
184 static_assert(std::is_floating_point<From>::value,
"From must be floating");
191 template <
typename To,
typename FromRep,
typename FromPeriod,
196 using From = std::chrono::duration<FromRep, FromPeriod>;
201 : std::ratio_divide<typename From::period, typename To::period> {};
203 static_assert(Factor::num > 0,
"num must be positive");
204 static_assert(Factor::den > 0,
"den must be positive");
210 using IntermediateRep =
211 typename std::common_type<
typename From::rep,
typename To::rep,
212 decltype(Factor::num)>::type;
215 IntermediateRep count =
216 lossless_integral_conversion<IntermediateRep>(from.count(), ec);
220 const auto max1 = detail::max_value<IntermediateRep>() / Factor::num;
226 (std::numeric_limits<IntermediateRep>::min)() / Factor::num;
232 count *= Factor::num;
236 auto tocount = lossless_integral_conversion<typename To::rep>(count, ec);
237 return ec ? To() : To(tocount);
243 template <
typename To,
typename FromRep,
typename FromPeriod,
245 FMT_ENABLE_IF(std::is_floating_point<typename To::rep>::value)>
248 using From = std::chrono::duration<FromRep, FromPeriod>;
252 return To{std::numeric_limits<typename To::rep>::quiet_NaN()};
258 if (std::isinf(from.count())) {
259 return To{from.count()};
265 : std::ratio_divide<typename From::period, typename To::period> {};
267 static_assert(Factor::num > 0,
"num must be positive");
268 static_assert(Factor::den > 0,
"den must be positive");
274 using IntermediateRep =
275 typename std::common_type<
typename From::rep,
typename To::rep,
276 decltype(Factor::num)>::type;
280 IntermediateRep
count =
281 safe_float_conversion<IntermediateRep>(from.count(), ec);
288 constexpr
auto max1 = detail::max_value<IntermediateRep>() /
289 static_cast<IntermediateRep
>(Factor::num);
294 constexpr
auto min1 = std::numeric_limits<IntermediateRep>::lowest() /
295 static_cast<IntermediateRep
>(Factor::num);
300 count *=
static_cast<IntermediateRep
>(Factor::num);
306 count /=
static_cast<common_t
>(Factor::den);
310 using ToRep =
typename To::rep;
312 const ToRep tocount = safe_float_conversion<ToRep>(count, ec);
326 template <
typename T =
void>
struct null {};
333 static const auto&
locale = std::locale::classic();
343 template <
typename CodeUnit>
345 const std::locale& loc) {
346 #if FMT_CLANG_VERSION
347 # pragma clang diagnostic push
348 # pragma clang diagnostic ignored "-Wdeprecated"
349 auto&
f = std::use_facet<std::codecvt<CodeUnit, char, std::mbstate_t>>(loc);
350 # pragma clang diagnostic pop
352 auto&
f = std::use_facet<std::codecvt<CodeUnit, char, std::mbstate_t>>(loc);
354 auto mb = std::mbstate_t();
355 const char* from_next =
nullptr;
356 auto result =
f.in(mb, in_buf.
begin(), in_buf.
end(), from_next,
357 std::begin(out.
buf), std::end(out.
buf), out.
end);
358 if (result != std::codecvt_base::ok)
359 FMT_THROW(format_error(
"failed to format time"));
362 template <
typename OutputIt>
368 #if FMT_MSC_VERSION != 0 || \
369 (defined(__GLIBCXX__) && !defined(_GLIBCXX_USE_DUAL_ABI))
372 using code_unit = wchar_t;
374 using code_unit = char32_t;
383 if (!u.convert({unit.buf, to_unsigned(unit.end - unit.buf)}))
384 FMT_THROW(format_error(
"failed to format time"));
385 return copy_str<char>(u.c_str(), u.c_str() + u.size(), out);
387 return copy_str<char>(
in.data(),
in.data() +
in.size(), out);
390 template <
typename Char,
typename OutputIt,
396 return copy_str<Char>(unit.
buf, unit.
end, out);
399 template <
typename Char,
typename OutputIt,
406 template <
typename Char>
408 const std::locale& loc,
char format,
char modifier) {
410 auto&& os = std::basic_ostream<Char>(&format_buf);
412 const auto& facet = std::use_facet<std::time_put<Char>>(loc);
413 auto end = facet.put(os, os, Char(
' '), &
time,
format, modifier);
414 if (end.failed())
FMT_THROW(format_error(
"failed to format time"));
417 template <
typename Char,
typename OutputIt,
419 auto write(OutputIt out,
const std::tm&
time,
const std::locale& loc,
420 char format,
char modifier = 0) -> OutputIt {
421 auto&& buf = get_buffer<Char>(out);
422 do_write<Char>(buf,
time, loc,
format, modifier);
426 template <
typename Char,
typename OutputIt,
428 auto write(OutputIt out,
const std::tm&
time,
const std::locale& loc,
429 char format,
char modifier = 0) -> OutputIt {
431 do_write<char>(buf,
time, loc,
format, modifier);
435 template <
typename Rep1,
typename Rep2>
437 :
public std::integral_constant<bool,
438 (std::is_integral<Rep1>::value &&
439 std::is_integral<Rep2>::value) ||
440 (std::is_floating_point<Rep1>::value &&
441 std::is_floating_point<Rep2>::value)> {
445 typename To,
typename FromRep,
typename FromPeriod,
448 #if FMT_SAFE_DURATION_CAST
452 To to = safe_duration_cast::safe_duration_cast<To>(from, ec);
453 if (ec)
FMT_THROW(format_error(
"cannot format duration"));
457 return std::chrono::duration_cast<To>(from);
462 typename To,
typename FromRep,
typename FromPeriod,
463 FMT_ENABLE_IF(!is_same_arithmetic_type<FromRep, typename To::rep>::value)>
466 return std::chrono::duration_cast<To>(from);
469 template <
typename Duration>
471 std::chrono::time_point<std::chrono::system_clock, Duration> time_point)
476 return fmt_duration_cast<std::chrono::duration<std::time_t>>(
477 time_point.time_since_epoch())
494 dispatcher(std::time_t t) : time_(t) {}
497 using namespace fmt::detail;
498 return handle(localtime_r(&time_, &tm_));
501 auto handle(std::tm* tm) ->
bool {
return tm !=
nullptr; }
504 using namespace fmt::detail;
508 auto fallback(
int res) ->
bool {
return res == 0; }
512 using namespace fmt::detail;
515 return tm !=
nullptr;
521 if (!lt.run())
FMT_THROW(format_error(
"time_t value out of range"));
525 #if FMT_USE_LOCAL_TIME
526 template <
typename Duration>
527 inline auto localtime(std::chrono::local_time<Duration>
time) -> std::tm {
543 dispatcher(std::time_t t) : time_(t) {}
546 using namespace fmt::detail;
547 return handle(
gmtime_r(&time_, &tm_));
550 auto handle(std::tm* tm) ->
bool {
return tm !=
nullptr; }
553 using namespace fmt::detail;
554 return fallback(
gmtime_s(&tm_, &time_));
557 auto fallback(
int res) ->
bool {
return res == 0; }
563 return tm !=
nullptr;
567 auto gt = dispatcher(
time);
569 if (!gt.run())
FMT_THROW(format_error(
"time_t value out of range"));
573 template <
typename Duration>
575 std::chrono::time_point<std::chrono::system_clock, Duration> time_point)
586 unsigned c,
char sep) {
587 unsigned long long digits =
588 a | (b << 24) | (static_cast<unsigned long long>(c) << 48);
598 digits += (((digits * 205) >> 11) & 0x000f00000f00000f) * 6;
600 digits = ((digits & 0x00f00000f00000f0) >> 4) |
601 ((digits & 0x000f00000f00000f) << 8);
602 auto usep =
static_cast<unsigned long long>(sep);
604 digits |= 0x3030003030003030 | (usep << 16) | (usep << 40);
606 constexpr
const size_t len = 8;
609 std::memcpy(tmp, &digits, len);
610 std::reverse_copy(tmp, tmp + len, buf);
612 std::memcpy(buf, &digits, len);
616 template <
typename Period>
618 if (std::is_same<Period, std::atto>::value)
return "as";
619 if (std::is_same<Period, std::femto>::value)
return "fs";
620 if (std::is_same<Period, std::pico>::value)
return "ps";
621 if (std::is_same<Period, std::nano>::value)
return "ns";
622 if (std::is_same<Period, std::micro>::value)
return "µs";
623 if (std::is_same<Period, std::milli>::value)
return "ms";
624 if (std::is_same<Period, std::centi>::value)
return "cs";
625 if (std::is_same<Period, std::deci>::value)
return "ds";
626 if (std::is_same<Period, std::ratio<1>>::
value)
return "s";
627 if (std::is_same<Period, std::deca>::value)
return "das";
628 if (std::is_same<Period, std::hecto>::value)
return "hs";
629 if (std::is_same<Period, std::kilo>::value)
return "ks";
630 if (std::is_same<Period, std::mega>::value)
return "Ms";
631 if (std::is_same<Period, std::giga>::value)
return "Gs";
632 if (std::is_same<Period, std::tera>::value)
return "Ts";
633 if (std::is_same<Period, std::peta>::value)
return "Ps";
634 if (std::is_same<Period, std::exa>::value)
return "Es";
635 if (std::is_same<Period, std::ratio<60>>::
value)
return "min";
636 if (std::is_same<Period, std::ratio<3600>>::
value)
return "h";
637 if (std::is_same<Period, std::ratio<86400>>::
value)
return "d";
659 template <
typename OutputIt>
661 if (pad == pad_type::none)
return out;
665 template <
typename OutputIt>
667 if (pad != pad_type::none) *out++ = pad == pad_type::space ?
' ' :
'0';
672 template <
typename Char,
typename Handler>
674 Handler&& handler) ->
const Char* {
675 if (begin == end || *begin ==
'}')
return begin;
676 if (*begin !=
'%')
FMT_THROW(format_error(
"invalid format"));
678 pad_type pad = pad_type::unspecified;
686 if (begin !=
ptr) handler.on_text(begin,
ptr);
688 if (
ptr == end)
FMT_THROW(format_error(
"invalid format"));
692 pad = pad_type::space;
696 pad = pad_type::none;
700 pad = pad_type::zero;
704 if (
ptr == end)
FMT_THROW(format_error(
"invalid format"));
708 handler.on_text(
ptr - 1,
ptr);
711 const Char newline[] = {
'\n'};
712 handler.on_text(newline, newline + 1);
716 const Char tab[] = {
'\t'};
717 handler.on_text(tab, tab + 1);
722 handler.on_year(numeric_system::standard);
725 handler.on_short_year(numeric_system::standard);
728 handler.on_century(numeric_system::standard);
731 handler.on_iso_week_based_year();
734 handler.on_iso_week_based_short_year();
738 handler.on_abbr_weekday();
741 handler.on_full_weekday();
744 handler.on_dec0_weekday(numeric_system::standard);
747 handler.on_dec1_weekday(numeric_system::standard);
752 handler.on_abbr_month();
755 handler.on_full_month();
758 handler.on_dec_month(numeric_system::standard);
762 handler.on_dec0_week_of_year(numeric_system::standard);
765 handler.on_dec1_week_of_year(numeric_system::standard);
768 handler.on_iso_week_of_year(numeric_system::standard);
771 handler.on_day_of_year();
774 handler.on_day_of_month(numeric_system::standard);
777 handler.on_day_of_month_space(numeric_system::standard);
781 handler.on_24_hour(numeric_system::standard, pad);
784 handler.on_12_hour(numeric_system::standard, pad);
787 handler.on_minute(numeric_system::standard, pad);
790 handler.on_second(numeric_system::standard, pad);
794 handler.on_datetime(numeric_system::standard);
797 handler.on_loc_date(numeric_system::standard);
800 handler.on_loc_time(numeric_system::standard);
803 handler.on_us_date();
806 handler.on_iso_date();
809 handler.on_12_hour_time();
812 handler.on_24_hour_time();
815 handler.on_iso_time();
821 handler.on_duration_value();
824 handler.on_duration_unit();
827 handler.on_utc_offset(numeric_system::standard);
830 handler.on_tz_name();
834 if (
ptr == end)
FMT_THROW(format_error(
"invalid format"));
838 handler.on_year(numeric_system::alternative);
841 handler.on_offset_year();
844 handler.on_century(numeric_system::alternative);
847 handler.on_datetime(numeric_system::alternative);
850 handler.on_loc_date(numeric_system::alternative);
853 handler.on_loc_time(numeric_system::alternative);
856 handler.on_utc_offset(numeric_system::alternative);
859 FMT_THROW(format_error(
"invalid format"));
864 if (
ptr == end)
FMT_THROW(format_error(
"invalid format"));
868 handler.on_short_year(numeric_system::alternative);
871 handler.on_dec_month(numeric_system::alternative);
874 handler.on_dec0_week_of_year(numeric_system::alternative);
877 handler.on_dec1_week_of_year(numeric_system::alternative);
880 handler.on_iso_week_of_year(numeric_system::alternative);
883 handler.on_day_of_month(numeric_system::alternative);
886 handler.on_day_of_month_space(numeric_system::alternative);
889 handler.on_dec0_weekday(numeric_system::alternative);
892 handler.on_dec1_weekday(numeric_system::alternative);
895 handler.on_24_hour(numeric_system::alternative, pad);
898 handler.on_12_hour(numeric_system::alternative, pad);
901 handler.on_minute(numeric_system::alternative, pad);
904 handler.on_second(numeric_system::alternative, pad);
907 handler.on_utc_offset(numeric_system::alternative);
910 FMT_THROW(format_error(
"invalid format"));
914 FMT_THROW(format_error(
"invalid format"));
918 if (begin !=
ptr) handler.on_text(begin,
ptr);
924 static_cast<Derived*
>(
this)->unsupported();
967 template <
typename Char>
1006 static constexpr
const char* full_name_list[] = {
1007 "Sunday",
"Monday",
"Tuesday",
"Wednesday",
1008 "Thursday",
"Friday",
"Saturday"};
1009 return wday >= 0 && wday <= 6 ? full_name_list[wday] :
"?";
1012 static constexpr
const char* short_name_list[] = {
"Sun",
"Mon",
"Tue",
"Wed",
1013 "Thu",
"Fri",
"Sat"};
1014 return wday >= 0 && wday <= 6 ? short_name_list[wday] :
"???";
1018 static constexpr
const char* full_name_list[] = {
1019 "January",
"February",
"March",
"April",
"May",
"June",
1020 "July",
"August",
"September",
"October",
"November",
"December"};
1021 return mon >= 0 && mon <= 11 ? full_name_list[mon] :
"?";
1024 static constexpr
const char* short_name_list[] = {
1025 "Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
1026 "Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec",
1028 return mon >= 0 && mon <= 11 ? short_name_list[mon] :
"???";
1031 template <
typename T,
typename =
void>
1033 template <
typename T>
1037 template <
typename T,
typename =
void>
1039 template <
typename T>
1044 inline void tzset_once() {
1045 static bool init = []() ->
bool {
1054 template <
typename T,
typename Int, FMT_ENABLE_IF(std::is_
integral<T>::value)>
1056 if (!std::is_unsigned<Int>::value &&
1058 FMT_THROW(fmt::format_error(
"chrono value is out of range"));
1060 return static_cast<Int
>(
value);
1062 template <
typename T,
typename Int, FMT_ENABLE_IF(!std::is_
integral<T>::value)>
1064 if (value < 0 || value >
static_cast<T
>(upper))
1065 FMT_THROW(format_error(
"invalid value"));
1066 return static_cast<Int
>(value);
1069 constexpr
auto pow10(std::uint32_t n) ->
long long {
1070 return n == 0 ? 1 : 10 *
pow10(n - 1);
1076 template <
long long Num,
long long Den,
int N = 0,
1077 bool Enabled = (N < 19) && (Num <= max_value<long long>() / 10)>
1085 template <
long long Num,
long long Den,
int N>
1087 static constexpr
int value = (Num % Den == 0) ? N : 6;
1092 template <
typename Char,
typename OutputIt,
typename Duration>
1094 constexpr
auto num_fractional_digits =
1096 Duration::period::den>
::value;
1098 using subsecond_precision = std::chrono::duration<
1099 typename std::common_type<
typename Duration::rep,
1100 std::chrono::seconds::rep>
::type,
1103 const auto fractional =
d - fmt_duration_cast<std::chrono::seconds>(
d);
1104 const auto subseconds =
1105 std::chrono::treat_as_floating_point<
1106 typename subsecond_precision::rep>
::value
1107 ? fractional.count()
1108 : fmt_duration_cast<subsecond_precision>(fractional).count();
1112 int leading_zeroes = (std::max)(0, num_fractional_digits - num_digits);
1114 FMT_ASSERT(!std::is_floating_point<typename Duration::rep>::value,
"");
1115 if (std::ratio_less<
typename subsecond_precision::period,
1116 std::chrono::seconds::period>::
value) {
1119 out = format_decimal<Char>(out, n, num_digits).end;
1123 leading_zeroes = (std::min)(leading_zeroes,
precision);
1125 int remaining =
precision - leading_zeroes;
1126 if (remaining != 0 && remaining < num_digits) {
1128 out = format_decimal<Char>(out, n, remaining).end;
1131 out = format_decimal<Char>(out, n, num_digits).end;
1132 remaining -= num_digits;
1140 template <
typename Duration>
1142 int num_fractional_digits = -1) {
1143 using rep =
typename Duration::rep;
1144 FMT_ASSERT(std::is_floating_point<rep>::value,
"");
1146 auto val = duration.count();
1148 if (num_fractional_digits < 0) {
1151 using namespace std;
1152 num_fractional_digits =
1154 Duration::period::den>
::value;
1155 if (num_fractional_digits < 6 &&
static_cast<rep
>(round(val)) != val)
1156 num_fractional_digits = 6;
1160 std::fmod(val *
static_cast<rep
>(Duration::period::num) /
1161 static_cast<rep
>(Duration::period::den),
1162 static_cast<rep
>(60)),
1163 num_fractional_digits);
1166 template <
typename OutputIt,
typename Char,
1167 typename Duration = std::chrono::seconds>
1170 static constexpr
int days_per_week = 7;
1179 FMT_ASSERT(tm_.tm_sec >= 0 && tm_.tm_sec <= 61,
"");
1183 FMT_ASSERT(tm_.tm_min >= 0 && tm_.tm_min <= 59,
"");
1187 FMT_ASSERT(tm_.tm_hour >= 0 && tm_.tm_hour <= 23,
"");
1191 FMT_ASSERT(tm_.tm_mday >= 1 && tm_.tm_mday <= 31,
"");
1195 FMT_ASSERT(tm_.tm_mon >= 0 && tm_.tm_mon <= 11,
"");
1198 auto tm_year() const noexcept ->
long long {
return 1900ll + tm_.tm_year; }
1200 FMT_ASSERT(tm_.tm_wday >= 0 && tm_.tm_wday <= 6,
"");
1204 FMT_ASSERT(tm_.tm_yday >= 0 && tm_.tm_yday <= 365,
"");
1209 const auto h = tm_hour();
1210 const auto z = h < 12 ? h : h - 12;
1211 return z == 0 ? 12 :
z;
1219 auto l = year % 100;
1221 return static_cast<int>(l);
1226 const auto prev_year = curr_year - 1;
1228 (curr_year + curr_year / 4 - curr_year / 100 + curr_year / 400) %
1231 (prev_year + prev_year / 4 - prev_year / 100 + prev_year / 400) %
1233 return 52 + ((curr_p == 4 || prev_p == 3) ? 1 : 0);
1236 return (tm_yday + 11 - (tm_wday == 0 ? days_per_week : tm_wday)) /
1240 const auto year = tm_year();
1241 const auto w = iso_week_num(tm_yday(), tm_wday());
1242 if (w < 1)
return year - 1;
1243 if (w > iso_year_weeks(year))
return year + 1;
1247 const auto year = tm_year();
1248 const auto w = iso_week_num(tm_yday(), tm_wday());
1249 if (w < 1)
return iso_year_weeks(year - 1);
1250 if (w > iso_year_weeks(year))
return 1;
1270 *out_++ =
static_cast<char>(
'0' + v);
1285 out_ = format_decimal<Char>(out_, n, num_digits).end;
1288 if (year >= 0 && year < 10000) {
1289 write2(
static_cast<int>(year / 100));
1290 write2(
static_cast<int>(year % 100));
1292 write_year_extended(year);
1304 write2(
static_cast<int>(offset / 60));
1305 if (ns != numeric_system::standard) *out_++ =
':';
1306 write2(
static_cast<int>(offset % 60));
1308 template <
typename T, FMT_ENABLE_IF(has_member_data_tm_gmtoff<T>::value)>
1310 write_utc_offset(tm.tm_gmtoff, ns);
1312 template <
typename T, FMT_ENABLE_IF(!has_member_data_tm_gmtoff<T>::value)>
1314 #if defined(_WIN32) && defined(_UCRT)
1319 _get_timezone(&offset);
1322 _get_dstbias(&dstbias);
1325 write_utc_offset(-offset, ns);
1327 if (ns == numeric_system::standard)
return format_localized(
'z');
1331 std::time_t gt = std::mktime(>m);
1332 std::tm ltm =
gmtime(gt);
1333 std::time_t lt = std::mktime(<m);
1334 long offset = gt - lt;
1335 write_utc_offset(offset, ns);
1339 template <
typename T, FMT_ENABLE_IF(has_member_data_tm_zone<T>::value)>
1342 out_ = write_tm_str<Char>(out_, tm.tm_zone, loc_);
1344 format_localized(
'Z');
1346 template <
typename T, FMT_ENABLE_IF(!has_member_data_tm_zone<T>::value)>
1348 format_localized(
'Z');
1352 out_ = write<Char>(out_, tm_, loc_,
format, modifier);
1356 tm_writer(
const std::locale& loc, OutputIt out,
const std::tm& tm,
1357 const Duration* subsecs =
nullptr)
1364 auto out() const -> OutputIt {
return out_; }
1367 out_ = copy_str<Char>(begin, end, out_);
1374 format_localized(
'a');
1380 format_localized(
'A');
1383 if (is_classic_ || ns == numeric_system::standard)
return write1(tm_wday());
1384 format_localized(
'w',
'O');
1387 if (is_classic_ || ns == numeric_system::standard) {
1388 auto wday = tm_wday();
1389 write1(wday == 0 ? days_per_week : wday);
1391 format_localized(
'u',
'O');
1399 format_localized(
'b');
1405 format_localized(
'B');
1414 on_day_of_month_space(numeric_system::standard);
1418 on_year(numeric_system::standard);
1420 format_localized(
'c', ns == numeric_system::standard ?
'\0' :
'E');
1427 format_localized(
'x', ns == numeric_system::standard ?
'\0' :
'E');
1433 format_localized(
'X', ns == numeric_system::standard ?
'\0' :
'E');
1440 out_ = copy_str<Char>(std::begin(buf), std::end(buf), out_);
1443 auto year = tm_year();
1446 if (year >= 0 && year < 10000) {
1450 write_year_extended(year);
1456 out_ = copy_str<Char>(std::begin(buf) + offset, std::end(buf), out_);
1463 if (is_classic_ || ns == numeric_system::standard)
1464 return write_year(tm_year());
1465 format_localized(
'Y',
'E');
1468 if (is_classic_ || ns == numeric_system::standard)
1469 return write2(split_year_lower(tm_year()));
1470 format_localized(
'y',
'O');
1473 if (is_classic_)
return write2(split_year_lower(tm_year()));
1474 format_localized(
'y',
'E');
1478 if (is_classic_ || ns == numeric_system::standard) {
1479 auto year = tm_year();
1480 auto upper = year / 100;
1481 if (year >= -99 && year < 0) {
1485 }
else if (upper >= 0 && upper < 100) {
1486 write2(
static_cast<int>(upper));
1488 out_ = write<Char>(out_, upper);
1491 format_localized(
'C',
'E');
1496 if (is_classic_ || ns == numeric_system::standard)
1497 return write2(tm_mon() + 1);
1498 format_localized(
'm',
'O');
1502 if (is_classic_ || ns == numeric_system::standard)
1503 return write2((tm_yday() + days_per_week - tm_wday()) / days_per_week);
1504 format_localized(
'U',
'O');
1507 if (is_classic_ || ns == numeric_system::standard) {
1508 auto wday = tm_wday();
1509 write2((tm_yday() + days_per_week -
1510 (wday == 0 ? (days_per_week - 1) : (wday - 1))) /
1513 format_localized(
'W',
'O');
1517 if (is_classic_ || ns == numeric_system::standard)
1518 return write2(tm_iso_week_of_year());
1519 format_localized(
'V',
'O');
1524 write2(split_year_lower(tm_iso_week_year()));
1528 auto yday = tm_yday() + 1;
1533 if (is_classic_ || ns == numeric_system::standard)
return write2(tm_mday());
1534 format_localized(
'd',
'O');
1537 if (is_classic_ || ns == numeric_system::standard) {
1539 const char* d2 =
digits2(mday);
1540 *out_++ = mday < 10 ?
' ' : d2[0];
1543 format_localized(
'e',
'O');
1548 if (is_classic_ || ns == numeric_system::standard)
1549 return write2(tm_hour(), pad);
1550 format_localized(
'H',
'O');
1553 if (is_classic_ || ns == numeric_system::standard)
1554 return write2(tm_hour12(), pad);
1555 format_localized(
'I',
'O');
1558 if (is_classic_ || ns == numeric_system::standard)
1559 return write2(tm_min(), pad);
1560 format_localized(
'M',
'O');
1564 if (is_classic_ || ns == numeric_system::standard) {
1565 write2(tm_sec(), pad);
1567 if (std::is_floating_point<typename Duration::rep>::value) {
1570 if (buf.size() > 1) {
1572 out_ =
std::copy(buf.begin() + 1, buf.end(), out_);
1575 write_fractional_seconds<Char>(out_, *subsecs_);
1580 format_localized(
'S',
'O');
1589 out_ = copy_str<Char>(std::begin(buf), std::end(buf), out_);
1593 format_localized(
'r');
1604 on_second(numeric_system::standard, pad_type::unspecified);
1609 *out_++ = tm_hour() < 12 ?
'A' :
'P';
1612 format_localized(
'p');
1622 bool has_precision_integral =
false;
1626 template <
typename Char>
1638 if (has_precision_integral) {
1639 FMT_THROW(format_error(
"precision not allowed for this argument type"));
1645 template <
typename T,
1646 FMT_ENABLE_IF(std::is_integral<T>::value&& has_isfinite<T>::value)>
1651 template <
typename T, FMT_ENABLE_IF(std::is_
integral<T>::value)>
1653 return x %
static_cast<T
>(
y);
1655 template <
typename T, FMT_ENABLE_IF(std::is_
floating_po
int<T>::value)>
1656 inline auto mod(T
x,
int y) -> T {
1657 return std::fmod(
x,
static_cast<T
>(
y));
1662 template <typename T, bool INTEGRAL = std::is_integral<T>::value>
1671 template <
typename Rep,
typename Period,
1674 -> std::chrono::duration<Rep, std::milli> {
1677 #if FMT_SAFE_DURATION_CAST
1678 using CommonSecondsType =
1679 typename std::common_type<decltype(
d), std::chrono::seconds>
::type;
1680 const auto d_as_common = fmt_duration_cast<CommonSecondsType>(
d);
1681 const auto d_as_whole_seconds =
1682 fmt_duration_cast<std::chrono::seconds>(d_as_common);
1684 const auto diff = d_as_common - d_as_whole_seconds;
1686 fmt_duration_cast<std::chrono::duration<Rep, std::milli>>(diff);
1689 auto s = fmt_duration_cast<std::chrono::seconds>(
d);
1690 return fmt_duration_cast<std::chrono::milliseconds>(
d -
s);
1694 template <
typename Char,
typename Rep,
typename OutputIt,
1697 return write<Char>(out, val);
1700 template <
typename Char,
typename Rep,
typename OutputIt,
1704 specs.precision = precision;
1707 return write<Char>(out, val, specs);
1710 template <
typename Char,
typename OutputIt>
1712 return std::copy(unit.begin(), unit.end(), out);
1715 template <
typename OutputIt>
1723 template <
typename Char,
typename Period,
typename OutputIt>
1725 if (
const char* unit = get_units<Period>())
1728 out = write<Char>(out, Period::num);
1731 out = write<Char>(out, Period::den);
1743 bool has_locale_ =
false;
1748 ::new (&locale_) std::locale(loc.template get<std::locale>());
1751 if (has_locale_) locale_.~locale();
1753 operator const std::locale&()
const {
1758 template <
typename FormatContext,
typename OutputIt,
typename Rep,
1764 bool localized =
false;
1779 std::chrono::duration<Rep, Period> d)
1784 if (
d.count() < 0) {
1792 s = fmt_duration_cast<seconds>(std::chrono::duration<rep, Period>(val));
1813 auto days() const -> Rep {
return static_cast<Rep
>(
s.count() / 86400); }
1815 return static_cast<Rep
>(
mod((
s.count() / 3600), 24));
1819 Rep hour =
static_cast<Rep
>(
mod((
s.count() / 3600), 12));
1820 return hour <= 0 ? 12 : hour;
1824 return static_cast<Rep
>(
mod((
s.count() / 60), 60));
1826 auto second() const -> Rep {
return static_cast<Rep
>(
mod(
s.count(), 60)); }
1829 auto time = std::tm();
1849 if (
width > num_digits) {
1852 out = format_decimal<char_type>(out, n, num_digits).end;
1859 template <
typename Callback,
typename... Args>
1861 if (
isnan(val))
return write_nan();
1900 if (handle_nan_inf())
return;
1905 if (handle_nan_inf())
return;
1907 if (ns == numeric_system::standard)
return write(hour(), 2, pad);
1910 format_tm(
time, &tm_writer_type::on_24_hour, ns, pad);
1914 if (handle_nan_inf())
return;
1916 if (ns == numeric_system::standard)
return write(hour12(), 2, pad);
1919 format_tm(
time, &tm_writer_type::on_12_hour, ns, pad);
1923 if (handle_nan_inf())
return;
1925 if (ns == numeric_system::standard)
return write(minute(), 2, pad);
1928 format_tm(
time, &tm_writer_type::on_minute, ns, pad);
1932 if (handle_nan_inf())
return;
1934 if (ns == numeric_system::standard) {
1935 if (std::is_floating_point<rep>::value) {
1939 if (negative) *out++ =
'-';
1940 if (buf.size() < 2 || buf[1] ==
'.') {
1943 out =
std::copy(buf.begin(), buf.end(), out);
1945 write(second(), 2, pad);
1946 write_fractional_seconds<char_type>(
1947 out, std::chrono::duration<rep, Period>(val),
precision);
1953 format_tm(
time, &tm_writer_type::on_second, ns, pad);
1957 if (handle_nan_inf())
return;
1958 format_tm(
time(), &tm_writer_type::on_12_hour_time);
1962 if (handle_nan_inf()) {
1976 if (handle_nan_inf())
return;
1977 on_second(numeric_system::standard, pad_type::unspecified);
1981 if (handle_nan_inf())
return;
1982 format_tm(
time(), &tm_writer_type::on_am_pm);
1986 if (handle_nan_inf())
return;
1988 out = format_duration_value<char_type>(out, val,
precision);
1992 out = format_duration_unit<char_type, Period>(out);
1998 #if defined(__cpp_lib_chrono) && __cpp_lib_chrono >= 201907
1999 using weekday = std::chrono::weekday;
2009 : value(
static_cast<unsigned char>(wd != 7 ? wd : 0)) {}
2010 constexpr
auto c_encoding() const noexcept ->
unsigned {
return value; }
2019 bool localized =
false;
2023 -> decltype(ctx.begin()) {
2024 auto begin = ctx.begin(), end = ctx.end();
2025 if (begin != end && *begin ==
'L') {
2032 template <
typename FormatContext>
2034 auto time = std::tm();
2035 time.tm_wday =
static_cast<int>(wd.c_encoding());
2043 template <
typename Rep,
typename Period,
typename Char>
2049 bool localized_ =
false;
2054 -> decltype(ctx.begin()) {
2055 auto it = ctx.begin(), end = ctx.end();
2056 if (it == end || *it ==
'}')
return it;
2059 if (it == end)
return it;
2062 if (it == end)
return it;
2066 checker.has_precision_integral = !std::is_floating_point<Rep>::value;
2070 if (it != end && *it ==
'L') {
2079 template <
typename FormatContext>
2080 auto format(std::chrono::duration<Rep, Period> d, FormatContext& ctx)
const
2081 -> decltype(ctx.out()) {
2082 auto specs = specs_;
2083 auto precision = specs.precision;
2084 specs.precision = -1;
2085 auto begin = format_str_.begin(), end = format_str_.end();
2089 auto out = std::back_inserter(buf);
2090 detail::handle_dynamic_spec<detail::width_checker>(specs.width, width_ref_,
2092 detail::handle_dynamic_spec<detail::precision_checker>(precision,
2093 precision_ref_, ctx);
2094 if (begin == end || *begin ==
'}') {
2095 out = detail::format_duration_value<Char>(out,
d.count(), precision);
2096 detail::format_duration_unit<Char, Period>(out);
2098 using chrono_formatter =
2100 auto f = chrono_formatter(ctx, out,
d);
2101 f.precision = precision;
2102 f.localized = localized_;
2106 ctx.out(), basic_string_view<Char>(buf.data(), buf.size()), specs);
2110 template <
typename Char,
typename Duration>
2111 struct formatter<
std::chrono::time_point<std::chrono::system_clock, Duration>,
2117 template <
typename FormatContext>
2118 auto format(std::chrono::time_point<std::chrono::system_clock, Duration> val,
2119 FormatContext& ctx)
const -> decltype(ctx.out()) {
2120 using period =
typename Duration::period;
2122 period::num != 1 || period::den != 1 ||
2123 std::is_floating_point<typename Duration::rep>::value)) {
2124 const auto epoch = val.time_since_epoch();
2125 auto subsecs = detail::fmt_duration_cast<Duration>(
2126 epoch - detail::fmt_duration_cast<std::chrono::seconds>(epoch));
2128 if (subsecs.count() < 0) {
2130 detail::fmt_duration_cast<Duration>(std::chrono::seconds(1));
2131 if (epoch.count() < ((Duration::min)() + second).count())
2132 FMT_THROW(format_error(
"duration is too small"));
2144 #if FMT_USE_LOCAL_TIME
2145 template <
typename Char,
typename Duration>
2146 struct formatter<
std::chrono::local_time<Duration>, Char>
2152 template <
typename FormatContext>
2153 auto format(std::chrono::local_time<Duration> val, FormatContext& ctx)
const
2154 -> decltype(ctx.out()) {
2155 using period =
typename Duration::period;
2156 if (period::num != 1 || period::den != 1 ||
2157 std::is_floating_point<typename Duration::rep>::value) {
2158 const auto epoch = val.time_since_epoch();
2159 const auto subsecs = detail::fmt_duration_cast<Duration>(
2160 epoch - detail::fmt_duration_cast<std::chrono::seconds>(epoch));
2170 #if FMT_USE_UTC_TIME
2171 template <
typename Char,
typename Duration>
2172 struct formatter<
std::chrono::time_point<std::chrono::utc_clock, Duration>,
2174 :
formatter<std::chrono::time_point<std::chrono::system_clock, Duration>,
2176 template <
typename FormatContext>
2177 auto format(std::chrono::time_point<std::chrono::utc_clock, Duration> val,
2178 FormatContext& ctx)
const -> decltype(ctx.out()) {
2180 std::chrono::time_point<std::chrono::system_clock, Duration>,
2181 Char>
::format(std::chrono::utc_clock::to_sys(val), ctx);
2194 template <
typename FormatContext,
typename Duration>
2196 const Duration* subsecs)
const -> decltype(ctx.out()) {
2197 auto specs = specs_;
2199 auto out = std::back_inserter(buf);
2200 detail::handle_dynamic_spec<detail::width_checker>(specs.width, width_ref_,
2203 auto loc_ref = ctx.locale();
2209 ctx.out(), basic_string_view<Char>(buf.data(), buf.size()), specs);
2214 -> decltype(ctx.begin()) {
2215 auto it = ctx.begin(), end = ctx.end();
2216 if (it == end || *it ==
'}')
return it;
2219 if (it == end)
return it;
2222 if (it == end)
return it;
2230 template <
typename FormatContext>
2231 auto format(
const std::tm& tm, FormatContext& ctx)
const
2232 -> decltype(ctx.out()) {
2233 return do_format<FormatContext, std::chrono::seconds>(tm, ctx,
nullptr);
2240 #endif // FMT_CHRONO_H_