22 #ifndef FMT_SAFE_DURATION_CAST 23 # define FMT_SAFE_DURATION_CAST 1 25 #if FMT_SAFE_DURATION_CAST 35 template <
typename To,
typename From,
37 std::numeric_limits<From>::is_signed ==
38 std::numeric_limits<To>::is_signed)>
41 using F = std::numeric_limits<From>;
42 using T = std::numeric_limits<To>;
47 if (F::digits <= T::digits) {
51 if (from < T::min() || from > T::max()) {
57 return static_cast<To
>(from);
64 template <
typename To,
typename From,
66 std::numeric_limits<From>::is_signed !=
67 std::numeric_limits<To>::is_signed)>
70 using F = std::numeric_limits<From>;
71 using T = std::numeric_limits<To>;
75 if (F::is_signed && !T::is_signed) {
83 if (F::digits <= T::digits) {
87 if (from > static_cast<From>(T::max())) {
94 if (!F::is_signed && T::is_signed) {
96 if (F::digits < T::digits) {
100 if (from > static_cast<From>(T::max())) {
109 return static_cast<To
>(from);
113 template <
typename To,
typename From,
134 template <
typename To,
typename From,
138 using T = std::numeric_limits<To>;
139 static_assert(std::is_floating_point<From>::value,
"From must be floating");
140 static_assert(std::is_floating_point<To>::value,
"To must be floating");
144 if (from >= T::lowest() && from <= T::max()) {
145 return static_cast<To
>(from);
153 return static_cast<To
>(from);
156 template <
typename To,
typename From,
160 static_assert(std::is_floating_point<From>::value,
"From must be floating");
167 template <
typename To,
typename FromRep,
typename FromPeriod,
172 using From = std::chrono::duration<FromRep, FromPeriod>;
177 : std::ratio_divide<typename From::period, typename To::period> {};
179 static_assert(Factor::num > 0,
"num must be positive");
180 static_assert(Factor::den > 0,
"den must be positive");
186 using IntermediateRep =
187 typename std::common_type<
typename From::rep,
typename To::rep,
188 decltype(Factor::num)>
::type;
191 IntermediateRep count =
192 lossless_integral_conversion<IntermediateRep>(from.count(), ec);
197 if (Factor::num != 1) {
198 const auto max1 = internal::max_value<IntermediateRep>() / Factor::num;
203 const auto min1 = std::numeric_limits<IntermediateRep>::min() / Factor::num;
208 count *= Factor::num;
212 if (Factor::den != 1) {
213 count /= Factor::den;
216 using ToRep =
typename To::rep;
217 const ToRep tocount = lossless_integral_conversion<ToRep>(count, ec);
227 template <
typename To,
typename FromRep,
typename FromPeriod,
229 FMT_ENABLE_IF(std::is_floating_point<typename To::rep>::value)>
232 using From = std::chrono::duration<FromRep, FromPeriod>;
236 return To{std::numeric_limits<typename To::rep>::quiet_NaN()};
242 if (std::isinf(from.count())) {
243 return To{from.count()};
249 : std::ratio_divide<typename From::period, typename To::period> {};
251 static_assert(Factor::num > 0,
"num must be positive");
252 static_assert(Factor::den > 0,
"den must be positive");
258 using IntermediateRep =
259 typename std::common_type<
typename From::rep,
typename To::rep,
260 decltype(Factor::num)>
::type;
264 IntermediateRep count =
265 safe_float_conversion<IntermediateRep>(from.count(), ec);
271 if (Factor::num != 1) {
272 constexpr
auto max1 = internal::max_value<IntermediateRep>() /
273 static_cast<IntermediateRep>(Factor::num);
278 constexpr
auto min1 = std::numeric_limits<IntermediateRep>::lowest() /
279 static_cast<IntermediateRep
>(Factor::num);
284 count *=
static_cast<IntermediateRep
>(Factor::num);
288 if (Factor::den != 1) {
290 count /=
static_cast<common_t
>(Factor::den);
294 using ToRep =
typename To::rep;
296 const ToRep tocount = safe_float_conversion<ToRep>(count, ec);
322 dispatcher(std::time_t t) : time_(t) {}
325 using namespace fmt::internal;
326 return handle(localtime_r(&time_, &tm_));
329 bool handle(std::tm* tm) {
return tm !=
nullptr; }
332 using namespace fmt::internal;
336 bool fallback(
int res) {
return res == 0; }
340 using namespace fmt::internal;
343 return tm !=
nullptr;
354 inline std::tm
gmtime(std::time_t time) {
359 dispatcher(std::time_t t) : time_(t) {}
362 using namespace fmt::internal;
363 return handle(
gmtime_r(&time_, &tm_));
366 bool handle(std::tm* tm) {
return tm !=
nullptr; }
369 using namespace fmt::internal;
370 return fallback(
gmtime_s(&tm_, &time_));
373 bool fallback(
int res) {
return res == 0; }
379 return tm !=
nullptr;
391 const std::tm* time) {
395 inline std::size_t
strftime(
wchar_t* str, std::size_t count,
396 const wchar_t*
format,
const std::tm* time) {
397 return std::wcsftime(str, count, format, time);
401 template <
typename Char>
struct formatter<std::tm, Char> {
402 template <
typename ParseContext>
403 auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
404 auto it = ctx.begin();
405 if (it != ctx.end() && *it ==
':') ++it;
407 while (end != ctx.end() && *end !=
'}') ++end;
409 tm_format.append(it, end);
410 tm_format.push_back(
'\0');
414 template <
typename FormatContext>
415 auto format(
const std::tm& tm, FormatContext& ctx) -> decltype(ctx.out()) {
417 std::size_t start = buf.
size();
419 std::size_t size = buf.
capacity() - start;
423 buf.
resize(start + count);
426 if (size >= tm_format.size() * 256) {
433 const std::size_t MIN_GROWTH = 10;
446 template <>
FMT_CONSTEXPR const char* get_units<std::atto>() {
return "as"; }
447 template <>
FMT_CONSTEXPR const char* get_units<std::femto>() {
return "fs"; }
448 template <>
FMT_CONSTEXPR const char* get_units<std::pico>() {
return "ps"; }
449 template <>
FMT_CONSTEXPR const char* get_units<std::nano>() {
return "ns"; }
450 template <>
FMT_CONSTEXPR const char* get_units<std::micro>() {
return "µs"; }
451 template <>
FMT_CONSTEXPR const char* get_units<std::milli>() {
return "ms"; }
452 template <>
FMT_CONSTEXPR const char* get_units<std::centi>() {
return "cs"; }
453 template <>
FMT_CONSTEXPR const char* get_units<std::deci>() {
return "ds"; }
454 template <>
FMT_CONSTEXPR const char* get_units<std::ratio<1>>() {
return "s"; }
455 template <>
FMT_CONSTEXPR const char* get_units<std::deca>() {
return "das"; }
456 template <>
FMT_CONSTEXPR const char* get_units<std::hecto>() {
return "hs"; }
457 template <>
FMT_CONSTEXPR const char* get_units<std::kilo>() {
return "ks"; }
458 template <>
FMT_CONSTEXPR const char* get_units<std::mega>() {
return "Ms"; }
459 template <>
FMT_CONSTEXPR const char* get_units<std::giga>() {
return "Gs"; }
460 template <>
FMT_CONSTEXPR const char* get_units<std::tera>() {
return "Ts"; }
461 template <>
FMT_CONSTEXPR const char* get_units<std::peta>() {
return "Ps"; }
462 template <>
FMT_CONSTEXPR const char* get_units<std::exa>() {
return "Es"; }
477 template <
typename Char,
typename Handler>
489 if (begin !=
ptr) handler.on_text(begin,
ptr);
495 handler.on_text(
ptr - 1,
ptr);
498 const char newline[] =
"\n";
499 handler.on_text(newline, newline + 1);
503 const char tab[] =
"\t";
504 handler.on_text(tab, tab + 1);
509 handler.on_abbr_weekday();
512 handler.on_full_weekday();
515 handler.on_dec0_weekday(numeric_system::standard);
518 handler.on_dec1_weekday(numeric_system::standard);
522 handler.on_abbr_month();
525 handler.on_full_month();
529 handler.on_24_hour(numeric_system::standard);
532 handler.on_12_hour(numeric_system::standard);
535 handler.on_minute(numeric_system::standard);
538 handler.on_second(numeric_system::standard);
542 handler.on_datetime(numeric_system::standard);
545 handler.on_loc_date(numeric_system::standard);
548 handler.on_loc_time(numeric_system::standard);
551 handler.on_us_date();
554 handler.on_iso_date();
557 handler.on_12_hour_time();
560 handler.on_24_hour_time();
563 handler.on_iso_time();
569 handler.on_duration_value();
572 handler.on_duration_unit();
575 handler.on_utc_offset();
578 handler.on_tz_name();
586 handler.on_datetime(numeric_system::alternative);
589 handler.on_loc_date(numeric_system::alternative);
592 handler.on_loc_time(numeric_system::alternative);
604 handler.on_dec0_weekday(numeric_system::alternative);
607 handler.on_dec1_weekday(numeric_system::alternative);
610 handler.on_24_hour(numeric_system::alternative);
613 handler.on_12_hour(numeric_system::alternative);
616 handler.on_minute(numeric_system::alternative);
619 handler.on_second(numeric_system::alternative);
630 if (begin !=
ptr) handler.on_text(begin,
ptr);
637 template <
typename Char>
void on_text(
const Char*,
const Char*) {}
663 template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
667 template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)>
672 template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
676 template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)>
682 template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
684 FMT_ASSERT(value >= 0 && value <= upper,
"invalid value");
686 return static_cast<int>(value);
688 template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)>
691 std::isnan(value) || (value >= 0 && value <= static_cast<T>(upper)),
694 return static_cast<int>(value);
697 template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
698 inline T
mod(T x,
int y) {
699 return x %
static_cast<T
>(y);
701 template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)>
702 inline T
mod(T x,
int y) {
703 return std::fmod(x, static_cast<T>(y));
708 template <typename T, bool INTEGRAL = std::is_integral<T>::value>
717 #if FMT_SAFE_DURATION_CAST 719 template <
typename To,
typename FromRep,
typename FromPeriod>
728 template <
typename Rep,
typename Period,
731 std::chrono::duration<Rep, Period> d) {
734 #if FMT_SAFE_DURATION_CAST 735 using CommonSecondsType =
738 const auto d_as_whole_seconds =
741 const auto diff = d_as_common - d_as_whole_seconds;
746 auto s = std::chrono::duration_cast<std::chrono::seconds>(d);
747 return std::chrono::duration_cast<std::chrono::milliseconds>(d - s);
751 template <
typename Rep,
typename Period,
754 std::chrono::duration<Rep, Period> d) {
756 auto ms =
mod(d.count() *
static_cast<common_type
>(Period::num) /
757 static_cast<common_type>(Period::den) * 1000,
759 return std::chrono::duration<Rep, std::milli>(
static_cast<Rep
>(ms));
762 template <
typename Rep,
typename OutputIt>
764 if (precision >= 0)
return format_to(out,
"{:.{}f}", val, precision);
765 return format_to(out, std::is_floating_point<Rep>::value ?
"{:g}" :
"{}",
769 template <
typename Period,
typename OutputIt>
771 if (
const char* unit = get_units<Period>())
return format_to(out,
"{}", unit);
772 if (Period::den == 1)
return format_to(out,
"[{}]s", Period::num);
773 return format_to(out,
"[{}/{}]s", Period::num, Period::den);
776 template <
typename FormatContext,
typename OutputIt,
typename Rep,
795 std::chrono::duration<Rep, Period> d)
798 val(static_cast<
rep>(d.count())),
807 #if FMT_SAFE_DURATION_CAST 809 auto tmpval = std::chrono::duration<rep, Period>(val);
812 s = std::chrono::duration_cast<
seconds>(
813 std::chrono::duration<rep, Period>(val));
835 Rep
hour()
const {
return static_cast<Rep
>(
mod((s.count() / 3600), 24)); }
838 Rep hour =
static_cast<Rep
>(
mod((s.count() / 3600), 12));
839 return hour <= 0 ? 12 : hour;
842 Rep
minute()
const {
return static_cast<Rep
>(
mod((s.count() / 60), 60)); }
843 Rep
second()
const {
return static_cast<Rep
>(
mod(s.count(), 60)); }
846 auto time = std::tm();
862 if (
isnan(value))
return write_nan();
866 if (width > num_digits) out = std::fill_n(out, width - num_digits,
'0');
867 out = format_decimal<char_type>(out, n, num_digits);
875 if (
isnan(val))
return write_nan();
876 auto locale = context.locale().template get<std::locale>();
877 auto& facet = std::use_facet<std::time_put<char_type>>(locale);
878 std::basic_ostringstream<char_type> os;
880 facet.put(os, os,
' ', &time, format, format + std::strlen(format));
905 if (handle_nan_inf())
return;
907 if (ns == numeric_system::standard)
return write(hour(), 2);
910 format_localized(time,
"%OH");
914 if (handle_nan_inf())
return;
916 if (ns == numeric_system::standard)
return write(hour12(), 2);
919 format_localized(time,
"%OI");
923 if (handle_nan_inf())
return;
925 if (ns == numeric_system::standard)
return write(minute(), 2);
928 format_localized(time,
"%OM");
932 if (handle_nan_inf())
return;
934 if (ns == numeric_system::standard) {
936 #if FMT_SAFE_DURATION_CAST 938 using duration_rep = std::chrono::duration<rep, Period>;
939 using duration_Rep = std::chrono::duration<Rep, Period>;
942 auto tmpval = std::chrono::duration<Rep, Period>(val);
945 if (ms != std::chrono::milliseconds(0)) {
947 write(ms.count(), 3);
953 format_localized(time,
"%OS");
957 if (handle_nan_inf())
return;
959 format_localized(time(),
"%r");
963 if (handle_nan_inf()) {
977 if (handle_nan_inf())
return;
982 if (handle_nan_inf())
return;
983 format_localized(time(),
"%p");
987 if (handle_nan_inf())
return;
996 template <
typename Rep,
typename Period,
typename Char>
997 struct formatter<std::chrono::duration<Rep, Period>, Char> {
1007 struct spec_handler {
1027 void on_fill(Char fill) { f.specs.fill[0] = fill; }
1034 f.width_ref = make_arg_ref(arg_id);
1038 f.precision_ref = make_arg_ref(arg_id);
1043 struct parse_range {
1049 auto begin = ctx.
begin(), end = ctx.
end();
1050 if (begin == end || *begin ==
'}')
return {begin, begin};
1051 spec_handler handler{*
this, ctx, format_str};
1053 if (begin == end)
return {begin, begin};
1055 if (begin == end)
return {begin, begin};
1056 if (*begin ==
'.') {
1057 if (std::is_floating_point<Rep>::value)
1060 handler.on_error(
"precision not allowed for this argument type");
1063 return {begin, end};
1070 -> decltype(ctx.begin()) {
1071 auto range = do_parse(ctx);
1077 template <
typename FormatContext>
1079 auto begin = format_str.
begin(), end = format_str.
end();
1083 auto out = std::back_inserter(buf);
1086 internal::handle_dynamic_spec<internal::width_checker>(specs.
width,
1088 internal::handle_dynamic_spec<internal::precision_checker>(
1089 precision, precision_ref, ctx);
1090 if (begin == end || *begin ==
'}') {
1092 internal::format_chrono_duration_unit<Period>(out);
1099 w.write(buf.
data(), buf.
size(), specs);
1106 #endif // FMT_CHRONO_H_
#define FMT_BEGIN_NAMESPACE
#define FMT_ASSERT(condition, message)
std::basic_string< Char > format(const text_style &ts, const S &format_str, const Args &... args)
std::size_t size() const FMT_NOEXCEPT
FMT_CONSTEXPR iterator end() const
FMT_CONSTEXPR iterator end() const FMT_NOEXCEPT
FMT_CONSTEXPR const Char * parse_chrono_format(const Char *begin, const Char *end, Handler &&handler)
bool_constant< is_integral< T >::value &&!std::is_same< T, bool >::value &&!std::is_same< T, char >::value &&!std::is_same< T, wchar_t >::value > is_integer
OutputIt format_chrono_duration_value(OutputIt out, Rep val, int precision)
typename std::make_unsigned< T >::type type
To safe_duration_cast(std::chrono::duration< FromRep, FromPeriod > from, int &ec)
FMT_CONSTEXPR void check_arg_id(int)
FMT_CONSTEXPR bool is_negative(T value)
FMT_CONSTEXPR iterator begin() const FMT_NOEXCEPT
FMT_CONSTEXPR int next_arg_id()
FMT_CONSTEXPR const Char * parse_width(const Char *begin, const Char *end, Handler &&handler)
std::tm localtime(std::time_t time)
int count_digits(uint64_t n)
OutputIt format_to(OutputIt out, const CompiledFormat &cf, const Args &... args)
#define FMT_END_NAMESPACE
FMT_CONSTEXPR const char * get_units()
OutputIterator copy(const RangeT &range, OutputIterator out)
std::chrono::duration< Rep, std::milli > get_milliseconds(std::chrono::duration< Rep, Period > d)
#define FMT_ENABLE_IF(...)
typename std::conditional< B, T, F >::type conditional_t
void reserve(std::size_t new_capacity)
FMT_CONSTEXPR const Char * parse_precision(const Char *begin, const Char *end, Handler &&handler)
int to_nonnegative_int(T value, int upper)
std::tm gmtime(std::time_t time)
FMT_CONSTEXPR To lossless_integral_conversion(const From from, int &ec)
std::size_t capacity() const FMT_NOEXCEPT
void resize(std::size_t new_size)
To fmt_safe_duration_cast(std::chrono::duration< FromRep, FromPeriod > from)
FMT_CONSTEXPR iterator begin() const
std::size_t strftime(wchar_t *str, std::size_t count, const wchar_t *format, const std::tm *time)
FMT_CONSTEXPR To safe_float_conversion(const From from, int &ec)
FMT_CONSTEXPR const Char * parse_align(const Char *begin, const Char *end, Handler &&handler)
std::size_t strftime(char *str, std::size_t count, const char *format, const std::tm *time)
conditional_t< std::numeric_limits< T >::digits<=32, uint32_t, conditional_t< std::numeric_limits< T >::digits<=64, uint64_t, uint128_t > > uint32_or_64_or_128_t
void write(std::basic_ostream< Char > &os, buffer< Char > &buf)
static OutputIt format_chrono_duration_unit(OutputIt out)
FMT_CONSTEXPR std::make_unsigned< Int >::type to_unsigned(Int value)