• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Formatting library for C++ - chrono support
2 //
3 // Copyright (c) 2012 - present, Victor Zverovich
4 // All rights reserved.
5 //
6 // For the license information refer to format.h.
7 
8 #ifndef FMT_CHRONO_H_
9 #define FMT_CHRONO_H_
10 
11 #include <chrono>
12 #include <ctime>
13 #include <locale>
14 #include <sstream>
15 
16 #include "format.h"
17 #include "locale.h"
18 
19 FMT_BEGIN_NAMESPACE
20 
21 // Enable safe chrono durations, unless explicitly disabled.
22 #ifndef FMT_SAFE_DURATION_CAST
23 #  define FMT_SAFE_DURATION_CAST 1
24 #endif
25 #if FMT_SAFE_DURATION_CAST
26 
27 // For conversion between std::chrono::durations without undefined
28 // behaviour or erroneous results.
29 // This is a stripped down version of duration_cast, for inclusion in fmt.
30 // See https://github.com/pauldreik/safe_duration_cast
31 //
32 // Copyright Paul Dreik 2019
33 namespace safe_duration_cast {
34 
35 template <typename To, typename From,
36           FMT_ENABLE_IF(!std::is_same<From, To>::value &&
37                         std::numeric_limits<From>::is_signed ==
38                             std::numeric_limits<To>::is_signed)>
lossless_integral_conversion(const From from,int & ec)39 FMT_CONSTEXPR To lossless_integral_conversion(const From from, int& ec) {
40   ec = 0;
41   using F = std::numeric_limits<From>;
42   using T = std::numeric_limits<To>;
43   static_assert(F::is_integer, "From must be integral");
44   static_assert(T::is_integer, "To must be integral");
45 
46   // A and B are both signed, or both unsigned.
47   if (F::digits <= T::digits) {
48     // From fits in To without any problem.
49   } else {
50     // From does not always fit in To, resort to a dynamic check.
51     if (from < (T::min)() || from > (T::max)()) {
52       // outside range.
53       ec = 1;
54       return {};
55     }
56   }
57   return static_cast<To>(from);
58 }
59 
60 /**
61  * converts From to To, without loss. If the dynamic value of from
62  * can't be converted to To without loss, ec is set.
63  */
64 template <typename To, typename From,
65           FMT_ENABLE_IF(!std::is_same<From, To>::value &&
66                         std::numeric_limits<From>::is_signed !=
67                             std::numeric_limits<To>::is_signed)>
lossless_integral_conversion(const From from,int & ec)68 FMT_CONSTEXPR To lossless_integral_conversion(const From from, int& ec) {
69   ec = 0;
70   using F = std::numeric_limits<From>;
71   using T = std::numeric_limits<To>;
72   static_assert(F::is_integer, "From must be integral");
73   static_assert(T::is_integer, "To must be integral");
74 
75   if (detail::const_check(F::is_signed && !T::is_signed)) {
76     // From may be negative, not allowed!
77     if (fmt::detail::is_negative(from)) {
78       ec = 1;
79       return {};
80     }
81     // From is positive. Can it always fit in To?
82     if (F::digits > T::digits &&
83         from > static_cast<From>(detail::max_value<To>())) {
84       ec = 1;
85       return {};
86     }
87   }
88 
89   if (!F::is_signed && T::is_signed && F::digits >= T::digits &&
90       from > static_cast<From>(detail::max_value<To>())) {
91     ec = 1;
92     return {};
93   }
94   return static_cast<To>(from);  // Lossless conversion.
95 }
96 
97 template <typename To, typename From,
98           FMT_ENABLE_IF(std::is_same<From, To>::value)>
lossless_integral_conversion(const From from,int & ec)99 FMT_CONSTEXPR To lossless_integral_conversion(const From from, int& ec) {
100   ec = 0;
101   return from;
102 }  // function
103 
104 // clang-format off
105 /**
106  * converts From to To if possible, otherwise ec is set.
107  *
108  * input                            |    output
109  * ---------------------------------|---------------
110  * NaN                              | NaN
111  * Inf                              | Inf
112  * normal, fits in output           | converted (possibly lossy)
113  * normal, does not fit in output   | ec is set
114  * subnormal                        | best effort
115  * -Inf                             | -Inf
116  */
117 // clang-format on
118 template <typename To, typename From,
119           FMT_ENABLE_IF(!std::is_same<From, To>::value)>
safe_float_conversion(const From from,int & ec)120 FMT_CONSTEXPR To safe_float_conversion(const From from, int& ec) {
121   ec = 0;
122   using T = std::numeric_limits<To>;
123   static_assert(std::is_floating_point<From>::value, "From must be floating");
124   static_assert(std::is_floating_point<To>::value, "To must be floating");
125 
126   // catch the only happy case
127   if (std::isfinite(from)) {
128     if (from >= T::lowest() && from <= (T::max)()) {
129       return static_cast<To>(from);
130     }
131     // not within range.
132     ec = 1;
133     return {};
134   }
135 
136   // nan and inf will be preserved
137   return static_cast<To>(from);
138 }  // function
139 
140 template <typename To, typename From,
141           FMT_ENABLE_IF(std::is_same<From, To>::value)>
safe_float_conversion(const From from,int & ec)142 FMT_CONSTEXPR To safe_float_conversion(const From from, int& ec) {
143   ec = 0;
144   static_assert(std::is_floating_point<From>::value, "From must be floating");
145   return from;
146 }
147 
148 /**
149  * safe duration cast between integral durations
150  */
151 template <typename To, typename FromRep, typename FromPeriod,
152           FMT_ENABLE_IF(std::is_integral<FromRep>::value),
153           FMT_ENABLE_IF(std::is_integral<typename To::rep>::value)>
safe_duration_cast(std::chrono::duration<FromRep,FromPeriod> from,int & ec)154 To safe_duration_cast(std::chrono::duration<FromRep, FromPeriod> from,
155                       int& ec) {
156   using From = std::chrono::duration<FromRep, FromPeriod>;
157   ec = 0;
158   // the basic idea is that we need to convert from count() in the from type
159   // to count() in the To type, by multiplying it with this:
160   struct Factor
161       : std::ratio_divide<typename From::period, typename To::period> {};
162 
163   static_assert(Factor::num > 0, "num must be positive");
164   static_assert(Factor::den > 0, "den must be positive");
165 
166   // the conversion is like this: multiply from.count() with Factor::num
167   // /Factor::den and convert it to To::rep, all this without
168   // overflow/underflow. let's start by finding a suitable type that can hold
169   // both To, From and Factor::num
170   using IntermediateRep =
171       typename std::common_type<typename From::rep, typename To::rep,
172                                 decltype(Factor::num)>::type;
173 
174   // safe conversion to IntermediateRep
175   IntermediateRep count =
176       lossless_integral_conversion<IntermediateRep>(from.count(), ec);
177   if (ec) return {};
178   // multiply with Factor::num without overflow or underflow
179   if (detail::const_check(Factor::num != 1)) {
180     const auto max1 = detail::max_value<IntermediateRep>() / Factor::num;
181     if (count > max1) {
182       ec = 1;
183       return {};
184     }
185     const auto min1 =
186         (std::numeric_limits<IntermediateRep>::min)() / Factor::num;
187     if (count < min1) {
188       ec = 1;
189       return {};
190     }
191     count *= Factor::num;
192   }
193 
194   if (detail::const_check(Factor::den != 1)) count /= Factor::den;
195   auto tocount = lossless_integral_conversion<typename To::rep>(count, ec);
196   return ec ? To() : To(tocount);
197 }
198 
199 /**
200  * safe duration_cast between floating point durations
201  */
202 template <typename To, typename FromRep, typename FromPeriod,
203           FMT_ENABLE_IF(std::is_floating_point<FromRep>::value),
204           FMT_ENABLE_IF(std::is_floating_point<typename To::rep>::value)>
safe_duration_cast(std::chrono::duration<FromRep,FromPeriod> from,int & ec)205 To safe_duration_cast(std::chrono::duration<FromRep, FromPeriod> from,
206                       int& ec) {
207   using From = std::chrono::duration<FromRep, FromPeriod>;
208   ec = 0;
209   if (std::isnan(from.count())) {
210     // nan in, gives nan out. easy.
211     return To{std::numeric_limits<typename To::rep>::quiet_NaN()};
212   }
213   // maybe we should also check if from is denormal, and decide what to do about
214   // it.
215 
216   // +-inf should be preserved.
217   if (std::isinf(from.count())) {
218     return To{from.count()};
219   }
220 
221   // the basic idea is that we need to convert from count() in the from type
222   // to count() in the To type, by multiplying it with this:
223   struct Factor
224       : std::ratio_divide<typename From::period, typename To::period> {};
225 
226   static_assert(Factor::num > 0, "num must be positive");
227   static_assert(Factor::den > 0, "den must be positive");
228 
229   // the conversion is like this: multiply from.count() with Factor::num
230   // /Factor::den and convert it to To::rep, all this without
231   // overflow/underflow. let's start by finding a suitable type that can hold
232   // both To, From and Factor::num
233   using IntermediateRep =
234       typename std::common_type<typename From::rep, typename To::rep,
235                                 decltype(Factor::num)>::type;
236 
237   // force conversion of From::rep -> IntermediateRep to be safe,
238   // even if it will never happen be narrowing in this context.
239   IntermediateRep count =
240       safe_float_conversion<IntermediateRep>(from.count(), ec);
241   if (ec) {
242     return {};
243   }
244 
245   // multiply with Factor::num without overflow or underflow
246   if (Factor::num != 1) {
247     constexpr auto max1 = detail::max_value<IntermediateRep>() /
248                           static_cast<IntermediateRep>(Factor::num);
249     if (count > max1) {
250       ec = 1;
251       return {};
252     }
253     constexpr auto min1 = std::numeric_limits<IntermediateRep>::lowest() /
254                           static_cast<IntermediateRep>(Factor::num);
255     if (count < min1) {
256       ec = 1;
257       return {};
258     }
259     count *= static_cast<IntermediateRep>(Factor::num);
260   }
261 
262   // this can't go wrong, right? den>0 is checked earlier.
263   if (Factor::den != 1) {
264     using common_t = typename std::common_type<IntermediateRep, intmax_t>::type;
265     count /= static_cast<common_t>(Factor::den);
266   }
267 
268   // convert to the to type, safely
269   using ToRep = typename To::rep;
270 
271   const ToRep tocount = safe_float_conversion<ToRep>(count, ec);
272   if (ec) {
273     return {};
274   }
275   return To{tocount};
276 }
277 }  // namespace safe_duration_cast
278 #endif
279 
280 // Prevents expansion of a preceding token as a function-style macro.
281 // Usage: f FMT_NOMACRO()
282 #define FMT_NOMACRO
283 
284 namespace detail {
FMT_NOMACRO(...)285 inline null<> localtime_r FMT_NOMACRO(...) { return null<>(); }
localtime_s(...)286 inline null<> localtime_s(...) { return null<>(); }
gmtime_r(...)287 inline null<> gmtime_r(...) { return null<>(); }
gmtime_s(...)288 inline null<> gmtime_s(...) { return null<>(); }
289 }  // namespace detail
290 
291 // Thread-safe replacement for std::localtime
localtime(std::time_t time)292 inline std::tm localtime(std::time_t time) {
293   struct dispatcher {
294     std::time_t time_;
295     std::tm tm_;
296 
297     dispatcher(std::time_t t) : time_(t) {}
298 
299     bool run() {
300       using namespace fmt::detail;
301       return handle(localtime_r(&time_, &tm_));
302     }
303 
304     bool handle(std::tm* tm) { return tm != nullptr; }
305 
306     bool handle(detail::null<>) {
307       using namespace fmt::detail;
308       return fallback(localtime_s(&tm_, &time_));
309     }
310 
311     bool fallback(int res) { return res == 0; }
312 
313 #if !FMT_MSC_VER
314     bool fallback(detail::null<>) {
315       using namespace fmt::detail;
316       std::tm* tm = std::localtime(&time_);
317       if (tm) tm_ = *tm;
318       return tm != nullptr;
319     }
320 #endif
321   };
322   dispatcher lt(time);
323   // Too big time values may be unsupported.
324   if (!lt.run()) FMT_THROW(format_error("time_t value out of range"));
325   return lt.tm_;
326 }
327 
localtime(std::chrono::time_point<std::chrono::system_clock> time_point)328 inline std::tm localtime(
329     std::chrono::time_point<std::chrono::system_clock> time_point) {
330   return localtime(std::chrono::system_clock::to_time_t(time_point));
331 }
332 
333 // Thread-safe replacement for std::gmtime
gmtime(std::time_t time)334 inline std::tm gmtime(std::time_t time) {
335   struct dispatcher {
336     std::time_t time_;
337     std::tm tm_;
338 
339     dispatcher(std::time_t t) : time_(t) {}
340 
341     bool run() {
342       using namespace fmt::detail;
343       return handle(gmtime_r(&time_, &tm_));
344     }
345 
346     bool handle(std::tm* tm) { return tm != nullptr; }
347 
348     bool handle(detail::null<>) {
349       using namespace fmt::detail;
350       return fallback(gmtime_s(&tm_, &time_));
351     }
352 
353     bool fallback(int res) { return res == 0; }
354 
355 #if !FMT_MSC_VER
356     bool fallback(detail::null<>) {
357       std::tm* tm = std::gmtime(&time_);
358       if (tm) tm_ = *tm;
359       return tm != nullptr;
360     }
361 #endif
362   };
363   dispatcher gt(time);
364   // Too big time values may be unsupported.
365   if (!gt.run()) FMT_THROW(format_error("time_t value out of range"));
366   return gt.tm_;
367 }
368 
gmtime(std::chrono::time_point<std::chrono::system_clock> time_point)369 inline std::tm gmtime(
370     std::chrono::time_point<std::chrono::system_clock> time_point) {
371   return gmtime(std::chrono::system_clock::to_time_t(time_point));
372 }
373 
374 namespace detail {
strftime(char * str,size_t count,const char * format,const std::tm * time)375 inline size_t strftime(char* str, size_t count, const char* format,
376                        const std::tm* time) {
377   return std::strftime(str, count, format, time);
378 }
379 
strftime(wchar_t * str,size_t count,const wchar_t * format,const std::tm * time)380 inline size_t strftime(wchar_t* str, size_t count, const wchar_t* format,
381                        const std::tm* time) {
382   return std::wcsftime(str, count, format, time);
383 }
384 }  // namespace detail
385 
386 template <typename Char>
387 struct formatter<std::chrono::time_point<std::chrono::system_clock>, Char>
388     : formatter<std::tm, Char> {
389   template <typename FormatContext>
390   auto format(std::chrono::time_point<std::chrono::system_clock> val,
391               FormatContext& ctx) -> decltype(ctx.out()) {
392     std::tm time = localtime(val);
393     return formatter<std::tm, Char>::format(time, ctx);
394   }
395 };
396 
397 template <typename Char> struct formatter<std::tm, Char> {
398   template <typename ParseContext>
399   auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
400     auto it = ctx.begin();
401     if (it != ctx.end() && *it == ':') ++it;
402     auto end = it;
403     while (end != ctx.end() && *end != '}') ++end;
404     tm_format.reserve(detail::to_unsigned(end - it + 1));
405     tm_format.append(it, end);
406     tm_format.push_back('\0');
407     return end;
408   }
409 
410   template <typename FormatContext>
411   auto format(const std::tm& tm, FormatContext& ctx) -> decltype(ctx.out()) {
412     basic_memory_buffer<Char> buf;
413     size_t start = buf.size();
414     for (;;) {
415       size_t size = buf.capacity() - start;
416       size_t count = detail::strftime(&buf[start], size, &tm_format[0], &tm);
417       if (count != 0) {
418         buf.resize(start + count);
419         break;
420       }
421       if (size >= tm_format.size() * 256) {
422         // If the buffer is 256 times larger than the format string, assume
423         // that `strftime` gives an empty result. There doesn't seem to be a
424         // better way to distinguish the two cases:
425         // https://github.com/fmtlib/fmt/issues/367
426         break;
427       }
428       const size_t MIN_GROWTH = 10;
429       buf.reserve(buf.capacity() + (size > MIN_GROWTH ? size : MIN_GROWTH));
430     }
431     return std::copy(buf.begin(), buf.end(), ctx.out());
432   }
433 
434   basic_memory_buffer<Char> tm_format;
435 };
436 
437 namespace detail {
438 template <typename Period> FMT_CONSTEXPR const char* get_units() {
439   return nullptr;
440 }
441 template <> FMT_CONSTEXPR const char* get_units<std::atto>() { return "as"; }
442 template <> FMT_CONSTEXPR const char* get_units<std::femto>() { return "fs"; }
443 template <> FMT_CONSTEXPR const char* get_units<std::pico>() { return "ps"; }
444 template <> FMT_CONSTEXPR const char* get_units<std::nano>() { return "ns"; }
445 template <> FMT_CONSTEXPR const char* get_units<std::micro>() { return "µs"; }
446 template <> FMT_CONSTEXPR const char* get_units<std::milli>() { return "ms"; }
447 template <> FMT_CONSTEXPR const char* get_units<std::centi>() { return "cs"; }
448 template <> FMT_CONSTEXPR const char* get_units<std::deci>() { return "ds"; }
449 template <> FMT_CONSTEXPR const char* get_units<std::ratio<1>>() { return "s"; }
450 template <> FMT_CONSTEXPR const char* get_units<std::deca>() { return "das"; }
451 template <> FMT_CONSTEXPR const char* get_units<std::hecto>() { return "hs"; }
452 template <> FMT_CONSTEXPR const char* get_units<std::kilo>() { return "ks"; }
453 template <> FMT_CONSTEXPR const char* get_units<std::mega>() { return "Ms"; }
454 template <> FMT_CONSTEXPR const char* get_units<std::giga>() { return "Gs"; }
455 template <> FMT_CONSTEXPR const char* get_units<std::tera>() { return "Ts"; }
456 template <> FMT_CONSTEXPR const char* get_units<std::peta>() { return "Ps"; }
457 template <> FMT_CONSTEXPR const char* get_units<std::exa>() { return "Es"; }
458 template <> FMT_CONSTEXPR const char* get_units<std::ratio<60>>() {
459   return "m";
460 }
461 template <> FMT_CONSTEXPR const char* get_units<std::ratio<3600>>() {
462   return "h";
463 }
464 
465 enum class numeric_system {
466   standard,
467   // Alternative numeric system, e.g. 十二 instead of 12 in ja_JP locale.
468   alternative
469 };
470 
471 // Parses a put_time-like format string and invokes handler actions.
472 template <typename Char, typename Handler>
473 FMT_CONSTEXPR const Char* parse_chrono_format(const Char* begin,
474                                               const Char* end,
475                                               Handler&& handler) {
476   auto ptr = begin;
477   while (ptr != end) {
478     auto c = *ptr;
479     if (c == '}') break;
480     if (c != '%') {
481       ++ptr;
482       continue;
483     }
484     if (begin != ptr) handler.on_text(begin, ptr);
485     ++ptr;  // consume '%'
486     if (ptr == end) FMT_THROW(format_error("invalid format"));
487     c = *ptr++;
488     switch (c) {
489     case '%':
490       handler.on_text(ptr - 1, ptr);
491       break;
492     case 'n': {
493       const Char newline[] = {'\n'};
494       handler.on_text(newline, newline + 1);
495       break;
496     }
497     case 't': {
498       const Char tab[] = {'\t'};
499       handler.on_text(tab, tab + 1);
500       break;
501     }
502     // Day of the week:
503     case 'a':
504       handler.on_abbr_weekday();
505       break;
506     case 'A':
507       handler.on_full_weekday();
508       break;
509     case 'w':
510       handler.on_dec0_weekday(numeric_system::standard);
511       break;
512     case 'u':
513       handler.on_dec1_weekday(numeric_system::standard);
514       break;
515     // Month:
516     case 'b':
517       handler.on_abbr_month();
518       break;
519     case 'B':
520       handler.on_full_month();
521       break;
522     // Hour, minute, second:
523     case 'H':
524       handler.on_24_hour(numeric_system::standard);
525       break;
526     case 'I':
527       handler.on_12_hour(numeric_system::standard);
528       break;
529     case 'M':
530       handler.on_minute(numeric_system::standard);
531       break;
532     case 'S':
533       handler.on_second(numeric_system::standard);
534       break;
535     // Other:
536     case 'c':
537       handler.on_datetime(numeric_system::standard);
538       break;
539     case 'x':
540       handler.on_loc_date(numeric_system::standard);
541       break;
542     case 'X':
543       handler.on_loc_time(numeric_system::standard);
544       break;
545     case 'D':
546       handler.on_us_date();
547       break;
548     case 'F':
549       handler.on_iso_date();
550       break;
551     case 'r':
552       handler.on_12_hour_time();
553       break;
554     case 'R':
555       handler.on_24_hour_time();
556       break;
557     case 'T':
558       handler.on_iso_time();
559       break;
560     case 'p':
561       handler.on_am_pm();
562       break;
563     case 'Q':
564       handler.on_duration_value();
565       break;
566     case 'q':
567       handler.on_duration_unit();
568       break;
569     case 'z':
570       handler.on_utc_offset();
571       break;
572     case 'Z':
573       handler.on_tz_name();
574       break;
575     // Alternative representation:
576     case 'E': {
577       if (ptr == end) FMT_THROW(format_error("invalid format"));
578       c = *ptr++;
579       switch (c) {
580       case 'c':
581         handler.on_datetime(numeric_system::alternative);
582         break;
583       case 'x':
584         handler.on_loc_date(numeric_system::alternative);
585         break;
586       case 'X':
587         handler.on_loc_time(numeric_system::alternative);
588         break;
589       default:
590         FMT_THROW(format_error("invalid format"));
591       }
592       break;
593     }
594     case 'O':
595       if (ptr == end) FMT_THROW(format_error("invalid format"));
596       c = *ptr++;
597       switch (c) {
598       case 'w':
599         handler.on_dec0_weekday(numeric_system::alternative);
600         break;
601       case 'u':
602         handler.on_dec1_weekday(numeric_system::alternative);
603         break;
604       case 'H':
605         handler.on_24_hour(numeric_system::alternative);
606         break;
607       case 'I':
608         handler.on_12_hour(numeric_system::alternative);
609         break;
610       case 'M':
611         handler.on_minute(numeric_system::alternative);
612         break;
613       case 'S':
614         handler.on_second(numeric_system::alternative);
615         break;
616       default:
617         FMT_THROW(format_error("invalid format"));
618       }
619       break;
620     default:
621       FMT_THROW(format_error("invalid format"));
622     }
623     begin = ptr;
624   }
625   if (begin != ptr) handler.on_text(begin, ptr);
626   return ptr;
627 }
628 
629 struct chrono_format_checker {
630   FMT_NORETURN void report_no_date() { FMT_THROW(format_error("no date")); }
631 
632   template <typename Char> void on_text(const Char*, const Char*) {}
633   FMT_NORETURN void on_abbr_weekday() { report_no_date(); }
634   FMT_NORETURN void on_full_weekday() { report_no_date(); }
635   FMT_NORETURN void on_dec0_weekday(numeric_system) { report_no_date(); }
636   FMT_NORETURN void on_dec1_weekday(numeric_system) { report_no_date(); }
637   FMT_NORETURN void on_abbr_month() { report_no_date(); }
638   FMT_NORETURN void on_full_month() { report_no_date(); }
639   void on_24_hour(numeric_system) {}
640   void on_12_hour(numeric_system) {}
641   void on_minute(numeric_system) {}
642   void on_second(numeric_system) {}
643   FMT_NORETURN void on_datetime(numeric_system) { report_no_date(); }
644   FMT_NORETURN void on_loc_date(numeric_system) { report_no_date(); }
645   FMT_NORETURN void on_loc_time(numeric_system) { report_no_date(); }
646   FMT_NORETURN void on_us_date() { report_no_date(); }
647   FMT_NORETURN void on_iso_date() { report_no_date(); }
648   void on_12_hour_time() {}
649   void on_24_hour_time() {}
650   void on_iso_time() {}
651   void on_am_pm() {}
652   void on_duration_value() {}
653   void on_duration_unit() {}
654   FMT_NORETURN void on_utc_offset() { report_no_date(); }
655   FMT_NORETURN void on_tz_name() { report_no_date(); }
656 };
657 
658 template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
659 inline bool isnan(T) {
660   return false;
661 }
662 template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)>
663 inline bool isnan(T value) {
664   return std::isnan(value);
665 }
666 
667 template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
668 inline bool isfinite(T) {
669   return true;
670 }
671 template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)>
672 inline bool isfinite(T value) {
673   return std::isfinite(value);
674 }
675 
676 // Converts value to int and checks that it's in the range [0, upper).
677 template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
678 inline int to_nonnegative_int(T value, int upper) {
679   FMT_ASSERT(value >= 0 && value <= upper, "invalid value");
680   (void)upper;
681   return static_cast<int>(value);
682 }
683 template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)>
684 inline int to_nonnegative_int(T value, int upper) {
685   FMT_ASSERT(
686       std::isnan(value) || (value >= 0 && value <= static_cast<T>(upper)),
687       "invalid value");
688   (void)upper;
689   return static_cast<int>(value);
690 }
691 
692 template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
693 inline T mod(T x, int y) {
694   return x % static_cast<T>(y);
695 }
696 template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)>
697 inline T mod(T x, int y) {
698   return std::fmod(x, static_cast<T>(y));
699 }
700 
701 // If T is an integral type, maps T to its unsigned counterpart, otherwise
702 // leaves it unchanged (unlike std::make_unsigned).
703 template <typename T, bool INTEGRAL = std::is_integral<T>::value>
704 struct make_unsigned_or_unchanged {
705   using type = T;
706 };
707 
708 template <typename T> struct make_unsigned_or_unchanged<T, true> {
709   using type = typename std::make_unsigned<T>::type;
710 };
711 
712 #if FMT_SAFE_DURATION_CAST
713 // throwing version of safe_duration_cast
714 template <typename To, typename FromRep, typename FromPeriod>
715 To fmt_safe_duration_cast(std::chrono::duration<FromRep, FromPeriod> from) {
716   int ec;
717   To to = safe_duration_cast::safe_duration_cast<To>(from, ec);
718   if (ec) FMT_THROW(format_error("cannot format duration"));
719   return to;
720 }
721 #endif
722 
723 template <typename Rep, typename Period,
724           FMT_ENABLE_IF(std::is_integral<Rep>::value)>
725 inline std::chrono::duration<Rep, std::milli> get_milliseconds(
726     std::chrono::duration<Rep, Period> d) {
727   // this may overflow and/or the result may not fit in the
728   // target type.
729 #if FMT_SAFE_DURATION_CAST
730   using CommonSecondsType =
731       typename std::common_type<decltype(d), std::chrono::seconds>::type;
732   const auto d_as_common = fmt_safe_duration_cast<CommonSecondsType>(d);
733   const auto d_as_whole_seconds =
734       fmt_safe_duration_cast<std::chrono::seconds>(d_as_common);
735   // this conversion should be nonproblematic
736   const auto diff = d_as_common - d_as_whole_seconds;
737   const auto ms =
738       fmt_safe_duration_cast<std::chrono::duration<Rep, std::milli>>(diff);
739   return ms;
740 #else
741   auto s = std::chrono::duration_cast<std::chrono::seconds>(d);
742   return std::chrono::duration_cast<std::chrono::milliseconds>(d - s);
743 #endif
744 }
745 
746 template <typename Rep, typename Period,
747           FMT_ENABLE_IF(std::is_floating_point<Rep>::value)>
748 inline std::chrono::duration<Rep, std::milli> get_milliseconds(
749     std::chrono::duration<Rep, Period> d) {
750   using common_type = typename std::common_type<Rep, std::intmax_t>::type;
751   auto ms = mod(d.count() * static_cast<common_type>(Period::num) /
752                     static_cast<common_type>(Period::den) * 1000,
753                 1000);
754   return std::chrono::duration<Rep, std::milli>(static_cast<Rep>(ms));
755 }
756 
757 template <typename Char, typename Rep, typename OutputIt>
758 OutputIt format_duration_value(OutputIt out, Rep val, int precision) {
759   const Char pr_f[] = {'{', ':', '.', '{', '}', 'f', '}', 0};
760   if (precision >= 0) return format_to(out, pr_f, val, precision);
761   const Char fp_f[] = {'{', ':', 'g', '}', 0};
762   const Char format[] = {'{', '}', 0};
763   return format_to(out, std::is_floating_point<Rep>::value ? fp_f : format,
764                    val);
765 }
766 template <typename Char, typename OutputIt>
767 OutputIt copy_unit(string_view unit, OutputIt out, Char) {
768   return std::copy(unit.begin(), unit.end(), out);
769 }
770 
771 template <typename OutputIt>
772 OutputIt copy_unit(string_view unit, OutputIt out, wchar_t) {
773   // This works when wchar_t is UTF-32 because units only contain characters
774   // that have the same representation in UTF-16 and UTF-32.
775   utf8_to_utf16 u(unit);
776   return std::copy(u.c_str(), u.c_str() + u.size(), out);
777 }
778 
779 template <typename Char, typename Period, typename OutputIt>
780 OutputIt format_duration_unit(OutputIt out) {
781   if (const char* unit = get_units<Period>())
782     return copy_unit(string_view(unit), out, Char());
783   const Char num_f[] = {'[', '{', '}', ']', 's', 0};
784   if (const_check(Period::den == 1)) return format_to(out, num_f, Period::num);
785   const Char num_def_f[] = {'[', '{', '}', '/', '{', '}', ']', 's', 0};
786   return format_to(out, num_def_f, Period::num, Period::den);
787 }
788 
789 template <typename FormatContext, typename OutputIt, typename Rep,
790           typename Period>
791 struct chrono_formatter {
792   FormatContext& context;
793   OutputIt out;
794   int precision;
795   // rep is unsigned to avoid overflow.
796   using rep =
797       conditional_t<std::is_integral<Rep>::value && sizeof(Rep) < sizeof(int),
798                     unsigned, typename make_unsigned_or_unchanged<Rep>::type>;
799   rep val;
800   using seconds = std::chrono::duration<rep>;
801   seconds s;
802   using milliseconds = std::chrono::duration<rep, std::milli>;
803   bool negative;
804 
805   using char_type = typename FormatContext::char_type;
806 
807   explicit chrono_formatter(FormatContext& ctx, OutputIt o,
808                             std::chrono::duration<Rep, Period> d)
809       : context(ctx),
810         out(o),
811         val(static_cast<rep>(d.count())),
812         negative(false) {
813     if (d.count() < 0) {
814       val = 0 - val;
815       negative = true;
816     }
817 
818     // this may overflow and/or the result may not fit in the
819     // target type.
820 #if FMT_SAFE_DURATION_CAST
821     // might need checked conversion (rep!=Rep)
822     auto tmpval = std::chrono::duration<rep, Period>(val);
823     s = fmt_safe_duration_cast<seconds>(tmpval);
824 #else
825     s = std::chrono::duration_cast<seconds>(
826         std::chrono::duration<rep, Period>(val));
827 #endif
828   }
829 
830   // returns true if nan or inf, writes to out.
831   bool handle_nan_inf() {
832     if (isfinite(val)) {
833       return false;
834     }
835     if (isnan(val)) {
836       write_nan();
837       return true;
838     }
839     // must be +-inf
840     if (val > 0) {
841       write_pinf();
842     } else {
843       write_ninf();
844     }
845     return true;
846   }
847 
848   Rep hour() const { return static_cast<Rep>(mod((s.count() / 3600), 24)); }
849 
850   Rep hour12() const {
851     Rep hour = static_cast<Rep>(mod((s.count() / 3600), 12));
852     return hour <= 0 ? 12 : hour;
853   }
854 
855   Rep minute() const { return static_cast<Rep>(mod((s.count() / 60), 60)); }
856   Rep second() const { return static_cast<Rep>(mod(s.count(), 60)); }
857 
858   std::tm time() const {
859     auto time = std::tm();
860     time.tm_hour = to_nonnegative_int(hour(), 24);
861     time.tm_min = to_nonnegative_int(minute(), 60);
862     time.tm_sec = to_nonnegative_int(second(), 60);
863     return time;
864   }
865 
866   void write_sign() {
867     if (negative) {
868       *out++ = '-';
869       negative = false;
870     }
871   }
872 
873   void write(Rep value, int width) {
874     write_sign();
875     if (isnan(value)) return write_nan();
876     uint32_or_64_or_128_t<int> n =
877         to_unsigned(to_nonnegative_int(value, max_value<int>()));
878     int num_digits = detail::count_digits(n);
879     if (width > num_digits) out = std::fill_n(out, width - num_digits, '0');
880     out = format_decimal<char_type>(out, n, num_digits).end;
881   }
882 
883   void write_nan() { std::copy_n("nan", 3, out); }
884   void write_pinf() { std::copy_n("inf", 3, out); }
885   void write_ninf() { std::copy_n("-inf", 4, out); }
886 
887   void format_localized(const tm& time, char format, char modifier = 0) {
888     if (isnan(val)) return write_nan();
889     auto locale = context.locale().template get<std::locale>();
890     auto& facet = std::use_facet<std::time_put<char_type>>(locale);
891     std::basic_ostringstream<char_type> os;
892     os.imbue(locale);
893     facet.put(os, os, ' ', &time, format, modifier);
894     auto str = os.str();
895     std::copy(str.begin(), str.end(), out);
896   }
897 
898   void on_text(const char_type* begin, const char_type* end) {
899     std::copy(begin, end, out);
900   }
901 
902   // These are not implemented because durations don't have date information.
903   void on_abbr_weekday() {}
904   void on_full_weekday() {}
905   void on_dec0_weekday(numeric_system) {}
906   void on_dec1_weekday(numeric_system) {}
907   void on_abbr_month() {}
908   void on_full_month() {}
909   void on_datetime(numeric_system) {}
910   void on_loc_date(numeric_system) {}
911   void on_loc_time(numeric_system) {}
912   void on_us_date() {}
913   void on_iso_date() {}
914   void on_utc_offset() {}
915   void on_tz_name() {}
916 
917   void on_24_hour(numeric_system ns) {
918     if (handle_nan_inf()) return;
919 
920     if (ns == numeric_system::standard) return write(hour(), 2);
921     auto time = tm();
922     time.tm_hour = to_nonnegative_int(hour(), 24);
923     format_localized(time, 'H', 'O');
924   }
925 
926   void on_12_hour(numeric_system ns) {
927     if (handle_nan_inf()) return;
928 
929     if (ns == numeric_system::standard) return write(hour12(), 2);
930     auto time = tm();
931     time.tm_hour = to_nonnegative_int(hour12(), 12);
932     format_localized(time, 'I', 'O');
933   }
934 
935   void on_minute(numeric_system ns) {
936     if (handle_nan_inf()) return;
937 
938     if (ns == numeric_system::standard) return write(minute(), 2);
939     auto time = tm();
940     time.tm_min = to_nonnegative_int(minute(), 60);
941     format_localized(time, 'M', 'O');
942   }
943 
944   void on_second(numeric_system ns) {
945     if (handle_nan_inf()) return;
946 
947     if (ns == numeric_system::standard) {
948       write(second(), 2);
949 #if FMT_SAFE_DURATION_CAST
950       // convert rep->Rep
951       using duration_rep = std::chrono::duration<rep, Period>;
952       using duration_Rep = std::chrono::duration<Rep, Period>;
953       auto tmpval = fmt_safe_duration_cast<duration_Rep>(duration_rep{val});
954 #else
955       auto tmpval = std::chrono::duration<Rep, Period>(val);
956 #endif
957       auto ms = get_milliseconds(tmpval);
958       if (ms != std::chrono::milliseconds(0)) {
959         *out++ = '.';
960         write(ms.count(), 3);
961       }
962       return;
963     }
964     auto time = tm();
965     time.tm_sec = to_nonnegative_int(second(), 60);
966     format_localized(time, 'S', 'O');
967   }
968 
969   void on_12_hour_time() {
970     if (handle_nan_inf()) return;
971     format_localized(time(), 'r');
972   }
973 
974   void on_24_hour_time() {
975     if (handle_nan_inf()) {
976       *out++ = ':';
977       handle_nan_inf();
978       return;
979     }
980 
981     write(hour(), 2);
982     *out++ = ':';
983     write(minute(), 2);
984   }
985 
986   void on_iso_time() {
987     on_24_hour_time();
988     *out++ = ':';
989     if (handle_nan_inf()) return;
990     write(second(), 2);
991   }
992 
993   void on_am_pm() {
994     if (handle_nan_inf()) return;
995     format_localized(time(), 'p');
996   }
997 
998   void on_duration_value() {
999     if (handle_nan_inf()) return;
1000     write_sign();
1001     out = format_duration_value<char_type>(out, val, precision);
1002   }
1003 
1004   void on_duration_unit() {
1005     out = format_duration_unit<char_type, Period>(out);
1006   }
1007 };
1008 }  // namespace detail
1009 
1010 template <typename Rep, typename Period, typename Char>
1011 struct formatter<std::chrono::duration<Rep, Period>, Char> {
1012  private:
1013   basic_format_specs<Char> specs;
1014   int precision;
1015   using arg_ref_type = detail::arg_ref<Char>;
1016   arg_ref_type width_ref;
1017   arg_ref_type precision_ref;
1018   mutable basic_string_view<Char> format_str;
1019   using duration = std::chrono::duration<Rep, Period>;
1020 
1021   struct spec_handler {
1022     formatter& f;
1023     basic_format_parse_context<Char>& context;
1024     basic_string_view<Char> format_str;
1025 
1026     template <typename Id> FMT_CONSTEXPR arg_ref_type make_arg_ref(Id arg_id) {
1027       context.check_arg_id(arg_id);
1028       return arg_ref_type(arg_id);
1029     }
1030 
1031     FMT_CONSTEXPR arg_ref_type make_arg_ref(basic_string_view<Char> arg_id) {
1032       context.check_arg_id(arg_id);
1033       return arg_ref_type(arg_id);
1034     }
1035 
1036     FMT_CONSTEXPR arg_ref_type make_arg_ref(detail::auto_id) {
1037       return arg_ref_type(context.next_arg_id());
1038     }
1039 
1040     void on_error(const char* msg) { FMT_THROW(format_error(msg)); }
1041     void on_fill(basic_string_view<Char> fill) { f.specs.fill = fill; }
1042     void on_align(align_t align) { f.specs.align = align; }
1043     void on_width(int width) { f.specs.width = width; }
1044     void on_precision(int _precision) { f.precision = _precision; }
1045     void end_precision() {}
1046 
1047     template <typename Id> void on_dynamic_width(Id arg_id) {
1048       f.width_ref = make_arg_ref(arg_id);
1049     }
1050 
1051     template <typename Id> void on_dynamic_precision(Id arg_id) {
1052       f.precision_ref = make_arg_ref(arg_id);
1053     }
1054   };
1055 
1056   using iterator = typename basic_format_parse_context<Char>::iterator;
1057   struct parse_range {
1058     iterator begin;
1059     iterator end;
1060   };
1061 
1062   FMT_CONSTEXPR parse_range do_parse(basic_format_parse_context<Char>& ctx) {
1063     auto begin = ctx.begin(), end = ctx.end();
1064     if (begin == end || *begin == '}') return {begin, begin};
1065     spec_handler handler{*this, ctx, format_str};
1066     begin = detail::parse_align(begin, end, handler);
1067     if (begin == end) return {begin, begin};
1068     begin = detail::parse_width(begin, end, handler);
1069     if (begin == end) return {begin, begin};
1070     if (*begin == '.') {
1071       if (std::is_floating_point<Rep>::value)
1072         begin = detail::parse_precision(begin, end, handler);
1073       else
1074         handler.on_error("precision not allowed for this argument type");
1075     }
1076     end = parse_chrono_format(begin, end, detail::chrono_format_checker());
1077     return {begin, end};
1078   }
1079 
1080  public:
1081   formatter() : precision(-1) {}
1082 
1083   FMT_CONSTEXPR auto parse(basic_format_parse_context<Char>& ctx)
1084       -> decltype(ctx.begin()) {
1085     auto range = do_parse(ctx);
1086     format_str = basic_string_view<Char>(
1087         &*range.begin, detail::to_unsigned(range.end - range.begin));
1088     return range.end;
1089   }
1090 
1091   template <typename FormatContext>
1092   auto format(const duration& d, FormatContext& ctx) -> decltype(ctx.out()) {
1093     auto begin = format_str.begin(), end = format_str.end();
1094     // As a possible future optimization, we could avoid extra copying if width
1095     // is not specified.
1096     basic_memory_buffer<Char> buf;
1097     auto out = std::back_inserter(buf);
1098     detail::handle_dynamic_spec<detail::width_checker>(specs.width, width_ref,
1099                                                        ctx);
1100     detail::handle_dynamic_spec<detail::precision_checker>(precision,
1101                                                            precision_ref, ctx);
1102     if (begin == end || *begin == '}') {
1103       out = detail::format_duration_value<Char>(out, d.count(), precision);
1104       detail::format_duration_unit<Char, Period>(out);
1105     } else {
1106       detail::chrono_formatter<FormatContext, decltype(out), Rep, Period> f(
1107           ctx, out, d);
1108       f.precision = precision;
1109       parse_chrono_format(begin, end, f);
1110     }
1111     return detail::write(
1112         ctx.out(), basic_string_view<Char>(buf.data(), buf.size()), specs);
1113   }
1114 };
1115 
1116 FMT_END_NAMESPACE
1117 
1118 #endif  // FMT_CHRONO_H_
1119