Photon 1.0.0
Loading...
Searching...
No Matches
chrono.h
Go to the documentation of this file.
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 <algorithm>
12#include <chrono>
13#include <cmath> // std::isfinite
14#include <cstring> // std::memcpy
15#include <ctime>
16#include <iterator>
17#include <locale>
18#include <ostream>
19#include <type_traits>
20
21#include "format.h"
22
24
25// Enable tzset.
26#ifndef FMT_USE_TZSET
27// UWP doesn't provide _tzset.
28#if FMT_HAS_INCLUDE("winapifamily.h")
29#include <winapifamily.h>
30#endif
31#if defined(_WIN32) && (!defined(WINAPI_FAMILY) || \
32 (WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP))
33#define FMT_USE_TZSET 1
34#else
35#define FMT_USE_TZSET 0
36#endif
37#endif
38
39// Enable safe chrono durations, unless explicitly disabled.
40#ifndef FMT_SAFE_DURATION_CAST
41#define FMT_SAFE_DURATION_CAST 1
42#endif
43#if FMT_SAFE_DURATION_CAST
44
45// For conversion between std::chrono::durations without undefined
46// behaviour or erroneous results.
47// This is a stripped down version of duration_cast, for inclusion in fmt.
48// See https://github.com/pauldreik/safe_duration_cast
49//
50// Copyright Paul Dreik 2019
52{
53
54 template <typename To, typename From, FMT_ENABLE_IF(!std::is_same<From, To>::value && std::numeric_limits<From>::is_signed == std::numeric_limits<To>::is_signed)>
55 FMT_CONSTEXPR To lossless_integral_conversion(const From from, int& ec)
56 {
57 ec = 0;
58 using F = std::numeric_limits<From>;
59 using T = std::numeric_limits<To>;
60 static_assert(F::is_integer, "From must be integral");
61 static_assert(T::is_integer, "To must be integral");
62
63 // A and B are both signed, or both unsigned.
64 if (detail::const_check(F::digits <= T::digits))
65 {
66 // From fits in To without any problem.
67 }
68 else
69 {
70 // From does not always fit in To, resort to a dynamic check.
71 if (from < (T::min)() || from > (T::max)())
72 {
73 // outside range.
74 ec = 1;
75 return {};
76 }
77 }
78 return static_cast<To>(from);
79 }
80
85 template <typename To, typename From, FMT_ENABLE_IF(!std::is_same<From, To>::value && std::numeric_limits<From>::is_signed != std::numeric_limits<To>::is_signed)>
86 FMT_CONSTEXPR To lossless_integral_conversion(const From from, int& ec)
87 {
88 ec = 0;
89 using F = std::numeric_limits<From>;
90 using T = std::numeric_limits<To>;
91 static_assert(F::is_integer, "From must be integral");
92 static_assert(T::is_integer, "To must be integral");
93
94 if (detail::const_check(F::is_signed && !T::is_signed))
95 {
96 // From may be negative, not allowed!
97 if (fmt::detail::is_negative(from))
98 {
99 ec = 1;
100 return {};
101 }
102 // From is positive. Can it always fit in To?
103 if (detail::const_check(F::digits > T::digits) &&
104 from > static_cast<From>(detail::max_value<To>()))
105 {
106 ec = 1;
107 return {};
108 }
109 }
110
111 if (detail::const_check(!F::is_signed && T::is_signed &&
112 F::digits >= T::digits) &&
113 from > static_cast<From>(detail::max_value<To>()))
114 {
115 ec = 1;
116 return {};
117 }
118 return static_cast<To>(from); // Lossless conversion.
119 }
120
121 template <typename To, typename From, FMT_ENABLE_IF(std::is_same<From, To>::value)>
122 FMT_CONSTEXPR To lossless_integral_conversion(const From from, int& ec)
123 {
124 ec = 0;
125 return from;
126 } // function
127
128 // clang-format off
141 // clang-format on
142 template <typename To, typename From, FMT_ENABLE_IF(!std::is_same<From, To>::value)>
143 FMT_CONSTEXPR To safe_float_conversion(const From from, int& ec)
144 {
145 ec = 0;
146 using T = std::numeric_limits<To>;
147 static_assert(std::is_floating_point<From>::value, "From must be floating");
148 static_assert(std::is_floating_point<To>::value, "To must be floating");
149
150 // catch the only happy case
151 if (std::isfinite(from))
152 {
153 if (from >= T::lowest() && from <= (T::max)())
154 {
155 return static_cast<To>(from);
156 }
157 // not within range.
158 ec = 1;
159 return {};
160 }
161
162 // nan and inf will be preserved
163 return static_cast<To>(from);
164 } // function
165
166 template <typename To, typename From, FMT_ENABLE_IF(std::is_same<From, To>::value)>
167 FMT_CONSTEXPR To safe_float_conversion(const From from, int& ec)
168 {
169 ec = 0;
170 static_assert(std::is_floating_point<From>::value, "From must be floating");
171 return from;
172 }
173
177 template <typename To, typename FromRep, typename FromPeriod, FMT_ENABLE_IF(std::is_integral<FromRep>::value), FMT_ENABLE_IF(std::is_integral<typename To::rep>::value)>
178 To safe_duration_cast(std::chrono::duration<FromRep, FromPeriod> from,
179 int& ec)
180 {
181 using From = std::chrono::duration<FromRep, FromPeriod>;
182 ec = 0;
183 // the basic idea is that we need to convert from count() in the from type
184 // to count() in the To type, by multiplying it with this:
185 struct Factor
186 : std::ratio_divide<typename From::period, typename To::period>
187 {
188 };
189
190 static_assert(Factor::num > 0, "num must be positive");
191 static_assert(Factor::den > 0, "den must be positive");
192
193 // the conversion is like this: multiply from.count() with Factor::num
194 // /Factor::den and convert it to To::rep, all this without
195 // overflow/underflow. let's start by finding a suitable type that can hold
196 // both To, From and Factor::num
197 using IntermediateRep =
198 typename std::common_type<typename From::rep, typename To::rep,
199 decltype(Factor::num)>::type;
200
201 // safe conversion to IntermediateRep
202 IntermediateRep count =
203 lossless_integral_conversion<IntermediateRep>(from.count(), ec);
204 if (ec)
205 return {};
206 // multiply with Factor::num without overflow or underflow
207 if (detail::const_check(Factor::num != 1))
208 {
209 const auto max1 = detail::max_value<IntermediateRep>() / Factor::num;
210 if (count > max1)
211 {
212 ec = 1;
213 return {};
214 }
215 const auto min1 =
216 (std::numeric_limits<IntermediateRep>::min)() / Factor::num;
217 if (!std::is_unsigned<IntermediateRep>::value && count < min1)
218 {
219 ec = 1;
220 return {};
221 }
222 count *= Factor::num;
223 }
224
225 if (detail::const_check(Factor::den != 1))
226 count /= Factor::den;
227 auto tocount = lossless_integral_conversion<typename To::rep>(count, ec);
228 return ec ? To() : To(tocount);
229 }
230
234 template <typename To, typename FromRep, typename FromPeriod, FMT_ENABLE_IF(std::is_floating_point<FromRep>::value), FMT_ENABLE_IF(std::is_floating_point<typename To::rep>::value)>
235 To safe_duration_cast(std::chrono::duration<FromRep, FromPeriod> from,
236 int& ec)
237 {
238 using From = std::chrono::duration<FromRep, FromPeriod>;
239 ec = 0;
240 if (std::isnan(from.count()))
241 {
242 // nan in, gives nan out. easy.
243 return To{std::numeric_limits<typename To::rep>::quiet_NaN()};
244 }
245 // maybe we should also check if from is denormal, and decide what to do about
246 // it.
247
248 // +-inf should be preserved.
249 if (std::isinf(from.count()))
250 {
251 return To{from.count()};
252 }
253
254 // the basic idea is that we need to convert from count() in the from type
255 // to count() in the To type, by multiplying it with this:
256 struct Factor
257 : std::ratio_divide<typename From::period, typename To::period>
258 {
259 };
260
261 static_assert(Factor::num > 0, "num must be positive");
262 static_assert(Factor::den > 0, "den must be positive");
263
264 // the conversion is like this: multiply from.count() with Factor::num
265 // /Factor::den and convert it to To::rep, all this without
266 // overflow/underflow. let's start by finding a suitable type that can hold
267 // both To, From and Factor::num
268 using IntermediateRep =
269 typename std::common_type<typename From::rep, typename To::rep,
270 decltype(Factor::num)>::type;
271
272 // force conversion of From::rep -> IntermediateRep to be safe,
273 // even if it will never happen be narrowing in this context.
274 IntermediateRep count =
275 safe_float_conversion<IntermediateRep>(from.count(), ec);
276 if (ec)
277 {
278 return {};
279 }
280
281 // multiply with Factor::num without overflow or underflow
282 if (detail::const_check(Factor::num != 1))
283 {
284 constexpr auto max1 = detail::max_value<IntermediateRep>() /
285 static_cast<IntermediateRep>(Factor::num);
286 if (count > max1)
287 {
288 ec = 1;
289 return {};
290 }
291 constexpr auto min1 = std::numeric_limits<IntermediateRep>::lowest() /
292 static_cast<IntermediateRep>(Factor::num);
293 if (count < min1)
294 {
295 ec = 1;
296 return {};
297 }
298 count *= static_cast<IntermediateRep>(Factor::num);
299 }
300
301 // this can't go wrong, right? den>0 is checked earlier.
302 if (detail::const_check(Factor::den != 1))
303 {
304 using common_t = typename std::common_type<IntermediateRep, intmax_t>::type;
305 count /= static_cast<common_t>(Factor::den);
306 }
307
308 // convert to the to type, safely
309 using ToRep = typename To::rep;
310
311 const ToRep tocount = safe_float_conversion<ToRep>(count, ec);
312 if (ec)
313 {
314 return {};
315 }
316 return To{tocount};
317 }
318} // namespace safe_duration_cast
319#endif
320
321// Prevents expansion of a preceding token as a function-style macro.
322// Usage: f FMT_NOMACRO()
323#define FMT_NOMACRO
324
325namespace detail
326{
327 template <typename T = void>
328 struct null
329 {
330 };
331 inline null<> localtime_r FMT_NOMACRO(...)
332 {
333 return null<>();
334 }
335 inline null<> localtime_s(...)
336 {
337 return null<>();
338 }
339 inline null<> gmtime_r(...)
340 {
341 return null<>();
342 }
343 inline null<> gmtime_s(...)
344 {
345 return null<>();
346 }
347
348 inline const std::locale& get_classic_locale()
349 {
350 static const auto& locale = std::locale::classic();
351 return locale;
352 }
353
354 template <typename CodeUnit>
356 {
357 static constexpr const size_t max_size = 32;
358 CodeUnit buf[max_size];
359 CodeUnit* end;
360 };
361 template <typename CodeUnit>
362 constexpr const size_t codecvt_result<CodeUnit>::max_size;
363
364 template <typename CodeUnit>
365 void write_codecvt(codecvt_result<CodeUnit>& out, string_view in_buf, const std::locale& loc)
366 {
367#if FMT_CLANG_VERSION
368#pragma clang diagnostic push
369#pragma clang diagnostic ignored "-Wdeprecated"
370 auto& f = std::use_facet<std::codecvt<CodeUnit, char, std::mbstate_t>>(loc);
371#pragma clang diagnostic pop
372#else
373 auto& f = std::use_facet<std::codecvt<CodeUnit, char, std::mbstate_t>>(loc);
374#endif
375 auto mb = std::mbstate_t();
376 const char* from_next = nullptr;
377 auto result = f.in(mb, in_buf.begin(), in_buf.end(), from_next,
378 std::begin(out.buf), std::end(out.buf), out.end);
379 if (result != std::codecvt_base::ok)
380 FMT_THROW(format_error("failed to format time"));
381 }
382
383 template <typename OutputIt>
384 auto write_encoded_tm_str(OutputIt out, string_view in, const std::locale& loc)
385 -> OutputIt
386 {
387 if (detail::is_utf8() && loc != get_classic_locale())
388 {
389 // char16_t and char32_t codecvts are broken in MSVC (linkage errors) and
390 // gcc-4.
391#if FMT_MSC_VERSION != 0 || \
392 (defined(__GLIBCXX__) && !defined(_GLIBCXX_USE_DUAL_ABI))
393 // The _GLIBCXX_USE_DUAL_ABI macro is always defined in libstdc++ from gcc-5
394 // and newer.
395 using code_unit = wchar_t;
396#else
397 using code_unit = char32_t;
398#endif
399
400 using unit_t = codecvt_result<code_unit>;
401 unit_t unit;
402 write_codecvt(unit, in, loc);
403 // In UTF-8 is used one to four one-byte code units.
405 for (code_unit* p = unit.buf; p != unit.end; ++p)
406 {
407 uint32_t c = static_cast<uint32_t>(*p);
408 if (sizeof(code_unit) == 2 && c >= 0xd800 && c <= 0xdfff)
409 {
410 // surrogate pair
411 ++p;
412 if (p == unit.end || (c & 0xfc00) != 0xd800 ||
413 (*p & 0xfc00) != 0xdc00)
414 {
415 FMT_THROW(format_error("failed to format time"));
416 }
417 c = (c << 10) + static_cast<uint32_t>(*p) - 0x35fdc00;
418 }
419 if (c < 0x80)
420 {
421 buf.push_back(static_cast<char>(c));
422 }
423 else if (c < 0x800)
424 {
425 buf.push_back(static_cast<char>(0xc0 | (c >> 6)));
426 buf.push_back(static_cast<char>(0x80 | (c & 0x3f)));
427 }
428 else if ((c >= 0x800 && c <= 0xd7ff) || (c >= 0xe000 && c <= 0xffff))
429 {
430 buf.push_back(static_cast<char>(0xe0 | (c >> 12)));
431 buf.push_back(static_cast<char>(0x80 | ((c & 0xfff) >> 6)));
432 buf.push_back(static_cast<char>(0x80 | (c & 0x3f)));
433 }
434 else if (c >= 0x10000 && c <= 0x10ffff)
435 {
436 buf.push_back(static_cast<char>(0xf0 | (c >> 18)));
437 buf.push_back(static_cast<char>(0x80 | ((c & 0x3ffff) >> 12)));
438 buf.push_back(static_cast<char>(0x80 | ((c & 0xfff) >> 6)));
439 buf.push_back(static_cast<char>(0x80 | (c & 0x3f)));
440 }
441 else
442 {
443 FMT_THROW(format_error("failed to format time"));
444 }
445 }
446 return copy_str<char>(buf.data(), buf.data() + buf.size(), out);
447 }
448 return copy_str<char>(in.data(), in.data() + in.size(), out);
449 }
450
451 template <typename Char, typename OutputIt, FMT_ENABLE_IF(!std::is_same<Char, char>::value)>
452 auto write_tm_str(OutputIt out, string_view sv, const std::locale& loc)
453 -> OutputIt
454 {
456 write_codecvt(unit, sv, loc);
457 return copy_str<Char>(unit.buf, unit.end, out);
458 }
459
460 template <typename Char, typename OutputIt, FMT_ENABLE_IF(std::is_same<Char, char>::value)>
461 auto write_tm_str(OutputIt out, string_view sv, const std::locale& loc)
462 -> OutputIt
463 {
464 return write_encoded_tm_str(out, sv, loc);
465 }
466
467 template <typename Char>
468 inline void do_write(buffer<Char>& buf, const std::tm& time, const std::locale& loc, char format, char modifier)
469 {
470 auto&& format_buf = formatbuf<std::basic_streambuf<Char>>(buf);
471 auto&& os = std::basic_ostream<Char>(&format_buf);
472 os.imbue(loc);
473 using iterator = std::ostreambuf_iterator<Char>;
474 const auto& facet = std::use_facet<std::time_put<Char, iterator>>(loc);
475 auto end = facet.put(os, os, Char(' '), &time, format, modifier);
476 if (end.failed())
477 FMT_THROW(format_error("failed to format time"));
478 }
479
480 template <typename Char, typename OutputIt, FMT_ENABLE_IF(!std::is_same<Char, char>::value)>
481 auto write(OutputIt out, const std::tm& time, const std::locale& loc, char format, char modifier = 0) -> OutputIt
482 {
483 auto&& buf = get_buffer<Char>(out);
484 do_write<Char>(buf, time, loc, format, modifier);
485 return buf.out();
486 }
487
488 template <typename Char, typename OutputIt, FMT_ENABLE_IF(std::is_same<Char, char>::value)>
489 auto write(OutputIt out, const std::tm& time, const std::locale& loc, char format, char modifier = 0) -> OutputIt
490 {
491 auto&& buf = basic_memory_buffer<Char>();
492 do_write<char>(buf, time, loc, format, modifier);
493 return write_encoded_tm_str(out, string_view(buf.data(), buf.size()), loc);
494 }
495
496} // namespace detail
497
499
505inline std::tm localtime(std::time_t time)
506{
507 struct dispatcher
508 {
509 std::time_t time_;
510 std::tm tm_;
511
512 dispatcher(std::time_t t)
513 : time_(t)
514 {
515 }
516
517 bool run()
518 {
519 using namespace fmt::detail;
520 return handle(localtime_r(&time_, &tm_));
521 }
522
523 bool handle(std::tm* tm)
524 {
525 return tm != nullptr;
526 }
527
528 bool handle(detail::null<>)
529 {
530 using namespace fmt::detail;
531 return fallback(localtime_s(&tm_, &time_));
532 }
533
534 bool fallback(int res)
535 {
536 return res == 0;
537 }
538
539#if !FMT_MSC_VERSION
540 bool fallback(detail::null<>)
541 {
542 using namespace fmt::detail;
543 std::tm* tm = std::localtime(&time_);
544 if (tm)
545 tm_ = *tm;
546 return tm != nullptr;
547 }
548#endif
549 };
550 dispatcher lt(time);
551 // Too big time values may be unsupported.
552 if (!lt.run())
553 FMT_THROW(format_error("time_t value out of range"));
554 return lt.tm_;
555}
556
557inline std::tm localtime(
558 std::chrono::time_point<std::chrono::system_clock> time_point)
559{
560 return localtime(std::chrono::system_clock::to_time_t(time_point));
561}
562
568inline std::tm gmtime(std::time_t time)
569{
570 struct dispatcher
571 {
572 std::time_t time_;
573 std::tm tm_;
574
575 dispatcher(std::time_t t)
576 : time_(t)
577 {
578 }
579
580 bool run()
581 {
582 using namespace fmt::detail;
583 return handle(gmtime_r(&time_, &tm_));
584 }
585
586 bool handle(std::tm* tm)
587 {
588 return tm != nullptr;
589 }
590
591 bool handle(detail::null<>)
592 {
593 using namespace fmt::detail;
594 return fallback(gmtime_s(&tm_, &time_));
595 }
596
597 bool fallback(int res)
598 {
599 return res == 0;
600 }
601
602#if !FMT_MSC_VERSION
603 bool fallback(detail::null<>)
604 {
605 std::tm* tm = std::gmtime(&time_);
606 if (tm)
607 tm_ = *tm;
608 return tm != nullptr;
609 }
610#endif
611 };
612 dispatcher gt(time);
613 // Too big time values may be unsupported.
614 if (!gt.run())
615 FMT_THROW(format_error("time_t value out of range"));
616 return gt.tm_;
617}
618
619inline std::tm gmtime(
620 std::chrono::time_point<std::chrono::system_clock> time_point)
621{
622 return gmtime(std::chrono::system_clock::to_time_t(time_point));
623}
624
626
627// Writes two-digit numbers a, b and c separated by sep to buf.
628// The method by Pavel Novikov based on
629// https://johnnylee-sde.github.io/Fast-unsigned-integer-to-time-string/.
630inline void write_digit2_separated(char* buf, unsigned a, unsigned b, unsigned c, char sep)
631{
632 unsigned long long digits =
633 a | (b << 24) | (static_cast<unsigned long long>(c) << 48);
634 // Convert each value to BCD.
635 // We have x = a * 10 + b and we want to convert it to BCD y = a * 16 + b.
636 // The difference is
637 // y - x = a * 6
638 // a can be found from x:
639 // a = floor(x / 10)
640 // then
641 // y = x + a * 6 = x + floor(x / 10) * 6
642 // floor(x / 10) is (x * 205) >> 11 (needs 16 bits).
643 digits += (((digits * 205) >> 11) & 0x000f00000f00000f) * 6;
644 // Put low nibbles to high bytes and high nibbles to low bytes.
645 digits = ((digits & 0x00f00000f00000f0) >> 4) |
646 ((digits & 0x000f00000f00000f) << 8);
647 auto usep = static_cast<unsigned long long>(sep);
648 // Add ASCII '0' to each digit byte and insert separators.
649 digits |= 0x3030003030003030 | (usep << 16) | (usep << 40);
650
651 constexpr const size_t len = 8;
652 if (const_check(is_big_endian()))
653 {
654 char tmp[len];
655 std::memcpy(tmp, &digits, len);
656 std::reverse_copy(tmp, tmp + len, buf);
657 }
658 else
659 {
660 std::memcpy(buf, &digits, len);
661 }
662}
663
664template <typename Period>
665FMT_CONSTEXPR inline const char* get_units()
666{
667 if (std::is_same<Period, std::atto>::value)
668 return "as";
669 if (std::is_same<Period, std::femto>::value)
670 return "fs";
671 if (std::is_same<Period, std::pico>::value)
672 return "ps";
673 if (std::is_same<Period, std::nano>::value)
674 return "ns";
675 if (std::is_same<Period, std::micro>::value)
676 return "µs";
677 if (std::is_same<Period, std::milli>::value)
678 return "ms";
679 if (std::is_same<Period, std::centi>::value)
680 return "cs";
681 if (std::is_same<Period, std::deci>::value)
682 return "ds";
683 if (std::is_same<Period, std::ratio<1>>::value)
684 return "s";
685 if (std::is_same<Period, std::deca>::value)
686 return "das";
687 if (std::is_same<Period, std::hecto>::value)
688 return "hs";
689 if (std::is_same<Period, std::kilo>::value)
690 return "ks";
691 if (std::is_same<Period, std::mega>::value)
692 return "Ms";
693 if (std::is_same<Period, std::giga>::value)
694 return "Gs";
695 if (std::is_same<Period, std::tera>::value)
696 return "Ts";
697 if (std::is_same<Period, std::peta>::value)
698 return "Ps";
699 if (std::is_same<Period, std::exa>::value)
700 return "Es";
701 if (std::is_same<Period, std::ratio<60>>::value)
702 return "m";
703 if (std::is_same<Period, std::ratio<3600>>::value)
704 return "h";
705 return nullptr;
706}
707
709{
710 standard,
711 // Alternative numeric system, e.g. 十二 instead of 12 in ja_JP locale.
713};
714
715// Parses a put_time-like format string and invokes handler actions.
716template <typename Char, typename Handler>
717FMT_CONSTEXPR const Char* parse_chrono_format(const Char* begin,
718 const Char* end,
719 Handler&& handler)
720{
721 auto ptr = begin;
722 while (ptr != end)
723 {
724 auto c = *ptr;
725 if (c == '}')
726 break;
727 if (c != '%')
728 {
729 ++ptr;
730 continue;
731 }
732 if (begin != ptr)
733 handler.on_text(begin, ptr);
734 ++ptr; // consume '%'
735 if (ptr == end)
736 FMT_THROW(format_error("invalid format"));
737 c = *ptr++;
738 switch (c)
739 {
740 case '%':
741 handler.on_text(ptr - 1, ptr);
742 break;
743 case 'n': {
744 const Char newline[] = {'\n'};
745 handler.on_text(newline, newline + 1);
746 break;
747 }
748 case 't': {
749 const Char tab[] = {'\t'};
750 handler.on_text(tab, tab + 1);
751 break;
752 }
753 // Year:
754 case 'Y':
755 handler.on_year(numeric_system::standard);
756 break;
757 case 'y':
758 handler.on_short_year(numeric_system::standard);
759 break;
760 case 'C':
761 handler.on_century(numeric_system::standard);
762 break;
763 case 'G':
764 handler.on_iso_week_based_year();
765 break;
766 case 'g':
767 handler.on_iso_week_based_short_year();
768 break;
769 // Day of the week:
770 case 'a':
771 handler.on_abbr_weekday();
772 break;
773 case 'A':
774 handler.on_full_weekday();
775 break;
776 case 'w':
777 handler.on_dec0_weekday(numeric_system::standard);
778 break;
779 case 'u':
780 handler.on_dec1_weekday(numeric_system::standard);
781 break;
782 // Month:
783 case 'b':
784 case 'h':
785 handler.on_abbr_month();
786 break;
787 case 'B':
788 handler.on_full_month();
789 break;
790 case 'm':
791 handler.on_dec_month(numeric_system::standard);
792 break;
793 // Day of the year/month:
794 case 'U':
795 handler.on_dec0_week_of_year(numeric_system::standard);
796 break;
797 case 'W':
798 handler.on_dec1_week_of_year(numeric_system::standard);
799 break;
800 case 'V':
801 handler.on_iso_week_of_year(numeric_system::standard);
802 break;
803 case 'j':
804 handler.on_day_of_year();
805 break;
806 case 'd':
807 handler.on_day_of_month(numeric_system::standard);
808 break;
809 case 'e':
810 handler.on_day_of_month_space(numeric_system::standard);
811 break;
812 // Hour, minute, second:
813 case 'H':
814 handler.on_24_hour(numeric_system::standard);
815 break;
816 case 'I':
817 handler.on_12_hour(numeric_system::standard);
818 break;
819 case 'M':
820 handler.on_minute(numeric_system::standard);
821 break;
822 case 'S':
823 handler.on_second(numeric_system::standard);
824 break;
825 // Other:
826 case 'c':
827 handler.on_datetime(numeric_system::standard);
828 break;
829 case 'x':
830 handler.on_loc_date(numeric_system::standard);
831 break;
832 case 'X':
833 handler.on_loc_time(numeric_system::standard);
834 break;
835 case 'D':
836 handler.on_us_date();
837 break;
838 case 'F':
839 handler.on_iso_date();
840 break;
841 case 'r':
842 handler.on_12_hour_time();
843 break;
844 case 'R':
845 handler.on_24_hour_time();
846 break;
847 case 'T':
848 handler.on_iso_time();
849 break;
850 case 'p':
851 handler.on_am_pm();
852 break;
853 case 'Q':
854 handler.on_duration_value();
855 break;
856 case 'q':
857 handler.on_duration_unit();
858 break;
859 case 'z':
860 handler.on_utc_offset();
861 break;
862 case 'Z':
863 handler.on_tz_name();
864 break;
865 // Alternative representation:
866 case 'E': {
867 if (ptr == end)
868 FMT_THROW(format_error("invalid format"));
869 c = *ptr++;
870 switch (c)
871 {
872 case 'Y':
873 handler.on_year(numeric_system::alternative);
874 break;
875 case 'y':
876 handler.on_offset_year();
877 break;
878 case 'C':
879 handler.on_century(numeric_system::alternative);
880 break;
881 case 'c':
882 handler.on_datetime(numeric_system::alternative);
883 break;
884 case 'x':
885 handler.on_loc_date(numeric_system::alternative);
886 break;
887 case 'X':
888 handler.on_loc_time(numeric_system::alternative);
889 break;
890 default:
891 FMT_THROW(format_error("invalid format"));
892 }
893 break;
894 }
895 case 'O':
896 if (ptr == end)
897 FMT_THROW(format_error("invalid format"));
898 c = *ptr++;
899 switch (c)
900 {
901 case 'y':
902 handler.on_short_year(numeric_system::alternative);
903 break;
904 case 'm':
905 handler.on_dec_month(numeric_system::alternative);
906 break;
907 case 'U':
908 handler.on_dec0_week_of_year(numeric_system::alternative);
909 break;
910 case 'W':
911 handler.on_dec1_week_of_year(numeric_system::alternative);
912 break;
913 case 'V':
914 handler.on_iso_week_of_year(numeric_system::alternative);
915 break;
916 case 'd':
917 handler.on_day_of_month(numeric_system::alternative);
918 break;
919 case 'e':
920 handler.on_day_of_month_space(numeric_system::alternative);
921 break;
922 case 'w':
923 handler.on_dec0_weekday(numeric_system::alternative);
924 break;
925 case 'u':
926 handler.on_dec1_weekday(numeric_system::alternative);
927 break;
928 case 'H':
929 handler.on_24_hour(numeric_system::alternative);
930 break;
931 case 'I':
932 handler.on_12_hour(numeric_system::alternative);
933 break;
934 case 'M':
935 handler.on_minute(numeric_system::alternative);
936 break;
937 case 'S':
938 handler.on_second(numeric_system::alternative);
939 break;
940 default:
941 FMT_THROW(format_error("invalid format"));
942 }
943 break;
944 default:
945 FMT_THROW(format_error("invalid format"));
946 }
947 begin = ptr;
948 }
949 if (begin != ptr)
950 handler.on_text(begin, ptr);
951 return ptr;
952}
953
954template <typename Derived>
956{
958 {
959 static_cast<Derived*>(this)->unsupported();
960 }
970 {
971 unsupported();
972 }
986 {
987 unsupported();
988 }
990 {
991 unsupported();
992 }
1002 {
1003 unsupported();
1004 }
1006 {
1007 unsupported();
1008 }
1026 {
1027 unsupported();
1028 }
1066 {
1067 unsupported();
1068 }
1070 {
1071 unsupported();
1072 }
1074 {
1075 unsupported();
1076 }
1078 {
1079 unsupported();
1080 }
1082 {
1083 unsupported();
1084 }
1086 {
1087 unsupported();
1088 }
1090 {
1091 unsupported();
1092 }
1094 {
1095 unsupported();
1096 }
1098 {
1099 unsupported();
1100 }
1102 {
1103 unsupported();
1104 }
1105};
1106
1108{
1110 {
1111 FMT_THROW(format_error("no format"));
1112 }
1113
1114 template <typename Char>
1115 FMT_CONSTEXPR void on_text(const Char*, const Char*)
1116 {
1117 }
1125 {
1126 }
1137 {
1138 }
1140 {
1141 }
1149 {
1150 }
1152 {
1153 }
1167 {
1168 }
1197 {
1198 }
1200 {
1201 }
1203 {
1204 }
1206 {
1207 }
1209 {
1210 }
1212 {
1213 }
1215 {
1216 }
1218 {
1219 }
1220};
1221
1222inline const char* tm_wday_full_name(int wday)
1223{
1224 static constexpr const char* full_name_list[] = {
1225 "Sunday", "Monday", "Tuesday", "Wednesday",
1226 "Thursday", "Friday", "Saturday"};
1227 return wday >= 0 && wday <= 6 ? full_name_list[wday] : "?";
1228}
1229inline const char* tm_wday_short_name(int wday)
1230{
1231 static constexpr const char* short_name_list[] = {"Sun", "Mon", "Tue", "Wed",
1232 "Thu", "Fri", "Sat"};
1233 return wday >= 0 && wday <= 6 ? short_name_list[wday] : "???";
1234}
1235
1236inline const char* tm_mon_full_name(int mon)
1237{
1238 static constexpr const char* full_name_list[] = {
1239 "January", "February", "March", "April", "May", "June",
1240 "July", "August", "September", "October", "November", "December"};
1241 return mon >= 0 && mon <= 11 ? full_name_list[mon] : "?";
1242}
1243inline const char* tm_mon_short_name(int mon)
1244{
1245 static constexpr const char* short_name_list[] = {
1246 "Jan",
1247 "Feb",
1248 "Mar",
1249 "Apr",
1250 "May",
1251 "Jun",
1252 "Jul",
1253 "Aug",
1254 "Sep",
1255 "Oct",
1256 "Nov",
1257 "Dec",
1258 };
1259 return mon >= 0 && mon <= 11 ? short_name_list[mon] : "???";
1260}
1261
1262template <typename T, typename = void>
1263struct has_member_data_tm_gmtoff : std::false_type
1264{
1265};
1266template <typename T>
1267struct has_member_data_tm_gmtoff<T, void_t<decltype(T::tm_gmtoff)>>
1268 : std::true_type
1269{
1270};
1271
1272template <typename T, typename = void>
1273struct has_member_data_tm_zone : std::false_type
1274{
1275};
1276template <typename T>
1277struct has_member_data_tm_zone<T, void_t<decltype(T::tm_zone)>>
1278 : std::true_type
1279{
1280};
1281
1282#if FMT_USE_TZSET
1283inline void tzset_once()
1284{
1285 static bool init = []() -> bool {
1286 _tzset();
1287 return true;
1288 }();
1289 ignore_unused(init);
1290}
1291#endif
1292
1293template <typename OutputIt, typename Char>
1295{
1296private:
1297 static constexpr int days_per_week = 7;
1298
1299 const std::locale& loc_;
1300 const bool is_classic_;
1301 OutputIt out_;
1302 const std::tm& tm_;
1303
1304 auto tm_sec() const noexcept -> int
1305 {
1306 FMT_ASSERT(tm_.tm_sec >= 0 && tm_.tm_sec <= 61, "");
1307 return tm_.tm_sec;
1308 }
1309 auto tm_min() const noexcept -> int
1310 {
1311 FMT_ASSERT(tm_.tm_min >= 0 && tm_.tm_min <= 59, "");
1312 return tm_.tm_min;
1313 }
1314 auto tm_hour() const noexcept -> int
1315 {
1316 FMT_ASSERT(tm_.tm_hour >= 0 && tm_.tm_hour <= 23, "");
1317 return tm_.tm_hour;
1318 }
1319 auto tm_mday() const noexcept -> int
1320 {
1321 FMT_ASSERT(tm_.tm_mday >= 1 && tm_.tm_mday <= 31, "");
1322 return tm_.tm_mday;
1323 }
1324 auto tm_mon() const noexcept -> int
1325 {
1326 FMT_ASSERT(tm_.tm_mon >= 0 && tm_.tm_mon <= 11, "");
1327 return tm_.tm_mon;
1328 }
1329 auto tm_year() const noexcept -> long long
1330 {
1331 return 1900ll + tm_.tm_year;
1332 }
1333 auto tm_wday() const noexcept -> int
1334 {
1335 FMT_ASSERT(tm_.tm_wday >= 0 && tm_.tm_wday <= 6, "");
1336 return tm_.tm_wday;
1337 }
1338 auto tm_yday() const noexcept -> int
1339 {
1340 FMT_ASSERT(tm_.tm_yday >= 0 && tm_.tm_yday <= 365, "");
1341 return tm_.tm_yday;
1342 }
1343
1344 auto tm_hour12() const noexcept -> int
1345 {
1346 const auto h = tm_hour();
1347 const auto z = h < 12 ? h : h - 12;
1348 return z == 0 ? 12 : z;
1349 }
1350
1351 // POSIX and the C Standard are unclear or inconsistent about what %C and %y
1352 // do if the year is negative or exceeds 9999. Use the convention that %C
1353 // concatenated with %y yields the same output as %Y, and that %Y contains at
1354 // least 4 characters, with more only if necessary.
1355 auto split_year_lower(long long year) const noexcept -> int
1356 {
1357 auto l = year % 100;
1358 if (l < 0)
1359 l = -l; // l in [0, 99]
1360 return static_cast<int>(l);
1361 }
1362
1363 // Algorithm:
1364 // https://en.wikipedia.org/wiki/ISO_week_date#Calculating_the_week_number_from_a_month_and_day_of_the_month_or_ordinal_date
1365 auto iso_year_weeks(long long curr_year) const noexcept -> int
1366 {
1367 const auto prev_year = curr_year - 1;
1368 const auto curr_p =
1369 (curr_year + curr_year / 4 - curr_year / 100 + curr_year / 400) %
1371 const auto prev_p =
1372 (prev_year + prev_year / 4 - prev_year / 100 + prev_year / 400) %
1374 return 52 + ((curr_p == 4 || prev_p == 3) ? 1 : 0);
1375 }
1376 auto iso_week_num(int tm_yday, int tm_wday) const noexcept -> int
1377 {
1378 return (tm_yday + 11 - (tm_wday == 0 ? days_per_week : tm_wday)) /
1380 }
1381 auto tm_iso_week_year() const noexcept -> long long
1382 {
1383 const auto year = tm_year();
1384 const auto w = iso_week_num(tm_yday(), tm_wday());
1385 if (w < 1)
1386 return year - 1;
1387 if (w > iso_year_weeks(year))
1388 return year + 1;
1389 return year;
1390 }
1391 auto tm_iso_week_of_year() const noexcept -> int
1392 {
1393 const auto year = tm_year();
1394 const auto w = iso_week_num(tm_yday(), tm_wday());
1395 if (w < 1)
1396 return iso_year_weeks(year - 1);
1397 if (w > iso_year_weeks(year))
1398 return 1;
1399 return w;
1400 }
1401
1402 void write1(int value)
1403 {
1404 *out_++ = static_cast<char>('0' + to_unsigned(value) % 10);
1405 }
1406 void write2(int value)
1407 {
1408 const char* d = digits2(to_unsigned(value) % 100);
1409 *out_++ = *d++;
1410 *out_++ = *d;
1411 }
1412
1413 void write_year_extended(long long year)
1414 {
1415 // At least 4 characters.
1416 int width = 4;
1417 if (year < 0)
1418 {
1419 *out_++ = '-';
1420 year = 0 - year;
1421 --width;
1422 }
1424 const int num_digits = count_digits(n);
1425 if (width > num_digits)
1426 out_ = std::fill_n(out_, width - num_digits, '0');
1427 out_ = format_decimal<Char>(out_, n, num_digits).end;
1428 }
1429 void write_year(long long year)
1430 {
1431 if (year >= 0 && year < 10000)
1432 {
1433 write2(static_cast<int>(year / 100));
1434 write2(static_cast<int>(year % 100));
1435 }
1436 else
1437 {
1438 write_year_extended(year);
1439 }
1440 }
1441
1443 {
1444 if (offset < 0)
1445 {
1446 *out_++ = '-';
1447 offset = -offset;
1448 }
1449 else
1450 {
1451 *out_++ = '+';
1452 }
1453 offset /= 60;
1454 write2(static_cast<int>(offset / 60));
1455 write2(static_cast<int>(offset % 60));
1456 }
1457 template <typename T, FMT_ENABLE_IF(has_member_data_tm_gmtoff<T>::value)>
1458 void format_utc_offset_impl(const T& tm)
1459 {
1460 write_utc_offset(tm.tm_gmtoff);
1461 }
1462 template <typename T, FMT_ENABLE_IF(!has_member_data_tm_gmtoff<T>::value)>
1463 void format_utc_offset_impl(const T& tm)
1464 {
1465#if defined(_WIN32) && defined(_UCRT)
1466#if FMT_USE_TZSET
1467 tzset_once();
1468#endif
1469 long offset = 0;
1470 _get_timezone(&offset);
1471 if (tm.tm_isdst)
1472 {
1473 long dstbias = 0;
1474 _get_dstbias(&dstbias);
1475 offset += dstbias;
1476 }
1478#else
1479 ignore_unused(tm);
1480 format_localized('z');
1481#endif
1482 }
1483
1484 template <typename T, FMT_ENABLE_IF(has_member_data_tm_zone<T>::value)>
1485 void format_tz_name_impl(const T& tm)
1486 {
1487 if (is_classic_)
1488 out_ = write_tm_str<Char>(out_, tm.tm_zone, loc_);
1489 else
1490 format_localized('Z');
1491 }
1492 template <typename T, FMT_ENABLE_IF(!has_member_data_tm_zone<T>::value)>
1493 void format_tz_name_impl(const T&)
1494 {
1495 format_localized('Z');
1496 }
1497
1498 void format_localized(char format, char modifier = 0)
1499 {
1500 out_ = write<Char>(out_, tm_, loc_, format, modifier);
1501 }
1502
1503public:
1504 tm_writer(const std::locale& loc, OutputIt out, const std::tm& tm)
1505 : loc_(loc),
1506 is_classic_(loc_ == get_classic_locale()),
1507 out_(out),
1508 tm_(tm)
1509 {
1510 }
1511
1512 OutputIt out() const
1513 {
1514 return out_;
1515 }
1516
1517 FMT_CONSTEXPR void on_text(const Char* begin, const Char* end)
1518 {
1519 out_ = copy_str<Char>(begin, end, out_);
1520 }
1521
1523 {
1524 if (is_classic_)
1526 else
1527 format_localized('a');
1528 }
1530 {
1531 if (is_classic_)
1533 else
1534 format_localized('A');
1535 }
1537 {
1539 return write1(tm_wday());
1540 format_localized('w', 'O');
1541 }
1543 {
1545 {
1546 auto wday = tm_wday();
1547 write1(wday == 0 ? days_per_week : wday);
1548 }
1549 else
1550 {
1551 format_localized('u', 'O');
1552 }
1553 }
1554
1556 {
1557 if (is_classic_)
1559 else
1560 format_localized('b');
1561 }
1563 {
1564 if (is_classic_)
1566 else
1567 format_localized('B');
1568 }
1569
1571 {
1572 if (is_classic_)
1573 {
1575 *out_++ = ' ';
1576 on_abbr_month();
1577 *out_++ = ' ';
1579 *out_++ = ' ';
1580 on_iso_time();
1581 *out_++ = ' ';
1583 }
1584 else
1585 {
1586 format_localized('c', ns == numeric_system::standard ? '\0' : 'E');
1587 }
1588 }
1590 {
1591 if (is_classic_)
1592 on_us_date();
1593 else
1594 format_localized('x', ns == numeric_system::standard ? '\0' : 'E');
1595 }
1597 {
1598 if (is_classic_)
1599 on_iso_time();
1600 else
1601 format_localized('X', ns == numeric_system::standard ? '\0' : 'E');
1602 }
1604 {
1605 char buf[8];
1609 out_ = copy_str<Char>(std::begin(buf), std::end(buf), out_);
1610 }
1612 {
1613 auto year = tm_year();
1614 char buf[10];
1615 size_t offset = 0;
1616 if (year >= 0 && year < 10000)
1617 {
1618 copy2(buf, digits2(static_cast<size_t>(year / 100)));
1619 }
1620 else
1621 {
1622 offset = 4;
1623 write_year_extended(year);
1624 year = 0;
1625 }
1626 write_digit2_separated(buf + 2, static_cast<unsigned>(year % 100),
1628 '-');
1629 out_ = copy_str<Char>(std::begin(buf) + offset, std::end(buf), out_);
1630 }
1631
1633 {
1635 }
1637 {
1639 }
1640
1642 {
1644 return write_year(tm_year());
1645 format_localized('Y', 'E');
1646 }
1648 {
1650 return write2(split_year_lower(tm_year()));
1651 format_localized('y', 'O');
1652 }
1654 {
1655 if (is_classic_)
1656 return write2(split_year_lower(tm_year()));
1657 format_localized('y', 'E');
1658 }
1659
1661 {
1663 {
1664 auto year = tm_year();
1665 auto upper = year / 100;
1666 if (year >= -99 && year < 0)
1667 {
1668 // Zero upper on negative year.
1669 *out_++ = '-';
1670 *out_++ = '0';
1671 }
1672 else if (upper >= 0 && upper < 100)
1673 {
1674 write2(static_cast<int>(upper));
1675 }
1676 else
1677 {
1678 out_ = write<Char>(out_, upper);
1679 }
1680 }
1681 else
1682 {
1683 format_localized('C', 'E');
1684 }
1685 }
1686
1688 {
1690 return write2(tm_mon() + 1);
1691 format_localized('m', 'O');
1692 }
1693
1695 {
1697 return write2((tm_yday() + days_per_week - tm_wday()) / days_per_week);
1698 format_localized('U', 'O');
1699 }
1701 {
1703 {
1704 auto wday = tm_wday();
1706 (wday == 0 ? (days_per_week - 1) : (wday - 1))) /
1708 }
1709 else
1710 {
1711 format_localized('W', 'O');
1712 }
1713 }
1715 {
1717 return write2(tm_iso_week_of_year());
1718 format_localized('V', 'O');
1719 }
1720
1729
1731 {
1732 auto yday = tm_yday() + 1;
1733 write1(yday / 100);
1734 write2(yday % 100);
1735 }
1737 {
1739 return write2(tm_mday());
1740 format_localized('d', 'O');
1741 }
1743 {
1745 {
1746 auto mday = to_unsigned(tm_mday()) % 100;
1747 const char* d2 = digits2(mday);
1748 *out_++ = mday < 10 ? ' ' : d2[0];
1749 *out_++ = d2[1];
1750 }
1751 else
1752 {
1753 format_localized('e', 'O');
1754 }
1755 }
1756
1758 {
1760 return write2(tm_hour());
1761 format_localized('H', 'O');
1762 }
1764 {
1766 return write2(tm_hour12());
1767 format_localized('I', 'O');
1768 }
1770 {
1772 return write2(tm_min());
1773 format_localized('M', 'O');
1774 }
1776 {
1778 return write2(tm_sec());
1779 format_localized('S', 'O');
1780 }
1781
1783 {
1784 if (is_classic_)
1785 {
1786 char buf[8];
1788 to_unsigned(tm_min()), to_unsigned(tm_sec()), ':');
1789 out_ = copy_str<Char>(std::begin(buf), std::end(buf), out_);
1790 *out_++ = ' ';
1791 on_am_pm();
1792 }
1793 else
1794 {
1795 format_localized('r');
1796 }
1797 }
1799 {
1800 write2(tm_hour());
1801 *out_++ = ':';
1802 write2(tm_min());
1803 }
1805 {
1806 char buf[8];
1808 to_unsigned(tm_sec()), ':');
1809 out_ = copy_str<Char>(std::begin(buf), std::end(buf), out_);
1810 }
1811
1813 {
1814 if (is_classic_)
1815 {
1816 *out_++ = tm_hour() < 12 ? 'A' : 'P';
1817 *out_++ = 'M';
1818 }
1819 else
1820 {
1821 format_localized('p');
1822 }
1823 }
1824
1825 // These apply to chrono durations but not tm.
1827 {
1828 }
1830 {
1831 }
1832};
1833
1835{
1837 {
1838 FMT_THROW(format_error("no date"));
1839 }
1840
1841 template <typename Char>
1842 FMT_CONSTEXPR void on_text(const Char*, const Char*)
1843 {
1844 }
1858 {
1859 }
1861 {
1862 }
1864 {
1865 }
1867 {
1868 }
1870 {
1871 }
1873 {
1874 }
1875};
1876
1877template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
1878inline bool isfinite(T)
1879{
1880 return true;
1881}
1882
1883// Converts value to Int and checks that it's in the range [0, upper).
1884template <typename T, typename Int, FMT_ENABLE_IF(std::is_integral<T>::value)>
1885inline Int to_nonnegative_int(T value, Int upper)
1886{
1887 FMT_ASSERT(std::is_unsigned<Int>::value ||
1888 (value >= 0 && to_unsigned(value) <= to_unsigned(upper)),
1889 "invalid value");
1890 (void)upper;
1891 return static_cast<Int>(value);
1892}
1893template <typename T, typename Int, FMT_ENABLE_IF(!std::is_integral<T>::value)>
1894inline Int to_nonnegative_int(T value, Int upper)
1895{
1896 if (value < 0 || value > static_cast<T>(upper))
1897 FMT_THROW(format_error("invalid value"));
1898 return static_cast<Int>(value);
1899}
1900
1901template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
1902inline T mod(T x, int y)
1903{
1904 return x % static_cast<T>(y);
1905}
1906template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)>
1907inline T mod(T x, int y)
1908{
1909 return std::fmod(x, static_cast<T>(y));
1910}
1911
1912// If T is an integral type, maps T to its unsigned counterpart, otherwise
1913// leaves it unchanged (unlike std::make_unsigned).
1914template <typename T, bool INTEGRAL = std::is_integral<T>::value>
1916{
1917 using type = T;
1918};
1919
1920template <typename T>
1922{
1923 using type = typename std::make_unsigned<T>::type;
1924};
1925
1926#if FMT_SAFE_DURATION_CAST
1927// throwing version of safe_duration_cast
1928template <typename To, typename FromRep, typename FromPeriod>
1929To fmt_safe_duration_cast(std::chrono::duration<FromRep, FromPeriod> from)
1930{
1931 int ec;
1932 To to = safe_duration_cast::safe_duration_cast<To>(from, ec);
1933 if (ec)
1934 FMT_THROW(format_error("cannot format duration"));
1935 return to;
1936}
1937#endif
1938
1939template <typename Rep, typename Period, FMT_ENABLE_IF(std::is_integral<Rep>::value)>
1940inline std::chrono::duration<Rep, std::milli> get_milliseconds(
1941 std::chrono::duration<Rep, Period> d)
1942{
1943 // this may overflow and/or the result may not fit in the
1944 // target type.
1945#if FMT_SAFE_DURATION_CAST
1946 using CommonSecondsType =
1947 typename std::common_type<decltype(d), std::chrono::seconds>::type;
1948 const auto d_as_common = fmt_safe_duration_cast<CommonSecondsType>(d);
1949 const auto d_as_whole_seconds =
1950 fmt_safe_duration_cast<std::chrono::seconds>(d_as_common);
1951 // this conversion should be nonproblematic
1952 const auto diff = d_as_common - d_as_whole_seconds;
1953 const auto ms =
1954 fmt_safe_duration_cast<std::chrono::duration<Rep, std::milli>>(diff);
1955 return ms;
1956#else
1957 auto s = std::chrono::duration_cast<std::chrono::seconds>(d);
1958 return std::chrono::duration_cast<std::chrono::milliseconds>(d - s);
1959#endif
1960}
1961
1962// Counts the number of fractional digits in the range [0, 18] according to the
1963// C++20 spec. If more than 18 fractional digits are required then returns 6 for
1964// microseconds precision.
1965template <long long Num, long long Den, int N = 0, bool Enabled = (N < 19) && (Num <= max_value<long long>() / 10)>
1967{
1968 static constexpr int value =
1970};
1971
1972// Base case that doesn't instantiate any more templates
1973// in order to avoid overflow.
1974template <long long Num, long long Den, int N>
1975struct count_fractional_digits<Num, Den, N, false>
1976{
1977 static constexpr int value = (Num % Den == 0) ? N : 6;
1978};
1979
1980constexpr long long pow10(std::uint32_t n)
1981{
1982 return n == 0 ? 1 : 10 * pow10(n - 1);
1983}
1984
1985template <class Rep, class Period, FMT_ENABLE_IF(std::numeric_limits<Rep>::is_signed)>
1986constexpr std::chrono::duration<Rep, Period> abs(
1987 std::chrono::duration<Rep, Period> d)
1988{
1989 // We need to compare the duration using the count() method directly
1990 // due to a compiler bug in clang-11 regarding the spaceship operator,
1991 // when -Wzero-as-null-pointer-constant is enabled.
1992 // In clang-12 the bug has been fixed. See
1993 // https://bugs.llvm.org/show_bug.cgi?id=46235 and the reproducible example:
1994 // https://www.godbolt.org/z/Knbb5joYx.
1995 return d.count() >= d.zero().count() ? d : -d;
1996}
1997
1998template <class Rep, class Period, FMT_ENABLE_IF(!std::numeric_limits<Rep>::is_signed)>
1999constexpr std::chrono::duration<Rep, Period> abs(
2000 std::chrono::duration<Rep, Period> d)
2001{
2002 return d;
2003}
2004
2005template <typename Char, typename Rep, typename OutputIt, FMT_ENABLE_IF(std::is_integral<Rep>::value)>
2006OutputIt format_duration_value(OutputIt out, Rep val, int)
2007{
2008 return write<Char>(out, val);
2009}
2010
2011template <typename Char, typename Rep, typename OutputIt, FMT_ENABLE_IF(std::is_floating_point<Rep>::value)>
2012OutputIt format_duration_value(OutputIt out, Rep val, int precision)
2013{
2014 auto specs = basic_format_specs<Char>();
2015 specs.precision = precision;
2016 specs.type = precision >= 0 ? presentation_type::fixed_lower
2018 return write<Char>(out, val, specs);
2019}
2020
2021template <typename Char, typename OutputIt>
2022OutputIt copy_unit(string_view unit, OutputIt out, Char)
2023{
2024 return std::copy(unit.begin(), unit.end(), out);
2025}
2026
2027template <typename OutputIt>
2028OutputIt copy_unit(string_view unit, OutputIt out, wchar_t)
2029{
2030 // This works when wchar_t is UTF-32 because units only contain characters
2031 // that have the same representation in UTF-16 and UTF-32.
2032 utf8_to_utf16 u(unit);
2033 return std::copy(u.c_str(), u.c_str() + u.size(), out);
2034}
2035
2036template <typename Char, typename Period, typename OutputIt>
2037OutputIt format_duration_unit(OutputIt out)
2038{
2039 if (const char* unit = get_units<Period>())
2040 return copy_unit(string_view(unit), out, Char());
2041 *out++ = '[';
2042 out = write<Char>(out, Period::num);
2043 if (const_check(Period::den != 1))
2044 {
2045 *out++ = '/';
2046 out = write<Char>(out, Period::den);
2047 }
2048 *out++ = ']';
2049 *out++ = 's';
2050 return out;
2051}
2052
2054{
2055private:
2056 union {
2057 std::locale locale_;
2058 };
2059 bool has_locale_ = false;
2060
2061public:
2062 get_locale(bool localized, locale_ref loc)
2063 : has_locale_(localized)
2064 {
2065 if (localized)
2066 ::new (&locale_) std::locale(loc.template get<std::locale>());
2067 }
2069 {
2070 if (has_locale_)
2071 locale_.~locale();
2072 }
2073 operator const std::locale&() const
2074 {
2075 return has_locale_ ? locale_ : get_classic_locale();
2076 }
2077};
2078
2079template <typename FormatContext, typename OutputIt, typename Rep, typename Period>
2081{
2082 FormatContext& context;
2083 OutputIt out;
2085 bool localized = false;
2086 // rep is unsigned to avoid overflow.
2087 using rep =
2088 conditional_t<std::is_integral<Rep>::value && sizeof(Rep) < sizeof(int),
2089 unsigned,
2092 using seconds = std::chrono::duration<rep>;
2094 using milliseconds = std::chrono::duration<rep, std::milli>;
2096
2097 using char_type = typename FormatContext::char_type;
2099
2100 chrono_formatter(FormatContext& ctx, OutputIt o, std::chrono::duration<Rep, Period> d)
2101 : context(ctx),
2102 out(o),
2103 val(static_cast<rep>(d.count())),
2104 negative(false)
2105 {
2106 if (d.count() < 0)
2107 {
2108 val = 0 - val;
2109 negative = true;
2110 }
2111
2112 // this may overflow and/or the result may not fit in the
2113 // target type.
2114#if FMT_SAFE_DURATION_CAST
2115 // might need checked conversion (rep!=Rep)
2116 auto tmpval = std::chrono::duration<rep, Period>(val);
2117 s = fmt_safe_duration_cast<seconds>(tmpval);
2118#else
2119 s = std::chrono::duration_cast<seconds>(
2120 std::chrono::duration<rep, Period>(val));
2121#endif
2122 }
2123
2124 // returns true if nan or inf, writes to out.
2126 {
2127 if (isfinite(val))
2128 {
2129 return false;
2130 }
2131 if (isnan(val))
2132 {
2133 write_nan();
2134 return true;
2135 }
2136 // must be +-inf
2137 if (val > 0)
2138 {
2139 write_pinf();
2140 }
2141 else
2142 {
2143 write_ninf();
2144 }
2145 return true;
2146 }
2147
2148 Rep hour() const
2149 {
2150 return static_cast<Rep>(mod((s.count() / 3600), 24));
2151 }
2152
2153 Rep hour12() const
2154 {
2155 Rep hour = static_cast<Rep>(mod((s.count() / 3600), 12));
2156 return hour <= 0 ? 12 : hour;
2157 }
2158
2159 Rep minute() const
2160 {
2161 return static_cast<Rep>(mod((s.count() / 60), 60));
2162 }
2163 Rep second() const
2164 {
2165 return static_cast<Rep>(mod(s.count(), 60));
2166 }
2167
2168 std::tm time() const
2169 {
2170 auto time = std::tm();
2171 time.tm_hour = to_nonnegative_int(hour(), 24);
2172 time.tm_min = to_nonnegative_int(minute(), 60);
2173 time.tm_sec = to_nonnegative_int(second(), 60);
2174 return time;
2175 }
2176
2178 {
2179 if (negative)
2180 {
2181 *out++ = '-';
2182 negative = false;
2183 }
2184 }
2185
2186 void write(Rep value, int width)
2187 {
2188 write_sign();
2189 if (isnan(value))
2190 return write_nan();
2192 to_unsigned(to_nonnegative_int(value, max_value<int>()));
2193 int num_digits = detail::count_digits(n);
2194 if (width > num_digits)
2195 out = std::fill_n(out, width - num_digits, '0');
2196 out = format_decimal<char_type>(out, n, num_digits).end;
2197 }
2198
2199 template <typename Duration>
2201 {
2202 FMT_ASSERT(!std::is_floating_point<typename Duration::rep>::value, "");
2203 constexpr auto num_fractional_digits =
2204 count_fractional_digits<Duration::period::num,
2205 Duration::period::den>::value;
2206
2207 using subsecond_precision = std::chrono::duration<
2208 typename std::common_type<typename Duration::rep,
2209 std::chrono::seconds::rep>::type,
2210 std::ratio<1, detail::pow10(num_fractional_digits)>>;
2211 if (std::ratio_less<typename subsecond_precision::period,
2212 std::chrono::seconds::period>::value)
2213 {
2214 *out++ = '.';
2215 auto fractional =
2216 detail::abs(d) - std::chrono::duration_cast<std::chrono::seconds>(d);
2217 auto subseconds =
2218 std::chrono::treat_as_floating_point<
2219 typename subsecond_precision::rep>::value
2220 ? fractional.count()
2221 : std::chrono::duration_cast<subsecond_precision>(fractional)
2222 .count();
2224 to_unsigned(to_nonnegative_int(subseconds, max_value<long long>()));
2225 int num_digits = detail::count_digits(n);
2226 if (num_fractional_digits > num_digits)
2227 out = std::fill_n(out, num_fractional_digits - num_digits, '0');
2228 out = format_decimal<char_type>(out, n, num_digits).end;
2229 }
2230 }
2231
2233 {
2234 std::copy_n("nan", 3, out);
2235 }
2237 {
2238 std::copy_n("inf", 3, out);
2239 }
2241 {
2242 std::copy_n("-inf", 4, out);
2243 }
2244
2245 template <typename Callback, typename... Args>
2246 void format_tm(const tm& time, Callback cb, Args... args)
2247 {
2248 if (isnan(val))
2249 return write_nan();
2250 get_locale loc(localized, context.locale());
2251 auto w = tm_writer_type(loc, out, time);
2252 (w.*cb)(args...);
2253 out = w.out();
2254 }
2255
2256 void on_text(const char_type* begin, const char_type* end)
2257 {
2258 std::copy(begin, end, out);
2259 }
2260
2261 // These are not implemented because durations don't have date information.
2263 {
2264 }
2266 {
2267 }
2269 {
2270 }
2272 {
2273 }
2275 {
2276 }
2278 {
2279 }
2281 {
2282 }
2284 {
2285 }
2287 {
2288 }
2290 {
2291 }
2293 {
2294 }
2296 {
2297 }
2299 {
2300 }
2302 {
2303 }
2305 {
2306 }
2308 {
2309 }
2311 {
2312 }
2314 {
2315 }
2317 {
2318 }
2320 {
2321 }
2332 {
2333 }
2335 {
2336 }
2340
2342 {
2343 if (handle_nan_inf())
2344 return;
2345
2346 if (ns == numeric_system::standard)
2347 return write(hour(), 2);
2348 auto time = tm();
2349 time.tm_hour = to_nonnegative_int(hour(), 24);
2350 format_tm(time, &tm_writer_type::on_24_hour, ns);
2351 }
2352
2354 {
2355 if (handle_nan_inf())
2356 return;
2357
2358 if (ns == numeric_system::standard)
2359 return write(hour12(), 2);
2360 auto time = tm();
2361 time.tm_hour = to_nonnegative_int(hour12(), 12);
2362 format_tm(time, &tm_writer_type::on_12_hour, ns);
2363 }
2364
2366 {
2367 if (handle_nan_inf())
2368 return;
2369
2370 if (ns == numeric_system::standard)
2371 return write(minute(), 2);
2372 auto time = tm();
2373 time.tm_min = to_nonnegative_int(minute(), 60);
2374 format_tm(time, &tm_writer_type::on_minute, ns);
2375 }
2376
2378 {
2379 if (handle_nan_inf())
2380 return;
2381
2382 if (ns == numeric_system::standard)
2383 {
2384 if (std::is_floating_point<rep>::value)
2385 {
2386 constexpr auto num_fractional_digits =
2388 auto buf = memory_buffer();
2389 format_to(std::back_inserter(buf), runtime("{:.{}f}"),
2390 std::fmod(val * static_cast<rep>(Period::num) /
2391 static_cast<rep>(Period::den),
2392 static_cast<rep>(60)),
2393 num_fractional_digits);
2394 if (negative)
2395 *out++ = '-';
2396 if (buf.size() < 2 || buf[1] == '.')
2397 *out++ = '0';
2398 out = std::copy(buf.begin(), buf.end(), out);
2399 }
2400 else
2401 {
2402 write(second(), 2);
2403 write_fractional_seconds(std::chrono::duration<rep, Period>(val));
2404 }
2405 return;
2406 }
2407 auto time = tm();
2408 time.tm_sec = to_nonnegative_int(second(), 60);
2409 format_tm(time, &tm_writer_type::on_second, ns);
2410 }
2411
2413 {
2414 if (handle_nan_inf())
2415 return;
2416 format_tm(time(), &tm_writer_type::on_12_hour_time);
2417 }
2418
2420 {
2421 if (handle_nan_inf())
2422 {
2423 *out++ = ':';
2425 return;
2426 }
2427
2428 write(hour(), 2);
2429 *out++ = ':';
2430 write(minute(), 2);
2431 }
2432
2434 {
2436 *out++ = ':';
2437 if (handle_nan_inf())
2438 return;
2440 }
2441
2443 {
2444 if (handle_nan_inf())
2445 return;
2446 format_tm(time(), &tm_writer_type::on_am_pm);
2447 }
2448
2450 {
2451 if (handle_nan_inf())
2452 return;
2453 write_sign();
2454 out = format_duration_value<char_type>(out, val, precision);
2455 }
2456
2458 {
2459 out = format_duration_unit<char_type, Period>(out);
2460 }
2461};
2462
2464
2465#if defined(__cpp_lib_chrono) && __cpp_lib_chrono >= 201907
2466using weekday = std::chrono::weekday;
2467#else
2468// A fallback version of weekday.
2470{
2471private:
2472 unsigned char value;
2473
2474public:
2475 weekday() = default;
2476 explicit constexpr weekday(unsigned wd) noexcept
2477 : value(static_cast<unsigned char>(wd != 7 ? wd : 0))
2478 {
2479 }
2480 constexpr unsigned c_encoding() const noexcept
2481 {
2482 return value;
2483 }
2484};
2485
2487{
2488};
2489#endif
2490
2491// A rudimentary weekday formatter.
2492template <typename Char>
2493struct formatter<weekday, Char>
2494{
2495private:
2496 bool localized = false;
2497
2498public:
2500 -> decltype(ctx.begin())
2501 {
2502 auto begin = ctx.begin(), end = ctx.end();
2503 if (begin != end && *begin == 'L')
2504 {
2505 ++begin;
2506 localized = true;
2507 }
2508 return begin;
2509 }
2510
2511 template <typename FormatContext>
2512 auto format(weekday wd, FormatContext& ctx) const -> decltype(ctx.out())
2513 {
2514 auto time = std::tm();
2515 time.tm_wday = static_cast<int>(wd.c_encoding());
2516 detail::get_locale loc(localized, ctx.locale());
2517 auto w = detail::tm_writer<decltype(ctx.out()), Char>(loc, ctx.out(), time);
2518 w.on_abbr_weekday();
2519 return w.out();
2520 }
2521};
2522
2523template <typename Rep, typename Period, typename Char>
2524struct formatter<std::chrono::duration<Rep, Period>, Char>
2525{
2526private:
2528 int precision = -1;
2529 using arg_ref_type = detail::arg_ref<Char>;
2532 bool localized = false;
2534 using duration = std::chrono::duration<Rep, Period>;
2535
2536 struct spec_handler
2537 {
2541
2542 template <typename Id>
2544 {
2545 context.check_arg_id(arg_id);
2546 return arg_ref_type(arg_id);
2547 }
2548
2550 {
2551 context.check_arg_id(arg_id);
2552 return arg_ref_type(arg_id);
2553 }
2554
2556 {
2557 return arg_ref_type(context.next_arg_id());
2558 }
2559
2560 void on_error(const char* msg)
2561 {
2562 FMT_THROW(format_error(msg));
2563 }
2565 {
2566 f.specs.fill = fill;
2567 }
2569 {
2570 f.specs.align = align;
2571 }
2572 FMT_CONSTEXPR void on_width(int width)
2573 {
2574 f.specs.width = width;
2575 }
2576 FMT_CONSTEXPR void on_precision(int _precision)
2577 {
2578 f.precision = _precision;
2579 }
2581 {
2582 }
2583
2584 template <typename Id>
2586 {
2587 f.width_ref = make_arg_ref(arg_id);
2588 }
2589
2590 template <typename Id>
2592 {
2593 f.precision_ref = make_arg_ref(arg_id);
2594 }
2595 };
2596
2598 struct parse_range
2599 {
2602 };
2603
2605 {
2606 auto begin = ctx.begin(), end = ctx.end();
2607 if (begin == end || *begin == '}')
2608 return {begin, begin};
2609 spec_handler handler{*this, ctx, format_str};
2610 begin = detail::parse_align(begin, end, handler);
2611 if (begin == end)
2612 return {begin, begin};
2613 begin = detail::parse_width(begin, end, handler);
2614 if (begin == end)
2615 return {begin, begin};
2616 if (*begin == '.')
2617 {
2618 if (std::is_floating_point<Rep>::value)
2619 begin = detail::parse_precision(begin, end, handler);
2620 else
2621 handler.on_error("precision not allowed for this argument type");
2622 }
2623 if (begin != end && *begin == 'L')
2624 {
2625 ++begin;
2626 localized = true;
2627 }
2628 end = detail::parse_chrono_format(begin, end,
2629 detail::chrono_format_checker());
2630 return {begin, end};
2631 }
2632
2633public:
2635 -> decltype(ctx.begin())
2636 {
2637 auto range = do_parse(ctx);
2638 format_str = basic_string_view<Char>(
2639 &*range.begin, detail::to_unsigned(range.end - range.begin));
2640 return range.end;
2641 }
2642
2643 template <typename FormatContext>
2644 auto format(const duration& d, FormatContext& ctx) const
2645 -> decltype(ctx.out())
2646 {
2647 auto specs_copy = specs;
2648 auto precision_copy = precision;
2649 auto begin = format_str.begin(), end = format_str.end();
2650 // As a possible future optimization, we could avoid extra copying if width
2651 // is not specified.
2653 auto out = std::back_inserter(buf);
2654 detail::handle_dynamic_spec<detail::width_checker>(specs_copy.width,
2655 width_ref, ctx);
2656 detail::handle_dynamic_spec<detail::precision_checker>(precision_copy,
2657 precision_ref, ctx);
2658 if (begin == end || *begin == '}')
2659 {
2660 out = detail::format_duration_value<Char>(out, d.count(), precision_copy);
2661 detail::format_duration_unit<Char, Period>(out);
2662 }
2663 else
2664 {
2665 detail::chrono_formatter<FormatContext, decltype(out), Rep, Period> f(
2666 ctx, out, d);
2667 f.precision = precision_copy;
2668 f.localized = localized;
2669 detail::parse_chrono_format(begin, end, f);
2670 }
2671 return detail::write(
2672 ctx.out(), basic_string_view<Char>(buf.data(), buf.size()), specs_copy);
2673 }
2674};
2675
2676template <typename Char, typename Duration>
2677struct formatter<std::chrono::time_point<std::chrono::system_clock, Duration>,
2678 Char> : formatter<std::tm, Char>
2679{
2681 {
2682 basic_string_view<Char> default_specs =
2683 detail::string_literal<Char, '%', 'F', ' ', '%', 'T'>{};
2684 this->do_parse(default_specs.begin(), default_specs.end());
2685 }
2686
2687 template <typename FormatContext>
2688 auto format(std::chrono::time_point<std::chrono::system_clock> val,
2689 FormatContext& ctx) const -> decltype(ctx.out())
2690 {
2692 }
2693};
2694
2695template <typename Char>
2696struct formatter<std::tm, Char>
2697{
2698private:
2699 enum class spec
2700 {
2701 unknown,
2703 hh_mm_ss,
2704 };
2705 spec spec_ = spec::unknown;
2707
2708protected:
2709 template <typename It>
2710 FMT_CONSTEXPR auto do_parse(It begin, It end) -> It
2711 {
2712 if (begin != end && *begin == ':')
2713 ++begin;
2714 end = detail::parse_chrono_format(begin, end, detail::tm_format_checker());
2715 // Replace default spec only if the new spec is not empty.
2716 if (end != begin)
2717 specs = {begin, detail::to_unsigned(end - begin)};
2718 return end;
2719 }
2720
2721public:
2723 -> decltype(ctx.begin())
2724 {
2725 auto end = this->do_parse(ctx.begin(), ctx.end());
2726 // basic_string_view<>::compare isn't constexpr before C++17.
2727 if (specs.size() == 2 && specs[0] == Char('%'))
2728 {
2729 if (specs[1] == Char('F'))
2730 spec_ = spec::year_month_day;
2731 else if (specs[1] == Char('T'))
2732 spec_ = spec::hh_mm_ss;
2733 }
2734 return end;
2735 }
2736
2737 template <typename FormatContext>
2738 auto format(const std::tm& tm, FormatContext& ctx) const
2739 -> decltype(ctx.out())
2740 {
2741 const auto loc_ref = ctx.locale();
2742 detail::get_locale loc(static_cast<bool>(loc_ref), loc_ref);
2743 auto w = detail::tm_writer<decltype(ctx.out()), Char>(loc, ctx.out(), tm);
2744 if (spec_ == spec::year_month_day)
2745 w.on_iso_date();
2746 else if (spec_ == spec::hh_mm_ss)
2747 w.on_iso_time();
2748 else
2749 detail::parse_chrono_format(specs.begin(), specs.end(), w);
2750 return w.out();
2751 }
2752};
2753
2756
2757#endif // FMT_CHRONO_H_
constexpr long long pow10(std::uint32_t n)
Definition chrono.h:1980
To fmt_safe_duration_cast(std::chrono::duration< FromRep, FromPeriod > from)
Definition chrono.h:1929
#define FMT_NOMACRO
Definition chrono.h:323
const char * tm_mon_full_name(int mon)
Definition chrono.h:1236
constexpr std::chrono::duration< Rep, Period > abs(std::chrono::duration< Rep, Period > d)
Definition chrono.h:1986
FMT_CONSTEXPR const Char * parse_chrono_format(const Char *begin, const Char *end, Handler &&handler)
Definition chrono.h:717
numeric_system
Definition chrono.h:709
OutputIt copy_unit(string_view unit, OutputIt out, Char)
Definition chrono.h:2022
OutputIt format_duration_value(OutputIt out, Rep val, int)
Definition chrono.h:2006
FMT_MODULE_EXPORT_BEGIN std::tm localtime(std::time_t time)
Definition chrono.h:505
std::chrono::duration< Rep, std::milli > get_milliseconds(std::chrono::duration< Rep, Period > d)
Definition chrono.h:1940
OutputIt format_duration_unit(OutputIt out)
Definition chrono.h:2037
const char * tm_wday_full_name(int wday)
Definition chrono.h:1222
std::tm gmtime(std::time_t time)
Definition chrono.h:568
bool isfinite(T)
Definition chrono.h:1878
const char * tm_wday_short_name(int wday)
Definition chrono.h:1229
const char * tm_mon_short_name(int mon)
Definition chrono.h:1243
FMT_CONSTEXPR const char * get_units()
Definition chrono.h:665
T mod(T x, int y)
Definition chrono.h:1902
Int to_nonnegative_int(T value, Int upper)
Definition chrono.h:1885
FMT_BEGIN_DETAIL_NAMESPACE void write_digit2_separated(char *buf, unsigned a, unsigned b, unsigned c, char sep)
Definition chrono.h:630
Definition core.h:770
FMT_CONSTEXPR void check_arg_id(int id)
Definition core.h:830
constexpr auto end() const noexcept -> iterator
Definition core.h:799
typename basic_string_view< Char >::iterator iterator
Definition core.h:779
FMT_CONSTEXPR auto next_arg_id() -> int
Definition core.h:814
constexpr auto begin() const noexcept -> iterator
Definition core.h:791
Definition format.h:955
constexpr auto end() const noexcept -> iterator
Definition core.h:550
constexpr auto size() const noexcept -> size_t
Definition core.h:541
constexpr auto begin() const noexcept -> iterator
Definition core.h:546
Definition format.h:284
Definition format.h:1113
Definition chrono.h:2054
get_locale(bool localized, locale_ref loc)
Definition chrono.h:2062
std::locale locale_
Definition chrono.h:2057
bool has_locale_
Definition chrono.h:2059
~get_locale()
Definition chrono.h:2068
Definition core.h:2245
Definition chrono.h:1295
auto split_year_lower(long long year) const noexcept -> int
Definition chrono.h:1355
auto tm_mday() const noexcept -> int
Definition chrono.h:1319
void on_am_pm()
Definition chrono.h:1812
void on_duration_value()
Definition chrono.h:1826
void on_datetime(numeric_system ns)
Definition chrono.h:1570
void write_utc_offset(long offset)
Definition chrono.h:1442
void on_abbr_weekday()
Definition chrono.h:1522
void on_dec1_weekday(numeric_system ns)
Definition chrono.h:1542
tm_writer(const std::locale &loc, OutputIt out, const std::tm &tm)
Definition chrono.h:1504
void format_tz_name_impl(const T &)
Definition chrono.h:1493
void on_minute(numeric_system ns)
Definition chrono.h:1769
void write1(int value)
Definition chrono.h:1402
void format_utc_offset_impl(const T &tm)
Definition chrono.h:1458
void on_day_of_month_space(numeric_system ns)
Definition chrono.h:1742
void on_tz_name()
Definition chrono.h:1636
void on_year(numeric_system ns)
Definition chrono.h:1641
FMT_CONSTEXPR void on_text(const Char *begin, const Char *end)
Definition chrono.h:1517
auto iso_week_num(int tm_yday, int tm_wday) const noexcept -> int
Definition chrono.h:1376
auto tm_hour12() const noexcept -> int
Definition chrono.h:1344
void format_tz_name_impl(const T &tm)
Definition chrono.h:1485
void on_duration_unit()
Definition chrono.h:1829
void on_iso_time()
Definition chrono.h:1804
void on_dec_month(numeric_system ns)
Definition chrono.h:1687
void on_iso_week_based_year()
Definition chrono.h:1721
auto tm_iso_week_of_year() const noexcept -> int
Definition chrono.h:1391
OutputIt out_
Definition chrono.h:1301
auto tm_wday() const noexcept -> int
Definition chrono.h:1333
void on_loc_time(numeric_system ns)
Definition chrono.h:1596
void on_offset_year()
Definition chrono.h:1653
void on_second(numeric_system ns)
Definition chrono.h:1775
OutputIt out() const
Definition chrono.h:1512
void on_iso_week_based_short_year()
Definition chrono.h:1725
void on_dec1_week_of_year(numeric_system ns)
Definition chrono.h:1700
void on_abbr_month()
Definition chrono.h:1555
void on_dec0_weekday(numeric_system ns)
Definition chrono.h:1536
void on_24_hour(numeric_system ns)
Definition chrono.h:1757
void on_iso_date()
Definition chrono.h:1611
void on_day_of_year()
Definition chrono.h:1730
void on_iso_week_of_year(numeric_system ns)
Definition chrono.h:1714
auto tm_year() const noexcept -> long long
Definition chrono.h:1329
auto tm_min() const noexcept -> int
Definition chrono.h:1309
auto tm_yday() const noexcept -> int
Definition chrono.h:1338
auto iso_year_weeks(long long curr_year) const noexcept -> int
Definition chrono.h:1365
void on_24_hour_time()
Definition chrono.h:1798
void on_full_weekday()
Definition chrono.h:1529
void on_us_date()
Definition chrono.h:1603
const std::tm & tm_
Definition chrono.h:1302
auto tm_sec() const noexcept -> int
Definition chrono.h:1304
const std::locale & loc_
Definition chrono.h:1299
void write_year(long long year)
Definition chrono.h:1429
void on_full_month()
Definition chrono.h:1562
void on_12_hour_time()
Definition chrono.h:1782
void on_short_year(numeric_system ns)
Definition chrono.h:1647
void write_year_extended(long long year)
Definition chrono.h:1413
void on_dec0_week_of_year(numeric_system ns)
Definition chrono.h:1694
void on_loc_date(numeric_system ns)
Definition chrono.h:1589
void on_utc_offset()
Definition chrono.h:1632
auto tm_iso_week_year() const noexcept -> long long
Definition chrono.h:1381
void write2(int value)
Definition chrono.h:1406
static constexpr int days_per_week
Definition chrono.h:1297
auto tm_mon() const noexcept -> int
Definition chrono.h:1324
const bool is_classic_
Definition chrono.h:1300
void on_century(numeric_system ns)
Definition chrono.h:1660
void format_localized(char format, char modifier=0)
Definition chrono.h:1498
void on_12_hour(numeric_system ns)
Definition chrono.h:1763
void on_day_of_month(numeric_system ns)
Definition chrono.h:1736
auto tm_hour() const noexcept -> int
Definition chrono.h:1314
Definition format.h:1514
Definition core.h:1598
Definition chrono.h:2470
unsigned char value
Definition chrono.h:2472
constexpr weekday(unsigned wd) noexcept
Definition chrono.h:2476
weekday()=default
constexpr unsigned c_encoding() const noexcept
Definition chrono.h:2480
Definition chrono.h:2487
auto format_to(OutputIt out, const text_style &ts, const S &format_str, Args &&... args) -> typename std::enable_if< enable, OutputIt >::type
Definition color.h:677
std::basic_string< Char > format(const text_style &ts, const S &format_str, const Args &... args)
Definition color.h:646
constexpr FMT_INLINE auto const_check(T value) -> T
Definition core.h:390
#define FMT_ASSERT(condition, message)
Definition core.h:403
basic_string_view< char > string_view
Definition core.h:604
align::type align_t
Definition core.h:2687
#define FMT_END_DETAIL_NAMESPACE
Definition core.h:231
#define FMT_MODULE_EXPORT_BEGIN
Definition core.h:226
constexpr auto count() -> size_t
Definition core.h:1538
#define FMT_CONSTEXPR
Definition core.h:106
type
Definition core.h:681
#define FMT_BEGIN_NAMESPACE
Definition core.h:214
#define FMT_BEGIN_DETAIL_NAMESPACE
Definition core.h:228
FMT_BEGIN_DETAIL_NAMESPACE FMT_CONSTEXPR void ignore_unused(const T &...)
Definition core.h:373
void void_t
Definition core.h:2201
FMT_CONSTEXPR auto to_unsigned(Int value) -> typename std::make_unsigned< Int >::type
Definition core.h:455
#define FMT_NORETURN
Definition core.h:163
typename std::conditional< B, T, F >::type conditional_t
Definition core.h:304
auto runtime(string_view s) -> basic_runtime< char >
Definition core.h:4070
#define FMT_END_NAMESPACE
Definition core.h:219
#define FMT_MODULE_EXPORT_END
Definition core.h:227
#define offset(member)
Definition css_properties.cpp:5
#define out
Definition encodings.cpp:5
constexpr bool isnan(T value)
Definition format.h:2978
FMT_CONSTEXPR20 auto count_digits(uint64_t n) -> int
Definition format.h:1294
FMT_CONSTEXPR20 FMT_INLINE void copy2(Char *dst, const char *src)
Definition format.h:1425
conditional_t< num_bits< T >()<=32 &&!FMT_REDUCE_INT_INSTANTIATIONS, uint32_t, conditional_t< num_bits< T >()<=64, uint64_t, uint128_t > > uint32_or_64_or_128_t
Definition format.h:1212
constexpr const char * digits2(size_t value)
Definition format.h:1222
FMT_NOINLINE FMT_CONSTEXPR auto fill(OutputIt it, size_t n, const fill_t< Char > &fill) -> OutputIt
Definition format.h:2004
basic_memory_buffer< char > memory_buffer
Definition format.h:1095
#define FMT_THROW(x)
Definition format.h:99
auto ptr(T p) -> const void *
Definition format.h:4568
FMT_CONSTEXPR auto write(OutputIt out, Char value, const basic_format_specs< Char > &specs, locale_ref loc={}) -> OutputIt
Definition format.h:2272
#define in
Definition internal.h:15
Definition core.h:2677
Definition args.h:20
null gmtime_s(...)
Definition chrono.h:343
auto write(OutputIt out, const std::tm &time, const std::locale &loc, char format, char modifier=0) -> OutputIt
Definition chrono.h:481
auto write_encoded_tm_str(OutputIt out, string_view in, const std::locale &loc) -> OutputIt
Definition chrono.h:384
void do_write(buffer< Char > &buf, const std::tm &time, const std::locale &loc, char format, char modifier)
Definition chrono.h:468
null gmtime_r(...)
Definition chrono.h:339
const std::locale & get_classic_locale()
Definition chrono.h:348
null localtime_s(...)
Definition chrono.h:335
auto write_tm_str(OutputIt out, string_view sv, const std::locale &loc) -> OutputIt
Definition chrono.h:452
void write_codecvt(codecvt_result< CodeUnit > &out, string_view in_buf, const std::locale &loc)
Definition chrono.h:365
Definition format.h:3057
Definition chrono.h:52
FMT_CONSTEXPR To safe_float_conversion(const From from, int &ec)
Definition chrono.h:143
FMT_CONSTEXPR To lossless_integral_conversion(const From from, int &ec)
Definition chrono.h:55
Definition uuid.h:926
Definition core.h:2772
Definition chrono.h:1835
FMT_CONSTEXPR void on_duration_unit()
Definition chrono.h:1872
FMT_CONSTEXPR void on_am_pm()
Definition chrono.h:1866
FMT_CONSTEXPR void on_24_hour_time()
Definition chrono.h:1860
FMT_CONSTEXPR void on_iso_time()
Definition chrono.h:1863
FMT_CONSTEXPR void on_duration_value()
Definition chrono.h:1869
FMT_CONSTEXPR void on_minute(numeric_system)
Definition chrono.h:1851
FMT_NORETURN void unsupported()
Definition chrono.h:1836
FMT_CONSTEXPR void on_12_hour(numeric_system)
Definition chrono.h:1848
FMT_CONSTEXPR void on_24_hour(numeric_system)
Definition chrono.h:1845
FMT_CONSTEXPR void on_second(numeric_system)
Definition chrono.h:1854
FMT_CONSTEXPR void on_12_hour_time()
Definition chrono.h:1857
FMT_CONSTEXPR void on_text(const Char *, const Char *)
Definition chrono.h:1842
Definition chrono.h:2081
void on_tz_name()
Definition chrono.h:2298
void on_full_month()
Definition chrono.h:2277
void on_us_date()
Definition chrono.h:2289
tm_writer< OutputIt, char_type > tm_writer_type
Definition chrono.h:2098
void on_datetime(numeric_system)
Definition chrono.h:2280
typename FormatContext::char_type char_type
Definition chrono.h:2097
void on_minute(numeric_system ns)
Definition chrono.h:2365
void format_tm(const tm &time, Callback cb, Args... args)
Definition chrono.h:2246
void write_pinf()
Definition chrono.h:2236
void on_am_pm()
Definition chrono.h:2442
void on_utc_offset()
Definition chrono.h:2295
void on_duration_value()
Definition chrono.h:2449
void on_24_hour_time()
Definition chrono.h:2419
void on_day_of_month(numeric_system)
Definition chrono.h:2334
void on_12_hour_time()
Definition chrono.h:2412
OutputIt out
Definition chrono.h:2083
void on_second(numeric_system ns)
Definition chrono.h:2377
void on_iso_week_of_year(numeric_system)
Definition chrono.h:2328
void on_text(const char_type *begin, const char_type *end)
Definition chrono.h:2256
void on_abbr_weekday()
Definition chrono.h:2262
void on_dec0_weekday(numeric_system)
Definition chrono.h:2268
void on_loc_date(numeric_system)
Definition chrono.h:2283
void on_12_hour(numeric_system ns)
Definition chrono.h:2353
bool negative
Definition chrono.h:2095
Rep second() const
Definition chrono.h:2163
std::chrono::duration< rep > seconds
Definition chrono.h:2092
rep val
Definition chrono.h:2091
void on_abbr_month()
Definition chrono.h:2274
bool handle_nan_inf()
Definition chrono.h:2125
void write(Rep value, int width)
Definition chrono.h:2186
void on_year(numeric_system)
Definition chrono.h:2301
std::chrono::duration< rep, std::milli > milliseconds
Definition chrono.h:2094
void on_day_of_year()
Definition chrono.h:2331
void on_offset_year()
Definition chrono.h:2307
FormatContext & context
Definition chrono.h:2082
void write_fractional_seconds(Duration d)
Definition chrono.h:2200
Rep minute() const
Definition chrono.h:2159
seconds s
Definition chrono.h:2093
void on_short_year(numeric_system)
Definition chrono.h:2304
int precision
Definition chrono.h:2084
void write_ninf()
Definition chrono.h:2240
chrono_formatter(FormatContext &ctx, OutputIt o, std::chrono::duration< Rep, Period > d)
Definition chrono.h:2100
void on_duration_unit()
Definition chrono.h:2457
std::tm time() const
Definition chrono.h:2168
bool localized
Definition chrono.h:2085
Rep hour() const
Definition chrono.h:2148
void write_sign()
Definition chrono.h:2177
void on_full_weekday()
Definition chrono.h:2265
void on_dec_month(numeric_system)
Definition chrono.h:2319
Rep hour12() const
Definition chrono.h:2153
void on_loc_time(numeric_system)
Definition chrono.h:2286
void on_iso_date()
Definition chrono.h:2292
void on_iso_week_based_year()
Definition chrono.h:2313
void on_iso_week_based_short_year()
Definition chrono.h:2316
void on_24_hour(numeric_system ns)
Definition chrono.h:2341
void on_day_of_month_space(numeric_system)
Definition chrono.h:2337
conditional_t< std::is_integral< Rep >::value &&sizeof(Rep)< sizeof(int), unsigned, typename make_unsigned_or_unchanged< Rep >::type > rep
Definition chrono.h:2090
void on_dec1_weekday(numeric_system)
Definition chrono.h:2271
void on_century(numeric_system)
Definition chrono.h:2310
void on_dec0_week_of_year(numeric_system)
Definition chrono.h:2322
void write_nan()
Definition chrono.h:2232
void on_iso_time()
Definition chrono.h:2433
void on_dec1_week_of_year(numeric_system)
Definition chrono.h:2325
Definition chrono.h:1967
Definition chrono.h:356
static constexpr const size_t max_size
Definition chrono.h:357
CodeUnit * end
Definition chrono.h:359
CodeUnit buf[max_size]
Definition chrono.h:358
Definition chrono.h:329
Definition format.h:269
FMT_CONSTEXPR void on_precision(int _precision)
Definition chrono.h:2576
FMT_CONSTEXPR void on_fill(basic_string_view< Char > fill)
Definition chrono.h:2564
FMT_CONSTEXPR void on_width(int width)
Definition chrono.h:2572
basic_format_parse_context< Char > & context
Definition chrono.h:2539
basic_string_view< Char > format_str
Definition chrono.h:2540
void on_error(const char *msg)
Definition chrono.h:2560
FMT_CONSTEXPR arg_ref_type make_arg_ref(basic_string_view< Char > arg_id)
Definition chrono.h:2549
FMT_CONSTEXPR arg_ref_type make_arg_ref(Id arg_id)
Definition chrono.h:2543
FMT_CONSTEXPR void on_align(align_t align)
Definition chrono.h:2568
FMT_CONSTEXPR void on_dynamic_width(Id arg_id)
Definition chrono.h:2585
FMT_CONSTEXPR arg_ref_type make_arg_ref(detail::auto_id)
Definition chrono.h:2555
FMT_CONSTEXPR void end_precision()
Definition chrono.h:2580
FMT_CONSTEXPR void on_dynamic_precision(Id arg_id)
Definition chrono.h:2591
detail::arg_ref< Char > arg_ref_type
Definition chrono.h:2529
arg_ref_type width_ref
Definition chrono.h:2530
FMT_CONSTEXPR parse_range do_parse(basic_format_parse_context< Char > &ctx)
Definition chrono.h:2604
typename basic_format_parse_context< Char >::iterator iterator
Definition chrono.h:2597
std::chrono::duration< Rep, Period > duration
Definition chrono.h:2534
FMT_CONSTEXPR auto parse(basic_format_parse_context< Char > &ctx) -> decltype(ctx.begin())
Definition chrono.h:2634
basic_format_specs< Char > specs
Definition chrono.h:2527
basic_string_view< Char > format_str
Definition chrono.h:2533
arg_ref_type precision_ref
Definition chrono.h:2531
auto format(const duration &d, FormatContext &ctx) const -> decltype(ctx.out())
Definition chrono.h:2644
auto format(std::chrono::time_point< std::chrono::system_clock > val, FormatContext &ctx) const -> decltype(ctx.out())
Definition chrono.h:2688
auto format(const std::tm &tm, FormatContext &ctx) const -> decltype(ctx.out())
Definition chrono.h:2738
spec
Definition chrono.h:2700
basic_string_view< Char > specs
Definition chrono.h:2706
FMT_CONSTEXPR auto parse(basic_format_parse_context< Char > &ctx) -> decltype(ctx.begin())
Definition chrono.h:2722
FMT_CONSTEXPR auto do_parse(It begin, It end) -> It
Definition chrono.h:2710
FMT_CONSTEXPR auto parse(basic_format_parse_context< Char > &ctx) -> decltype(ctx.begin())
Definition chrono.h:2499
auto format(weekday wd, FormatContext &ctx) const -> decltype(ctx.out())
Definition chrono.h:2512
Definition core.h:944
Definition chrono.h:1264
Definition chrono.h:1274
typename std::make_unsigned< T >::type type
Definition chrono.h:1923
Definition chrono.h:1916
T type
Definition chrono.h:1917
Definition chrono.h:956
FMT_CONSTEXPR void on_datetime(numeric_system)
Definition chrono.h:1053
FMT_CONSTEXPR void on_offset_year()
Definition chrono.h:969
FMT_CONSTEXPR void on_full_month()
Definition chrono.h:1005
FMT_CONSTEXPR void on_day_of_month_space(numeric_system)
Definition chrono.h:1033
FMT_CONSTEXPR void on_second(numeric_system)
Definition chrono.h:1049
FMT_CONSTEXPR void on_abbr_month()
Definition chrono.h:1001
FMT_CONSTEXPR void on_dec1_week_of_year(numeric_system)
Definition chrono.h:1017
FMT_CONSTEXPR void on_short_year(numeric_system)
Definition chrono.h:965
FMT_CONSTEXPR void on_us_date()
Definition chrono.h:1065
FMT_CONSTEXPR void on_am_pm()
Definition chrono.h:1085
FMT_CONSTEXPR void on_dec0_weekday(numeric_system)
Definition chrono.h:993
FMT_CONSTEXPR void on_abbr_weekday()
Definition chrono.h:985
FMT_CONSTEXPR void on_utc_offset()
Definition chrono.h:1097
FMT_CONSTEXPR void on_iso_date()
Definition chrono.h:1069
FMT_CONSTEXPR void on_day_of_month(numeric_system)
Definition chrono.h:1029
FMT_CONSTEXPR void on_duration_unit()
Definition chrono.h:1093
FMT_CONSTEXPR void on_24_hour(numeric_system)
Definition chrono.h:1037
FMT_CONSTEXPR void on_dec_month(numeric_system)
Definition chrono.h:1009
FMT_CONSTEXPR void on_dec0_week_of_year(numeric_system)
Definition chrono.h:1013
FMT_CONSTEXPR void on_iso_week_based_year()
Definition chrono.h:977
FMT_CONSTEXPR void on_12_hour(numeric_system)
Definition chrono.h:1041
FMT_CONSTEXPR void on_full_weekday()
Definition chrono.h:989
FMT_CONSTEXPR void on_day_of_year()
Definition chrono.h:1025
FMT_CONSTEXPR void unsupported()
Definition chrono.h:957
FMT_CONSTEXPR void on_duration_value()
Definition chrono.h:1089
FMT_CONSTEXPR void on_12_hour_time()
Definition chrono.h:1073
FMT_CONSTEXPR void on_loc_date(numeric_system)
Definition chrono.h:1057
FMT_CONSTEXPR void on_iso_time()
Definition chrono.h:1081
FMT_CONSTEXPR void on_dec1_weekday(numeric_system)
Definition chrono.h:997
FMT_CONSTEXPR void on_century(numeric_system)
Definition chrono.h:973
FMT_CONSTEXPR void on_24_hour_time()
Definition chrono.h:1077
FMT_CONSTEXPR void on_year(numeric_system)
Definition chrono.h:961
FMT_CONSTEXPR void on_loc_time(numeric_system)
Definition chrono.h:1061
FMT_CONSTEXPR void on_iso_week_based_short_year()
Definition chrono.h:981
FMT_CONSTEXPR void on_minute(numeric_system)
Definition chrono.h:1045
FMT_CONSTEXPR void on_tz_name()
Definition chrono.h:1101
FMT_CONSTEXPR void on_iso_week_of_year(numeric_system)
Definition chrono.h:1021
Definition chrono.h:1108
FMT_CONSTEXPR void on_12_hour(numeric_system)
Definition chrono.h:1178
FMT_CONSTEXPR void on_abbr_weekday()
Definition chrono.h:1136
FMT_CONSTEXPR void on_12_hour_time()
Definition chrono.h:1202
FMT_CONSTEXPR void on_utc_offset()
Definition chrono.h:1214
FMT_CONSTEXPR void on_offset_year()
Definition chrono.h:1124
FMT_CONSTEXPR void on_dec1_week_of_year(numeric_system)
Definition chrono.h:1160
FMT_CONSTEXPR void on_short_year(numeric_system)
Definition chrono.h:1121
FMT_CONSTEXPR void on_24_hour_time()
Definition chrono.h:1205
FMT_CONSTEXPR void on_24_hour(numeric_system)
Definition chrono.h:1175
FMT_CONSTEXPR void on_minute(numeric_system)
Definition chrono.h:1181
FMT_CONSTEXPR void on_text(const Char *, const Char *)
Definition chrono.h:1115
FMT_CONSTEXPR void on_am_pm()
Definition chrono.h:1211
FMT_CONSTEXPR void on_datetime(numeric_system)
Definition chrono.h:1187
FMT_CONSTEXPR void on_dec0_week_of_year(numeric_system)
Definition chrono.h:1157
FMT_CONSTEXPR void on_us_date()
Definition chrono.h:1196
FMT_CONSTEXPR void on_loc_time(numeric_system)
Definition chrono.h:1193
FMT_CONSTEXPR void on_iso_week_based_year()
Definition chrono.h:1130
FMT_CONSTEXPR void on_abbr_month()
Definition chrono.h:1148
FMT_CONSTEXPR void on_century(numeric_system)
Definition chrono.h:1127
FMT_CONSTEXPR void on_loc_date(numeric_system)
Definition chrono.h:1190
FMT_CONSTEXPR void on_dec_month(numeric_system)
Definition chrono.h:1154
FMT_CONSTEXPR void on_iso_date()
Definition chrono.h:1199
FMT_CONSTEXPR void on_iso_time()
Definition chrono.h:1208
FMT_CONSTEXPR void on_iso_week_of_year(numeric_system)
Definition chrono.h:1163
FMT_CONSTEXPR void on_second(numeric_system)
Definition chrono.h:1184
FMT_CONSTEXPR void on_day_of_month(numeric_system)
Definition chrono.h:1169
FMT_CONSTEXPR void on_iso_week_based_short_year()
Definition chrono.h:1133
FMT_CONSTEXPR void on_day_of_year()
Definition chrono.h:1166
FMT_CONSTEXPR void on_full_weekday()
Definition chrono.h:1139
FMT_CONSTEXPR void on_full_month()
Definition chrono.h:1151
FMT_NORETURN void unsupported()
Definition chrono.h:1109
FMT_CONSTEXPR void on_dec0_weekday(numeric_system)
Definition chrono.h:1142
FMT_CONSTEXPR void on_dec1_weekday(numeric_system)
Definition chrono.h:1145
FMT_CONSTEXPR void on_day_of_month_space(numeric_system)
Definition chrono.h:1172
FMT_CONSTEXPR void on_tz_name()
Definition chrono.h:1217
FMT_CONSTEXPR void on_year(numeric_system)
Definition chrono.h:1118
b
Definition tag_strings.h:61
s
Definition tag_strings.h:47
a
Definition tag_strings.h:43
ms
Definition tag_strings.h:92
u
Definition tag_strings.h:62
time
Definition tag_strings.h:53
p
Definition tag_strings.h:29