WPILibC++ 2025.1.1
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#ifndef FMT_MODULE
12# include <algorithm>
13# include <chrono>
14# include <cmath> // std::isfinite
15# include <cstring> // std::memcpy
16# include <ctime>
17# include <iterator>
18# include <locale>
19# include <ostream>
20# include <type_traits>
21#endif
22
23#include "format.h"
24
25namespace fmt_detail {
26struct time_zone {
27 template <typename Duration, typename T>
28 auto to_sys(T)
29 -> std::chrono::time_point<std::chrono::system_clock, Duration> {
30 return {};
31 }
32};
33template <typename... T> inline auto current_zone(T...) -> time_zone* {
34 return nullptr;
35}
36
37template <typename... T> inline void _tzset(T...) {}
38} // namespace fmt_detail
39
41
42// Enable safe chrono durations, unless explicitly disabled.
43#ifndef FMT_SAFE_DURATION_CAST
44# define FMT_SAFE_DURATION_CAST 1
45#endif
46#if FMT_SAFE_DURATION_CAST
47
48// For conversion between std::chrono::durations without undefined
49// behaviour or erroneous results.
50// This is a stripped down version of duration_cast, for inclusion in fmt.
51// See https://github.com/pauldreik/safe_duration_cast
52//
53// Copyright Paul Dreik 2019
54namespace safe_duration_cast {
55
56template <typename To, typename From,
57 FMT_ENABLE_IF(!std::is_same<From, To>::value &&
58 std::numeric_limits<From>::is_signed ==
59 std::numeric_limits<To>::is_signed)>
60FMT_CONSTEXPR auto lossless_integral_conversion(const From from, int& ec)
61 -> To {
62 ec = 0;
63 using F = std::numeric_limits<From>;
64 using T = std::numeric_limits<To>;
65 static_assert(F::is_integer, "From must be integral");
66 static_assert(T::is_integer, "To must be integral");
67
68 // A and B are both signed, or both unsigned.
69 if (detail::const_check(F::digits <= T::digits)) {
70 // From fits in To without any problem.
71 } else {
72 // From does not always fit in To, resort to a dynamic check.
73 if (from < (T::min)() || from > (T::max)()) {
74 // outside range.
75 ec = 1;
76 return {};
77 }
78 }
79 return static_cast<To>(from);
80}
81
82/// Converts From to To, without loss. If the dynamic value of from
83/// can't be converted to To without loss, ec is set.
84template <typename To, typename From,
85 FMT_ENABLE_IF(!std::is_same<From, To>::value &&
86 std::numeric_limits<From>::is_signed !=
87 std::numeric_limits<To>::is_signed)>
88FMT_CONSTEXPR auto lossless_integral_conversion(const From from, int& ec)
89 -> To {
90 ec = 0;
91 using F = std::numeric_limits<From>;
92 using T = std::numeric_limits<To>;
93 static_assert(F::is_integer, "From must be integral");
94 static_assert(T::is_integer, "To must be integral");
95
96 if (detail::const_check(F::is_signed && !T::is_signed)) {
97 // From may be negative, not allowed!
98 if (fmt::detail::is_negative(from)) {
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 ec = 1;
106 return {};
107 }
108 }
109
110 if (detail::const_check(!F::is_signed && T::is_signed &&
111 F::digits >= T::digits) &&
112 from > static_cast<From>(detail::max_value<To>())) {
113 ec = 1;
114 return {};
115 }
116 return static_cast<To>(from); // Lossless conversion.
117}
118
119template <typename To, typename From,
120 FMT_ENABLE_IF(std::is_same<From, To>::value)>
121FMT_CONSTEXPR auto lossless_integral_conversion(const From from, int& ec)
122 -> To {
123 ec = 0;
124 return from;
125} // function
126
127// clang-format off
128/**
129 * converts From to To if possible, otherwise ec is set.
130 *
131 * input | output
132 * ---------------------------------|---------------
133 * NaN | NaN
134 * Inf | Inf
135 * normal, fits in output | converted (possibly lossy)
136 * normal, does not fit in output | ec is set
137 * subnormal | best effort
138 * -Inf | -Inf
139 */
140// clang-format on
141template <typename To, typename From,
142 FMT_ENABLE_IF(!std::is_same<From, To>::value)>
143FMT_CONSTEXPR auto safe_float_conversion(const From from, int& ec) -> To {
144 ec = 0;
145 using T = std::numeric_limits<To>;
146 static_assert(std::is_floating_point<From>::value, "From must be floating");
147 static_assert(std::is_floating_point<To>::value, "To must be floating");
148
149 // catch the only happy case
150 if (std::isfinite(from)) {
151 if (from >= T::lowest() && from <= (T::max)()) {
152 return static_cast<To>(from);
153 }
154 // not within range.
155 ec = 1;
156 return {};
157 }
158
159 // nan and inf will be preserved
160 return static_cast<To>(from);
161} // function
162
163template <typename To, typename From,
164 FMT_ENABLE_IF(std::is_same<From, To>::value)>
165FMT_CONSTEXPR auto safe_float_conversion(const From from, int& ec) -> To {
166 ec = 0;
167 static_assert(std::is_floating_point<From>::value, "From must be floating");
168 return from;
169}
170
171/// Safe duration_cast between floating point durations
172template <typename To, typename FromRep, typename FromPeriod,
173 FMT_ENABLE_IF(std::is_floating_point<FromRep>::value),
174 FMT_ENABLE_IF(std::is_floating_point<typename To::rep>::value)>
175auto safe_duration_cast(std::chrono::duration<FromRep, FromPeriod> from,
176 int& ec) -> To {
177 using From = std::chrono::duration<FromRep, FromPeriod>;
178 ec = 0;
179 if (std::isnan(from.count())) {
180 // nan in, gives nan out. easy.
181 return To{std::numeric_limits<typename To::rep>::quiet_NaN()};
182 }
183 // maybe we should also check if from is denormal, and decide what to do about
184 // it.
185
186 // +-inf should be preserved.
187 if (std::isinf(from.count())) {
188 return To{from.count()};
189 }
190
191 // the basic idea is that we need to convert from count() in the from type
192 // to count() in the To type, by multiplying it with this:
193 struct Factor
194 : std::ratio_divide<typename From::period, typename To::period> {};
195
196 static_assert(Factor::num > 0, "num must be positive");
197 static_assert(Factor::den > 0, "den must be positive");
198
199 // the conversion is like this: multiply from.count() with Factor::num
200 // /Factor::den and convert it to To::rep, all this without
201 // overflow/underflow. let's start by finding a suitable type that can hold
202 // both To, From and Factor::num
203 using IntermediateRep =
204 typename std::common_type<typename From::rep, typename To::rep,
205 decltype(Factor::num)>::type;
206
207 // force conversion of From::rep -> IntermediateRep to be safe,
208 // even if it will never happen be narrowing in this context.
209 IntermediateRep count =
210 safe_float_conversion<IntermediateRep>(from.count(), ec);
211 if (ec) {
212 return {};
213 }
214
215 // multiply with Factor::num without overflow or underflow
216 if (detail::const_check(Factor::num != 1)) {
217 constexpr auto max1 = detail::max_value<IntermediateRep>() /
218 static_cast<IntermediateRep>(Factor::num);
219 if (count > max1) {
220 ec = 1;
221 return {};
222 }
223 constexpr auto min1 = std::numeric_limits<IntermediateRep>::lowest() /
224 static_cast<IntermediateRep>(Factor::num);
225 if (count < min1) {
226 ec = 1;
227 return {};
228 }
229 count *= static_cast<IntermediateRep>(Factor::num);
230 }
231
232 // this can't go wrong, right? den>0 is checked earlier.
233 if (detail::const_check(Factor::den != 1)) {
234 using common_t = typename std::common_type<IntermediateRep, intmax_t>::type;
235 count /= static_cast<common_t>(Factor::den);
236 }
237
238 // convert to the to type, safely
239 using ToRep = typename To::rep;
240
241 const ToRep tocount = safe_float_conversion<ToRep>(count, ec);
242 if (ec) {
243 return {};
244 }
245 return To{tocount};
246}
247} // namespace safe_duration_cast
248#endif
249
250namespace detail {
251
252// Check if std::chrono::utc_time is available.
253#ifdef FMT_USE_UTC_TIME
254// Use the provided definition.
255#elif defined(__cpp_lib_chrono)
256# define FMT_USE_UTC_TIME (__cpp_lib_chrono >= 201907L)
257#else
258# define FMT_USE_UTC_TIME 0
259#endif
260#if FMT_USE_UTC_TIME
261using utc_clock = std::chrono::utc_clock;
262#else
263struct utc_clock {
264 void to_sys();
265};
266#endif
267
268// Check if std::chrono::local_time is available.
269#ifdef FMT_USE_LOCAL_TIME
270// Use the provided definition.
271#elif defined(__cpp_lib_chrono)
272# define FMT_USE_LOCAL_TIME (__cpp_lib_chrono >= 201907L)
273#else
274# define FMT_USE_LOCAL_TIME 0
275#endif
276#if FMT_USE_LOCAL_TIME
277using local_t = std::chrono::local_t;
278#else
279struct local_t {};
280#endif
281
282} // namespace detail
283
284template <typename Duration>
285using sys_time = std::chrono::time_point<std::chrono::system_clock, Duration>;
286
287template <typename Duration>
288using utc_time = std::chrono::time_point<detail::utc_clock, Duration>;
289
290template <class Duration>
291using local_time = std::chrono::time_point<detail::local_t, Duration>;
292
293namespace detail {
294
295// Prevents expansion of a preceding token as a function-style macro.
296// Usage: f FMT_NOMACRO()
297#define FMT_NOMACRO
298
299template <typename T = void> struct null {};
300inline auto localtime_r FMT_NOMACRO(...) -> null<> { return null<>(); }
301inline auto localtime_s(...) -> null<> { return null<>(); }
302inline auto gmtime_r(...) -> null<> { return null<>(); }
303inline auto gmtime_s(...) -> null<> { return null<>(); }
304
305// It is defined here and not in ostream.h because the latter has expensive
306// includes.
307template <typename StreamBuf> class formatbuf : public StreamBuf {
308 private:
309 using char_type = typename StreamBuf::char_type;
310 using streamsize = decltype(std::declval<StreamBuf>().sputn(nullptr, 0));
311 using int_type = typename StreamBuf::int_type;
312 using traits_type = typename StreamBuf::traits_type;
313
314 buffer<char_type>& buffer_;
315
316 public:
317 explicit formatbuf(buffer<char_type>& buf) : buffer_(buf) {}
318
319 protected:
320 // The put area is always empty. This makes the implementation simpler and has
321 // the advantage that the streambuf and the buffer are always in sync and
322 // sputc never writes into uninitialized memory. A disadvantage is that each
323 // call to sputc always results in a (virtual) call to overflow. There is no
324 // disadvantage here for sputn since this always results in a call to xsputn.
325
326 auto overflow(int_type ch) -> int_type override {
327 if (!traits_type::eq_int_type(ch, traits_type::eof()))
328 buffer_.push_back(static_cast<char_type>(ch));
329 return ch;
330 }
331
332 auto xsputn(const char_type* s, streamsize count) -> streamsize override {
333 buffer_.append(s, s + count);
334 return count;
335 }
336};
337
338inline auto get_classic_locale() -> const std::locale& {
339 static const auto& locale = std::locale::classic();
340 return locale;
341}
342
343template <typename CodeUnit> struct codecvt_result {
344 static constexpr const size_t max_size = 32;
345 CodeUnit buf[max_size];
346 CodeUnit* end;
347};
348
349template <typename CodeUnit>
351 const std::locale& loc) {
352 FMT_PRAGMA_CLANG(diagnostic push)
353 FMT_PRAGMA_CLANG(diagnostic ignored "-Wdeprecated")
354 auto& f = std::use_facet<std::codecvt<CodeUnit, char, std::mbstate_t>>(loc);
355 FMT_PRAGMA_CLANG(diagnostic pop)
356 auto mb = std::mbstate_t();
357 const char* from_next = nullptr;
358 auto result = f.in(mb, in.begin(), in.end(), from_next, std::begin(out.buf),
359 std::end(out.buf), out.end);
360 if (result != std::codecvt_base::ok)
361 FMT_THROW(format_error("failed to format time"));
362}
363
364template <typename OutputIt>
365auto write_encoded_tm_str(OutputIt out, string_view in, const std::locale& loc)
366 -> OutputIt {
367 if (detail::use_utf8 && loc != get_classic_locale()) {
368 // char16_t and char32_t codecvts are broken in MSVC (linkage errors) and
369 // gcc-4.
370#if FMT_MSC_VERSION != 0 || \
371 (defined(__GLIBCXX__) && \
372 (!defined(_GLIBCXX_USE_DUAL_ABI) || _GLIBCXX_USE_DUAL_ABI == 0))
373 // The _GLIBCXX_USE_DUAL_ABI macro is always defined in libstdc++ from gcc-5
374 // and newer.
375 using code_unit = wchar_t;
376#else
377 using code_unit = char32_t;
378#endif
379
380 using unit_t = codecvt_result<code_unit>;
381 unit_t unit;
382 write_codecvt(unit, in, loc);
383 // In UTF-8 is used one to four one-byte code units.
384 auto u =
386 if (!u.convert({unit.buf, to_unsigned(unit.end - unit.buf)}))
387 FMT_THROW(format_error("failed to format time"));
388 return copy<char>(u.c_str(), u.c_str() + u.size(), out);
389 }
390 return copy<char>(in.data(), in.data() + in.size(), out);
391}
392
393template <typename Char, typename OutputIt,
394 FMT_ENABLE_IF(!std::is_same<Char, char>::value)>
395auto write_tm_str(OutputIt out, string_view sv, const std::locale& loc)
396 -> OutputIt {
398 write_codecvt(unit, sv, loc);
399 return copy<Char>(unit.buf, unit.end, out);
400}
401
402template <typename Char, typename OutputIt,
403 FMT_ENABLE_IF(std::is_same<Char, char>::value)>
404auto write_tm_str(OutputIt out, string_view sv, const std::locale& loc)
405 -> OutputIt {
406 return write_encoded_tm_str(out, sv, loc);
407}
408
409template <typename Char>
410inline void do_write(buffer<Char>& buf, const std::tm& time,
411 const std::locale& loc, char format, char modifier) {
412 auto&& format_buf = formatbuf<std::basic_streambuf<Char>>(buf);
413 auto&& os = std::basic_ostream<Char>(&format_buf);
414 os.imbue(loc);
415 const auto& facet = std::use_facet<std::time_put<Char>>(loc);
416 auto end = facet.put(os, os, Char(' '), &time, format, modifier);
417 if (end.failed()) FMT_THROW(format_error("failed to format time"));
418}
419
420template <typename Char, typename OutputIt,
421 FMT_ENABLE_IF(!std::is_same<Char, char>::value)>
422auto write(OutputIt out, const std::tm& time, const std::locale& loc,
423 char format, char modifier = 0) -> OutputIt {
424 auto&& buf = get_buffer<Char>(out);
425 do_write<Char>(buf, time, loc, format, modifier);
426 return get_iterator(buf, out);
427}
428
429template <typename Char, typename OutputIt,
430 FMT_ENABLE_IF(std::is_same<Char, char>::value)>
431auto write(OutputIt out, const std::tm& time, const std::locale& loc,
432 char format, char modifier = 0) -> OutputIt {
433 auto&& buf = basic_memory_buffer<Char>();
434 do_write<char>(buf, time, loc, format, modifier);
435 return write_encoded_tm_str(out, string_view(buf.data(), buf.size()), loc);
436}
437
438template <typename Rep1, typename Rep2>
440 : public std::integral_constant<bool,
441 (std::is_integral<Rep1>::value &&
442 std::is_integral<Rep2>::value) ||
443 (std::is_floating_point<Rep1>::value &&
444 std::is_floating_point<Rep2>::value)> {
445};
446
448 FMT_THROW(format_error("cannot format duration"));
449}
450
451// Cast one integral duration to another with an overflow check.
452template <typename To, typename FromRep, typename FromPeriod,
453 FMT_ENABLE_IF(std::is_integral<FromRep>::value&&
454 std::is_integral<typename To::rep>::value)>
455auto duration_cast(std::chrono::duration<FromRep, FromPeriod> from) -> To {
456#if !FMT_SAFE_DURATION_CAST
457 return std::chrono::duration_cast<To>(from);
458#else
459 // The conversion factor: to.count() == factor * from.count().
460 using factor = std::ratio_divide<FromPeriod, typename To::period>;
461
462 using common_rep = typename std::common_type<FromRep, typename To::rep,
463 decltype(factor::num)>::type;
464
465 int ec = 0;
466 auto count = safe_duration_cast::lossless_integral_conversion<common_rep>(
467 from.count(), ec);
468 if (ec) throw_duration_error();
469
470 // Multiply from.count() by factor and check for overflow.
471 if (const_check(factor::num != 1)) {
472 if (count > max_value<common_rep>() / factor::num) throw_duration_error();
473 const auto min = (std::numeric_limits<common_rep>::min)() / factor::num;
474 if (const_check(!std::is_unsigned<common_rep>::value) && count < min)
476 count *= factor::num;
477 }
478 if (const_check(factor::den != 1)) count /= factor::den;
479 auto to =
480 To(safe_duration_cast::lossless_integral_conversion<typename To::rep>(
481 count, ec));
482 if (ec) throw_duration_error();
483 return to;
484#endif
485}
486
487template <typename To, typename FromRep, typename FromPeriod,
488 FMT_ENABLE_IF(std::is_floating_point<FromRep>::value&&
489 std::is_floating_point<typename To::rep>::value)>
490auto duration_cast(std::chrono::duration<FromRep, FromPeriod> from) -> To {
491#if FMT_SAFE_DURATION_CAST
492 // Throwing version of safe_duration_cast is only available for
493 // integer to integer or float to float casts.
494 int ec;
495 To to = safe_duration_cast::safe_duration_cast<To>(from, ec);
496 if (ec) throw_duration_error();
497 return to;
498#else
499 // Standard duration cast, may overflow.
500 return std::chrono::duration_cast<To>(from);
501#endif
502}
503
504template <
505 typename To, typename FromRep, typename FromPeriod,
506 FMT_ENABLE_IF(!is_same_arithmetic_type<FromRep, typename To::rep>::value)>
507auto duration_cast(std::chrono::duration<FromRep, FromPeriod> from) -> To {
508 // Mixed integer <-> float cast is not supported by safe_duration_cast.
509 return std::chrono::duration_cast<To>(from);
510}
511
512template <typename Duration>
513auto to_time_t(sys_time<Duration> time_point) -> std::time_t {
514 // Cannot use std::chrono::system_clock::to_time_t since this would first
515 // require a cast to std::chrono::system_clock::time_point, which could
516 // overflow.
518 time_point.time_since_epoch())
519 .count();
520}
521
522// Workaround a bug in libstdc++ which sets __cpp_lib_chrono to 201907 without
523// providing current_zone(): https://github.com/fmtlib/fmt/issues/4160.
524template <typename T> FMT_CONSTEXPR auto has_current_zone() -> bool {
525 using namespace std::chrono;
526 using namespace fmt_detail;
527 return !std::is_same<decltype(current_zone()), fmt_detail::time_zone*>::value;
528}
529} // namespace detail
530
532
533/**
534 * Converts given time since epoch as `std::time_t` value into calendar time,
535 * expressed in local time. Unlike `std::localtime`, this function is
536 * thread-safe on most platforms.
537 */
538inline auto localtime(std::time_t time) -> std::tm {
539 struct dispatcher {
540 std::time_t time_;
541 std::tm tm_;
542
543 inline dispatcher(std::time_t t) : time_(t) {}
544
545 inline auto run() -> bool {
546 using namespace fmt::detail;
547 return handle(localtime_r(&time_, &tm_));
548 }
549
550 inline auto handle(std::tm* tm) -> bool { return tm != nullptr; }
551
552 inline auto handle(detail::null<>) -> bool {
553 using namespace fmt::detail;
554 return fallback(localtime_s(&tm_, &time_));
555 }
556
557 inline auto fallback(int res) -> bool { return res == 0; }
558
559#if !FMT_MSC_VERSION
560 inline auto fallback(detail::null<>) -> bool {
561 using namespace fmt::detail;
562 std::tm* tm = std::localtime(&time_);
563 if (tm) tm_ = *tm;
564 return tm != nullptr;
565 }
566#endif
567 };
568 dispatcher lt(time);
569 // Too big time values may be unsupported.
570 if (!lt.run()) FMT_THROW(format_error("time_t value out of range"));
571 return lt.tm_;
572}
573
574#if FMT_USE_LOCAL_TIME
575template <typename Duration,
577inline auto localtime(std::chrono::local_time<Duration> time) -> std::tm {
578 using namespace std::chrono;
579 using namespace fmt_detail;
580 return localtime(detail::to_time_t(current_zone()->to_sys<Duration>(time)));
581}
582#endif
583
584/**
585 * Converts given time since epoch as `std::time_t` value into calendar time,
586 * expressed in Coordinated Universal Time (UTC). Unlike `std::gmtime`, this
587 * function is thread-safe on most platforms.
588 */
589inline auto gmtime(std::time_t time) -> std::tm {
590 struct dispatcher {
591 std::time_t time_;
592 std::tm tm_;
593
594 inline dispatcher(std::time_t t) : time_(t) {}
595
596 inline auto run() -> bool {
597 using namespace fmt::detail;
598 return handle(gmtime_r(&time_, &tm_));
599 }
600
601 inline auto handle(std::tm* tm) -> bool { return tm != nullptr; }
602
603 inline auto handle(detail::null<>) -> bool {
604 using namespace fmt::detail;
605 return fallback(gmtime_s(&tm_, &time_));
606 }
607
608 inline auto fallback(int res) -> bool { return res == 0; }
609
610#if !FMT_MSC_VERSION
611 inline auto fallback(detail::null<>) -> bool {
612 std::tm* tm = std::gmtime(&time_);
613 if (tm) tm_ = *tm;
614 return tm != nullptr;
615 }
616#endif
617 };
618 auto gt = dispatcher(time);
619 // Too big time values may be unsupported.
620 if (!gt.run()) FMT_THROW(format_error("time_t value out of range"));
621 return gt.tm_;
622}
623
624template <typename Duration>
625inline auto gmtime(sys_time<Duration> time_point) -> std::tm {
626 return gmtime(detail::to_time_t(time_point));
627}
628
629namespace detail {
630
631// Writes two-digit numbers a, b and c separated by sep to buf.
632// The method by Pavel Novikov based on
633// https://johnnylee-sde.github.io/Fast-unsigned-integer-to-time-string/.
634inline void write_digit2_separated(char* buf, unsigned a, unsigned b,
635 unsigned c, char sep) {
636 unsigned long long digits =
637 a | (b << 24) | (static_cast<unsigned long long>(c) << 48);
638 // Convert each value to BCD.
639 // We have x = a * 10 + b and we want to convert it to BCD y = a * 16 + b.
640 // The difference is
641 // y - x = a * 6
642 // a can be found from x:
643 // a = floor(x / 10)
644 // then
645 // y = x + a * 6 = x + floor(x / 10) * 6
646 // floor(x / 10) is (x * 205) >> 11 (needs 16 bits).
647 digits += (((digits * 205) >> 11) & 0x000f00000f00000f) * 6;
648 // Put low nibbles to high bytes and high nibbles to low bytes.
649 digits = ((digits & 0x00f00000f00000f0) >> 4) |
650 ((digits & 0x000f00000f00000f) << 8);
651 auto usep = static_cast<unsigned long long>(sep);
652 // Add ASCII '0' to each digit byte and insert separators.
653 digits |= 0x3030003030003030 | (usep << 16) | (usep << 40);
654
655 constexpr const size_t len = 8;
656 if (const_check(is_big_endian())) {
657 char tmp[len];
658 std::memcpy(tmp, &digits, len);
659 std::reverse_copy(tmp, tmp + len, buf);
660 } else {
661 std::memcpy(buf, &digits, len);
662 }
663}
664
665template <typename Period>
666FMT_CONSTEXPR inline auto get_units() -> const char* {
667 if (std::is_same<Period, std::atto>::value) return "as";
668 if (std::is_same<Period, std::femto>::value) return "fs";
669 if (std::is_same<Period, std::pico>::value) return "ps";
670 if (std::is_same<Period, std::nano>::value) return "ns";
671 if (std::is_same<Period, std::micro>::value)
672 return detail::use_utf8 ? "µs" : "us";
673 if (std::is_same<Period, std::milli>::value) return "ms";
674 if (std::is_same<Period, std::centi>::value) return "cs";
675 if (std::is_same<Period, std::deci>::value) return "ds";
676 if (std::is_same<Period, std::ratio<1>>::value) return "s";
677 if (std::is_same<Period, std::deca>::value) return "das";
678 if (std::is_same<Period, std::hecto>::value) return "hs";
679 if (std::is_same<Period, std::kilo>::value) return "ks";
680 if (std::is_same<Period, std::mega>::value) return "Ms";
681 if (std::is_same<Period, std::giga>::value) return "Gs";
682 if (std::is_same<Period, std::tera>::value) return "Ts";
683 if (std::is_same<Period, std::peta>::value) return "Ps";
684 if (std::is_same<Period, std::exa>::value) return "Es";
685 if (std::is_same<Period, std::ratio<60>>::value) return "min";
686 if (std::is_same<Period, std::ratio<3600>>::value) return "h";
687 if (std::is_same<Period, std::ratio<86400>>::value) return "d";
688 return nullptr;
689}
690
691enum class numeric_system {
692 standard,
693 // Alternative numeric system, e.g. 十二 instead of 12 in ja_JP locale.
695};
696
697// Glibc extensions for formatting numeric values.
698enum class pad_type {
699 // Pad a numeric result string with zeros (the default).
700 zero,
701 // Do not pad a numeric result string.
702 none,
703 // Pad a numeric result string with spaces.
704 space,
705};
706
707template <typename OutputIt>
708auto write_padding(OutputIt out, pad_type pad, int width) -> OutputIt {
709 if (pad == pad_type::none) return out;
710 return detail::fill_n(out, width, pad == pad_type::space ? ' ' : '0');
711}
712
713template <typename OutputIt>
714auto write_padding(OutputIt out, pad_type pad) -> OutputIt {
715 if (pad != pad_type::none) *out++ = pad == pad_type::space ? ' ' : '0';
716 return out;
717}
718
719// Parses a put_time-like format string and invokes handler actions.
720template <typename Char, typename Handler>
721FMT_CONSTEXPR auto parse_chrono_format(const Char* begin, const Char* end,
722 Handler&& handler) -> const Char* {
723 if (begin == end || *begin == '}') return begin;
724 if (*begin != '%') FMT_THROW(format_error("invalid format"));
725 auto ptr = begin;
726 while (ptr != end) {
728 auto c = *ptr;
729 if (c == '}') break;
730 if (c != '%') {
731 ++ptr;
732 continue;
733 }
734 if (begin != ptr) handler.on_text(begin, ptr);
735 ++ptr; // consume '%'
736 if (ptr == end) FMT_THROW(format_error("invalid format"));
737 c = *ptr;
738 switch (c) {
739 case '_':
740 pad = pad_type::space;
741 ++ptr;
742 break;
743 case '-':
744 pad = pad_type::none;
745 ++ptr;
746 break;
747 }
748 if (ptr == end) FMT_THROW(format_error("invalid format"));
749 c = *ptr++;
750 switch (c) {
751 case '%': handler.on_text(ptr - 1, ptr); break;
752 case 'n': {
753 const Char newline[] = {'\n'};
754 handler.on_text(newline, newline + 1);
755 break;
756 }
757 case 't': {
758 const Char tab[] = {'\t'};
759 handler.on_text(tab, tab + 1);
760 break;
761 }
762 // Year:
763 case 'Y': handler.on_year(numeric_system::standard, pad); break;
764 case 'y': handler.on_short_year(numeric_system::standard); break;
765 case 'C': handler.on_century(numeric_system::standard); break;
766 case 'G': handler.on_iso_week_based_year(); break;
767 case 'g': handler.on_iso_week_based_short_year(); break;
768 // Day of the week:
769 case 'a': handler.on_abbr_weekday(); break;
770 case 'A': handler.on_full_weekday(); break;
771 case 'w': handler.on_dec0_weekday(numeric_system::standard); break;
772 case 'u': handler.on_dec1_weekday(numeric_system::standard); break;
773 // Month:
774 case 'b':
775 case 'h': handler.on_abbr_month(); break;
776 case 'B': handler.on_full_month(); break;
777 case 'm': handler.on_dec_month(numeric_system::standard, pad); break;
778 // Day of the year/month:
779 case 'U':
780 handler.on_dec0_week_of_year(numeric_system::standard, pad);
781 break;
782 case 'W':
783 handler.on_dec1_week_of_year(numeric_system::standard, pad);
784 break;
785 case 'V': handler.on_iso_week_of_year(numeric_system::standard, pad); break;
786 case 'j': handler.on_day_of_year(pad); break;
787 case 'd': handler.on_day_of_month(numeric_system::standard, pad); break;
788 case 'e':
789 handler.on_day_of_month(numeric_system::standard, pad_type::space);
790 break;
791 // Hour, minute, second:
792 case 'H': handler.on_24_hour(numeric_system::standard, pad); break;
793 case 'I': handler.on_12_hour(numeric_system::standard, pad); break;
794 case 'M': handler.on_minute(numeric_system::standard, pad); break;
795 case 'S': handler.on_second(numeric_system::standard, pad); break;
796 // Other:
797 case 'c': handler.on_datetime(numeric_system::standard); break;
798 case 'x': handler.on_loc_date(numeric_system::standard); break;
799 case 'X': handler.on_loc_time(numeric_system::standard); break;
800 case 'D': handler.on_us_date(); break;
801 case 'F': handler.on_iso_date(); break;
802 case 'r': handler.on_12_hour_time(); break;
803 case 'R': handler.on_24_hour_time(); break;
804 case 'T': handler.on_iso_time(); break;
805 case 'p': handler.on_am_pm(); break;
806 case 'Q': handler.on_duration_value(); break;
807 case 'q': handler.on_duration_unit(); break;
808 case 'z': handler.on_utc_offset(numeric_system::standard); break;
809 case 'Z': handler.on_tz_name(); break;
810 // Alternative representation:
811 case 'E': {
812 if (ptr == end) FMT_THROW(format_error("invalid format"));
813 c = *ptr++;
814 switch (c) {
815 case 'Y': handler.on_year(numeric_system::alternative, pad); break;
816 case 'y': handler.on_offset_year(); break;
817 case 'C': handler.on_century(numeric_system::alternative); break;
818 case 'c': handler.on_datetime(numeric_system::alternative); break;
819 case 'x': handler.on_loc_date(numeric_system::alternative); break;
820 case 'X': handler.on_loc_time(numeric_system::alternative); break;
821 case 'z': handler.on_utc_offset(numeric_system::alternative); break;
822 default: FMT_THROW(format_error("invalid format"));
823 }
824 break;
825 }
826 case 'O':
827 if (ptr == end) FMT_THROW(format_error("invalid format"));
828 c = *ptr++;
829 switch (c) {
830 case 'y': handler.on_short_year(numeric_system::alternative); break;
831 case 'm': handler.on_dec_month(numeric_system::alternative, pad); break;
832 case 'U':
833 handler.on_dec0_week_of_year(numeric_system::alternative, pad);
834 break;
835 case 'W':
836 handler.on_dec1_week_of_year(numeric_system::alternative, pad);
837 break;
838 case 'V':
839 handler.on_iso_week_of_year(numeric_system::alternative, pad);
840 break;
841 case 'd':
842 handler.on_day_of_month(numeric_system::alternative, pad);
843 break;
844 case 'e':
845 handler.on_day_of_month(numeric_system::alternative, pad_type::space);
846 break;
847 case 'w': handler.on_dec0_weekday(numeric_system::alternative); break;
848 case 'u': handler.on_dec1_weekday(numeric_system::alternative); break;
849 case 'H': handler.on_24_hour(numeric_system::alternative, pad); break;
850 case 'I': handler.on_12_hour(numeric_system::alternative, pad); break;
851 case 'M': handler.on_minute(numeric_system::alternative, pad); break;
852 case 'S': handler.on_second(numeric_system::alternative, pad); break;
853 case 'z': handler.on_utc_offset(numeric_system::alternative); break;
854 default: FMT_THROW(format_error("invalid format"));
855 }
856 break;
857 default: FMT_THROW(format_error("invalid format"));
858 }
859 begin = ptr;
860 }
861 if (begin != ptr) handler.on_text(begin, ptr);
862 return ptr;
863}
864
865template <typename Derived> struct null_chrono_spec_handler {
867 static_cast<Derived*>(this)->unsupported();
868 }
912};
913
914struct tm_format_checker : null_chrono_spec_handler<tm_format_checker> {
915 FMT_NORETURN inline void unsupported() {
916 FMT_THROW(format_error("no format"));
917 }
918
919 template <typename Char>
920 FMT_CONSTEXPR void on_text(const Char*, const Char*) {}
954};
955
956inline auto tm_wday_full_name(int wday) -> const char* {
957 static constexpr const char* full_name_list[] = {
958 "Sunday", "Monday", "Tuesday", "Wednesday",
959 "Thursday", "Friday", "Saturday"};
960 return wday >= 0 && wday <= 6 ? full_name_list[wday] : "?";
961}
962inline auto tm_wday_short_name(int wday) -> const char* {
963 static constexpr const char* short_name_list[] = {"Sun", "Mon", "Tue", "Wed",
964 "Thu", "Fri", "Sat"};
965 return wday >= 0 && wday <= 6 ? short_name_list[wday] : "???";
966}
967
968inline auto tm_mon_full_name(int mon) -> const char* {
969 static constexpr const char* full_name_list[] = {
970 "January", "February", "March", "April", "May", "June",
971 "July", "August", "September", "October", "November", "December"};
972 return mon >= 0 && mon <= 11 ? full_name_list[mon] : "?";
973}
974inline auto tm_mon_short_name(int mon) -> const char* {
975 static constexpr const char* short_name_list[] = {
976 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
977 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
978 };
979 return mon >= 0 && mon <= 11 ? short_name_list[mon] : "???";
980}
981
982template <typename T, typename = void>
983struct has_member_data_tm_gmtoff : std::false_type {};
984template <typename T>
985struct has_member_data_tm_gmtoff<T, void_t<decltype(T::tm_gmtoff)>>
986 : std::true_type {};
987
988template <typename T, typename = void>
989struct has_member_data_tm_zone : std::false_type {};
990template <typename T>
991struct has_member_data_tm_zone<T, void_t<decltype(T::tm_zone)>>
992 : std::true_type {};
993
994inline void tzset_once() {
995 static bool init = []() {
996 using namespace fmt_detail;
997 _tzset();
998 return false;
999 }();
1000 ignore_unused(init);
1001}
1002
1003// Converts value to Int and checks that it's in the range [0, upper).
1004template <typename T, typename Int, FMT_ENABLE_IF(std::is_integral<T>::value)>
1005inline auto to_nonnegative_int(T value, Int upper) -> Int {
1006 if (!std::is_unsigned<Int>::value &&
1007 (value < 0 || to_unsigned(value) > to_unsigned(upper))) {
1008 FMT_THROW(fmt::format_error("chrono value is out of range"));
1009 }
1010 return static_cast<Int>(value);
1011}
1012template <typename T, typename Int, FMT_ENABLE_IF(!std::is_integral<T>::value)>
1013inline auto to_nonnegative_int(T value, Int upper) -> Int {
1014 auto int_value = static_cast<Int>(value);
1015 if (int_value < 0 || value > static_cast<T>(upper))
1016 FMT_THROW(format_error("invalid value"));
1017 return int_value;
1018}
1019
1020constexpr auto pow10(std::uint32_t n) -> long long {
1021 return n == 0 ? 1 : 10 * pow10(n - 1);
1022}
1023
1024// Counts the number of fractional digits in the range [0, 18] according to the
1025// C++20 spec. If more than 18 fractional digits are required then returns 6 for
1026// microseconds precision.
1027template <long long Num, long long Den, int N = 0,
1028 bool Enabled = (N < 19) && (Num <= max_value<long long>() / 10)>
1030 static constexpr int value =
1032};
1033
1034// Base case that doesn't instantiate any more templates
1035// in order to avoid overflow.
1036template <long long Num, long long Den, int N>
1038 static constexpr int value = (Num % Den == 0) ? N : 6;
1039};
1040
1041// Format subseconds which are given as an integer type with an appropriate
1042// number of digits.
1043template <typename Char, typename OutputIt, typename Duration>
1044void write_fractional_seconds(OutputIt& out, Duration d, int precision = -1) {
1045 constexpr auto num_fractional_digits =
1046 count_fractional_digits<Duration::period::num,
1047 Duration::period::den>::value;
1048
1049 using subsecond_precision = std::chrono::duration<
1050 typename std::common_type<typename Duration::rep,
1051 std::chrono::seconds::rep>::type,
1052 std::ratio<1, pow10(num_fractional_digits)>>;
1053
1054 const auto fractional = d - detail::duration_cast<std::chrono::seconds>(d);
1055 const auto subseconds =
1056 std::chrono::treat_as_floating_point<
1057 typename subsecond_precision::rep>::value
1058 ? fractional.count()
1059 : detail::duration_cast<subsecond_precision>(fractional).count();
1060 auto n = static_cast<uint32_or_64_or_128_t<long long>>(subseconds);
1061 const int num_digits = count_digits(n);
1062
1063 int leading_zeroes = (std::max)(0, num_fractional_digits - num_digits);
1064 if (precision < 0) {
1065 FMT_ASSERT(!std::is_floating_point<typename Duration::rep>::value, "");
1066 if (std::ratio_less<typename subsecond_precision::period,
1067 std::chrono::seconds::period>::value) {
1068 *out++ = '.';
1069 out = detail::fill_n(out, leading_zeroes, '0');
1070 out = format_decimal<Char>(out, n, num_digits);
1071 }
1072 } else if (precision > 0) {
1073 *out++ = '.';
1074 leading_zeroes = min_of(leading_zeroes, precision);
1075 int remaining = precision - leading_zeroes;
1076 out = detail::fill_n(out, leading_zeroes, '0');
1077 if (remaining < num_digits) {
1078 int num_truncated_digits = num_digits - remaining;
1079 n /= to_unsigned(pow10(to_unsigned(num_truncated_digits)));
1080 if (n != 0) out = format_decimal<Char>(out, n, remaining);
1081 return;
1082 }
1083 if (n != 0) {
1084 out = format_decimal<Char>(out, n, num_digits);
1085 remaining -= num_digits;
1086 }
1087 out = detail::fill_n(out, remaining, '0');
1088 }
1089}
1090
1091// Format subseconds which are given as a floating point type with an
1092// appropriate number of digits. We cannot pass the Duration here, as we
1093// explicitly need to pass the Rep value in the chrono_formatter.
1094template <typename Duration>
1095void write_floating_seconds(memory_buffer& buf, Duration duration,
1096 int num_fractional_digits = -1) {
1097 using rep = typename Duration::rep;
1098 FMT_ASSERT(std::is_floating_point<rep>::value, "");
1099
1100 auto val = duration.count();
1101
1102 if (num_fractional_digits < 0) {
1103 // For `std::round` with fallback to `round`:
1104 // On some toolchains `std::round` is not available (e.g. GCC 6).
1105 using namespace std;
1106 num_fractional_digits =
1107 count_fractional_digits<Duration::period::num,
1108 Duration::period::den>::value;
1109 if (num_fractional_digits < 6 && static_cast<rep>(round(val)) != val)
1110 num_fractional_digits = 6;
1111 }
1112
1113 fmt::format_to(std::back_inserter(buf), FMT_STRING("{:.{}f}"),
1114 std::fmod(val * static_cast<rep>(Duration::period::num) /
1115 static_cast<rep>(Duration::period::den),
1116 static_cast<rep>(60)),
1117 num_fractional_digits);
1118}
1119
1120template <typename OutputIt, typename Char,
1121 typename Duration = std::chrono::seconds>
1123 private:
1124 static constexpr int days_per_week = 7;
1125
1126 const std::locale& loc_;
1127 const bool is_classic_;
1128 OutputIt out_;
1129 const Duration* subsecs_;
1130 const std::tm& tm_;
1131
1132 auto tm_sec() const noexcept -> int {
1133 FMT_ASSERT(tm_.tm_sec >= 0 && tm_.tm_sec <= 61, "");
1134 return tm_.tm_sec;
1135 }
1136 auto tm_min() const noexcept -> int {
1137 FMT_ASSERT(tm_.tm_min >= 0 && tm_.tm_min <= 59, "");
1138 return tm_.tm_min;
1139 }
1140 auto tm_hour() const noexcept -> int {
1141 FMT_ASSERT(tm_.tm_hour >= 0 && tm_.tm_hour <= 23, "");
1142 return tm_.tm_hour;
1143 }
1144 auto tm_mday() const noexcept -> int {
1145 FMT_ASSERT(tm_.tm_mday >= 1 && tm_.tm_mday <= 31, "");
1146 return tm_.tm_mday;
1147 }
1148 auto tm_mon() const noexcept -> int {
1149 FMT_ASSERT(tm_.tm_mon >= 0 && tm_.tm_mon <= 11, "");
1150 return tm_.tm_mon;
1151 }
1152 auto tm_year() const noexcept -> long long { return 1900ll + tm_.tm_year; }
1153 auto tm_wday() const noexcept -> int {
1154 FMT_ASSERT(tm_.tm_wday >= 0 && tm_.tm_wday <= 6, "");
1155 return tm_.tm_wday;
1156 }
1157 auto tm_yday() const noexcept -> int {
1158 FMT_ASSERT(tm_.tm_yday >= 0 && tm_.tm_yday <= 365, "");
1159 return tm_.tm_yday;
1160 }
1161
1162 auto tm_hour12() const noexcept -> int {
1163 const auto h = tm_hour();
1164 const auto z = h < 12 ? h : h - 12;
1165 return z == 0 ? 12 : z;
1166 }
1167
1168 // POSIX and the C Standard are unclear or inconsistent about what %C and %y
1169 // do if the year is negative or exceeds 9999. Use the convention that %C
1170 // concatenated with %y yields the same output as %Y, and that %Y contains at
1171 // least 4 characters, with more only if necessary.
1172 auto split_year_lower(long long year) const noexcept -> int {
1173 auto l = year % 100;
1174 if (l < 0) l = -l; // l in [0, 99]
1175 return static_cast<int>(l);
1176 }
1177
1178 // Algorithm: https://en.wikipedia.org/wiki/ISO_week_date.
1179 auto iso_year_weeks(long long curr_year) const noexcept -> int {
1180 const auto prev_year = curr_year - 1;
1181 const auto curr_p =
1182 (curr_year + curr_year / 4 - curr_year / 100 + curr_year / 400) %
1183 days_per_week;
1184 const auto prev_p =
1185 (prev_year + prev_year / 4 - prev_year / 100 + prev_year / 400) %
1186 days_per_week;
1187 return 52 + ((curr_p == 4 || prev_p == 3) ? 1 : 0);
1188 }
1189 auto iso_week_num(int tm_yday, int tm_wday) const noexcept -> int {
1190 return (tm_yday + 11 - (tm_wday == 0 ? days_per_week : tm_wday)) /
1191 days_per_week;
1192 }
1193 auto tm_iso_week_year() const noexcept -> long long {
1194 const auto year = tm_year();
1195 const auto w = iso_week_num(tm_yday(), tm_wday());
1196 if (w < 1) return year - 1;
1197 if (w > iso_year_weeks(year)) return year + 1;
1198 return year;
1199 }
1200 auto tm_iso_week_of_year() const noexcept -> int {
1201 const auto year = tm_year();
1202 const auto w = iso_week_num(tm_yday(), tm_wday());
1203 if (w < 1) return iso_year_weeks(year - 1);
1204 if (w > iso_year_weeks(year)) return 1;
1205 return w;
1206 }
1207
1208 void write1(int value) {
1209 *out_++ = static_cast<char>('0' + to_unsigned(value) % 10);
1210 }
1211 void write2(int value) {
1212 const char* d = digits2(to_unsigned(value) % 100);
1213 *out_++ = *d++;
1214 *out_++ = *d;
1215 }
1216 void write2(int value, pad_type pad) {
1217 unsigned int v = to_unsigned(value) % 100;
1218 if (v >= 10) {
1219 const char* d = digits2(v);
1220 *out_++ = *d++;
1221 *out_++ = *d;
1222 } else {
1223 out_ = detail::write_padding(out_, pad);
1224 *out_++ = static_cast<char>('0' + v);
1225 }
1226 }
1227
1228 void write_year_extended(long long year, pad_type pad) {
1229 // At least 4 characters.
1230 int width = 4;
1231 bool negative = year < 0;
1232 if (negative) {
1233 year = 0 - year;
1234 --width;
1235 }
1237 const int num_digits = count_digits(n);
1238 if (negative && pad == pad_type::zero) *out_++ = '-';
1239 if (width > num_digits) {
1240 out_ = detail::write_padding(out_, pad, width - num_digits);
1241 }
1242 if (negative && pad != pad_type::zero) *out_++ = '-';
1243 out_ = format_decimal<Char>(out_, n, num_digits);
1244 }
1245 void write_year(long long year, pad_type pad) {
1246 write_year_extended(year, pad);
1247 }
1248
1249 void write_utc_offset(long long offset, numeric_system ns) {
1250 if (offset < 0) {
1251 *out_++ = '-';
1252 offset = -offset;
1253 } else {
1254 *out_++ = '+';
1255 }
1256 offset /= 60;
1257 write2(static_cast<int>(offset / 60));
1258 if (ns != numeric_system::standard) *out_++ = ':';
1259 write2(static_cast<int>(offset % 60));
1260 }
1261
1262 template <typename T, FMT_ENABLE_IF(has_member_data_tm_gmtoff<T>::value)>
1263 void format_utc_offset_impl(const T& tm, numeric_system ns) {
1264 write_utc_offset(tm.tm_gmtoff, ns);
1265 }
1266 template <typename T, FMT_ENABLE_IF(!has_member_data_tm_gmtoff<T>::value)>
1267 void format_utc_offset_impl(const T& tm, numeric_system ns) {
1268#if defined(_WIN32) && defined(_UCRT)
1269 tzset_once();
1270 long offset = 0;
1271 _get_timezone(&offset);
1272 if (tm.tm_isdst) {
1273 long dstbias = 0;
1274 _get_dstbias(&dstbias);
1275 offset += dstbias;
1276 }
1277 write_utc_offset(-offset, ns);
1278#else
1279 if (ns == numeric_system::standard) return format_localized('z');
1280
1281 // Extract timezone offset from timezone conversion functions.
1282 std::tm gtm = tm;
1283 std::time_t gt = std::mktime(&gtm);
1284 std::tm ltm = gmtime(gt);
1285 std::time_t lt = std::mktime(&ltm);
1286 long long offset = gt - lt;
1287 write_utc_offset(offset, ns);
1288#endif
1289 }
1290
1291 template <typename T, FMT_ENABLE_IF(has_member_data_tm_zone<T>::value)>
1292 void format_tz_name_impl(const T& tm) {
1293 if (is_classic_)
1294 out_ = write_tm_str<Char>(out_, tm.tm_zone, loc_);
1295 else
1296 format_localized('Z');
1297 }
1298 template <typename T, FMT_ENABLE_IF(!has_member_data_tm_zone<T>::value)>
1299 void format_tz_name_impl(const T&) {
1300 format_localized('Z');
1301 }
1302
1303 void format_localized(char format, char modifier = 0) {
1304 out_ = write<Char>(out_, tm_, loc_, format, modifier);
1305 }
1306
1307 public:
1308 tm_writer(const std::locale& loc, OutputIt out, const std::tm& tm,
1309 const Duration* subsecs = nullptr)
1310 : loc_(loc),
1311 is_classic_(loc_ == get_classic_locale()),
1312 out_(out),
1313 subsecs_(subsecs),
1314 tm_(tm) {}
1315
1316 auto out() const -> OutputIt { return out_; }
1317
1318 FMT_CONSTEXPR void on_text(const Char* begin, const Char* end) {
1319 out_ = copy<Char>(begin, end, out_);
1320 }
1321
1323 if (is_classic_)
1324 out_ = write(out_, tm_wday_short_name(tm_wday()));
1325 else
1326 format_localized('a');
1327 }
1329 if (is_classic_)
1330 out_ = write(out_, tm_wday_full_name(tm_wday()));
1331 else
1332 format_localized('A');
1333 }
1335 if (is_classic_ || ns == numeric_system::standard) return write1(tm_wday());
1336 format_localized('w', 'O');
1337 }
1339 if (is_classic_ || ns == numeric_system::standard) {
1340 auto wday = tm_wday();
1341 write1(wday == 0 ? days_per_week : wday);
1342 } else {
1343 format_localized('u', 'O');
1344 }
1345 }
1346
1348 if (is_classic_)
1349 out_ = write(out_, tm_mon_short_name(tm_mon()));
1350 else
1351 format_localized('b');
1352 }
1354 if (is_classic_)
1355 out_ = write(out_, tm_mon_full_name(tm_mon()));
1356 else
1357 format_localized('B');
1358 }
1359
1361 if (is_classic_) {
1363 *out_++ = ' ';
1364 on_abbr_month();
1365 *out_++ = ' ';
1367 *out_++ = ' ';
1368 on_iso_time();
1369 *out_++ = ' ';
1371 } else {
1372 format_localized('c', ns == numeric_system::standard ? '\0' : 'E');
1373 }
1374 }
1376 if (is_classic_)
1377 on_us_date();
1378 else
1379 format_localized('x', ns == numeric_system::standard ? '\0' : 'E');
1380 }
1382 if (is_classic_)
1383 on_iso_time();
1384 else
1385 format_localized('X', ns == numeric_system::standard ? '\0' : 'E');
1386 }
1387 void on_us_date() {
1388 char buf[8];
1389 write_digit2_separated(buf, to_unsigned(tm_mon() + 1),
1390 to_unsigned(tm_mday()),
1391 to_unsigned(split_year_lower(tm_year())), '/');
1392 out_ = copy<Char>(std::begin(buf), std::end(buf), out_);
1393 }
1395 auto year = tm_year();
1396 char buf[10];
1397 size_t offset = 0;
1398 if (year >= 0 && year < 10000) {
1399 write2digits(buf, static_cast<size_t>(year / 100));
1400 } else {
1401 offset = 4;
1402 write_year_extended(year, pad_type::zero);
1403 year = 0;
1404 }
1405 write_digit2_separated(buf + 2, static_cast<unsigned>(year % 100),
1406 to_unsigned(tm_mon() + 1), to_unsigned(tm_mday()),
1407 '-');
1408 out_ = copy<Char>(std::begin(buf) + offset, std::end(buf), out_);
1409 }
1410
1411 void on_utc_offset(numeric_system ns) { format_utc_offset_impl(tm_, ns); }
1412 void on_tz_name() { format_tz_name_impl(tm_); }
1413
1415 if (is_classic_ || ns == numeric_system::standard)
1416 return write_year(tm_year(), pad);
1417 format_localized('Y', 'E');
1418 }
1420 if (is_classic_ || ns == numeric_system::standard)
1421 return write2(split_year_lower(tm_year()));
1422 format_localized('y', 'O');
1423 }
1425 if (is_classic_) return write2(split_year_lower(tm_year()));
1426 format_localized('y', 'E');
1427 }
1428
1430 if (is_classic_ || ns == numeric_system::standard) {
1431 auto year = tm_year();
1432 auto upper = year / 100;
1433 if (year >= -99 && year < 0) {
1434 // Zero upper on negative year.
1435 *out_++ = '-';
1436 *out_++ = '0';
1437 } else if (upper >= 0 && upper < 100) {
1438 write2(static_cast<int>(upper));
1439 } else {
1440 out_ = write<Char>(out_, upper);
1441 }
1442 } else {
1443 format_localized('C', 'E');
1444 }
1445 }
1446
1448 if (is_classic_ || ns == numeric_system::standard)
1449 return write2(tm_mon() + 1, pad);
1450 format_localized('m', 'O');
1451 }
1452
1454 if (is_classic_ || ns == numeric_system::standard)
1455 return write2((tm_yday() + days_per_week - tm_wday()) / days_per_week,
1456 pad);
1457 format_localized('U', 'O');
1458 }
1460 if (is_classic_ || ns == numeric_system::standard) {
1461 auto wday = tm_wday();
1462 write2((tm_yday() + days_per_week -
1463 (wday == 0 ? (days_per_week - 1) : (wday - 1))) /
1464 days_per_week,
1465 pad);
1466 } else {
1467 format_localized('W', 'O');
1468 }
1469 }
1471 if (is_classic_ || ns == numeric_system::standard)
1472 return write2(tm_iso_week_of_year(), pad);
1473 format_localized('V', 'O');
1474 }
1475
1477 write_year(tm_iso_week_year(), pad_type::zero);
1478 }
1480 write2(split_year_lower(tm_iso_week_year()));
1481 }
1482
1484 auto yday = tm_yday() + 1;
1485 auto digit1 = yday / 100;
1486 if (digit1 != 0) {
1487 write1(digit1);
1488 } else {
1489 out_ = detail::write_padding(out_, pad);
1490 }
1491 write2(yday % 100, pad);
1492 }
1493
1495 if (is_classic_ || ns == numeric_system::standard)
1496 return write2(tm_mday(), pad);
1497 format_localized('d', 'O');
1498 }
1499
1501 if (is_classic_ || ns == numeric_system::standard)
1502 return write2(tm_hour(), pad);
1503 format_localized('H', 'O');
1504 }
1506 if (is_classic_ || ns == numeric_system::standard)
1507 return write2(tm_hour12(), pad);
1508 format_localized('I', 'O');
1509 }
1511 if (is_classic_ || ns == numeric_system::standard)
1512 return write2(tm_min(), pad);
1513 format_localized('M', 'O');
1514 }
1515
1517 if (is_classic_ || ns == numeric_system::standard) {
1518 write2(tm_sec(), pad);
1519 if (subsecs_) {
1520 if (std::is_floating_point<typename Duration::rep>::value) {
1521 auto buf = memory_buffer();
1522 write_floating_seconds(buf, *subsecs_);
1523 if (buf.size() > 1) {
1524 // Remove the leading "0", write something like ".123".
1525 out_ = copy<Char>(buf.begin() + 1, buf.end(), out_);
1526 }
1527 } else {
1528 write_fractional_seconds<Char>(out_, *subsecs_);
1529 }
1530 }
1531 } else {
1532 // Currently no formatting of subseconds when a locale is set.
1533 format_localized('S', 'O');
1534 }
1535 }
1536
1538 if (is_classic_) {
1539 char buf[8];
1540 write_digit2_separated(buf, to_unsigned(tm_hour12()),
1541 to_unsigned(tm_min()), to_unsigned(tm_sec()), ':');
1542 out_ = copy<Char>(std::begin(buf), std::end(buf), out_);
1543 *out_++ = ' ';
1544 on_am_pm();
1545 } else {
1546 format_localized('r');
1547 }
1548 }
1550 write2(tm_hour());
1551 *out_++ = ':';
1552 write2(tm_min());
1553 }
1556 *out_++ = ':';
1558 }
1559
1560 void on_am_pm() {
1561 if (is_classic_) {
1562 *out_++ = tm_hour() < 12 ? 'A' : 'P';
1563 *out_++ = 'M';
1564 } else {
1565 format_localized('p');
1566 }
1567 }
1568
1569 // These apply to chrono durations but not tm.
1572};
1573
1574struct chrono_format_checker : null_chrono_spec_handler<chrono_format_checker> {
1576
1577 FMT_NORETURN inline void unsupported() { FMT_THROW(format_error("no date")); }
1578
1579 template <typename Char>
1580 FMT_CONSTEXPR void on_text(const Char*, const Char*) {}
1592 FMT_THROW(format_error("precision not allowed for this argument type"));
1593 }
1595};
1596
1597template <typename T,
1598 FMT_ENABLE_IF(std::is_integral<T>::value&& has_isfinite<T>::value)>
1599inline auto isfinite(T) -> bool {
1600 return true;
1601}
1602
1603template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
1604inline auto mod(T x, int y) -> T {
1605 return x % static_cast<T>(y);
1606}
1607template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)>
1608inline auto mod(T x, int y) -> T {
1609 return std::fmod(x, static_cast<T>(y));
1610}
1611
1612// If T is an integral type, maps T to its unsigned counterpart, otherwise
1613// leaves it unchanged (unlike std::make_unsigned).
1614template <typename T, bool INTEGRAL = std::is_integral<T>::value>
1616 using type = T;
1617};
1618
1619template <typename T> struct make_unsigned_or_unchanged<T, true> {
1620 using type = typename std::make_unsigned<T>::type;
1621};
1622
1623template <typename Rep, typename Period,
1624 FMT_ENABLE_IF(std::is_integral<Rep>::value)>
1625inline auto get_milliseconds(std::chrono::duration<Rep, Period> d)
1626 -> std::chrono::duration<Rep, std::milli> {
1627 // this may overflow and/or the result may not fit in the
1628 // target type.
1629#if FMT_SAFE_DURATION_CAST
1630 using CommonSecondsType =
1631 typename std::common_type<decltype(d), std::chrono::seconds>::type;
1632 const auto d_as_common = detail::duration_cast<CommonSecondsType>(d);
1633 const auto d_as_whole_seconds =
1635 // this conversion should be nonproblematic
1636 const auto diff = d_as_common - d_as_whole_seconds;
1637 const auto ms =
1639 return ms;
1640#else
1643#endif
1644}
1645
1646template <typename Char, typename Rep, typename OutputIt,
1647 FMT_ENABLE_IF(std::is_integral<Rep>::value)>
1648auto format_duration_value(OutputIt out, Rep val, int) -> OutputIt {
1649 return write<Char>(out, val);
1650}
1651
1652template <typename Char, typename Rep, typename OutputIt,
1653 FMT_ENABLE_IF(std::is_floating_point<Rep>::value)>
1654auto format_duration_value(OutputIt out, Rep val, int precision) -> OutputIt {
1655 auto specs = format_specs();
1656 specs.precision = precision;
1657 specs.set_type(precision >= 0 ? presentation_type::fixed
1659 return write<Char>(out, val, specs);
1660}
1661
1662template <typename Char, typename OutputIt>
1663auto copy_unit(string_view unit, OutputIt out, Char) -> OutputIt {
1664 return copy<Char>(unit.begin(), unit.end(), out);
1665}
1666
1667template <typename OutputIt>
1668auto copy_unit(string_view unit, OutputIt out, wchar_t) -> OutputIt {
1669 // This works when wchar_t is UTF-32 because units only contain characters
1670 // that have the same representation in UTF-16 and UTF-32.
1671 utf8_to_utf16 u(unit);
1672 return copy<wchar_t>(u.c_str(), u.c_str() + u.size(), out);
1673}
1674
1675template <typename Char, typename Period, typename OutputIt>
1676auto format_duration_unit(OutputIt out) -> OutputIt {
1677 if (const char* unit = get_units<Period>())
1678 return copy_unit(string_view(unit), out, Char());
1679 *out++ = '[';
1680 out = write<Char>(out, Period::num);
1681 if (const_check(Period::den != 1)) {
1682 *out++ = '/';
1683 out = write<Char>(out, Period::den);
1684 }
1685 *out++ = ']';
1686 *out++ = 's';
1687 return out;
1688}
1689
1691 private:
1692 union {
1693 std::locale locale_;
1694 };
1695 bool has_locale_ = false;
1696
1697 public:
1698 inline get_locale(bool localized, locale_ref loc) : has_locale_(localized) {
1699 if (localized)
1700 ::new (&locale_) std::locale(loc.template get<std::locale>());
1701 }
1702 inline ~get_locale() {
1703 if (has_locale_) locale_.~locale();
1704 }
1705 inline operator const std::locale&() const {
1706 return has_locale_ ? locale_ : get_classic_locale();
1707 }
1708};
1709
1710template <typename FormatContext, typename OutputIt, typename Rep,
1711 typename Period>
1713 FormatContext& context;
1714 OutputIt out;
1716 bool localized = false;
1717 // rep is unsigned to avoid overflow.
1718 using rep =
1719 conditional_t<std::is_integral<Rep>::value && sizeof(Rep) < sizeof(int),
1720 unsigned, typename make_unsigned_or_unchanged<Rep>::type>;
1722 using seconds = std::chrono::duration<rep>;
1724 using milliseconds = std::chrono::duration<rep, std::milli>;
1726
1727 using char_type = typename FormatContext::char_type;
1729
1730 chrono_formatter(FormatContext& ctx, OutputIt o,
1731 std::chrono::duration<Rep, Period> d)
1732 : context(ctx),
1733 out(o),
1734 val(static_cast<rep>(d.count())),
1735 negative(false) {
1736 if (d.count() < 0) {
1737 val = 0 - val;
1738 negative = true;
1739 }
1740
1741 // this may overflow and/or the result may not fit in the
1742 // target type.
1743 // might need checked conversion (rep!=Rep)
1744 s = detail::duration_cast<seconds>(std::chrono::duration<rep, Period>(val));
1745 }
1746
1747 // returns true if nan or inf, writes to out.
1748 auto handle_nan_inf() -> bool {
1749 if (isfinite(val)) {
1750 return false;
1751 }
1752 if (isnan(val)) {
1753 write_nan();
1754 return true;
1755 }
1756 // must be +-inf
1757 if (val > 0) {
1758 write_pinf();
1759 } else {
1760 write_ninf();
1761 }
1762 return true;
1763 }
1764
1765 auto days() const -> Rep { return static_cast<Rep>(s.count() / 86400); }
1766 auto hour() const -> Rep {
1767 return static_cast<Rep>(mod((s.count() / 3600), 24));
1768 }
1769
1770 auto hour12() const -> Rep {
1771 Rep hour = static_cast<Rep>(mod((s.count() / 3600), 12));
1772 return hour <= 0 ? 12 : hour;
1773 }
1774
1775 auto minute() const -> Rep {
1776 return static_cast<Rep>(mod((s.count() / 60), 60));
1777 }
1778 auto second() const -> Rep { return static_cast<Rep>(mod(s.count(), 60)); }
1779
1780 auto time() const -> std::tm {
1781 auto time = std::tm();
1782 time.tm_hour = to_nonnegative_int(hour(), 24);
1783 time.tm_min = to_nonnegative_int(minute(), 60);
1784 time.tm_sec = to_nonnegative_int(second(), 60);
1785 return time;
1786 }
1787
1788 void write_sign() {
1789 if (negative) {
1790 *out++ = '-';
1791 negative = false;
1792 }
1793 }
1794
1795 void write(Rep value, int width, pad_type pad = pad_type::zero) {
1796 write_sign();
1797 if (isnan(value)) return write_nan();
1800 int num_digits = detail::count_digits(n);
1801 if (width > num_digits) {
1802 out = detail::write_padding(out, pad, width - num_digits);
1803 }
1804 out = format_decimal<char_type>(out, n, num_digits);
1805 }
1806
1807 void write_nan() { std::copy_n("nan", 3, out); }
1808 void write_pinf() { std::copy_n("inf", 3, out); }
1809 void write_ninf() { std::copy_n("-inf", 4, out); }
1810
1811 template <typename Callback, typename... Args>
1812 void format_tm(const tm& time, Callback cb, Args... args) {
1813 if (isnan(val)) return write_nan();
1815 auto w = tm_writer_type(loc, out, time);
1816 (w.*cb)(args...);
1817 out = w.out();
1818 }
1819
1820 void on_text(const char_type* begin, const char_type* end) {
1821 copy<char_type>(begin, end, out);
1822 }
1823
1824 // These are not implemented because durations don't have date information.
1834 void on_us_date() {}
1835 void on_iso_date() {}
1837 void on_tz_name() {}
1849
1851 if (handle_nan_inf()) return;
1852 write(days(), 0);
1853 }
1854
1856 if (handle_nan_inf()) return;
1857
1858 if (ns == numeric_system::standard) return write(hour(), 2, pad);
1859 auto time = tm();
1860 time.tm_hour = to_nonnegative_int(hour(), 24);
1862 }
1863
1865 if (handle_nan_inf()) return;
1866
1867 if (ns == numeric_system::standard) return write(hour12(), 2, pad);
1868 auto time = tm();
1869 time.tm_hour = to_nonnegative_int(hour12(), 12);
1871 }
1872
1874 if (handle_nan_inf()) return;
1875
1876 if (ns == numeric_system::standard) return write(minute(), 2, pad);
1877 auto time = tm();
1878 time.tm_min = to_nonnegative_int(minute(), 60);
1880 }
1881
1883 if (handle_nan_inf()) return;
1884
1885 if (ns == numeric_system::standard) {
1886 if (std::is_floating_point<rep>::value) {
1887 auto buf = memory_buffer();
1888 write_floating_seconds(buf, std::chrono::duration<rep, Period>(val),
1889 precision);
1890 if (negative) *out++ = '-';
1891 if (buf.size() < 2 || buf[1] == '.') {
1892 out = detail::write_padding(out, pad);
1893 }
1894 out = copy<char_type>(buf.begin(), buf.end(), out);
1895 } else {
1896 write(second(), 2, pad);
1898 out, std::chrono::duration<rep, Period>(val), precision);
1899 }
1900 return;
1901 }
1902 auto time = tm();
1903 time.tm_sec = to_nonnegative_int(second(), 60);
1905 }
1906
1908 if (handle_nan_inf()) return;
1910 }
1911
1913 if (handle_nan_inf()) {
1914 *out++ = ':';
1916 return;
1917 }
1918
1919 write(hour(), 2);
1920 *out++ = ':';
1921 write(minute(), 2);
1922 }
1923
1926 *out++ = ':';
1927 if (handle_nan_inf()) return;
1929 }
1930
1931 void on_am_pm() {
1932 if (handle_nan_inf()) return;
1934 }
1935
1937 if (handle_nan_inf()) return;
1938 write_sign();
1940 }
1941
1945};
1946
1947} // namespace detail
1948
1949#if defined(__cpp_lib_chrono) && __cpp_lib_chrono >= 201907
1950using weekday = std::chrono::weekday;
1951using day = std::chrono::day;
1952using month = std::chrono::month;
1953using year = std::chrono::year;
1954using year_month_day = std::chrono::year_month_day;
1955#else
1956// A fallback version of weekday.
1957class weekday {
1958 private:
1959 unsigned char value_;
1960
1961 public:
1962 weekday() = default;
1963 constexpr explicit weekday(unsigned wd) noexcept
1964 : value_(static_cast<unsigned char>(wd != 7 ? wd : 0)) {}
1965 constexpr auto c_encoding() const noexcept -> unsigned { return value_; }
1966};
1967
1968class day {
1969 private:
1970 unsigned char value_;
1971
1972 public:
1973 day() = default;
1974 constexpr explicit day(unsigned d) noexcept
1975 : value_(static_cast<unsigned char>(d)) {}
1976 constexpr explicit operator unsigned() const noexcept { return value_; }
1977};
1978
1979class month {
1980 private:
1981 unsigned char value_;
1982
1983 public:
1984 month() = default;
1985 constexpr explicit month(unsigned m) noexcept
1986 : value_(static_cast<unsigned char>(m)) {}
1987 constexpr explicit operator unsigned() const noexcept { return value_; }
1988};
1989
1990class year {
1991 private:
1992 int value_;
1993
1994 public:
1995 year() = default;
1996 constexpr explicit year(int y) noexcept : value_(y) {}
1997 constexpr explicit operator int() const noexcept { return value_; }
1998};
1999
2001 private:
2002 fmt::year year_;
2003 fmt::month month_;
2004 fmt::day day_;
2005
2006 public:
2007 year_month_day() = default;
2008 constexpr year_month_day(const year& y, const month& m, const day& d) noexcept
2009 : year_(y), month_(m), day_(d) {}
2010 constexpr auto year() const noexcept -> fmt::year { return year_; }
2011 constexpr auto month() const noexcept -> fmt::month { return month_; }
2012 constexpr auto day() const noexcept -> fmt::day { return day_; }
2013};
2014#endif
2015
2016template <typename Char>
2017struct formatter<weekday, Char> : private formatter<std::tm, Char> {
2018 private:
2019 bool localized_ = false;
2020 bool use_tm_formatter_ = false;
2021
2022 public:
2023 FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
2024 auto it = ctx.begin(), end = ctx.end();
2025 if (it != end && *it == 'L') {
2026 ++it;
2027 localized_ = true;
2028 return it;
2029 }
2030 use_tm_formatter_ = it != end && *it != '}';
2031 return use_tm_formatter_ ? formatter<std::tm, Char>::parse(ctx) : it;
2032 }
2033
2034 template <typename FormatContext>
2035 auto format(weekday wd, FormatContext& ctx) const -> decltype(ctx.out()) {
2036 auto time = std::tm();
2037 time.tm_wday = static_cast<int>(wd.c_encoding());
2038 if (use_tm_formatter_) return formatter<std::tm, Char>::format(time, ctx);
2039 detail::get_locale loc(localized_, ctx.locale());
2040 auto w = detail::tm_writer<decltype(ctx.out()), Char>(loc, ctx.out(), time);
2041 w.on_abbr_weekday();
2042 return w.out();
2043 }
2044};
2045
2046template <typename Char>
2047struct formatter<day, Char> : private formatter<std::tm, Char> {
2048 private:
2049 bool use_tm_formatter_ = false;
2050
2051 public:
2052 FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
2053 auto it = ctx.begin(), end = ctx.end();
2054 use_tm_formatter_ = it != end && *it != '}';
2055 return use_tm_formatter_ ? formatter<std::tm, Char>::parse(ctx) : it;
2056 }
2057
2058 template <typename FormatContext>
2059 auto format(day d, FormatContext& ctx) const -> decltype(ctx.out()) {
2060 auto time = std::tm();
2061 time.tm_mday = static_cast<int>(static_cast<unsigned>(d));
2062 if (use_tm_formatter_) return formatter<std::tm, Char>::format(time, ctx);
2063 detail::get_locale loc(false, ctx.locale());
2064 auto w = detail::tm_writer<decltype(ctx.out()), Char>(loc, ctx.out(), time);
2066 return w.out();
2067 }
2068};
2069
2070template <typename Char>
2071struct formatter<month, Char> : private formatter<std::tm, Char> {
2072 private:
2073 bool localized_ = false;
2074 bool use_tm_formatter_ = false;
2075
2076 public:
2077 FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
2078 auto it = ctx.begin(), end = ctx.end();
2079 if (it != end && *it == 'L') {
2080 ++it;
2081 localized_ = true;
2082 return it;
2083 }
2084 use_tm_formatter_ = it != end && *it != '}';
2085 return use_tm_formatter_ ? formatter<std::tm, Char>::parse(ctx) : it;
2086 }
2087
2088 template <typename FormatContext>
2089 auto format(month m, FormatContext& ctx) const -> decltype(ctx.out()) {
2090 auto time = std::tm();
2091 time.tm_mon = static_cast<int>(static_cast<unsigned>(m)) - 1;
2092 if (use_tm_formatter_) return formatter<std::tm, Char>::format(time, ctx);
2093 detail::get_locale loc(localized_, ctx.locale());
2094 auto w = detail::tm_writer<decltype(ctx.out()), Char>(loc, ctx.out(), time);
2095 w.on_abbr_month();
2096 return w.out();
2097 }
2098};
2099
2100template <typename Char>
2101struct formatter<year, Char> : private formatter<std::tm, Char> {
2102 private:
2103 bool use_tm_formatter_ = false;
2104
2105 public:
2106 FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
2107 auto it = ctx.begin(), end = ctx.end();
2108 use_tm_formatter_ = it != end && *it != '}';
2109 return use_tm_formatter_ ? formatter<std::tm, Char>::parse(ctx) : it;
2110 }
2111
2112 template <typename FormatContext>
2113 auto format(year y, FormatContext& ctx) const -> decltype(ctx.out()) {
2114 auto time = std::tm();
2115 time.tm_year = static_cast<int>(y) - 1900;
2116 if (use_tm_formatter_) return formatter<std::tm, Char>::format(time, ctx);
2117 detail::get_locale loc(false, ctx.locale());
2118 auto w = detail::tm_writer<decltype(ctx.out()), Char>(loc, ctx.out(), time);
2120 return w.out();
2121 }
2122};
2123
2124template <typename Char>
2125struct formatter<year_month_day, Char> : private formatter<std::tm, Char> {
2126 private:
2127 bool use_tm_formatter_ = false;
2128
2129 public:
2130 FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
2131 auto it = ctx.begin(), end = ctx.end();
2132 use_tm_formatter_ = it != end && *it != '}';
2133 return use_tm_formatter_ ? formatter<std::tm, Char>::parse(ctx) : it;
2134 }
2135
2136 template <typename FormatContext>
2137 auto format(year_month_day val, FormatContext& ctx) const
2138 -> decltype(ctx.out()) {
2139 auto time = std::tm();
2140 time.tm_year = static_cast<int>(val.year()) - 1900;
2141 time.tm_mon = static_cast<int>(static_cast<unsigned>(val.month())) - 1;
2142 time.tm_mday = static_cast<int>(static_cast<unsigned>(val.day()));
2143 if (use_tm_formatter_) return formatter<std::tm, Char>::format(time, ctx);
2144 detail::get_locale loc(true, ctx.locale());
2145 auto w = detail::tm_writer<decltype(ctx.out()), Char>(loc, ctx.out(), time);
2146 w.on_iso_date();
2147 return w.out();
2148 }
2149};
2150
2151template <typename Rep, typename Period, typename Char>
2152struct formatter<std::chrono::duration<Rep, Period>, Char> {
2153 private:
2154 format_specs specs_;
2155 detail::arg_ref<Char> width_ref_;
2156 detail::arg_ref<Char> precision_ref_;
2157 bool localized_ = false;
2159
2160 public:
2161 FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
2162 auto it = ctx.begin(), end = ctx.end();
2163 if (it == end || *it == '}') return it;
2164
2165 it = detail::parse_align(it, end, specs_);
2166 if (it == end) return it;
2167
2168 Char c = *it;
2169 if ((c >= '0' && c <= '9') || c == '{') {
2170 it = detail::parse_width(it, end, specs_, width_ref_, ctx);
2171 if (it == end) return it;
2172 }
2173
2174 auto checker = detail::chrono_format_checker();
2175 if (*it == '.') {
2176 checker.has_precision_integral = !std::is_floating_point<Rep>::value;
2177 it = detail::parse_precision(it, end, specs_, precision_ref_, ctx);
2178 }
2179 if (it != end && *it == 'L') {
2180 localized_ = true;
2181 ++it;
2182 }
2183 end = detail::parse_chrono_format(it, end, checker);
2184 fmt_ = {it, detail::to_unsigned(end - it)};
2185 return end;
2186 }
2187
2188 template <typename FormatContext>
2189 auto format(std::chrono::duration<Rep, Period> d, FormatContext& ctx) const
2190 -> decltype(ctx.out()) {
2191 auto specs = specs_;
2192 auto precision = specs.precision;
2193 specs.precision = -1;
2194 auto begin = fmt_.begin(), end = fmt_.end();
2195 // As a possible future optimization, we could avoid extra copying if width
2196 // is not specified.
2197 auto buf = basic_memory_buffer<Char>();
2198 auto out = basic_appender<Char>(buf);
2199 detail::handle_dynamic_spec(specs.dynamic_width(), specs.width, width_ref_,
2200 ctx);
2201 detail::handle_dynamic_spec(specs.dynamic_precision(), precision,
2202 precision_ref_, ctx);
2203 if (begin == end || *begin == '}') {
2204 out = detail::format_duration_value<Char>(out, d.count(), precision);
2206 } else {
2207 using chrono_formatter =
2208 detail::chrono_formatter<FormatContext, decltype(out), Rep, Period>;
2209 auto f = chrono_formatter(ctx, out, d);
2210 f.precision = precision;
2211 f.localized = localized_;
2212 detail::parse_chrono_format(begin, end, f);
2213 }
2214 return detail::write(
2215 ctx.out(), basic_string_view<Char>(buf.data(), buf.size()), specs);
2216 }
2217};
2218
2219template <typename Char> struct formatter<std::tm, Char> {
2220 private:
2221 format_specs specs_;
2222 detail::arg_ref<Char> width_ref_;
2223
2224 protected:
2226
2227 template <typename Duration, typename FormatContext>
2228 auto do_format(const std::tm& tm, FormatContext& ctx,
2229 const Duration* subsecs) const -> decltype(ctx.out()) {
2230 auto specs = specs_;
2231 auto buf = basic_memory_buffer<Char>();
2232 auto out = basic_appender<Char>(buf);
2233 detail::handle_dynamic_spec(specs.dynamic_width(), specs.width, width_ref_,
2234 ctx);
2235
2236 auto loc_ref = ctx.locale();
2237 detail::get_locale loc(static_cast<bool>(loc_ref), loc_ref);
2238 auto w =
2240 detail::parse_chrono_format(fmt_.begin(), fmt_.end(), w);
2241 return detail::write(
2242 ctx.out(), basic_string_view<Char>(buf.data(), buf.size()), specs);
2243 }
2244
2245 public:
2246 FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
2247 auto it = ctx.begin(), end = ctx.end();
2248 if (it == end || *it == '}') return it;
2249
2250 it = detail::parse_align(it, end, specs_);
2251 if (it == end) return it;
2252
2253 Char c = *it;
2254 if ((c >= '0' && c <= '9') || c == '{') {
2255 it = detail::parse_width(it, end, specs_, width_ref_, ctx);
2256 if (it == end) return it;
2257 }
2258
2260 // Replace the default format string only if the new spec is not empty.
2261 if (end != it) fmt_ = {it, detail::to_unsigned(end - it)};
2262 return end;
2263 }
2264
2265 template <typename FormatContext>
2266 auto format(const std::tm& tm, FormatContext& ctx) const
2267 -> decltype(ctx.out()) {
2268 return do_format<std::chrono::seconds>(tm, ctx, nullptr);
2269 }
2270};
2271
2272template <typename Char, typename Duration>
2273struct formatter<sys_time<Duration>, Char> : formatter<std::tm, Char> {
2277
2278 template <typename FormatContext>
2279 auto format(sys_time<Duration> val, FormatContext& ctx) const
2280 -> decltype(ctx.out()) {
2281 std::tm tm = gmtime(val);
2282 using period = typename Duration::period;
2284 period::num == 1 && period::den == 1 &&
2285 !std::is_floating_point<typename Duration::rep>::value)) {
2286 return formatter<std::tm, Char>::format(tm, ctx);
2287 }
2288 Duration epoch = val.time_since_epoch();
2289 Duration subsecs = detail::duration_cast<Duration>(
2291 if (subsecs.count() < 0) {
2292 auto second = detail::duration_cast<Duration>(std::chrono::seconds(1));
2293 if (tm.tm_sec != 0)
2294 --tm.tm_sec;
2295 else
2296 tm = gmtime(val - second);
2297 subsecs += detail::duration_cast<Duration>(std::chrono::seconds(1));
2298 }
2299 return formatter<std::tm, Char>::do_format(tm, ctx, &subsecs);
2300 }
2301};
2302
2303template <typename Duration, typename Char>
2304struct formatter<utc_time<Duration>, Char>
2305 : formatter<sys_time<Duration>, Char> {
2306 template <typename FormatContext>
2307 auto format(utc_time<Duration> val, FormatContext& ctx) const
2308 -> decltype(ctx.out()) {
2310 detail::utc_clock::to_sys(val), ctx);
2311 }
2312};
2313
2314template <typename Duration, typename Char>
2315struct formatter<local_time<Duration>, Char> : formatter<std::tm, Char> {
2319
2320 template <typename FormatContext>
2321 auto format(local_time<Duration> val, FormatContext& ctx) const
2322 -> decltype(ctx.out()) {
2323 using period = typename Duration::period;
2324 if (period::num == 1 && period::den == 1 &&
2325 !std::is_floating_point<typename Duration::rep>::value) {
2327 }
2328 auto epoch = val.time_since_epoch();
2329 auto subsecs = detail::duration_cast<Duration>(
2331 return formatter<std::tm, Char>::do_format(localtime(val), ctx, &subsecs);
2332 }
2333};
2334
2337
2338#endif // FMT_CHRONO_H_
and restrictions which apply to each piece of software is included later in this file and or inside of the individual applicable source files The disclaimer of warranty in the WPILib license above applies to all code in and nothing in any of the other licenses gives permission to use the names of FIRST nor the names of the WPILib contributors to endorse or promote products derived from this software The following pieces of software have additional or alternate and or and nanopb were all modified for use in Google Inc All rights reserved Redistribution and use in source and binary with or without are permitted provided that the following conditions are this list of conditions and the following disclaimer *Redistributions in binary form must reproduce the above copyright this list of conditions and the following disclaimer in the documentation and or other materials provided with the distribution *Neither the name of Google Inc nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY EXPRESS OR IMPLIED BUT NOT LIMITED THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY OR CONSEQUENTIAL WHETHER IN STRICT OR EVEN IF ADVISED OF THE POSSIBILITY OF SUCH January AND DISTRIBUTION Definitions License shall mean the terms and conditions for and distribution as defined by Sections through of this document Licensor shall mean the copyright owner or entity authorized by the copyright owner that is granting the License Legal Entity shall mean the union of the acting entity and all other entities that control are controlled by or are under common control with that entity For the purposes of this definition control direct or to cause the direction or management of such whether by contract or including but not limited to software source documentation and configuration files Object form shall mean any form resulting from mechanical transformation or translation of a Source including but not limited to compiled object generated and conversions to other media types Work shall mean the work of whether in Source or Object made available under the as indicated by a copyright notice that is included in or attached to the whether in Source or Object that is based or other modifications as a an original work of authorship For the purposes of this Derivative Works shall not include works that remain separable from
Definition ThirdPartyNotices.txt:141
Definition base.h:2408
A dynamically growing memory buffer for trivially copyable/constructible types with the first SIZE el...
Definition format.h:790
constexpr auto end() const noexcept -> iterator
Definition base.h:552
constexpr auto begin() const noexcept -> iterator
Definition base.h:551
Definition base.h:2607
FMT_CONSTEXPR auto locale() const -> detail::locale_ref
Definition base.h:2645
Definition chrono.h:1968
day()=default
constexpr day(unsigned d) noexcept
Definition chrono.h:1974
A contiguous memory buffer with an optional growing ability.
Definition base.h:1698
FMT_CONSTEXPR20 void append(const U *begin, const U *end)
Appends data to the end of the buffer.
Definition base.h:1780
FMT_CONSTEXPR void push_back(const T &value)
Definition base.h:1767
Definition chrono.h:307
formatbuf(buffer< char_type > &buf)
Definition chrono.h:317
auto xsputn(const char_type *s, streamsize count) -> streamsize override
Definition chrono.h:332
auto overflow(int_type ch) -> int_type override
Definition chrono.h:326
Definition chrono.h:1690
get_locale(bool localized, locale_ref loc)
Definition chrono.h:1698
std::locale locale_
Definition chrono.h:1693
~get_locale()
Definition chrono.h:1702
Definition chrono.h:1122
void on_offset_year()
Definition chrono.h:1424
void on_12_hour_time()
Definition chrono.h:1537
void on_dec0_week_of_year(numeric_system ns, pad_type pad)
Definition chrono.h:1453
void on_abbr_month()
Definition chrono.h:1347
void on_iso_date()
Definition chrono.h:1394
void on_iso_week_based_year()
Definition chrono.h:1476
void on_dec_month(numeric_system ns, pad_type pad)
Definition chrono.h:1447
void on_abbr_weekday()
Definition chrono.h:1322
void on_am_pm()
Definition chrono.h:1560
void on_dec0_weekday(numeric_system ns)
Definition chrono.h:1334
tm_writer(const std::locale &loc, OutputIt out, const std::tm &tm, const Duration *subsecs=nullptr)
Definition chrono.h:1308
void on_us_date()
Definition chrono.h:1387
void on_iso_time()
Definition chrono.h:1554
void on_duration_unit()
Definition chrono.h:1571
void on_24_hour_time()
Definition chrono.h:1549
void on_second(numeric_system ns, pad_type pad)
Definition chrono.h:1516
void on_full_weekday()
Definition chrono.h:1328
void on_12_hour(numeric_system ns, pad_type pad)
Definition chrono.h:1505
FMT_CONSTEXPR void on_text(const Char *begin, const Char *end)
Definition chrono.h:1318
void on_loc_time(numeric_system ns)
Definition chrono.h:1381
auto out() const -> OutputIt
Definition chrono.h:1316
void on_day_of_month(numeric_system ns, pad_type pad)
Definition chrono.h:1494
void on_tz_name()
Definition chrono.h:1412
void on_day_of_year(pad_type pad)
Definition chrono.h:1483
void on_short_year(numeric_system ns)
Definition chrono.h:1419
void on_iso_week_based_short_year()
Definition chrono.h:1479
void on_century(numeric_system ns)
Definition chrono.h:1429
void on_dec1_week_of_year(numeric_system ns, pad_type pad)
Definition chrono.h:1459
void on_minute(numeric_system ns, pad_type pad)
Definition chrono.h:1510
void on_dec1_weekday(numeric_system ns)
Definition chrono.h:1338
void on_year(numeric_system ns, pad_type pad)
Definition chrono.h:1414
void on_loc_date(numeric_system ns)
Definition chrono.h:1375
void on_full_month()
Definition chrono.h:1353
void on_utc_offset(numeric_system ns)
Definition chrono.h:1411
void on_duration_value()
Definition chrono.h:1570
void on_24_hour(numeric_system ns, pad_type pad)
Definition chrono.h:1500
void on_datetime(numeric_system ns)
Definition chrono.h:1360
void on_iso_week_of_year(numeric_system ns, pad_type pad)
Definition chrono.h:1470
Definition format.h:1289
Definition format.h:1272
auto size() const -> size_t
Definition format.h:1281
auto c_str() const -> const wchar_t *
Definition format.h:1282
Definition base.h:2081
Definition chrono.h:1979
constexpr month(unsigned m) noexcept
Definition chrono.h:1985
month()=default
Parsing context consisting of a format string range being parsed and an argument counter for automati...
Definition base.h:845
Definition chrono.h:1957
constexpr auto c_encoding() const noexcept -> unsigned
Definition chrono.h:1965
constexpr weekday(unsigned wd) noexcept
Definition chrono.h:1963
weekday()=default
Definition chrono.h:2000
constexpr auto year() const noexcept -> fmt::year
Definition chrono.h:2010
constexpr year_month_day(const year &y, const month &m, const day &d) noexcept
Definition chrono.h:2008
constexpr auto month() const noexcept -> fmt::month
Definition chrono.h:2011
year_month_day()=default
constexpr auto day() const noexcept -> fmt::day
Definition chrono.h:2012
Definition chrono.h:1990
year()=default
constexpr year(int y) noexcept
Definition chrono.h:1996
#define FMT_NOMACRO
Definition chrono.h:297
FMT_BEGIN_EXPORT auto localtime(std::time_t time) -> std::tm
Converts given time since epoch as std::time_t value into calendar time, expressed in local time.
Definition chrono.h:538
std::chrono::time_point< detail::utc_clock, Duration > utc_time
Definition chrono.h:288
std::chrono::time_point< std::chrono::system_clock, Duration > sys_time
Definition chrono.h:285
std::chrono::time_point< detail::local_t, Duration > local_time
Definition chrono.h:291
auto gmtime(std::time_t time) -> std::tm
Converts given time since epoch as std::time_t value into calendar time, expressed in Coordinated Uni...
Definition chrono.h:589
#define FMT_STRING(s)
Constructs a legacy compile-time format string from a string literal s.
Definition format.h:4092
FMT_INLINE auto format(detail::locale_ref loc, format_string< T... > fmt, T &&... args) -> std::string
Definition format.h:4146
basic_memory_buffer< char > memory_buffer
Definition format.h:891
#define FMT_THROW(x)
Definition format.h:149
auto ptr(T p) -> const void *
Converts p to const void* for pointer formatting.
Definition format.h:3821
detail namespace with internal helper functions
Definition input_adapters.h:32
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:994
auto get_iterator(Buf &buf, OutputIt) -> decltype(buf.out())
Definition base.h:2044
FMT_CONSTEXPR20 auto isfinite(T value) -> bool
Definition format.h:2486
auto tm_mon_short_name(int mon) -> const char *
Definition chrono.h:974
void write_floating_seconds(memory_buffer &buf, Duration duration, int num_fractional_digits=-1)
Definition chrono.h:1095
FMT_CONSTEXPR void ignore_unused(const T &...)
Definition base.h:348
FMT_CONSTEXPR auto parse_precision(const Char *begin, const Char *end, format_specs &specs, arg_ref< Char > &precision_ref, parse_context< Char > &ctx) -> const Char *
Definition base.h:1387
FMT_CONSTEXPR auto get_units() -> const char *
Definition chrono.h:666
auto is_big_endian() -> bool
Definition format.h:270
FMT_CONSTEXPR auto write(OutputIt out, Char value, const format_specs &specs, locale_ref loc={}) -> OutputIt
Definition format.h:1824
pad_type
Definition chrono.h:698
auto duration_cast(std::chrono::duration< FromRep, FromPeriod > from) -> To
Definition chrono.h:455
auto localtime_s(...) -> null<>
Definition chrono.h:301
void write_fractional_seconds(OutputIt &out, Duration d, int precision=-1)
Definition chrono.h:1044
auto format_duration_unit(OutputIt out) -> OutputIt
Definition chrono.h:1676
constexpr auto max_value() -> T
Definition format.h:407
@ value
the parser finished reading a JSON value
FMT_CONSTEXPR auto to_unsigned(Int value) -> make_unsigned_t< Int >
Definition base.h:422
numeric_system
Definition chrono.h:691
auto write_encoded_tm_str(OutputIt out, string_view in, const std::locale &loc) -> OutputIt
Definition chrono.h:365
void do_write(buffer< Char > &buf, const std::tm &time, const std::locale &loc, char format, char modifier)
Definition chrono.h:410
constexpr auto pow10(std::uint32_t n) -> long long
Definition chrono.h:1020
auto tm_wday_short_name(int wday) -> const char *
Definition chrono.h:962
auto to_time_t(sys_time< Duration > time_point) -> std::time_t
Definition chrono.h:513
auto digits2(size_t value) -> const char *
Definition format.h:1008
auto get_classic_locale() -> const std::locale &
Definition chrono.h:338
FMT_CONSTEXPR auto fill_n(OutputIt out, Size count, const T &value) -> OutputIt
Definition format.h:532
auto mod(T x, int y) -> T
Definition chrono.h:1604
@ use_utf8
Definition base.h:442
void write_digit2_separated(char *buf, unsigned a, unsigned b, unsigned c, char sep)
Definition chrono.h:634
FMT_ALWAYS_INLINE constexpr auto const_check(T val) -> T
Definition base.h:367
void tzset_once()
Definition chrono.h:994
@ null
null value
FMT_CONSTEXPR auto parse_width(const Char *begin, const Char *end, format_specs &specs, arg_ref< Char > &width_ref, parse_context< Char > &ctx) -> const Char *
Definition base.h:1378
FMT_NORETURN void throw_duration_error()
Definition chrono.h:447
auto get_milliseconds(std::chrono::duration< Rep, Period > d) -> std::chrono::duration< Rep, std::milli >
Definition chrono.h:1625
auto tm_mon_full_name(int mon) -> const char *
Definition chrono.h:968
FMT_CONSTEXPR20 auto copy(InputIt begin, InputIt end, OutputIt out) -> OutputIt
Definition base.h:1992
auto gmtime_r(...) -> null<>
Definition chrono.h:302
typename make_void< Ts... >::type void_t
Definition void_t.h:21
FMT_CONSTEXPR auto parse_align(const Char *begin, const Char *end, format_specs &specs) -> const Char *
Definition format.h:2184
auto to_nonnegative_int(T value, Int upper) -> Int
Definition chrono.h:1005
FMT_CONSTEXPR auto has_current_zone() -> bool
Definition chrono.h:524
auto copy_unit(string_view unit, OutputIt out, Char) -> OutputIt
Definition chrono.h:1663
auto write_padding(OutputIt out, pad_type pad, int width) -> OutputIt
Definition chrono.h:708
FMT_CONSTEXPR void handle_dynamic_spec(arg_id_kind kind, int &value, const arg_ref< typename Context::char_type > &ref, Context &ctx)
Definition format.h:3548
auto format_duration_value(OutputIt out, Rep val, int) -> OutputIt
Definition chrono.h:1648
type
Definition base.h:937
auto write_tm_str(OutputIt out, string_view sv, const std::locale &loc) -> OutputIt
Definition chrono.h:395
auto get_buffer(OutputIt out) -> iterator_buffer< OutputIt, T >
Definition base.h:2034
auto gmtime_s(...) -> null<>
Definition chrono.h:303
FMT_CONSTEXPR20 FMT_INLINE void write2digits(Char *out, size_t value)
Definition format.h:1178
constexpr auto count() -> int
Definition base.h:1028
FMT_CONSTEXPR20 auto count_digits(uint64_t n) -> int
Definition format.h:1068
auto tm_wday_full_name(int wday) -> const char *
Definition chrono.h:956
FMT_CONSTEXPR auto parse_chrono_format(const Char *begin, const Char *end, Handler &&handler) -> const Char *
Definition chrono.h:721
FMT_CONSTEXPR FMT_INLINE auto format_decimal(Char *out, UInt value, int num_digits) -> Char *
Definition format.h:1213
void write_codecvt(codecvt_result< CodeUnit > &out, string_view in, const std::locale &loc)
Definition chrono.h:350
constexpr auto isnan(T value) -> bool
Definition format.h:2473
Definition chrono.h:25
void _tzset(T...)
Definition chrono.h:37
auto current_zone(T...) -> time_zone *
Definition chrono.h:33
Implement std::hash so that hash_code can be used in STL containers.
Definition PointerIntPair.h:280
Definition chrono.h:1574
FMT_CONSTEXPR void on_duration_value() const
Definition chrono.h:1590
FMT_CONSTEXPR void on_day_of_year(pad_type)
Definition chrono.h:1581
FMT_CONSTEXPR void on_24_hour(numeric_system, pad_type)
Definition chrono.h:1582
FMT_CONSTEXPR void on_12_hour_time()
Definition chrono.h:1586
FMT_CONSTEXPR void on_text(const Char *, const Char *)
Definition chrono.h:1580
FMT_CONSTEXPR void on_duration_unit()
Definition chrono.h:1594
FMT_CONSTEXPR void on_iso_time()
Definition chrono.h:1588
FMT_CONSTEXPR void on_minute(numeric_system, pad_type)
Definition chrono.h:1584
bool has_precision_integral
Definition chrono.h:1575
FMT_CONSTEXPR void on_24_hour_time()
Definition chrono.h:1587
FMT_CONSTEXPR void on_12_hour(numeric_system, pad_type)
Definition chrono.h:1583
FMT_CONSTEXPR void on_am_pm()
Definition chrono.h:1589
FMT_NORETURN void unsupported()
Definition chrono.h:1577
FMT_CONSTEXPR void on_second(numeric_system, pad_type)
Definition chrono.h:1585
Definition chrono.h:1712
FormatContext & context
Definition chrono.h:1713
void on_dec_month(numeric_system, pad_type)
Definition chrono.h:1844
std::chrono::duration< rep > seconds
Definition chrono.h:1722
void on_abbr_weekday()
Definition chrono.h:1825
void on_duration_unit()
Definition chrono.h:1942
void on_dec0_week_of_year(numeric_system, pad_type)
Definition chrono.h:1845
void on_dec1_week_of_year(numeric_system, pad_type)
Definition chrono.h:1846
void write_ninf()
Definition chrono.h:1809
void on_year(numeric_system, pad_type)
Definition chrono.h:1838
void on_us_date()
Definition chrono.h:1834
void write_pinf()
Definition chrono.h:1808
void on_utc_offset(numeric_system)
Definition chrono.h:1836
void on_offset_year()
Definition chrono.h:1840
void on_iso_week_based_short_year()
Definition chrono.h:1843
void write_sign()
Definition chrono.h:1788
void on_minute(numeric_system ns, pad_type pad)
Definition chrono.h:1873
void on_iso_week_of_year(numeric_system, pad_type)
Definition chrono.h:1847
void on_duration_value()
Definition chrono.h:1936
void on_dec1_weekday(numeric_system)
Definition chrono.h:1828
void on_tz_name()
Definition chrono.h:1837
int precision
Definition chrono.h:1715
void on_text(const char_type *begin, const char_type *end)
Definition chrono.h:1820
auto minute() const -> Rep
Definition chrono.h:1775
void on_iso_week_based_year()
Definition chrono.h:1842
chrono_formatter(FormatContext &ctx, OutputIt o, std::chrono::duration< Rep, Period > d)
Definition chrono.h:1730
void on_dec0_weekday(numeric_system)
Definition chrono.h:1827
void on_loc_date(numeric_system)
Definition chrono.h:1832
void format_tm(const tm &time, Callback cb, Args... args)
Definition chrono.h:1812
void on_full_weekday()
Definition chrono.h:1826
void on_iso_time()
Definition chrono.h:1924
bool localized
Definition chrono.h:1716
void on_24_hour(numeric_system ns, pad_type pad)
Definition chrono.h:1855
void on_abbr_month()
Definition chrono.h:1829
void on_loc_time(numeric_system)
Definition chrono.h:1833
bool negative
Definition chrono.h:1725
void on_full_month()
Definition chrono.h:1830
auto second() const -> Rep
Definition chrono.h:1778
void on_day_of_month(numeric_system, pad_type)
Definition chrono.h:1848
void on_day_of_year(pad_type)
Definition chrono.h:1850
auto hour12() const -> Rep
Definition chrono.h:1770
OutputIt out
Definition chrono.h:1714
auto days() const -> Rep
Definition chrono.h:1765
auto time() const -> std::tm
Definition chrono.h:1780
std::chrono::duration< rep, std::milli > milliseconds
Definition chrono.h:1724
void on_century(numeric_system)
Definition chrono.h:1841
void on_12_hour(numeric_system ns, pad_type pad)
Definition chrono.h:1864
void write_nan()
Definition chrono.h:1807
void write(Rep value, int width, pad_type pad=pad_type::zero)
Definition chrono.h:1795
auto handle_nan_inf() -> bool
Definition chrono.h:1748
void on_12_hour_time()
Definition chrono.h:1907
void on_iso_date()
Definition chrono.h:1835
tm_writer< OutputIt, char_type > tm_writer_type
Definition chrono.h:1728
void on_datetime(numeric_system)
Definition chrono.h:1831
seconds s
Definition chrono.h:1723
void on_short_year(numeric_system)
Definition chrono.h:1839
typename FormatContext::char_type char_type
Definition chrono.h:1727
conditional_t< std::is_integral< Rep >::value &&sizeof(Rep)< sizeof(int), unsigned, typename make_unsigned_or_unchanged< Rep >::type > rep
Definition chrono.h:1718
void on_24_hour_time()
Definition chrono.h:1912
rep val
Definition chrono.h:1721
void on_am_pm()
Definition chrono.h:1931
auto hour() const -> Rep
Definition chrono.h:1766
void on_second(numeric_system ns, pad_type pad)
Definition chrono.h:1882
Definition chrono.h:343
static constexpr const size_t max_size
Definition chrono.h:344
CodeUnit * end
Definition chrono.h:346
CodeUnit buf[max_size]
Definition chrono.h:345
Definition chrono.h:1029
Definition chrono.h:983
Definition chrono.h:989
Definition chrono.h:444
Definition chrono.h:279
Definition base.h:2252
Definition format-inl.h:92
typename std::make_unsigned< T >::type type
Definition chrono.h:1620
Definition chrono.h:1615
T type
Definition chrono.h:1616
Definition chrono.h:865
FMT_CONSTEXPR void on_dec0_weekday(numeric_system)
Definition chrono.h:877
FMT_CONSTEXPR void on_iso_week_of_year(numeric_system, pad_type)
Definition chrono.h:888
FMT_CONSTEXPR void on_iso_date()
Definition chrono.h:903
FMT_CONSTEXPR void on_loc_date(numeric_system)
Definition chrono.h:900
FMT_CONSTEXPR void on_day_of_year(pad_type)
Definition chrono.h:891
FMT_CONSTEXPR void on_duration_value()
Definition chrono.h:908
FMT_CONSTEXPR void on_dec1_weekday(numeric_system)
Definition chrono.h:878
FMT_CONSTEXPR void on_12_hour(numeric_system)
Definition chrono.h:896
FMT_CONSTEXPR void on_duration_unit()
Definition chrono.h:909
FMT_CONSTEXPR void on_24_hour_time()
Definition chrono.h:905
FMT_CONSTEXPR void on_century(numeric_system)
Definition chrono.h:872
FMT_CONSTEXPR void on_minute(numeric_system)
Definition chrono.h:897
FMT_CONSTEXPR void on_utc_offset(numeric_system)
Definition chrono.h:910
FMT_CONSTEXPR void on_day_of_month(numeric_system, pad_type)
Definition chrono.h:892
FMT_CONSTEXPR void on_dec_month(numeric_system, pad_type)
Definition chrono.h:881
FMT_CONSTEXPR void on_iso_time()
Definition chrono.h:906
FMT_CONSTEXPR void on_datetime(numeric_system)
Definition chrono.h:899
FMT_CONSTEXPR void on_offset_year()
Definition chrono.h:871
FMT_CONSTEXPR void on_abbr_month()
Definition chrono.h:879
FMT_CONSTEXPR void on_second(numeric_system)
Definition chrono.h:898
FMT_CONSTEXPR void on_full_weekday()
Definition chrono.h:876
FMT_CONSTEXPR void on_iso_week_based_short_year()
Definition chrono.h:874
FMT_CONSTEXPR void on_us_date()
Definition chrono.h:902
FMT_CONSTEXPR void on_year(numeric_system, pad_type)
Definition chrono.h:869
FMT_CONSTEXPR void on_short_year(numeric_system)
Definition chrono.h:870
FMT_CONSTEXPR void on_tz_name()
Definition chrono.h:911
FMT_CONSTEXPR void on_dec1_week_of_year(numeric_system, pad_type)
Definition chrono.h:885
FMT_CONSTEXPR void on_12_hour_time()
Definition chrono.h:904
FMT_CONSTEXPR void on_full_month()
Definition chrono.h:880
FMT_CONSTEXPR void unsupported()
Definition chrono.h:866
FMT_CONSTEXPR void on_dec0_week_of_year(numeric_system, pad_type)
Definition chrono.h:882
FMT_CONSTEXPR void on_loc_time(numeric_system)
Definition chrono.h:901
FMT_CONSTEXPR void on_am_pm()
Definition chrono.h:907
FMT_CONSTEXPR void on_abbr_weekday()
Definition chrono.h:875
FMT_CONSTEXPR void on_iso_week_based_year()
Definition chrono.h:873
FMT_CONSTEXPR void on_24_hour(numeric_system)
Definition chrono.h:895
Definition chrono.h:299
Definition format.h:247
Definition chrono.h:914
FMT_CONSTEXPR void on_text(const Char *, const Char *)
Definition chrono.h:920
FMT_CONSTEXPR void on_24_hour_time()
Definition chrono.h:949
FMT_CONSTEXPR void on_full_weekday()
Definition chrono.h:928
FMT_CONSTEXPR void on_iso_time()
Definition chrono.h:950
FMT_CONSTEXPR void on_iso_week_of_year(numeric_system, pad_type)
Definition chrono.h:936
FMT_CONSTEXPR void on_iso_week_based_short_year()
Definition chrono.h:926
FMT_CONSTEXPR void on_iso_date()
Definition chrono.h:947
FMT_CONSTEXPR void on_abbr_weekday()
Definition chrono.h:927
FMT_CONSTEXPR void on_loc_time(numeric_system)
Definition chrono.h:945
FMT_CONSTEXPR void on_dec0_weekday(numeric_system)
Definition chrono.h:929
FMT_CONSTEXPR void on_dec1_week_of_year(numeric_system, pad_type)
Definition chrono.h:935
FMT_CONSTEXPR void on_iso_week_based_year()
Definition chrono.h:925
FMT_CONSTEXPR void on_abbr_month()
Definition chrono.h:931
FMT_CONSTEXPR void on_dec0_week_of_year(numeric_system, pad_type)
Definition chrono.h:934
FMT_CONSTEXPR void on_tz_name()
Definition chrono.h:953
FMT_CONSTEXPR void on_loc_date(numeric_system)
Definition chrono.h:944
FMT_CONSTEXPR void on_24_hour(numeric_system, pad_type)
Definition chrono.h:939
FMT_CONSTEXPR void on_day_of_month(numeric_system, pad_type)
Definition chrono.h:938
FMT_NORETURN void unsupported()
Definition chrono.h:915
FMT_CONSTEXPR void on_datetime(numeric_system)
Definition chrono.h:943
FMT_CONSTEXPR void on_day_of_year(pad_type)
Definition chrono.h:937
FMT_CONSTEXPR void on_utc_offset(numeric_system)
Definition chrono.h:952
FMT_CONSTEXPR void on_dec_month(numeric_system, pad_type)
Definition chrono.h:933
FMT_CONSTEXPR void on_full_month()
Definition chrono.h:932
FMT_CONSTEXPR void on_second(numeric_system, pad_type)
Definition chrono.h:942
FMT_CONSTEXPR void on_short_year(numeric_system)
Definition chrono.h:922
FMT_CONSTEXPR void on_offset_year()
Definition chrono.h:923
FMT_CONSTEXPR void on_year(numeric_system, pad_type)
Definition chrono.h:921
FMT_CONSTEXPR void on_am_pm()
Definition chrono.h:951
FMT_CONSTEXPR void on_12_hour_time()
Definition chrono.h:948
FMT_CONSTEXPR void on_12_hour(numeric_system, pad_type)
Definition chrono.h:940
FMT_CONSTEXPR void on_dec1_weekday(numeric_system)
Definition chrono.h:930
FMT_CONSTEXPR void on_century(numeric_system)
Definition chrono.h:924
FMT_CONSTEXPR void on_minute(numeric_system, pad_type)
Definition chrono.h:941
FMT_CONSTEXPR void on_us_date()
Definition chrono.h:946
Definition chrono.h:263
Definition chrono.h:26
auto to_sys(T) -> std::chrono::time_point< std::chrono::system_clock, Duration >
Definition chrono.h:28
Definition base.h:834
FMT_CONSTEXPR auto parse(parse_context< Char > &ctx) -> const Char *
Definition chrono.h:2052
auto format(day d, FormatContext &ctx) const -> decltype(ctx.out())
Definition chrono.h:2059
auto format(local_time< Duration > val, FormatContext &ctx) const -> decltype(ctx.out())
Definition chrono.h:2321
FMT_CONSTEXPR formatter()
Definition chrono.h:2316
auto format(month m, FormatContext &ctx) const -> decltype(ctx.out())
Definition chrono.h:2089
FMT_CONSTEXPR auto parse(parse_context< Char > &ctx) -> const Char *
Definition chrono.h:2077
auto format(std::chrono::duration< Rep, Period > d, FormatContext &ctx) const -> decltype(ctx.out())
Definition chrono.h:2189
FMT_CONSTEXPR auto parse(parse_context< Char > &ctx) -> const Char *
Definition chrono.h:2161
auto format(const std::tm &tm, FormatContext &ctx) const -> decltype(ctx.out())
Definition chrono.h:2266
basic_string_view< Char > fmt_
Definition chrono.h:2225
auto do_format(const std::tm &tm, FormatContext &ctx, const Duration *subsecs) const -> decltype(ctx.out())
Definition chrono.h:2228
FMT_CONSTEXPR auto parse(parse_context< Char > &ctx) -> const Char *
Definition chrono.h:2246
auto format(sys_time< Duration > val, FormatContext &ctx) const -> decltype(ctx.out())
Definition chrono.h:2279
FMT_CONSTEXPR formatter()
Definition chrono.h:2274
auto format(utc_time< Duration > val, FormatContext &ctx) const -> decltype(ctx.out())
Definition chrono.h:2307
FMT_CONSTEXPR auto parse(parse_context< Char > &ctx) -> const Char *
Definition chrono.h:2023
auto format(weekday wd, FormatContext &ctx) const -> decltype(ctx.out())
Definition chrono.h:2035
auto format(year y, FormatContext &ctx) const -> decltype(ctx.out())
Definition chrono.h:2113
FMT_CONSTEXPR auto parse(parse_context< Char > &ctx) -> const Char *
Definition chrono.h:2106
FMT_CONSTEXPR auto parse(parse_context< Char > &ctx) -> const Char *
Definition chrono.h:2130
auto format(year_month_day val, FormatContext &ctx) const -> decltype(ctx.out())
Definition chrono.h:2137
Definition base.h:651
Definition base.h:1224
#define FMT_ASSERT(condition, message)
Definition base.h:381
#define FMT_END_EXPORT
Definition base.h:250
#define FMT_PRAGMA_CLANG(x)
Definition base.h:230
basic_string_view< char > string_view
Definition base.h:603
constexpr auto min_of(T a, T b) -> T
Definition base.h:337
#define FMT_CONSTEXPR
Definition base.h:113
#define FMT_BEGIN_NAMESPACE
Definition base.h:239
#define FMT_ENABLE_IF(...)
Definition base.h:334
#define FMT_BEGIN_EXPORT
Definition base.h:249
#define FMT_NORETURN
Definition base.h:179
typename std::conditional< B, T, F >::type conditional_t
Definition base.h:299
#define FMT_END_NAMESPACE
Definition base.h:242