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