WPILibC++ 2027.0.0-alpha-2
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
26
27// Enable safe chrono durations, unless explicitly disabled.
28#ifndef FMT_SAFE_DURATION_CAST
29# define FMT_SAFE_DURATION_CAST 1
30#endif
31#if FMT_SAFE_DURATION_CAST
32
33// For conversion between std::chrono::durations without undefined
34// behaviour or erroneous results.
35// This is a stripped down version of duration_cast, for inclusion in fmt.
36// See https://github.com/pauldreik/safe_duration_cast
37//
38// Copyright Paul Dreik 2019
39namespace safe_duration_cast {
40
41template <typename To, typename From,
42 FMT_ENABLE_IF(!std::is_same<From, To>::value &&
43 std::numeric_limits<From>::is_signed ==
44 std::numeric_limits<To>::is_signed)>
45FMT_CONSTEXPR auto lossless_integral_conversion(const From from, int& ec)
46 -> To {
47 ec = 0;
48 using F = std::numeric_limits<From>;
49 using T = std::numeric_limits<To>;
50 static_assert(F::is_integer, "From must be integral");
51 static_assert(T::is_integer, "To must be integral");
52
53 // A and B are both signed, or both unsigned.
54 if (detail::const_check(F::digits <= T::digits)) {
55 // From fits in To without any problem.
56 } else {
57 // From does not always fit in To, resort to a dynamic check.
58 if (from < (T::min)() || from > (T::max)()) {
59 // outside range.
60 ec = 1;
61 return {};
62 }
63 }
64 return static_cast<To>(from);
65}
66
67/// Converts From to To, without loss. If the dynamic value of from
68/// can't be converted to To without loss, ec is set.
69template <typename To, typename From,
70 FMT_ENABLE_IF(!std::is_same<From, To>::value &&
71 std::numeric_limits<From>::is_signed !=
72 std::numeric_limits<To>::is_signed)>
73FMT_CONSTEXPR auto lossless_integral_conversion(const From from, int& ec)
74 -> To {
75 ec = 0;
76 using F = std::numeric_limits<From>;
77 using T = std::numeric_limits<To>;
78 static_assert(F::is_integer, "From must be integral");
79 static_assert(T::is_integer, "To must be integral");
80
81 if (detail::const_check(F::is_signed && !T::is_signed)) {
82 // From may be negative, not allowed!
83 if (fmt::detail::is_negative(from)) {
84 ec = 1;
85 return {};
86 }
87 // From is positive. Can it always fit in To?
88 if (detail::const_check(F::digits > T::digits) &&
89 from > static_cast<From>(detail::max_value<To>())) {
90 ec = 1;
91 return {};
92 }
93 }
94
95 if (detail::const_check(!F::is_signed && T::is_signed &&
96 F::digits >= T::digits) &&
97 from > static_cast<From>(detail::max_value<To>())) {
98 ec = 1;
99 return {};
100 }
101 return static_cast<To>(from); // Lossless conversion.
102}
103
104template <typename To, typename From,
105 FMT_ENABLE_IF(std::is_same<From, To>::value)>
106FMT_CONSTEXPR auto lossless_integral_conversion(const From from, int& ec)
107 -> To {
108 ec = 0;
109 return from;
110} // function
111
112// clang-format off
113/**
114 * converts From to To if possible, otherwise ec is set.
115 *
116 * input | output
117 * ---------------------------------|---------------
118 * NaN | NaN
119 * Inf | Inf
120 * normal, fits in output | converted (possibly lossy)
121 * normal, does not fit in output | ec is set
122 * subnormal | best effort
123 * -Inf | -Inf
124 */
125// clang-format on
126template <typename To, typename From,
127 FMT_ENABLE_IF(!std::is_same<From, To>::value)>
128FMT_CONSTEXPR auto safe_float_conversion(const From from, int& ec) -> To {
129 ec = 0;
130 using T = std::numeric_limits<To>;
131 static_assert(std::is_floating_point<From>::value, "From must be floating");
132 static_assert(std::is_floating_point<To>::value, "To must be floating");
133
134 // catch the only happy case
135 if (std::isfinite(from)) {
136 if (from >= T::lowest() && from <= (T::max)()) {
137 return static_cast<To>(from);
138 }
139 // not within range.
140 ec = 1;
141 return {};
142 }
143
144 // nan and inf will be preserved
145 return static_cast<To>(from);
146} // function
147
148template <typename To, typename From,
149 FMT_ENABLE_IF(std::is_same<From, To>::value)>
150FMT_CONSTEXPR auto safe_float_conversion(const From from, int& ec) -> To {
151 ec = 0;
152 static_assert(std::is_floating_point<From>::value, "From must be floating");
153 return from;
154}
155
156/// Safe duration_cast between floating point durations
157template <typename To, typename FromRep, typename FromPeriod,
158 FMT_ENABLE_IF(std::is_floating_point<FromRep>::value),
159 FMT_ENABLE_IF(std::is_floating_point<typename To::rep>::value)>
160auto safe_duration_cast(std::chrono::duration<FromRep, FromPeriod> from,
161 int& ec) -> To {
162 using From = std::chrono::duration<FromRep, FromPeriod>;
163 ec = 0;
164 if (std::isnan(from.count())) {
165 // nan in, gives nan out. easy.
166 return To{std::numeric_limits<typename To::rep>::quiet_NaN()};
167 }
168 // maybe we should also check if from is denormal, and decide what to do about
169 // it.
170
171 // +-inf should be preserved.
172 if (std::isinf(from.count())) {
173 return To{from.count()};
174 }
175
176 // the basic idea is that we need to convert from count() in the from type
177 // to count() in the To type, by multiplying it with this:
178 struct Factor
179 : std::ratio_divide<typename From::period, typename To::period> {};
180
181 static_assert(Factor::num > 0, "num must be positive");
182 static_assert(Factor::den > 0, "den must be positive");
183
184 // the conversion is like this: multiply from.count() with Factor::num
185 // /Factor::den and convert it to To::rep, all this without
186 // overflow/underflow. let's start by finding a suitable type that can hold
187 // both To, From and Factor::num
188 using IntermediateRep =
189 typename std::common_type<typename From::rep, typename To::rep,
190 decltype(Factor::num)>::type;
191
192 // force conversion of From::rep -> IntermediateRep to be safe,
193 // even if it will never happen be narrowing in this context.
194 IntermediateRep count =
195 safe_float_conversion<IntermediateRep>(from.count(), ec);
196 if (ec) {
197 return {};
198 }
199
200 // multiply with Factor::num without overflow or underflow
201 if (detail::const_check(Factor::num != 1)) {
202 constexpr auto max1 = detail::max_value<IntermediateRep>() /
203 static_cast<IntermediateRep>(Factor::num);
204 if (count > max1) {
205 ec = 1;
206 return {};
207 }
208 constexpr auto min1 = std::numeric_limits<IntermediateRep>::lowest() /
209 static_cast<IntermediateRep>(Factor::num);
210 if (count < min1) {
211 ec = 1;
212 return {};
213 }
214 count *= static_cast<IntermediateRep>(Factor::num);
215 }
216
217 // this can't go wrong, right? den>0 is checked earlier.
218 if (detail::const_check(Factor::den != 1)) {
219 using common_t = typename std::common_type<IntermediateRep, intmax_t>::type;
220 count /= static_cast<common_t>(Factor::den);
221 }
222
223 // convert to the to type, safely
224 using ToRep = typename To::rep;
225
226 const ToRep tocount = safe_float_conversion<ToRep>(count, ec);
227 if (ec) {
228 return {};
229 }
230 return To{tocount};
231}
232} // namespace safe_duration_cast
233#endif
234
235namespace detail {
236
237// Check if std::chrono::utc_time is available.
238#ifdef FMT_USE_UTC_TIME
239// Use the provided definition.
240#elif defined(__cpp_lib_chrono)
241# define FMT_USE_UTC_TIME (__cpp_lib_chrono >= 201907L)
242#else
243# define FMT_USE_UTC_TIME 0
244#endif
245#if FMT_USE_UTC_TIME
246using utc_clock = std::chrono::utc_clock;
247#else
248struct utc_clock {
249 template <typename T> void to_sys(T);
250};
251#endif
252
253// Check if std::chrono::local_time is available.
254#ifdef FMT_USE_LOCAL_TIME
255// Use the provided definition.
256#elif defined(__cpp_lib_chrono)
257# define FMT_USE_LOCAL_TIME (__cpp_lib_chrono >= 201907L)
258#else
259# define FMT_USE_LOCAL_TIME 0
260#endif
261#if FMT_USE_LOCAL_TIME
262using local_t = std::chrono::local_t;
263#else
264struct local_t {};
265#endif
266
267} // namespace detail
268
269template <typename Duration>
270using sys_time = std::chrono::time_point<std::chrono::system_clock, Duration>;
271
272template <typename Duration>
273using utc_time = std::chrono::time_point<detail::utc_clock, Duration>;
274
275template <class Duration>
276using local_time = std::chrono::time_point<detail::local_t, Duration>;
277
278namespace detail {
279
280// Prevents expansion of a preceding token as a function-style macro.
281// Usage: f FMT_NOMACRO()
282#define FMT_NOMACRO
283
284template <typename T = void> struct null {};
285inline auto localtime_r FMT_NOMACRO(...) -> null<> { return null<>(); }
286inline auto localtime_s(...) -> null<> { return null<>(); }
287inline auto gmtime_r(...) -> null<> { return null<>(); }
288inline auto gmtime_s(...) -> null<> { return null<>(); }
289
290// It is defined here and not in ostream.h because the latter has expensive
291// includes.
292template <typename StreamBuf> class formatbuf : public StreamBuf {
293 private:
294 using char_type = typename StreamBuf::char_type;
295 using streamsize = decltype(std::declval<StreamBuf>().sputn(nullptr, 0));
296 using int_type = typename StreamBuf::int_type;
297 using traits_type = typename StreamBuf::traits_type;
298
299 buffer<char_type>& buffer_;
300
301 public:
302 explicit formatbuf(buffer<char_type>& buf) : buffer_(buf) {}
303
304 protected:
305 // The put area is always empty. This makes the implementation simpler and has
306 // the advantage that the streambuf and the buffer are always in sync and
307 // sputc never writes into uninitialized memory. A disadvantage is that each
308 // call to sputc always results in a (virtual) call to overflow. There is no
309 // disadvantage here for sputn since this always results in a call to xsputn.
310
311 auto overflow(int_type ch) -> int_type override {
312 if (!traits_type::eq_int_type(ch, traits_type::eof()))
313 buffer_.push_back(static_cast<char_type>(ch));
314 return ch;
315 }
316
317 auto xsputn(const char_type* s, streamsize count) -> streamsize override {
318 buffer_.append(s, s + count);
319 return count;
320 }
321};
322
323inline auto get_classic_locale() -> const std::locale& {
324 static const auto& locale = std::locale::classic();
325 return locale;
326}
327
328template <typename CodeUnit> struct codecvt_result {
329 static constexpr size_t max_size = 32;
330 CodeUnit buf[max_size];
331 CodeUnit* end;
332};
333
334template <typename CodeUnit>
336 const std::locale& loc) {
337 FMT_PRAGMA_CLANG(diagnostic push)
338 FMT_PRAGMA_CLANG(diagnostic ignored "-Wdeprecated")
339 auto& f = std::use_facet<std::codecvt<CodeUnit, char, std::mbstate_t>>(loc);
340 FMT_PRAGMA_CLANG(diagnostic pop)
341 auto mb = std::mbstate_t();
342 const char* from_next = nullptr;
343 auto result = f.in(mb, in.begin(), in.end(), from_next, std::begin(out.buf),
344 std::end(out.buf), out.end);
345 if (result != std::codecvt_base::ok)
346 FMT_THROW(format_error("failed to format time"));
347}
348
349template <typename OutputIt>
350auto write_encoded_tm_str(OutputIt out, string_view in, const std::locale& loc)
351 -> OutputIt {
353 // char16_t and char32_t codecvts are broken in MSVC (linkage errors) and
354 // gcc-4.
355#if FMT_MSC_VERSION != 0 || \
356 (defined(__GLIBCXX__) && \
357 (!defined(_GLIBCXX_USE_DUAL_ABI) || _GLIBCXX_USE_DUAL_ABI == 0))
358 // The _GLIBCXX_USE_DUAL_ABI macro is always defined in libstdc++ from gcc-5
359 // and newer.
360 using code_unit = wchar_t;
361#else
362 using code_unit = char32_t;
363#endif
364
365 using unit_t = codecvt_result<code_unit>;
366 unit_t unit;
367 write_codecvt(unit, in, loc);
368 // In UTF-8 is used one to four one-byte code units.
369 auto u =
371 if (!u.convert({unit.buf, to_unsigned(unit.end - unit.buf)}))
372 FMT_THROW(format_error("failed to format time"));
373 return copy<char>(u.c_str(), u.c_str() + u.size(), out);
374 }
375 return copy<char>(in.data(), in.data() + in.size(), out);
376}
377
378template <typename Char, typename OutputIt,
379 FMT_ENABLE_IF(!std::is_same<Char, char>::value)>
380auto write_tm_str(OutputIt out, string_view sv, const std::locale& loc)
381 -> OutputIt {
383 write_codecvt(unit, sv, loc);
384 return copy<Char>(unit.buf, unit.end, out);
385}
386
387template <typename Char, typename OutputIt,
388 FMT_ENABLE_IF(std::is_same<Char, char>::value)>
389auto write_tm_str(OutputIt out, string_view sv, const std::locale& loc)
390 -> OutputIt {
391 return write_encoded_tm_str(out, sv, loc);
392}
393
394template <typename Char>
395inline void do_write(buffer<Char>& buf, const std::tm& time,
396 const std::locale& loc, char format, char modifier) {
397 auto&& format_buf = formatbuf<std::basic_streambuf<Char>>(buf);
398 auto&& os = std::basic_ostream<Char>(&format_buf);
399 os.imbue(loc);
400 const auto& facet = std::use_facet<std::time_put<Char>>(loc);
401 auto end = facet.put(os, os, Char(' '), &time, format, modifier);
402 if (end.failed()) FMT_THROW(format_error("failed to format time"));
403}
404
405template <typename Char, typename OutputIt,
406 FMT_ENABLE_IF(!std::is_same<Char, char>::value)>
407auto write(OutputIt out, const std::tm& time, const std::locale& loc,
408 char format, char modifier = 0) -> OutputIt {
409 auto&& buf = get_buffer<Char>(out);
410 do_write<Char>(buf, time, loc, format, modifier);
411 return get_iterator(buf, out);
412}
413
414template <typename Char, typename OutputIt,
415 FMT_ENABLE_IF(std::is_same<Char, char>::value)>
416auto write(OutputIt out, const std::tm& time, const std::locale& loc,
417 char format, char modifier = 0) -> OutputIt {
418 auto&& buf = basic_memory_buffer<Char>();
419 do_write<char>(buf, time, loc, format, modifier);
420 return write_encoded_tm_str(out, string_view(buf.data(), buf.size()), loc);
421}
422
423template <typename T, typename U>
425 bool_constant<(std::is_integral<T>::value && std::is_integral<U>::value) ||
426 (std::is_floating_point<T>::value &&
427 std::is_floating_point<U>::value)>;
428
430 FMT_THROW(format_error("cannot format duration"));
431}
432
433// Cast one integral duration to another with an overflow check.
434template <typename To, typename FromRep, typename FromPeriod,
435 FMT_ENABLE_IF(std::is_integral<FromRep>::value&&
436 std::is_integral<typename To::rep>::value)>
437auto duration_cast(std::chrono::duration<FromRep, FromPeriod> from) -> To {
438#if !FMT_SAFE_DURATION_CAST
439 return std::chrono::duration_cast<To>(from);
440#else
441 // The conversion factor: to.count() == factor * from.count().
442 using factor = std::ratio_divide<FromPeriod, typename To::period>;
443
444 using common_rep = typename std::common_type<FromRep, typename To::rep,
445 decltype(factor::num)>::type;
446
447 int ec = 0;
448 auto count = safe_duration_cast::lossless_integral_conversion<common_rep>(
449 from.count(), ec);
450 if (ec) throw_duration_error();
451
452 // Multiply from.count() by factor and check for overflow.
453 if (const_check(factor::num != 1)) {
454 if (count > max_value<common_rep>() / factor::num) throw_duration_error();
455 const auto min = (std::numeric_limits<common_rep>::min)() / factor::num;
456 if (const_check(!std::is_unsigned<common_rep>::value) && count < min)
458 count *= factor::num;
459 }
460 if (const_check(factor::den != 1)) count /= factor::den;
461 auto to =
462 To(safe_duration_cast::lossless_integral_conversion<typename To::rep>(
463 count, ec));
464 if (ec) throw_duration_error();
465 return to;
466#endif
467}
468
469template <typename To, typename FromRep, typename FromPeriod,
470 FMT_ENABLE_IF(std::is_floating_point<FromRep>::value&&
471 std::is_floating_point<typename To::rep>::value)>
472auto duration_cast(std::chrono::duration<FromRep, FromPeriod> from) -> To {
473#if FMT_SAFE_DURATION_CAST
474 // Throwing version of safe_duration_cast is only available for
475 // integer to integer or float to float casts.
476 int ec;
477 To to = safe_duration_cast::safe_duration_cast<To>(from, ec);
478 if (ec) throw_duration_error();
479 return to;
480#else
481 // Standard duration cast, may overflow.
482 return std::chrono::duration_cast<To>(from);
483#endif
484}
485
486template <typename To, typename FromRep, typename FromPeriod,
488 !is_similar_arithmetic_type<FromRep, typename To::rep>::value)>
489auto duration_cast(std::chrono::duration<FromRep, FromPeriod> from) -> To {
490 // Mixed integer <-> float cast is not supported by safe_duration_cast.
491 return std::chrono::duration_cast<To>(from);
492}
493
494template <typename Duration>
495auto to_time_t(sys_time<Duration> time_point) -> std::time_t {
496 // Cannot use std::chrono::system_clock::to_time_t since this would first
497 // require a cast to std::chrono::system_clock::time_point, which could
498 // overflow.
500 time_point.time_since_epoch())
501 .count();
502}
503
504namespace tz {
505
506// DEPRECATED!
507struct time_zone {
508 template <typename Duration, typename LocalTime>
509 auto to_sys(LocalTime) -> sys_time<Duration> {
510 return {};
511 }
512};
513template <typename... T> auto current_zone(T...) -> time_zone* {
514 return nullptr;
515}
516
517template <typename... T> void _tzset(T...) {}
518} // namespace tz
519
520// DEPRECATED!
521inline void tzset_once() {
522 static bool init = []() {
523 using namespace tz;
524 _tzset();
525 return false;
526 }();
527 ignore_unused(init);
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 */
538FMT_DEPRECATED inline 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>
576FMT_DEPRECATED auto localtime(std::chrono::local_time<Duration> time)
577 -> std::tm {
578 using namespace std::chrono;
579 using namespace detail::tz;
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 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
914class tm_format_checker : public null_chrono_spec_handler<tm_format_checker> {
915 private:
916 bool has_timezone_ = false;
917
918 public:
919 constexpr explicit tm_format_checker(bool has_timezone)
920 : has_timezone_(has_timezone) {}
921
922 FMT_NORETURN inline void unsupported() {
923 FMT_THROW(format_error("no format"));
924 }
925
926 template <typename Char>
927 FMT_CONSTEXPR void on_text(const Char*, const Char*) {}
960 if (!has_timezone_) FMT_THROW(format_error("no timezone"));
961 }
963 if (!has_timezone_) FMT_THROW(format_error("no timezone"));
964 }
965};
966
967inline auto tm_wday_full_name(int wday) -> const char* {
968 static constexpr const char* full_name_list[] = {
969 "Sunday", "Monday", "Tuesday", "Wednesday",
970 "Thursday", "Friday", "Saturday"};
971 return wday >= 0 && wday <= 6 ? full_name_list[wday] : "?";
972}
973inline auto tm_wday_short_name(int wday) -> const char* {
974 static constexpr const char* short_name_list[] = {"Sun", "Mon", "Tue", "Wed",
975 "Thu", "Fri", "Sat"};
976 return wday >= 0 && wday <= 6 ? short_name_list[wday] : "???";
977}
978
979inline auto tm_mon_full_name(int mon) -> const char* {
980 static constexpr const char* full_name_list[] = {
981 "January", "February", "March", "April", "May", "June",
982 "July", "August", "September", "October", "November", "December"};
983 return mon >= 0 && mon <= 11 ? full_name_list[mon] : "?";
984}
985inline auto tm_mon_short_name(int mon) -> const char* {
986 static constexpr const char* short_name_list[] = {
987 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
988 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
989 };
990 return mon >= 0 && mon <= 11 ? short_name_list[mon] : "???";
991}
992
993template <typename T, typename = void>
994struct has_tm_gmtoff : std::false_type {};
995template <typename T>
996struct has_tm_gmtoff<T, void_t<decltype(T::tm_gmtoff)>> : std::true_type {};
997
998template <typename T, typename = void> struct has_tm_zone : std::false_type {};
999template <typename T>
1000struct has_tm_zone<T, void_t<decltype(T::tm_zone)>> : std::true_type {};
1001
1002template <typename T, FMT_ENABLE_IF(has_tm_zone<T>::value)>
1003bool set_tm_zone(T& time, char* tz) {
1004 time.tm_zone = tz;
1005 return true;
1006}
1007template <typename T, FMT_ENABLE_IF(!has_tm_zone<T>::value)>
1008bool set_tm_zone(T&, char*) {
1009 return false;
1010}
1011
1012inline char* utc() {
1013 static char tz[] = "UTC";
1014 return tz;
1015}
1016
1017// Converts value to Int and checks that it's in the range [0, upper).
1018template <typename T, typename Int, FMT_ENABLE_IF(std::is_integral<T>::value)>
1019inline auto to_nonnegative_int(T value, Int upper) -> Int {
1020 if (!std::is_unsigned<Int>::value &&
1021 (value < 0 || to_unsigned(value) > to_unsigned(upper))) {
1022 FMT_THROW(format_error("chrono value is out of range"));
1023 }
1024 return static_cast<Int>(value);
1025}
1026template <typename T, typename Int, FMT_ENABLE_IF(!std::is_integral<T>::value)>
1027inline auto to_nonnegative_int(T value, Int upper) -> Int {
1028 auto int_value = static_cast<Int>(value);
1029 if (int_value < 0 || value > static_cast<T>(upper))
1030 FMT_THROW(format_error("invalid value"));
1031 return int_value;
1032}
1033
1034constexpr auto pow10(std::uint32_t n) -> long long {
1035 return n == 0 ? 1 : 10 * pow10(n - 1);
1036}
1037
1038// Counts the number of fractional digits in the range [0, 18] according to the
1039// C++20 spec. If more than 18 fractional digits are required then returns 6 for
1040// microseconds precision.
1041template <long long Num, long long Den, int N = 0,
1042 bool Enabled = (N < 19) && (Num <= max_value<long long>() / 10)>
1044 static constexpr int value =
1046};
1047
1048// Base case that doesn't instantiate any more templates
1049// in order to avoid overflow.
1050template <long long Num, long long Den, int N>
1052 static constexpr int value = (Num % Den == 0) ? N : 6;
1053};
1054
1055// Format subseconds which are given as an integer type with an appropriate
1056// number of digits.
1057template <typename Char, typename OutputIt, typename Duration>
1058void write_fractional_seconds(OutputIt& out, Duration d, int precision = -1) {
1059 constexpr auto num_fractional_digits =
1060 count_fractional_digits<Duration::period::num,
1061 Duration::period::den>::value;
1062
1063 using subsecond_precision = std::chrono::duration<
1064 typename std::common_type<typename Duration::rep,
1065 std::chrono::seconds::rep>::type,
1066 std::ratio<1, pow10(num_fractional_digits)>>;
1067
1068 const auto fractional = d - detail::duration_cast<std::chrono::seconds>(d);
1069 const auto subseconds =
1070 std::chrono::treat_as_floating_point<
1071 typename subsecond_precision::rep>::value
1072 ? fractional.count()
1073 : detail::duration_cast<subsecond_precision>(fractional).count();
1074 auto n = static_cast<uint32_or_64_or_128_t<long long>>(subseconds);
1075 const int num_digits = count_digits(n);
1076
1077 int leading_zeroes = (std::max)(0, num_fractional_digits - num_digits);
1078 if (precision < 0) {
1079 FMT_ASSERT(!std::is_floating_point<typename Duration::rep>::value, "");
1080 if (std::ratio_less<typename subsecond_precision::period,
1081 std::chrono::seconds::period>::value) {
1082 *out++ = '.';
1083 out = detail::fill_n(out, leading_zeroes, '0');
1084 out = format_decimal<Char>(out, n, num_digits);
1085 }
1086 } else if (precision > 0) {
1087 *out++ = '.';
1088 leading_zeroes = min_of(leading_zeroes, precision);
1089 int remaining = precision - leading_zeroes;
1090 out = detail::fill_n(out, leading_zeroes, '0');
1091 if (remaining < num_digits) {
1092 int num_truncated_digits = num_digits - remaining;
1093 n /= to_unsigned(pow10(to_unsigned(num_truncated_digits)));
1094 if (n != 0) out = format_decimal<Char>(out, n, remaining);
1095 return;
1096 }
1097 if (n != 0) {
1098 out = format_decimal<Char>(out, n, num_digits);
1099 remaining -= num_digits;
1100 }
1101 out = detail::fill_n(out, remaining, '0');
1102 }
1103}
1104
1105// Format subseconds which are given as a floating point type with an
1106// appropriate number of digits. We cannot pass the Duration here, as we
1107// explicitly need to pass the Rep value in the duration_formatter.
1108template <typename Duration>
1109void write_floating_seconds(memory_buffer& buf, Duration duration,
1110 int num_fractional_digits = -1) {
1111 using rep = typename Duration::rep;
1112 FMT_ASSERT(std::is_floating_point<rep>::value, "");
1113
1114 auto val = duration.count();
1115
1116 if (num_fractional_digits < 0) {
1117 // For `std::round` with fallback to `round`:
1118 // On some toolchains `std::round` is not available (e.g. GCC 6).
1119 using namespace std;
1120 num_fractional_digits =
1121 count_fractional_digits<Duration::period::num,
1122 Duration::period::den>::value;
1123 if (num_fractional_digits < 6 && static_cast<rep>(round(val)) != val)
1124 num_fractional_digits = 6;
1125 }
1126
1127 fmt::format_to(std::back_inserter(buf), FMT_STRING("{:.{}f}"),
1128 std::fmod(val * static_cast<rep>(Duration::period::num) /
1129 static_cast<rep>(Duration::period::den),
1130 static_cast<rep>(60)),
1131 num_fractional_digits);
1132}
1133
1134template <typename OutputIt, typename Char,
1135 typename Duration = std::chrono::seconds>
1137 private:
1138 static constexpr int days_per_week = 7;
1139
1140 const std::locale& loc_;
1141 bool is_classic_;
1142 OutputIt out_;
1143 const Duration* subsecs_;
1144 const std::tm& tm_;
1145
1146 auto tm_sec() const noexcept -> int {
1147 FMT_ASSERT(tm_.tm_sec >= 0 && tm_.tm_sec <= 61, "");
1148 return tm_.tm_sec;
1149 }
1150 auto tm_min() const noexcept -> int {
1151 FMT_ASSERT(tm_.tm_min >= 0 && tm_.tm_min <= 59, "");
1152 return tm_.tm_min;
1153 }
1154 auto tm_hour() const noexcept -> int {
1155 FMT_ASSERT(tm_.tm_hour >= 0 && tm_.tm_hour <= 23, "");
1156 return tm_.tm_hour;
1157 }
1158 auto tm_mday() const noexcept -> int {
1159 FMT_ASSERT(tm_.tm_mday >= 1 && tm_.tm_mday <= 31, "");
1160 return tm_.tm_mday;
1161 }
1162 auto tm_mon() const noexcept -> int {
1163 FMT_ASSERT(tm_.tm_mon >= 0 && tm_.tm_mon <= 11, "");
1164 return tm_.tm_mon;
1165 }
1166 auto tm_year() const noexcept -> long long { return 1900ll + tm_.tm_year; }
1167 auto tm_wday() const noexcept -> int {
1168 FMT_ASSERT(tm_.tm_wday >= 0 && tm_.tm_wday <= 6, "");
1169 return tm_.tm_wday;
1170 }
1171 auto tm_yday() const noexcept -> int {
1172 FMT_ASSERT(tm_.tm_yday >= 0 && tm_.tm_yday <= 365, "");
1173 return tm_.tm_yday;
1174 }
1175
1176 auto tm_hour12() const noexcept -> int {
1177 auto h = tm_hour();
1178 auto z = h < 12 ? h : h - 12;
1179 return z == 0 ? 12 : z;
1180 }
1181
1182 // POSIX and the C Standard are unclear or inconsistent about what %C and %y
1183 // do if the year is negative or exceeds 9999. Use the convention that %C
1184 // concatenated with %y yields the same output as %Y, and that %Y contains at
1185 // least 4 characters, with more only if necessary.
1186 auto split_year_lower(long long year) const noexcept -> int {
1187 auto l = year % 100;
1188 if (l < 0) l = -l; // l in [0, 99]
1189 return static_cast<int>(l);
1190 }
1191
1192 // Algorithm: https://en.wikipedia.org/wiki/ISO_week_date.
1193 auto iso_year_weeks(long long curr_year) const noexcept -> int {
1194 auto prev_year = curr_year - 1;
1195 auto curr_p =
1196 (curr_year + curr_year / 4 - curr_year / 100 + curr_year / 400) %
1197 days_per_week;
1198 auto prev_p =
1199 (prev_year + prev_year / 4 - prev_year / 100 + prev_year / 400) %
1200 days_per_week;
1201 return 52 + ((curr_p == 4 || prev_p == 3) ? 1 : 0);
1202 }
1203 auto iso_week_num(int tm_yday, int tm_wday) const noexcept -> int {
1204 return (tm_yday + 11 - (tm_wday == 0 ? days_per_week : tm_wday)) /
1205 days_per_week;
1206 }
1207 auto tm_iso_week_year() const noexcept -> long long {
1208 auto year = tm_year();
1209 auto w = iso_week_num(tm_yday(), tm_wday());
1210 if (w < 1) return year - 1;
1211 if (w > iso_year_weeks(year)) return year + 1;
1212 return year;
1213 }
1214 auto tm_iso_week_of_year() const noexcept -> int {
1215 auto year = tm_year();
1216 auto w = iso_week_num(tm_yday(), tm_wday());
1217 if (w < 1) return iso_year_weeks(year - 1);
1218 if (w > iso_year_weeks(year)) return 1;
1219 return w;
1220 }
1221
1222 void write1(int value) {
1223 *out_++ = static_cast<char>('0' + to_unsigned(value) % 10);
1224 }
1225 void write2(int value) {
1226 const char* d = digits2(to_unsigned(value) % 100);
1227 *out_++ = *d++;
1228 *out_++ = *d;
1229 }
1230 void write2(int value, pad_type pad) {
1231 unsigned int v = to_unsigned(value) % 100;
1232 if (v >= 10) {
1233 const char* d = digits2(v);
1234 *out_++ = *d++;
1235 *out_++ = *d;
1236 } else {
1237 out_ = detail::write_padding(out_, pad);
1238 *out_++ = static_cast<char>('0' + v);
1239 }
1240 }
1241
1242 void write_year_extended(long long year, pad_type pad) {
1243 // At least 4 characters.
1244 int width = 4;
1245 bool negative = year < 0;
1246 if (negative) {
1247 year = 0 - year;
1248 --width;
1249 }
1251 const int num_digits = count_digits(n);
1252 if (negative && pad == pad_type::zero) *out_++ = '-';
1253 if (width > num_digits)
1254 out_ = detail::write_padding(out_, pad, width - num_digits);
1255 if (negative && pad != pad_type::zero) *out_++ = '-';
1256 out_ = format_decimal<Char>(out_, n, num_digits);
1257 }
1258 void write_year(long long year, pad_type pad) {
1259 write_year_extended(year, pad);
1260 }
1261
1262 void write_utc_offset(long long offset, numeric_system ns) {
1263 if (offset < 0) {
1264 *out_++ = '-';
1265 offset = -offset;
1266 } else {
1267 *out_++ = '+';
1268 }
1269 offset /= 60;
1270 write2(static_cast<int>(offset / 60));
1271 if (ns != numeric_system::standard) *out_++ = ':';
1272 write2(static_cast<int>(offset % 60));
1273 }
1274
1275 template <typename T, FMT_ENABLE_IF(has_tm_gmtoff<T>::value)>
1276 void format_utc_offset(const T& tm, numeric_system ns) {
1277 write_utc_offset(tm.tm_gmtoff, ns);
1278 }
1279 template <typename T, FMT_ENABLE_IF(!has_tm_gmtoff<T>::value)>
1280 void format_utc_offset(const T&, numeric_system ns) {
1281 write_utc_offset(0, ns);
1282 }
1283
1284 template <typename T, FMT_ENABLE_IF(has_tm_zone<T>::value)>
1285 void format_tz_name(const T& tm) {
1286 out_ = write_tm_str<Char>(out_, tm.tm_zone, loc_);
1287 }
1288 template <typename T, FMT_ENABLE_IF(!has_tm_zone<T>::value)>
1289 void format_tz_name(const T&) {
1290 out_ = std::copy_n(utc(), 3, out_);
1291 }
1292
1293 void format_localized(char format, char modifier = 0) {
1294 out_ = write<Char>(out_, tm_, loc_, format, modifier);
1295 }
1296
1297 public:
1298 tm_writer(const std::locale& loc, OutputIt out, const std::tm& tm,
1299 const Duration* subsecs = nullptr)
1300 : loc_(loc),
1301 is_classic_(loc_ == get_classic_locale()),
1302 out_(out),
1303 subsecs_(subsecs),
1304 tm_(tm) {}
1305
1306 auto out() const -> OutputIt { return out_; }
1307
1308 FMT_CONSTEXPR void on_text(const Char* begin, const Char* end) {
1309 out_ = copy<Char>(begin, end, out_);
1310 }
1311
1313 if (is_classic_)
1314 out_ = write(out_, tm_wday_short_name(tm_wday()));
1315 else
1316 format_localized('a');
1317 }
1319 if (is_classic_)
1320 out_ = write(out_, tm_wday_full_name(tm_wday()));
1321 else
1322 format_localized('A');
1323 }
1325 if (is_classic_ || ns == numeric_system::standard) return write1(tm_wday());
1326 format_localized('w', 'O');
1327 }
1329 if (is_classic_ || ns == numeric_system::standard) {
1330 auto wday = tm_wday();
1331 write1(wday == 0 ? days_per_week : wday);
1332 } else {
1333 format_localized('u', 'O');
1334 }
1335 }
1336
1338 if (is_classic_)
1339 out_ = write(out_, tm_mon_short_name(tm_mon()));
1340 else
1341 format_localized('b');
1342 }
1344 if (is_classic_)
1345 out_ = write(out_, tm_mon_full_name(tm_mon()));
1346 else
1347 format_localized('B');
1348 }
1349
1351 if (is_classic_) {
1353 *out_++ = ' ';
1354 on_abbr_month();
1355 *out_++ = ' ';
1357 *out_++ = ' ';
1358 on_iso_time();
1359 *out_++ = ' ';
1361 } else {
1362 format_localized('c', ns == numeric_system::standard ? '\0' : 'E');
1363 }
1364 }
1366 if (is_classic_)
1367 on_us_date();
1368 else
1369 format_localized('x', ns == numeric_system::standard ? '\0' : 'E');
1370 }
1372 if (is_classic_)
1373 on_iso_time();
1374 else
1375 format_localized('X', ns == numeric_system::standard ? '\0' : 'E');
1376 }
1377 void on_us_date() {
1378 char buf[8];
1379 write_digit2_separated(buf, to_unsigned(tm_mon() + 1),
1380 to_unsigned(tm_mday()),
1381 to_unsigned(split_year_lower(tm_year())), '/');
1382 out_ = copy<Char>(std::begin(buf), std::end(buf), out_);
1383 }
1385 auto year = tm_year();
1386 char buf[10];
1387 size_t offset = 0;
1388 if (year >= 0 && year < 10000) {
1389 write2digits(buf, static_cast<size_t>(year / 100));
1390 } else {
1391 offset = 4;
1392 write_year_extended(year, pad_type::zero);
1393 year = 0;
1394 }
1395 write_digit2_separated(buf + 2, static_cast<unsigned>(year % 100),
1396 to_unsigned(tm_mon() + 1), to_unsigned(tm_mday()),
1397 '-');
1398 out_ = copy<Char>(std::begin(buf) + offset, std::end(buf), out_);
1399 }
1400
1401 void on_utc_offset(numeric_system ns) { format_utc_offset(tm_, ns); }
1402 void on_tz_name() { format_tz_name(tm_); }
1403
1405 if (is_classic_ || ns == numeric_system::standard)
1406 return write_year(tm_year(), pad);
1407 format_localized('Y', 'E');
1408 }
1410 if (is_classic_ || ns == numeric_system::standard)
1411 return write2(split_year_lower(tm_year()));
1412 format_localized('y', 'O');
1413 }
1415 if (is_classic_) return write2(split_year_lower(tm_year()));
1416 format_localized('y', 'E');
1417 }
1418
1420 if (is_classic_ || ns == numeric_system::standard) {
1421 auto year = tm_year();
1422 auto upper = year / 100;
1423 if (year >= -99 && year < 0) {
1424 // Zero upper on negative year.
1425 *out_++ = '-';
1426 *out_++ = '0';
1427 } else if (upper >= 0 && upper < 100) {
1428 write2(static_cast<int>(upper));
1429 } else {
1430 out_ = write<Char>(out_, upper);
1431 }
1432 } else {
1433 format_localized('C', 'E');
1434 }
1435 }
1436
1438 if (is_classic_ || ns == numeric_system::standard)
1439 return write2(tm_mon() + 1, pad);
1440 format_localized('m', 'O');
1441 }
1442
1444 if (is_classic_ || ns == numeric_system::standard)
1445 return write2((tm_yday() + days_per_week - tm_wday()) / days_per_week,
1446 pad);
1447 format_localized('U', 'O');
1448 }
1450 if (is_classic_ || ns == numeric_system::standard) {
1451 auto wday = tm_wday();
1452 write2((tm_yday() + days_per_week -
1453 (wday == 0 ? (days_per_week - 1) : (wday - 1))) /
1454 days_per_week,
1455 pad);
1456 } else {
1457 format_localized('W', 'O');
1458 }
1459 }
1461 if (is_classic_ || ns == numeric_system::standard)
1462 return write2(tm_iso_week_of_year(), pad);
1463 format_localized('V', 'O');
1464 }
1465
1467 write_year(tm_iso_week_year(), pad_type::zero);
1468 }
1470 write2(split_year_lower(tm_iso_week_year()));
1471 }
1472
1474 auto yday = tm_yday() + 1;
1475 auto digit1 = yday / 100;
1476 if (digit1 != 0)
1477 write1(digit1);
1478 else
1479 out_ = detail::write_padding(out_, pad);
1480 write2(yday % 100, pad);
1481 }
1482
1484 if (is_classic_ || ns == numeric_system::standard)
1485 return write2(tm_mday(), pad);
1486 format_localized('d', 'O');
1487 }
1488
1490 if (is_classic_ || ns == numeric_system::standard)
1491 return write2(tm_hour(), pad);
1492 format_localized('H', 'O');
1493 }
1495 if (is_classic_ || ns == numeric_system::standard)
1496 return write2(tm_hour12(), pad);
1497 format_localized('I', 'O');
1498 }
1500 if (is_classic_ || ns == numeric_system::standard)
1501 return write2(tm_min(), pad);
1502 format_localized('M', 'O');
1503 }
1504
1506 if (is_classic_ || ns == numeric_system::standard) {
1507 write2(tm_sec(), pad);
1508 if (subsecs_) {
1509 if (std::is_floating_point<typename Duration::rep>::value) {
1510 auto buf = memory_buffer();
1511 write_floating_seconds(buf, *subsecs_);
1512 if (buf.size() > 1) {
1513 // Remove the leading "0", write something like ".123".
1514 out_ = copy<Char>(buf.begin() + 1, buf.end(), out_);
1515 }
1516 } else {
1517 write_fractional_seconds<Char>(out_, *subsecs_);
1518 }
1519 }
1520 } else {
1521 // Currently no formatting of subseconds when a locale is set.
1522 format_localized('S', 'O');
1523 }
1524 }
1525
1527 if (is_classic_) {
1528 char buf[8];
1529 write_digit2_separated(buf, to_unsigned(tm_hour12()),
1530 to_unsigned(tm_min()), to_unsigned(tm_sec()), ':');
1531 out_ = copy<Char>(std::begin(buf), std::end(buf), out_);
1532 *out_++ = ' ';
1533 on_am_pm();
1534 } else {
1535 format_localized('r');
1536 }
1537 }
1539 write2(tm_hour());
1540 *out_++ = ':';
1541 write2(tm_min());
1542 }
1545 *out_++ = ':';
1547 }
1548
1549 void on_am_pm() {
1550 if (is_classic_) {
1551 *out_++ = tm_hour() < 12 ? 'A' : 'P';
1552 *out_++ = 'M';
1553 } else {
1554 format_localized('p');
1555 }
1556 }
1557
1558 // These apply to chrono durations but not tm.
1561};
1562
1563struct chrono_format_checker : null_chrono_spec_handler<chrono_format_checker> {
1565
1566 FMT_NORETURN inline void unsupported() { FMT_THROW(format_error("no date")); }
1567
1568 template <typename Char>
1569 FMT_CONSTEXPR void on_text(const Char*, const Char*) {}
1581 FMT_THROW(format_error("precision not allowed for this argument type"));
1582 }
1584};
1585
1586template <typename T,
1587 FMT_ENABLE_IF(std::is_integral<T>::value&& has_isfinite<T>::value)>
1588inline auto isfinite(T) -> bool {
1589 return true;
1590}
1591
1592template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
1593inline auto mod(T x, int y) -> T {
1594 return x % static_cast<T>(y);
1595}
1596template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)>
1597inline auto mod(T x, int y) -> T {
1598 return std::fmod(x, static_cast<T>(y));
1599}
1600
1601// If T is an integral type, maps T to its unsigned counterpart, otherwise
1602// leaves it unchanged (unlike std::make_unsigned).
1603template <typename T, bool INTEGRAL = std::is_integral<T>::value>
1605 using type = T;
1606};
1607
1608template <typename T> struct make_unsigned_or_unchanged<T, true> {
1609 using type = typename std::make_unsigned<T>::type;
1610};
1611
1612template <typename Rep, typename Period,
1613 FMT_ENABLE_IF(std::is_integral<Rep>::value)>
1614inline auto get_milliseconds(std::chrono::duration<Rep, Period> d)
1615 -> std::chrono::duration<Rep, std::milli> {
1616 // This may overflow and/or the result may not fit in the target type.
1617#if FMT_SAFE_DURATION_CAST
1618 using common_seconds_type =
1619 typename std::common_type<decltype(d), std::chrono::seconds>::type;
1620 auto d_as_common = detail::duration_cast<common_seconds_type>(d);
1621 auto d_as_whole_seconds =
1623 // This conversion should be nonproblematic.
1624 auto diff = d_as_common - d_as_whole_seconds;
1626 return ms;
1627#else
1630#endif
1631}
1632
1633template <typename Char, typename Rep, typename OutputIt,
1634 FMT_ENABLE_IF(std::is_integral<Rep>::value)>
1635auto format_duration_value(OutputIt out, Rep val, int) -> OutputIt {
1636 return write<Char>(out, val);
1637}
1638
1639template <typename Char, typename Rep, typename OutputIt,
1640 FMT_ENABLE_IF(std::is_floating_point<Rep>::value)>
1641auto format_duration_value(OutputIt out, Rep val, int precision) -> OutputIt {
1642 auto specs = format_specs();
1643 specs.precision = precision;
1644 specs.set_type(precision >= 0 ? presentation_type::fixed
1646 return write<Char>(out, val, specs);
1647}
1648
1649template <typename Char, typename OutputIt>
1650auto copy_unit(string_view unit, OutputIt out, Char) -> OutputIt {
1651 return copy<Char>(unit.begin(), unit.end(), out);
1652}
1653
1654template <typename OutputIt>
1655auto copy_unit(string_view unit, OutputIt out, wchar_t) -> OutputIt {
1656 // This works when wchar_t is UTF-32 because units only contain characters
1657 // that have the same representation in UTF-16 and UTF-32.
1658 utf8_to_utf16 u(unit);
1659 return copy<wchar_t>(u.c_str(), u.c_str() + u.size(), out);
1660}
1661
1662template <typename Char, typename Period, typename OutputIt>
1663auto format_duration_unit(OutputIt out) -> OutputIt {
1664 if (const char* unit = get_units<Period>())
1665 return copy_unit(string_view(unit), out, Char());
1666 *out++ = '[';
1667 out = write<Char>(out, Period::num);
1668 if (const_check(Period::den != 1)) {
1669 *out++ = '/';
1670 out = write<Char>(out, Period::den);
1671 }
1672 *out++ = ']';
1673 *out++ = 's';
1674 return out;
1675}
1676
1678 private:
1679 union {
1680 std::locale locale_;
1681 };
1682 bool has_locale_ = false;
1683
1684 public:
1685 inline get_locale(bool localized, locale_ref loc) : has_locale_(localized) {
1686 if (localized)
1687 ::new (&locale_) std::locale(loc.template get<std::locale>());
1688 }
1689 inline ~get_locale() {
1690 if (has_locale_) locale_.~locale();
1691 }
1692 inline operator const std::locale&() const {
1693 return has_locale_ ? locale_ : get_classic_locale();
1694 }
1695};
1696
1697template <typename Char, typename Rep, typename Period>
1701 // rep is unsigned to avoid overflow.
1702 using rep =
1703 conditional_t<std::is_integral<Rep>::value && sizeof(Rep) < sizeof(int),
1704 unsigned, typename make_unsigned_or_unchanged<Rep>::type>;
1708 bool localized = false;
1709 using seconds = std::chrono::duration<rep>;
1711 using milliseconds = std::chrono::duration<rep, std::milli>;
1713
1715
1716 duration_formatter(iterator o, std::chrono::duration<Rep, Period> d,
1717 locale_ref loc)
1718 : out(o), val(static_cast<rep>(d.count())), locale(loc), negative(false) {
1719 if (d.count() < 0) {
1720 val = 0 - val;
1721 negative = true;
1722 }
1723
1724 // this may overflow and/or the result may not fit in the
1725 // target type.
1726 // might need checked conversion (rep!=Rep)
1727 s = detail::duration_cast<seconds>(std::chrono::duration<rep, Period>(val));
1728 }
1729
1730 // returns true if nan or inf, writes to out.
1731 auto handle_nan_inf() -> bool {
1732 if (isfinite(val)) return false;
1733 if (isnan(val)) {
1734 write_nan();
1735 return true;
1736 }
1737 // must be +-inf
1738 if (val > 0)
1739 std::copy_n("inf", 3, out);
1740 else
1741 std::copy_n("-inf", 4, out);
1742 return true;
1743 }
1744
1745 auto days() const -> Rep { return static_cast<Rep>(s.count() / 86400); }
1746 auto hour() const -> Rep {
1747 return static_cast<Rep>(mod((s.count() / 3600), 24));
1748 }
1749
1750 auto hour12() const -> Rep {
1751 Rep hour = static_cast<Rep>(mod((s.count() / 3600), 12));
1752 return hour <= 0 ? 12 : hour;
1753 }
1754
1755 auto minute() const -> Rep {
1756 return static_cast<Rep>(mod((s.count() / 60), 60));
1757 }
1758 auto second() const -> Rep { return static_cast<Rep>(mod(s.count(), 60)); }
1759
1760 auto time() const -> std::tm {
1761 auto time = std::tm();
1762 time.tm_hour = to_nonnegative_int(hour(), 24);
1763 time.tm_min = to_nonnegative_int(minute(), 60);
1764 time.tm_sec = to_nonnegative_int(second(), 60);
1765 return time;
1766 }
1767
1768 void write_sign() {
1769 if (!negative) return;
1770 *out++ = '-';
1771 negative = false;
1772 }
1773
1774 void write(Rep value, int width, pad_type pad = pad_type::zero) {
1775 write_sign();
1776 if (isnan(value)) return write_nan();
1779 int num_digits = detail::count_digits(n);
1780 if (width > num_digits) {
1781 out = detail::write_padding(out, pad, width - num_digits);
1782 }
1783 out = format_decimal<Char>(out, n, num_digits);
1784 }
1785
1786 void write_nan() { std::copy_n("nan", 3, out); }
1787
1788 template <typename Callback, typename... Args>
1789 void format_tm(const tm& time, Callback cb, Args... args) {
1790 if (isnan(val)) return write_nan();
1792 auto w = tm_writer_type(loc, out, time);
1793 (w.*cb)(args...);
1794 out = w.out();
1795 }
1796
1797 void on_text(const Char* begin, const Char* end) {
1798 copy<Char>(begin, end, out);
1799 }
1800
1801 // These are not implemented because durations don't have date information.
1811 void on_us_date() {}
1812 void on_iso_date() {}
1814 void on_tz_name() {}
1826
1828 if (handle_nan_inf()) return;
1829 write(days(), 0);
1830 }
1831
1833 if (handle_nan_inf()) return;
1834
1835 if (ns == numeric_system::standard) return write(hour(), 2, pad);
1836 auto time = tm();
1837 time.tm_hour = to_nonnegative_int(hour(), 24);
1839 }
1840
1842 if (handle_nan_inf()) return;
1843
1844 if (ns == numeric_system::standard) return write(hour12(), 2, pad);
1845 auto time = tm();
1846 time.tm_hour = to_nonnegative_int(hour12(), 12);
1848 }
1849
1851 if (handle_nan_inf()) return;
1852
1853 if (ns == numeric_system::standard) return write(minute(), 2, pad);
1854 auto time = tm();
1855 time.tm_min = to_nonnegative_int(minute(), 60);
1857 }
1858
1860 if (handle_nan_inf()) return;
1861
1862 if (ns == numeric_system::standard) {
1863 if (std::is_floating_point<rep>::value) {
1864 auto buf = memory_buffer();
1865 write_floating_seconds(buf, std::chrono::duration<rep, Period>(val),
1866 precision);
1867 if (negative) *out++ = '-';
1868 if (buf.size() < 2 || buf[1] == '.')
1869 out = detail::write_padding(out, pad);
1870 out = copy<Char>(buf.begin(), buf.end(), out);
1871 } else {
1872 write(second(), 2, pad);
1874 out, std::chrono::duration<rep, Period>(val), precision);
1875 }
1876 return;
1877 }
1878 auto time = tm();
1879 time.tm_sec = to_nonnegative_int(second(), 60);
1881 }
1882
1884 if (handle_nan_inf()) return;
1886 }
1887
1889 if (handle_nan_inf()) {
1890 *out++ = ':';
1892 return;
1893 }
1894
1895 write(hour(), 2);
1896 *out++ = ':';
1897 write(minute(), 2);
1898 }
1899
1902 *out++ = ':';
1903 if (handle_nan_inf()) return;
1905 }
1906
1907 void on_am_pm() {
1908 if (handle_nan_inf()) return;
1910 }
1911
1913 if (handle_nan_inf()) return;
1914 write_sign();
1916 }
1917
1919};
1920
1921} // namespace detail
1922
1923#if defined(__cpp_lib_chrono) && __cpp_lib_chrono >= 201907
1924using weekday = std::chrono::weekday;
1925using day = std::chrono::day;
1926using month = std::chrono::month;
1927using year = std::chrono::year;
1928using year_month_day = std::chrono::year_month_day;
1929#else
1930// A fallback version of weekday.
1931class weekday {
1932 private:
1933 unsigned char value_;
1934
1935 public:
1936 weekday() = default;
1937 constexpr explicit weekday(unsigned wd) noexcept
1938 : value_(static_cast<unsigned char>(wd != 7 ? wd : 0)) {}
1939 constexpr auto c_encoding() const noexcept -> unsigned { return value_; }
1940};
1941
1942class day {
1943 private:
1944 unsigned char value_;
1945
1946 public:
1947 day() = default;
1948 constexpr explicit day(unsigned d) noexcept
1949 : value_(static_cast<unsigned char>(d)) {}
1950 constexpr explicit operator unsigned() const noexcept { return value_; }
1951};
1952
1953class month {
1954 private:
1955 unsigned char value_;
1956
1957 public:
1958 month() = default;
1959 constexpr explicit month(unsigned m) noexcept
1960 : value_(static_cast<unsigned char>(m)) {}
1961 constexpr explicit operator unsigned() const noexcept { return value_; }
1962};
1963
1964class year {
1965 private:
1966 int value_;
1967
1968 public:
1969 year() = default;
1970 constexpr explicit year(int y) noexcept : value_(y) {}
1971 constexpr explicit operator int() const noexcept { return value_; }
1972};
1973
1975 private:
1976 fmt::year year_;
1977 fmt::month month_;
1978 fmt::day day_;
1979
1980 public:
1981 year_month_day() = default;
1982 constexpr year_month_day(const year& y, const month& m, const day& d) noexcept
1983 : year_(y), month_(m), day_(d) {}
1984 constexpr auto year() const noexcept -> fmt::year { return year_; }
1985 constexpr auto month() const noexcept -> fmt::month { return month_; }
1986 constexpr auto day() const noexcept -> fmt::day { return day_; }
1987};
1988#endif // __cpp_lib_chrono >= 201907
1989
1990template <typename Char>
1991struct formatter<weekday, Char> : private formatter<std::tm, Char> {
1992 private:
1993 bool use_tm_formatter_ = false;
1994
1995 public:
1996 FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
1997 auto it = ctx.begin(), end = ctx.end();
1998 if (it != end && *it == 'L') {
1999 ++it;
2000 this->set_localized();
2001 }
2002 use_tm_formatter_ = it != end && *it != '}';
2003 return use_tm_formatter_ ? formatter<std::tm, Char>::parse(ctx) : it;
2004 }
2005
2006 template <typename FormatContext>
2007 auto format(weekday wd, FormatContext& ctx) const -> decltype(ctx.out()) {
2008 auto time = std::tm();
2009 time.tm_wday = static_cast<int>(wd.c_encoding());
2010 if (use_tm_formatter_) return formatter<std::tm, Char>::format(time, ctx);
2011 detail::get_locale loc(this->localized(), ctx.locale());
2012 auto w = detail::tm_writer<decltype(ctx.out()), Char>(loc, ctx.out(), time);
2013 w.on_abbr_weekday();
2014 return w.out();
2015 }
2016};
2017
2018template <typename Char>
2019struct formatter<day, Char> : private formatter<std::tm, Char> {
2020 private:
2021 bool use_tm_formatter_ = false;
2022
2023 public:
2024 FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
2025 auto it = ctx.begin(), end = ctx.end();
2026 use_tm_formatter_ = it != end && *it != '}';
2027 return use_tm_formatter_ ? formatter<std::tm, Char>::parse(ctx) : it;
2028 }
2029
2030 template <typename FormatContext>
2031 auto format(day d, FormatContext& ctx) const -> decltype(ctx.out()) {
2032 auto time = std::tm();
2033 time.tm_mday = static_cast<int>(static_cast<unsigned>(d));
2034 if (use_tm_formatter_) return formatter<std::tm, Char>::format(time, ctx);
2035 detail::get_locale loc(false, ctx.locale());
2036 auto w = detail::tm_writer<decltype(ctx.out()), Char>(loc, ctx.out(), time);
2038 return w.out();
2039 }
2040};
2041
2042template <typename Char>
2043struct formatter<month, Char> : private formatter<std::tm, Char> {
2044 private:
2045 bool use_tm_formatter_ = false;
2046
2047 public:
2048 FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
2049 auto it = ctx.begin(), end = ctx.end();
2050 if (it != end && *it == 'L') {
2051 ++it;
2052 this->set_localized();
2053 }
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(month m, FormatContext& ctx) const -> decltype(ctx.out()) {
2060 auto time = std::tm();
2061 time.tm_mon = static_cast<int>(static_cast<unsigned>(m)) - 1;
2062 if (use_tm_formatter_) return formatter<std::tm, Char>::format(time, ctx);
2063 detail::get_locale loc(this->localized(), ctx.locale());
2064 auto w = detail::tm_writer<decltype(ctx.out()), Char>(loc, ctx.out(), time);
2065 w.on_abbr_month();
2066 return w.out();
2067 }
2068};
2069
2070template <typename Char>
2071struct formatter<year, Char> : private formatter<std::tm, Char> {
2072 private:
2073 bool use_tm_formatter_ = false;
2074
2075 public:
2076 FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
2077 auto it = ctx.begin(), end = ctx.end();
2078 use_tm_formatter_ = it != end && *it != '}';
2079 return use_tm_formatter_ ? formatter<std::tm, Char>::parse(ctx) : it;
2080 }
2081
2082 template <typename FormatContext>
2083 auto format(year y, FormatContext& ctx) const -> decltype(ctx.out()) {
2084 auto time = std::tm();
2085 time.tm_year = static_cast<int>(y) - 1900;
2086 if (use_tm_formatter_) return formatter<std::tm, Char>::format(time, ctx);
2087 detail::get_locale loc(false, ctx.locale());
2088 auto w = detail::tm_writer<decltype(ctx.out()), Char>(loc, ctx.out(), time);
2090 return w.out();
2091 }
2092};
2093
2094template <typename Char>
2095struct formatter<year_month_day, Char> : private formatter<std::tm, Char> {
2096 private:
2097 bool use_tm_formatter_ = false;
2098
2099 public:
2100 FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
2101 auto it = ctx.begin(), end = ctx.end();
2102 use_tm_formatter_ = it != end && *it != '}';
2103 return use_tm_formatter_ ? formatter<std::tm, Char>::parse(ctx) : it;
2104 }
2105
2106 template <typename FormatContext>
2107 auto format(year_month_day val, FormatContext& ctx) const
2108 -> decltype(ctx.out()) {
2109 auto time = std::tm();
2110 time.tm_year = static_cast<int>(val.year()) - 1900;
2111 time.tm_mon = static_cast<int>(static_cast<unsigned>(val.month())) - 1;
2112 time.tm_mday = static_cast<int>(static_cast<unsigned>(val.day()));
2113 if (use_tm_formatter_) return formatter<std::tm, Char>::format(time, ctx);
2114 detail::get_locale loc(true, ctx.locale());
2115 auto w = detail::tm_writer<decltype(ctx.out()), Char>(loc, ctx.out(), time);
2116 w.on_iso_date();
2117 return w.out();
2118 }
2119};
2120
2121template <typename Rep, typename Period, typename Char>
2122struct formatter<std::chrono::duration<Rep, Period>, Char> {
2123 private:
2124 format_specs specs_;
2125 detail::arg_ref<Char> width_ref_;
2126 detail::arg_ref<Char> precision_ref_;
2128
2129 public:
2130 FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
2131 auto it = ctx.begin(), end = ctx.end();
2132 if (it == end || *it == '}') return it;
2133
2134 it = detail::parse_align(it, end, specs_);
2135 if (it == end) return it;
2136
2137 Char c = *it;
2138 if ((c >= '0' && c <= '9') || c == '{') {
2139 it = detail::parse_width(it, end, specs_, width_ref_, ctx);
2140 if (it == end) return it;
2141 }
2142
2143 auto checker = detail::chrono_format_checker();
2144 if (*it == '.') {
2145 checker.has_precision_integral = !std::is_floating_point<Rep>::value;
2146 it = detail::parse_precision(it, end, specs_, precision_ref_, ctx);
2147 }
2148 if (it != end && *it == 'L') {
2149 specs_.set_localized();
2150 ++it;
2151 }
2152 end = detail::parse_chrono_format(it, end, checker);
2153 fmt_ = {it, detail::to_unsigned(end - it)};
2154 return end;
2155 }
2156
2157 template <typename FormatContext>
2158 auto format(std::chrono::duration<Rep, Period> d, FormatContext& ctx) const
2159 -> decltype(ctx.out()) {
2160 auto specs = specs_;
2161 auto precision = specs.precision;
2162 specs.precision = -1;
2163 auto begin = fmt_.begin(), end = fmt_.end();
2164 // As a possible future optimization, we could avoid extra copying if width
2165 // is not specified.
2166 auto buf = basic_memory_buffer<Char>();
2167 auto out = basic_appender<Char>(buf);
2168 detail::handle_dynamic_spec(specs.dynamic_width(), specs.width, width_ref_,
2169 ctx);
2170 detail::handle_dynamic_spec(specs.dynamic_precision(), precision,
2171 precision_ref_, ctx);
2172 if (begin == end || *begin == '}') {
2173 out = detail::format_duration_value<Char>(out, d.count(), precision);
2175 } else {
2176 auto f =
2178 f.precision = precision;
2179 f.localized = specs_.localized();
2180 detail::parse_chrono_format(begin, end, f);
2181 }
2182 return detail::write(
2183 ctx.out(), basic_string_view<Char>(buf.data(), buf.size()), specs);
2184 }
2185};
2186
2187template <typename Char> struct formatter<std::tm, Char> {
2188 private:
2189 format_specs specs_;
2190 detail::arg_ref<Char> width_ref_;
2193
2194 protected:
2195 auto localized() const -> bool { return specs_.localized(); }
2197
2198 FMT_CONSTEXPR auto do_parse(parse_context<Char>& ctx, bool has_timezone)
2199 -> const Char* {
2200 auto it = ctx.begin(), end = ctx.end();
2201 if (it == end || *it == '}') return it;
2202
2203 it = detail::parse_align(it, end, specs_);
2204 if (it == end) return it;
2205
2206 Char c = *it;
2207 if ((c >= '0' && c <= '9') || c == '{') {
2208 it = detail::parse_width(it, end, specs_, width_ref_, ctx);
2209 if (it == end) return it;
2210 }
2211
2212 if (*it == 'L') {
2213 specs_.set_localized();
2214 ++it;
2215 }
2216
2217 end = detail::parse_chrono_format(it, end,
2218 detail::tm_format_checker(has_timezone));
2219 // Replace the default format string only if the new spec is not empty.
2220 if (end != it) fmt_ = {it, detail::to_unsigned(end - it)};
2221 return end;
2222 }
2223
2224 template <typename Duration, typename FormatContext>
2225 auto do_format(const std::tm& tm, FormatContext& ctx,
2226 const Duration* subsecs) const -> decltype(ctx.out()) {
2227 auto specs = specs_;
2228 auto buf = basic_memory_buffer<Char>();
2229 auto out = basic_appender<Char>(buf);
2230 detail::handle_dynamic_spec(specs.dynamic_width(), specs.width, width_ref_,
2231 ctx);
2232
2233 auto loc_ref = specs.localized() ? ctx.locale() : detail::locale_ref();
2234 detail::get_locale loc(static_cast<bool>(loc_ref), loc_ref);
2235 auto w = detail::tm_writer<basic_appender<Char>, Char, Duration>(
2236 loc, out, tm, subsecs);
2237 detail::parse_chrono_format(fmt_.begin(), fmt_.end(), w);
2238 return detail::write(
2239 ctx.out(), basic_string_view<Char>(buf.data(), buf.size()), specs);
2240 }
2241
2242 public:
2243 FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
2244 return do_parse(ctx, detail::has_tm_gmtoff<std::tm>::value);
2245 }
2246
2247 template <typename FormatContext>
2248 auto format(const std::tm& tm, FormatContext& ctx) const
2249 -> decltype(ctx.out()) {
2250 return do_format<std::chrono::seconds>(tm, ctx, nullptr);
2251 }
2252};
2253
2254// DEPRECATED! Reversed order of template parameters.
2255template <typename Char, typename Duration>
2256struct formatter<sys_time<Duration>, Char> : private formatter<std::tm, Char> {
2257 FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
2258 return this->do_parse(ctx, true);
2259 }
2260
2261 template <typename FormatContext>
2262 auto format(sys_time<Duration> val, FormatContext& ctx) const
2263 -> decltype(ctx.out()) {
2264 std::tm tm = gmtime(val);
2265 using period = typename Duration::period;
2267 period::num == 1 && period::den == 1 &&
2268 !std::is_floating_point<typename Duration::rep>::value)) {
2270 return formatter<std::tm, Char>::format(tm, ctx);
2271 }
2272 Duration epoch = val.time_since_epoch();
2273 Duration subsecs = detail::duration_cast<Duration>(
2275 if (subsecs.count() < 0) {
2276 auto second = detail::duration_cast<Duration>(std::chrono::seconds(1));
2277 if (tm.tm_sec != 0) {
2278 --tm.tm_sec;
2279 } else {
2280 tm = gmtime(val - second);
2282 }
2283 subsecs += second;
2284 }
2285 return formatter<std::tm, Char>::do_format(tm, ctx, &subsecs);
2286 }
2287};
2288
2289template <typename Duration, typename Char>
2290struct formatter<utc_time<Duration>, Char>
2291 : formatter<sys_time<Duration>, Char> {
2292 template <typename FormatContext>
2293 auto format(utc_time<Duration> val, FormatContext& ctx) const
2294 -> decltype(ctx.out()) {
2296 detail::utc_clock::to_sys(val), ctx);
2297 }
2298};
2299
2300template <typename Duration, typename Char>
2301struct formatter<local_time<Duration>, Char>
2302 : private formatter<std::tm, Char> {
2303 FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
2304 return this->do_parse(ctx, false);
2305 }
2306
2307 template <typename FormatContext>
2308 auto format(local_time<Duration> val, FormatContext& ctx) const
2309 -> decltype(ctx.out()) {
2310 auto time_since_epoch = val.time_since_epoch();
2311 auto seconds_since_epoch =
2313 // Use gmtime to prevent time zone conversion since local_time has an
2314 // unspecified time zone.
2315 std::tm t = gmtime(seconds_since_epoch.count());
2316 using period = typename Duration::period;
2317 if (period::num == 1 && period::den == 1 &&
2318 !std::is_floating_point<typename Duration::rep>::value) {
2319 return formatter<std::tm, Char>::format(t, ctx);
2320 }
2321 auto subsecs =
2322 detail::duration_cast<Duration>(time_since_epoch - seconds_since_epoch);
2323 return formatter<std::tm, Char>::do_format(t, ctx, &subsecs);
2324 }
2325};
2326
2329
2330#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 glfw and nanopb were 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:140
A dynamically growing memory buffer for trivially copyable/constructible types with the first SIZE el...
Definition format.h:774
constexpr auto localized() const -> bool
Definition base.h:801
FMT_CONSTEXPR void set_localized()
Definition base.h:804
constexpr auto end() const noexcept -> iterator
Definition base.h:566
constexpr auto begin() const noexcept -> iterator
Definition base.h:565
Definition chrono.h:1942
day()=default
constexpr day(unsigned d) noexcept
Definition chrono.h:1948
A contiguous memory buffer with an optional growing ability.
Definition base.h:1746
FMT_CONSTEXPR20 void append(const U *begin, const U *end)
Appends data to the end of the buffer.
Definition base.h:1828
FMT_CONSTEXPR void push_back(const T &value)
Definition base.h:1815
Definition chrono.h:292
formatbuf(buffer< char_type > &buf)
Definition chrono.h:302
auto xsputn(const char_type *s, streamsize count) -> streamsize override
Definition chrono.h:317
auto overflow(int_type ch) -> int_type override
Definition chrono.h:311
Definition chrono.h:1677
get_locale(bool localized, locale_ref loc)
Definition chrono.h:1685
std::locale locale_
Definition chrono.h:1680
~get_locale()
Definition chrono.h:1689
Definition base.h:2318
Definition chrono.h:914
FMT_CONSTEXPR void on_text(const Char *, const Char *)
Definition chrono.h:927
FMT_CONSTEXPR void on_24_hour_time()
Definition chrono.h:956
FMT_CONSTEXPR void on_full_weekday()
Definition chrono.h:935
constexpr tm_format_checker(bool has_timezone)
Definition chrono.h:919
FMT_CONSTEXPR void on_iso_time()
Definition chrono.h:957
FMT_CONSTEXPR void on_iso_week_of_year(numeric_system, pad_type)
Definition chrono.h:943
FMT_CONSTEXPR void on_iso_week_based_short_year()
Definition chrono.h:933
FMT_CONSTEXPR void on_iso_date()
Definition chrono.h:954
FMT_CONSTEXPR void on_abbr_weekday()
Definition chrono.h:934
FMT_CONSTEXPR void on_loc_time(numeric_system)
Definition chrono.h:952
FMT_CONSTEXPR void on_dec0_weekday(numeric_system)
Definition chrono.h:936
FMT_CONSTEXPR void on_dec1_week_of_year(numeric_system, pad_type)
Definition chrono.h:942
FMT_CONSTEXPR void on_iso_week_based_year()
Definition chrono.h:932
FMT_CONSTEXPR void on_abbr_month()
Definition chrono.h:938
FMT_CONSTEXPR void on_dec0_week_of_year(numeric_system, pad_type)
Definition chrono.h:941
FMT_CONSTEXPR void on_tz_name()
Definition chrono.h:962
FMT_CONSTEXPR void on_loc_date(numeric_system)
Definition chrono.h:951
FMT_CONSTEXPR void on_24_hour(numeric_system, pad_type)
Definition chrono.h:946
FMT_CONSTEXPR void on_day_of_month(numeric_system, pad_type)
Definition chrono.h:945
FMT_NORETURN void unsupported()
Definition chrono.h:922
FMT_CONSTEXPR void on_datetime(numeric_system)
Definition chrono.h:950
FMT_CONSTEXPR void on_day_of_year(pad_type)
Definition chrono.h:944
FMT_CONSTEXPR void on_utc_offset(numeric_system)
Definition chrono.h:959
FMT_CONSTEXPR void on_dec_month(numeric_system, pad_type)
Definition chrono.h:940
FMT_CONSTEXPR void on_full_month()
Definition chrono.h:939
FMT_CONSTEXPR void on_second(numeric_system, pad_type)
Definition chrono.h:949
FMT_CONSTEXPR void on_short_year(numeric_system)
Definition chrono.h:929
FMT_CONSTEXPR void on_offset_year()
Definition chrono.h:930
FMT_CONSTEXPR void on_year(numeric_system, pad_type)
Definition chrono.h:928
FMT_CONSTEXPR void on_am_pm()
Definition chrono.h:958
FMT_CONSTEXPR void on_12_hour_time()
Definition chrono.h:955
FMT_CONSTEXPR void on_12_hour(numeric_system, pad_type)
Definition chrono.h:947
FMT_CONSTEXPR void on_dec1_weekday(numeric_system)
Definition chrono.h:937
FMT_CONSTEXPR void on_century(numeric_system)
Definition chrono.h:931
FMT_CONSTEXPR void on_minute(numeric_system, pad_type)
Definition chrono.h:948
FMT_CONSTEXPR void on_us_date()
Definition chrono.h:953
Definition chrono.h:1136
void on_offset_year()
Definition chrono.h:1414
void on_12_hour_time()
Definition chrono.h:1526
void on_dec0_week_of_year(numeric_system ns, pad_type pad)
Definition chrono.h:1443
void on_abbr_month()
Definition chrono.h:1337
void on_iso_date()
Definition chrono.h:1384
void on_iso_week_based_year()
Definition chrono.h:1466
void on_dec_month(numeric_system ns, pad_type pad)
Definition chrono.h:1437
void on_abbr_weekday()
Definition chrono.h:1312
void on_am_pm()
Definition chrono.h:1549
void on_dec0_weekday(numeric_system ns)
Definition chrono.h:1324
tm_writer(const std::locale &loc, OutputIt out, const std::tm &tm, const Duration *subsecs=nullptr)
Definition chrono.h:1298
void on_us_date()
Definition chrono.h:1377
void on_iso_time()
Definition chrono.h:1543
void on_duration_unit()
Definition chrono.h:1560
void on_24_hour_time()
Definition chrono.h:1538
void on_second(numeric_system ns, pad_type pad)
Definition chrono.h:1505
void on_full_weekday()
Definition chrono.h:1318
void on_12_hour(numeric_system ns, pad_type pad)
Definition chrono.h:1494
FMT_CONSTEXPR void on_text(const Char *begin, const Char *end)
Definition chrono.h:1308
void on_loc_time(numeric_system ns)
Definition chrono.h:1371
auto out() const -> OutputIt
Definition chrono.h:1306
void on_day_of_month(numeric_system ns, pad_type pad)
Definition chrono.h:1483
void on_tz_name()
Definition chrono.h:1402
void on_day_of_year(pad_type pad)
Definition chrono.h:1473
void on_short_year(numeric_system ns)
Definition chrono.h:1409
void on_iso_week_based_short_year()
Definition chrono.h:1469
void on_century(numeric_system ns)
Definition chrono.h:1419
void on_dec1_week_of_year(numeric_system ns, pad_type pad)
Definition chrono.h:1449
void on_minute(numeric_system ns, pad_type pad)
Definition chrono.h:1499
void on_dec1_weekday(numeric_system ns)
Definition chrono.h:1328
void on_year(numeric_system ns, pad_type pad)
Definition chrono.h:1404
void on_loc_date(numeric_system ns)
Definition chrono.h:1365
void on_full_month()
Definition chrono.h:1343
void on_utc_offset(numeric_system ns)
Definition chrono.h:1401
void on_duration_value()
Definition chrono.h:1559
void on_24_hour(numeric_system ns, pad_type pad)
Definition chrono.h:1489
void on_datetime(numeric_system ns)
Definition chrono.h:1350
void on_iso_week_of_year(numeric_system ns, pad_type pad)
Definition chrono.h:1460
Definition format.h:1273
Definition format.h:1256
auto size() const -> size_t
Definition format.h:1265
auto c_str() const -> const wchar_t *
Definition format.h:1266
Definition base.h:2146
Definition chrono.h:1953
constexpr month(unsigned m) noexcept
Definition chrono.h:1959
month()=default
Parsing context consisting of a format string range being parsed and an argument counter for automati...
Definition base.h:866
Definition chrono.h:1931
constexpr auto c_encoding() const noexcept -> unsigned
Definition chrono.h:1939
constexpr weekday(unsigned wd) noexcept
Definition chrono.h:1937
weekday()=default
Definition chrono.h:1974
constexpr auto year() const noexcept -> fmt::year
Definition chrono.h:1984
constexpr year_month_day(const year &y, const month &m, const day &d) noexcept
Definition chrono.h:1982
constexpr auto month() const noexcept -> fmt::month
Definition chrono.h:1985
year_month_day()=default
constexpr auto day() const noexcept -> fmt::day
Definition chrono.h:1986
Definition chrono.h:1964
year()=default
constexpr year(int y) noexcept
Definition chrono.h:1970
#define FMT_NOMACRO
Definition chrono.h:282
std::chrono::time_point< detail::utc_clock, Duration > utc_time
Definition chrono.h:273
std::chrono::time_point< std::chrono::system_clock, Duration > sys_time
Definition chrono.h:270
std::chrono::time_point< detail::local_t, Duration > local_time
Definition chrono.h:276
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
FMT_BEGIN_EXPORT FMT_DEPRECATED 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
#define FMT_STRING(s)
Constructs a legacy compile-time format string from a string literal s.
Definition format.h:4196
basic_memory_buffer< char > memory_buffer
Definition format.h:875
#define FMT_THROW(x)
Definition format.h:178
auto ptr(T p) -> const void *
Converts p to const void* for pointer formatting.
Definition format.h:3925
FMT_INLINE auto format(const Locale &loc, format_string< T... > fmt, T &&... args) -> std::string
Definition format.h:4252
Definition chrono.h:504
void _tzset(T...)
Definition chrono.h:517
auto current_zone(T...) -> time_zone *
Definition chrono.h:513
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:978
auto get_iterator(Buf &buf, OutputIt) -> decltype(buf.out())
Definition base.h:2109
FMT_CONSTEXPR20 auto isfinite(T value) -> bool
Definition format.h:2575
auto tm_mon_short_name(int mon) -> const char *
Definition chrono.h:985
void write_floating_seconds(memory_buffer &buf, Duration duration, int num_fractional_digits=-1)
Definition chrono.h:1109
FMT_CONSTEXPR void ignore_unused(const T &...)
Definition base.h:363
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:1425
FMT_CONSTEXPR auto get_units() -> const char *
Definition chrono.h:666
auto is_big_endian() -> bool
Definition format.h:287
FMT_CONSTEXPR auto write(OutputIt out, Char value, const format_specs &specs, locale_ref loc={}) -> OutputIt
Definition format.h:1815
pad_type
Definition chrono.h:698
bool set_tm_zone(T &time, char *tz)
Definition chrono.h:1003
auto duration_cast(std::chrono::duration< FromRep, FromPeriod > from) -> To
Definition chrono.h:437
auto localtime_s(...) -> null<>
Definition chrono.h:286
void write_fractional_seconds(OutputIt &out, Duration d, int precision=-1)
Definition chrono.h:1058
auto format_duration_unit(OutputIt out) -> OutputIt
Definition chrono.h:1663
constexpr auto max_value() -> T
Definition format.h:424
@ value
the parser finished reading a JSON value
FMT_CONSTEXPR auto to_unsigned(Int value) -> make_unsigned_t< Int >
Definition base.h:437
numeric_system
Definition chrono.h:691
auto write_encoded_tm_str(OutputIt out, string_view in, const std::locale &loc) -> OutputIt
Definition chrono.h:350
void do_write(buffer< Char > &buf, const std::tm &time, const std::locale &loc, char format, char modifier)
Definition chrono.h:395
@ use_utf8
Definition base.h:457
constexpr auto pow10(std::uint32_t n) -> long long
Definition chrono.h:1034
auto tm_wday_short_name(int wday) -> const char *
Definition chrono.h:973
auto to_time_t(sys_time< Duration > time_point) -> std::time_t
Definition chrono.h:495
auto digits2(size_t value) -> const char *
Definition format.h:992
auto get_classic_locale() -> const std::locale &
Definition chrono.h:323
FMT_CONSTEXPR auto fill_n(OutputIt out, Size count, const T &value) -> OutputIt
Definition format.h:549
auto mod(T x, int y) -> T
Definition chrono.h:1593
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:382
void tzset_once()
Definition chrono.h:521
@ 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:1416
FMT_NORETURN void throw_duration_error()
Definition chrono.h:429
auto get_milliseconds(std::chrono::duration< Rep, Period > d) -> std::chrono::duration< Rep, std::milli >
Definition chrono.h:1614
auto tm_mon_full_name(int mon) -> const char *
Definition chrono.h:979
FMT_CONSTEXPR20 auto copy(InputIt begin, InputIt end, OutputIt out) -> OutputIt
Definition base.h:2051
auto gmtime_r(...) -> null<>
Definition chrono.h:287
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:2258
char * utc()
Definition chrono.h:1012
auto to_nonnegative_int(T value, Int upper) -> Int
Definition chrono.h:1019
auto copy_unit(string_view unit, OutputIt out, Char) -> OutputIt
Definition chrono.h:1650
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:3646
std::integral_constant< bool, Value > bool_constant
Definition type_traits.h:743
auto format_duration_value(OutputIt out, Rep val, int) -> OutputIt
Definition chrono.h:1635
type
Definition base.h:958
auto write_tm_str(OutputIt out, string_view sv, const std::locale &loc) -> OutputIt
Definition chrono.h:380
auto get_buffer(OutputIt out) -> iterator_buffer< OutputIt, T >
Definition base.h:2099
auto gmtime_s(...) -> null<>
Definition chrono.h:288
FMT_CONSTEXPR20 FMT_INLINE void write2digits(Char *out, size_t value)
Definition format.h:1162
constexpr auto count() -> int
Definition base.h:1054
FMT_CONSTEXPR20 auto count_digits(uint64_t n) -> int
Definition format.h:1052
auto tm_wday_full_name(int wday) -> const char *
Definition chrono.h:967
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:1197
void write_codecvt(codecvt_result< CodeUnit > &out, string_view in, const std::locale &loc)
Definition chrono.h:335
constexpr auto isnan(T value) -> bool
Definition format.h:2562
bool_constant<(std::is_integral< T >::value &&std::is_integral< U >::value)||(std::is_floating_point< T >::value && std::is_floating_point< U >::value)> is_similar_arithmetic_type
Definition chrono.h:424
Definition PointerIntPair.h:280
Definition chrono.h:1563
FMT_CONSTEXPR void on_duration_value() const
Definition chrono.h:1579
FMT_CONSTEXPR void on_day_of_year(pad_type)
Definition chrono.h:1570
FMT_CONSTEXPR void on_24_hour(numeric_system, pad_type)
Definition chrono.h:1571
FMT_CONSTEXPR void on_12_hour_time()
Definition chrono.h:1575
FMT_CONSTEXPR void on_text(const Char *, const Char *)
Definition chrono.h:1569
FMT_CONSTEXPR void on_duration_unit()
Definition chrono.h:1583
FMT_CONSTEXPR void on_iso_time()
Definition chrono.h:1577
FMT_CONSTEXPR void on_minute(numeric_system, pad_type)
Definition chrono.h:1573
bool has_precision_integral
Definition chrono.h:1564
FMT_CONSTEXPR void on_24_hour_time()
Definition chrono.h:1576
FMT_CONSTEXPR void on_12_hour(numeric_system, pad_type)
Definition chrono.h:1572
FMT_CONSTEXPR void on_am_pm()
Definition chrono.h:1578
FMT_NORETURN void unsupported()
Definition chrono.h:1566
FMT_CONSTEXPR void on_second(numeric_system, pad_type)
Definition chrono.h:1574
Definition chrono.h:328
CodeUnit * end
Definition chrono.h:331
static constexpr size_t max_size
Definition chrono.h:329
CodeUnit buf[max_size]
Definition chrono.h:330
Definition chrono.h:1043
Definition chrono.h:1698
void on_dec0_weekday(numeric_system)
Definition chrono.h:1804
void write(Rep value, int width, pad_type pad=pad_type::zero)
Definition chrono.h:1774
void on_datetime(numeric_system)
Definition chrono.h:1808
void write_nan()
Definition chrono.h:1786
void on_duration_unit()
Definition chrono.h:1918
void on_day_of_month(numeric_system, pad_type)
Definition chrono.h:1825
void on_day_of_year(pad_type)
Definition chrono.h:1827
void on_loc_time(numeric_system)
Definition chrono.h:1810
void on_tz_name()
Definition chrono.h:1814
void on_am_pm()
Definition chrono.h:1907
void on_24_hour_time()
Definition chrono.h:1888
auto minute() const -> Rep
Definition chrono.h:1755
void on_loc_date(numeric_system)
Definition chrono.h:1809
tm_writer< iterator, Char > tm_writer_type
Definition chrono.h:1714
auto time() const -> std::tm
Definition chrono.h:1760
void on_second(numeric_system ns, pad_type pad)
Definition chrono.h:1859
void on_full_month()
Definition chrono.h:1807
void format_tm(const tm &time, Callback cb, Args... args)
Definition chrono.h:1789
duration_formatter(iterator o, std::chrono::duration< Rep, Period > d, locale_ref loc)
Definition chrono.h:1716
void on_dec_month(numeric_system, pad_type)
Definition chrono.h:1821
void on_year(numeric_system, pad_type)
Definition chrono.h:1815
auto second() const -> Rep
Definition chrono.h:1758
void on_iso_time()
Definition chrono.h:1900
void on_12_hour(numeric_system ns, pad_type pad)
Definition chrono.h:1841
bool localized
Definition chrono.h:1708
conditional_t< std::is_integral< Rep >::value &&sizeof(Rep)< sizeof(int), unsigned, typename make_unsigned_or_unchanged< Rep >::type > rep
Definition chrono.h:1702
void on_century(numeric_system)
Definition chrono.h:1818
void on_iso_date()
Definition chrono.h:1812
auto hour() const -> Rep
Definition chrono.h:1746
std::chrono::duration< rep, std::milli > milliseconds
Definition chrono.h:1711
void on_text(const Char *begin, const Char *end)
Definition chrono.h:1797
iterator out
Definition chrono.h:1700
void on_abbr_month()
Definition chrono.h:1806
void on_dec1_weekday(numeric_system)
Definition chrono.h:1805
void write_sign()
Definition chrono.h:1768
void on_dec0_week_of_year(numeric_system, pad_type)
Definition chrono.h:1822
void on_minute(numeric_system ns, pad_type pad)
Definition chrono.h:1850
int precision
Definition chrono.h:1706
void on_short_year(numeric_system)
Definition chrono.h:1816
auto hour12() const -> Rep
Definition chrono.h:1750
seconds s
Definition chrono.h:1710
locale_ref locale
Definition chrono.h:1707
void on_duration_value()
Definition chrono.h:1912
void on_dec1_week_of_year(numeric_system, pad_type)
Definition chrono.h:1823
auto days() const -> Rep
Definition chrono.h:1745
rep val
Definition chrono.h:1705
bool negative
Definition chrono.h:1712
void on_us_date()
Definition chrono.h:1811
void on_iso_week_of_year(numeric_system, pad_type)
Definition chrono.h:1824
auto handle_nan_inf() -> bool
Definition chrono.h:1731
void on_12_hour_time()
Definition chrono.h:1883
void on_24_hour(numeric_system ns, pad_type pad)
Definition chrono.h:1832
void on_iso_week_based_short_year()
Definition chrono.h:1820
void on_abbr_weekday()
Definition chrono.h:1802
std::chrono::duration< rep > seconds
Definition chrono.h:1709
void on_utc_offset(numeric_system)
Definition chrono.h:1813
void on_full_weekday()
Definition chrono.h:1803
void on_iso_week_based_year()
Definition chrono.h:1819
void on_offset_year()
Definition chrono.h:1817
Definition format.h:2567
Definition chrono.h:994
Definition chrono.h:998
Definition chrono.h:264
Definition format-inl.h:92
typename std::make_unsigned< T >::type type
Definition chrono.h:1609
Definition chrono.h:1604
T type
Definition chrono.h:1605
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:284
Definition format.h:264
Definition chrono.h:507
auto to_sys(LocalTime) -> sys_time< Duration >
Definition chrono.h:509
Definition chrono.h:248
Definition base.h:855
FMT_CONSTEXPR auto parse(parse_context< Char > &ctx) -> const Char *
Definition chrono.h:2024
auto format(day d, FormatContext &ctx) const -> decltype(ctx.out())
Definition chrono.h:2031
auto format(local_time< Duration > val, FormatContext &ctx) const -> decltype(ctx.out())
Definition chrono.h:2308
FMT_CONSTEXPR auto parse(parse_context< Char > &ctx) -> const Char *
Definition chrono.h:2303
auto format(month m, FormatContext &ctx) const -> decltype(ctx.out())
Definition chrono.h:2059
FMT_CONSTEXPR auto parse(parse_context< Char > &ctx) -> const Char *
Definition chrono.h:2048
auto format(std::chrono::duration< Rep, Period > d, FormatContext &ctx) const -> decltype(ctx.out())
Definition chrono.h:2158
FMT_CONSTEXPR auto parse(parse_context< Char > &ctx) -> const Char *
Definition chrono.h:2130
auto format(const std::tm &tm, FormatContext &ctx) const -> decltype(ctx.out())
Definition chrono.h:2248
FMT_CONSTEXPR auto do_parse(parse_context< Char > &ctx, bool has_timezone) -> const Char *
Definition chrono.h:2198
auto do_format(const std::tm &tm, FormatContext &ctx, const Duration *subsecs) const -> decltype(ctx.out())
Definition chrono.h:2225
FMT_CONSTEXPR void set_localized()
Definition chrono.h:2196
FMT_CONSTEXPR auto parse(parse_context< Char > &ctx) -> const Char *
Definition chrono.h:2243
auto localized() const -> bool
Definition chrono.h:2195
auto format(sys_time< Duration > val, FormatContext &ctx) const -> decltype(ctx.out())
Definition chrono.h:2262
FMT_CONSTEXPR auto parse(parse_context< Char > &ctx) -> const Char *
Definition chrono.h:2257
auto format(utc_time< Duration > val, FormatContext &ctx) const -> decltype(ctx.out())
Definition chrono.h:2293
FMT_CONSTEXPR auto parse(parse_context< Char > &ctx) -> const Char *
Definition chrono.h:1996
auto format(weekday wd, FormatContext &ctx) const -> decltype(ctx.out())
Definition chrono.h:2007
auto format(year y, FormatContext &ctx) const -> decltype(ctx.out())
Definition chrono.h:2083
FMT_CONSTEXPR auto parse(parse_context< Char > &ctx) -> const Char *
Definition chrono.h:2076
FMT_CONSTEXPR auto parse(parse_context< Char > &ctx) -> const Char *
Definition chrono.h:2100
auto format(year_month_day val, FormatContext &ctx) const -> decltype(ctx.out())
Definition chrono.h:2107
Definition base.h:664
Definition base.h:1262
#define FMT_ASSERT(condition, message)
Definition base.h:396
#define FMT_END_EXPORT
Definition base.h:272
#define FMT_PRAGMA_CLANG(x)
Definition base.h:230
basic_string_view< char > string_view
Definition base.h:616
constexpr auto min_of(T a, T b) -> T
Definition base.h:352
#define FMT_CONSTEXPR
Definition base.h:113
#define FMT_BEGIN_NAMESPACE
Definition base.h:261
#define FMT_ENABLE_IF(...)
Definition base.h:349
#define FMT_BEGIN_EXPORT
Definition base.h:271
std::is_constructible< formatter< T, Char > > FMT_DEPRECATED
Definition base.h:2801
#define FMT_NORETURN
Definition base.h:193
typename std::conditional< B, T, F >::type conditional_t
Definition base.h:314
#define FMT_END_NAMESPACE
Definition base.h:264