WPILibC++ 2027.0.0-alpha-4
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 {
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).
612 // Do not pad a numeric result string.
614 // Pad a numeric result string with spaces.
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) return;
1598 ignore_unused(loc);
1599 ::new (&locale_) std::locale(
1601 loc.template get<std::locale>()
1602#endif
1603 );
1604 }
1605 inline ~get_locale() {
1606 if (has_locale_) locale_.~locale();
1607 }
1608 inline operator const std::locale&() const {
1609 return has_locale_ ? locale_ : get_classic_locale();
1610 }
1611};
1612
1613template <typename Char, typename Rep, typename Period>
1617 // rep is unsigned to avoid overflow.
1618 using rep =
1619 conditional_t<std::is_integral<Rep>::value && sizeof(Rep) < sizeof(int),
1620 unsigned, typename make_unsigned_or_unchanged<Rep>::type>;
1624 bool localized = false;
1625 using seconds = std::chrono::duration<rep>;
1627 using milliseconds = std::chrono::duration<rep, std::milli>;
1629
1631
1632 duration_formatter(iterator o, std::chrono::duration<Rep, Period> d,
1633 locale_ref loc)
1634 : out(o), val(static_cast<rep>(d.count())), locale(loc), negative(false) {
1635 if (d.count() < 0) {
1636 val = 0 - val;
1637 negative = true;
1638 }
1639
1640 // this may overflow and/or the result may not fit in the
1641 // target type.
1642 // might need checked conversion (rep!=Rep)
1643 s = detail::duration_cast<seconds>(std::chrono::duration<rep, Period>(val));
1644 }
1645
1646 // returns true if nan or inf, writes to out.
1647 auto handle_nan_inf() -> bool {
1648 if (isfinite(val)) return false;
1649 if (isnan(val)) {
1650 write_nan();
1651 return true;
1652 }
1653 // must be +-inf
1654 if (val > 0)
1655 std::copy_n("inf", 3, out);
1656 else
1657 std::copy_n("-inf", 4, out);
1658 return true;
1659 }
1660
1661 auto days() const -> Rep { return static_cast<Rep>(s.count() / 86400); }
1662 auto hour() const -> Rep {
1663 return static_cast<Rep>(mod((s.count() / 3600), 24));
1664 }
1665
1666 auto hour12() const -> Rep {
1667 Rep hour = static_cast<Rep>(mod((s.count() / 3600), 12));
1668 return hour <= 0 ? 12 : hour;
1669 }
1670
1671 auto minute() const -> Rep {
1672 return static_cast<Rep>(mod((s.count() / 60), 60));
1673 }
1674 auto second() const -> Rep { return static_cast<Rep>(mod(s.count(), 60)); }
1675
1676 auto time() const -> std::tm {
1677 auto time = std::tm();
1678 time.tm_hour = to_nonnegative_int(hour(), 24);
1679 time.tm_min = to_nonnegative_int(minute(), 60);
1680 time.tm_sec = to_nonnegative_int(second(), 60);
1681 return time;
1682 }
1683
1684 void write_sign() {
1685 if (!negative) return;
1686 *out++ = '-';
1687 negative = false;
1688 }
1689
1690 void write(Rep value, int width, pad_type pad = pad_type::zero) {
1691 write_sign();
1692 if (isnan(value)) return write_nan();
1695 int num_digits = detail::count_digits(n);
1696 if (width > num_digits) {
1697 out = detail::write_padding(out, pad, width - num_digits);
1698 }
1699 out = format_decimal<Char>(out, n, num_digits);
1700 }
1701
1702 void write_nan() { std::copy_n("nan", 3, out); }
1703
1704 template <typename Callback, typename... Args>
1705 void format_tm(const tm& time, Callback cb, Args... args) {
1706 if (isnan(val)) return write_nan();
1708 auto w = tm_writer_type(loc, out, time);
1709 (w.*cb)(args...);
1710 out = w.out();
1711 }
1712
1713 void on_text(const Char* begin, const Char* end) {
1714 copy<Char>(begin, end, out);
1715 }
1716
1717 // These are not implemented because durations don't have date information.
1727 void on_us_date() {}
1728 void on_iso_date() {}
1730 void on_tz_name() {}
1742
1744 if (handle_nan_inf()) return;
1745 write(days(), 0);
1746 }
1747
1749 if (handle_nan_inf()) return;
1750
1751 if (ns == numeric_system::standard) return write(hour(), 2, pad);
1752 auto time = tm();
1753 time.tm_hour = to_nonnegative_int(hour(), 24);
1755 }
1756
1758 if (handle_nan_inf()) return;
1759
1760 if (ns == numeric_system::standard) return write(hour12(), 2, pad);
1761 auto time = tm();
1762 time.tm_hour = to_nonnegative_int(hour12(), 12);
1764 }
1765
1767 if (handle_nan_inf()) return;
1768
1769 if (ns == numeric_system::standard) return write(minute(), 2, pad);
1770 auto time = tm();
1771 time.tm_min = to_nonnegative_int(minute(), 60);
1773 }
1774
1776 if (handle_nan_inf()) return;
1777
1778 if (ns == numeric_system::standard) {
1779 if (std::is_floating_point<rep>::value) {
1780 auto buf = memory_buffer();
1781 write_floating_seconds(buf, std::chrono::duration<rep, Period>(val),
1782 precision);
1783 if (negative) *out++ = '-';
1784 if (buf.size() < 2 || buf[1] == '.')
1786 out = copy<Char>(buf.begin(), buf.end(), out);
1787 } else {
1788 write(second(), 2, pad);
1790 out, std::chrono::duration<rep, Period>(val), precision);
1791 }
1792 return;
1793 }
1794 auto time = tm();
1795 time.tm_sec = to_nonnegative_int(second(), 60);
1797 }
1798
1800 if (handle_nan_inf()) return;
1802 }
1803
1805 if (handle_nan_inf()) {
1806 *out++ = ':';
1808 return;
1809 }
1810
1811 write(hour(), 2);
1812 *out++ = ':';
1813 write(minute(), 2);
1814 }
1815
1818 *out++ = ':';
1819 if (handle_nan_inf()) return;
1821 }
1822
1823 void on_am_pm() {
1824 if (handle_nan_inf()) return;
1826 }
1827
1829 if (handle_nan_inf()) return;
1830 write_sign();
1832 }
1833
1835};
1836
1837} // namespace detail
1838
1839#if defined(__cpp_lib_chrono) && __cpp_lib_chrono >= 201907
1840using weekday = std::chrono::weekday;
1841using day = std::chrono::day;
1842using month = std::chrono::month;
1843using year = std::chrono::year;
1844using year_month_day = std::chrono::year_month_day;
1845#else
1846// A fallback version of weekday.
1847class weekday {
1848 private:
1849 unsigned char value_;
1850
1851 public:
1852 weekday() = default;
1853 constexpr explicit weekday(unsigned wd) noexcept
1854 : value_(static_cast<unsigned char>(wd != 7 ? wd : 0)) {}
1855 constexpr auto c_encoding() const noexcept -> unsigned { return value_; }
1856};
1857
1858class day {
1859 private:
1860 unsigned char value_;
1861
1862 public:
1863 day() = default;
1864 constexpr explicit day(unsigned d) noexcept
1865 : value_(static_cast<unsigned char>(d)) {}
1866 constexpr explicit operator unsigned() const noexcept { return value_; }
1867};
1868
1869class month {
1870 private:
1871 unsigned char value_;
1872
1873 public:
1874 month() = default;
1875 constexpr explicit month(unsigned m) noexcept
1876 : value_(static_cast<unsigned char>(m)) {}
1877 constexpr explicit operator unsigned() const noexcept { return value_; }
1878};
1879
1880class year {
1881 private:
1882 int value_;
1883
1884 public:
1885 year() = default;
1886 constexpr explicit year(int y) noexcept : value_(y) {}
1887 constexpr explicit operator int() const noexcept { return value_; }
1888};
1889
1891 private:
1892 fmt::year year_;
1893 fmt::month month_;
1894 fmt::day day_;
1895
1896 public:
1897 year_month_day() = default;
1898 constexpr year_month_day(const year& y, const month& m, const day& d) noexcept
1899 : year_(y), month_(m), day_(d) {}
1900 constexpr auto year() const noexcept -> fmt::year { return year_; }
1901 constexpr auto month() const noexcept -> fmt::month { return month_; }
1902 constexpr auto day() const noexcept -> fmt::day { return day_; }
1903};
1904#endif // __cpp_lib_chrono >= 201907
1905
1906template <typename Char>
1907struct formatter<weekday, Char> : private formatter<std::tm, Char> {
1908 private:
1909 bool use_tm_formatter_ = false;
1910
1911 public:
1912 FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
1913 auto it = ctx.begin(), end = ctx.end();
1914 if (it != end && *it == 'L') {
1915 ++it;
1916 this->set_localized();
1917 }
1918 use_tm_formatter_ = it != end && *it != '}';
1919 return use_tm_formatter_ ? formatter<std::tm, Char>::parse(ctx) : it;
1920 }
1921
1922 template <typename FormatContext>
1923 auto format(weekday wd, FormatContext& ctx) const -> decltype(ctx.out()) {
1924 auto time = std::tm();
1925 time.tm_wday = static_cast<int>(wd.c_encoding());
1926 if (use_tm_formatter_) return formatter<std::tm, Char>::format(time, ctx);
1927 detail::get_locale loc(this->localized(), ctx.locale());
1928 auto w = detail::tm_writer<decltype(ctx.out()), Char>(loc, ctx.out(), time);
1929 w.on_abbr_weekday();
1930 return w.out();
1931 }
1932};
1933
1934template <typename Char>
1935struct formatter<day, Char> : private formatter<std::tm, Char> {
1936 private:
1937 bool use_tm_formatter_ = false;
1938
1939 public:
1940 FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
1941 auto it = ctx.begin(), end = ctx.end();
1942 use_tm_formatter_ = it != end && *it != '}';
1943 return use_tm_formatter_ ? formatter<std::tm, Char>::parse(ctx) : it;
1944 }
1945
1946 template <typename FormatContext>
1947 auto format(day d, FormatContext& ctx) const -> decltype(ctx.out()) {
1948 auto time = std::tm();
1949 time.tm_mday = static_cast<int>(static_cast<unsigned>(d));
1950 if (use_tm_formatter_) return formatter<std::tm, Char>::format(time, ctx);
1951 detail::get_locale loc(false, ctx.locale());
1952 auto w = detail::tm_writer<decltype(ctx.out()), Char>(loc, ctx.out(), time);
1954 return w.out();
1955 }
1956};
1957
1958template <typename Char>
1959struct formatter<month, Char> : private formatter<std::tm, Char> {
1960 private:
1961 bool use_tm_formatter_ = false;
1962
1963 public:
1964 FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
1965 auto it = ctx.begin(), end = ctx.end();
1966 if (it != end && *it == 'L') {
1967 ++it;
1968 this->set_localized();
1969 }
1970 use_tm_formatter_ = it != end && *it != '}';
1971 return use_tm_formatter_ ? formatter<std::tm, Char>::parse(ctx) : it;
1972 }
1973
1974 template <typename FormatContext>
1975 auto format(month m, FormatContext& ctx) const -> decltype(ctx.out()) {
1976 auto time = std::tm();
1977 time.tm_mon = static_cast<int>(static_cast<unsigned>(m)) - 1;
1978 if (use_tm_formatter_) return formatter<std::tm, Char>::format(time, ctx);
1979 detail::get_locale loc(this->localized(), ctx.locale());
1980 auto w = detail::tm_writer<decltype(ctx.out()), Char>(loc, ctx.out(), time);
1981 w.on_abbr_month();
1982 return w.out();
1983 }
1984};
1985
1986template <typename Char>
1987struct formatter<year, Char> : private formatter<std::tm, Char> {
1988 private:
1989 bool use_tm_formatter_ = false;
1990
1991 public:
1992 FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
1993 auto it = ctx.begin(), end = ctx.end();
1994 use_tm_formatter_ = it != end && *it != '}';
1995 return use_tm_formatter_ ? formatter<std::tm, Char>::parse(ctx) : it;
1996 }
1997
1998 template <typename FormatContext>
1999 auto format(year y, FormatContext& ctx) const -> decltype(ctx.out()) {
2000 auto time = std::tm();
2001 time.tm_year = static_cast<int>(y) - 1900;
2002 if (use_tm_formatter_) return formatter<std::tm, Char>::format(time, ctx);
2003 detail::get_locale loc(false, ctx.locale());
2004 auto w = detail::tm_writer<decltype(ctx.out()), Char>(loc, ctx.out(), time);
2006 return w.out();
2007 }
2008};
2009
2010template <typename Char>
2011struct formatter<year_month_day, Char> : private formatter<std::tm, Char> {
2012 private:
2013 bool use_tm_formatter_ = false;
2014
2015 public:
2016 FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
2017 auto it = ctx.begin(), end = ctx.end();
2018 use_tm_formatter_ = it != end && *it != '}';
2019 return use_tm_formatter_ ? formatter<std::tm, Char>::parse(ctx) : it;
2020 }
2021
2022 template <typename FormatContext>
2023 auto format(year_month_day val, FormatContext& ctx) const
2024 -> decltype(ctx.out()) {
2025 auto time = std::tm();
2026 time.tm_year = static_cast<int>(val.year()) - 1900;
2027 time.tm_mon = static_cast<int>(static_cast<unsigned>(val.month())) - 1;
2028 time.tm_mday = static_cast<int>(static_cast<unsigned>(val.day()));
2029 if (use_tm_formatter_) return formatter<std::tm, Char>::format(time, ctx);
2030 detail::get_locale loc(true, ctx.locale());
2031 auto w = detail::tm_writer<decltype(ctx.out()), Char>(loc, ctx.out(), time);
2032 w.on_iso_date();
2033 return w.out();
2034 }
2035};
2036
2037template <typename Rep, typename Period, typename Char>
2038struct formatter<std::chrono::duration<Rep, Period>, Char> {
2039 private:
2040 format_specs specs_;
2041 detail::arg_ref<Char> width_ref_;
2042 detail::arg_ref<Char> precision_ref_;
2044
2045 public:
2046 FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
2047 auto it = ctx.begin(), end = ctx.end();
2048 if (it == end || *it == '}') return it;
2049
2050 it = detail::parse_align(it, end, specs_);
2051 if (it == end) return it;
2052
2053 Char c = *it;
2054 if ((c >= '0' && c <= '9') || c == '{') {
2055 it = detail::parse_width(it, end, specs_, width_ref_, ctx);
2056 if (it == end) return it;
2057 }
2058
2059 auto checker = detail::chrono_format_checker();
2060 if (*it == '.') {
2061 checker.has_precision_integral = !std::is_floating_point<Rep>::value;
2062 it = detail::parse_precision(it, end, specs_, precision_ref_, ctx);
2063 }
2064 if (it != end && *it == 'L') {
2065 specs_.set_localized();
2066 ++it;
2067 }
2068 end = detail::parse_chrono_format(it, end, checker);
2069 fmt_ = {it, detail::to_unsigned(end - it)};
2070 return end;
2071 }
2072
2073 template <typename FormatContext>
2074 auto format(std::chrono::duration<Rep, Period> d, FormatContext& ctx) const
2075 -> decltype(ctx.out()) {
2076 auto specs = specs_;
2077 auto precision = specs.precision;
2078 specs.precision = -1;
2079 auto begin = fmt_.begin(), end = fmt_.end();
2080 // As a possible future optimization, we could avoid extra copying if width
2081 // is not specified.
2082 auto buf = basic_memory_buffer<Char>();
2083 auto out = basic_appender<Char>(buf);
2084 detail::handle_dynamic_spec(specs.dynamic_width(), specs.width, width_ref_,
2085 ctx);
2086 detail::handle_dynamic_spec(specs.dynamic_precision(), precision,
2087 precision_ref_, ctx);
2088 if (begin == end || *begin == '}') {
2089 out = detail::format_duration_value<Char>(out, d.count(), precision);
2091 } else {
2092 auto f =
2094 f.precision = precision;
2095 f.localized = specs_.localized();
2096 detail::parse_chrono_format(begin, end, f);
2097 }
2098 return detail::write(
2099 ctx.out(), basic_string_view<Char>(buf.data(), buf.size()), specs);
2100 }
2101};
2102
2103template <typename Char> struct formatter<std::tm, Char> {
2104 private:
2105 format_specs specs_;
2106 detail::arg_ref<Char> width_ref_;
2109
2110 protected:
2111 auto localized() const -> bool { return specs_.localized(); }
2112 FMT_CONSTEXPR void set_localized() { specs_.set_localized(); }
2113
2114 FMT_CONSTEXPR auto do_parse(parse_context<Char>& ctx, bool has_timezone)
2115 -> const Char* {
2116 auto it = ctx.begin(), end = ctx.end();
2117 if (it == end || *it == '}') return it;
2118
2119 it = detail::parse_align(it, end, specs_);
2120 if (it == end) return it;
2121
2122 Char c = *it;
2123 if ((c >= '0' && c <= '9') || c == '{') {
2124 it = detail::parse_width(it, end, specs_, width_ref_, ctx);
2125 if (it == end) return it;
2126 }
2127
2128 if (*it == 'L') {
2129 specs_.set_localized();
2130 ++it;
2131 }
2132
2133 end = detail::parse_chrono_format(it, end,
2134 detail::tm_format_checker(has_timezone));
2135 // Replace the default format string only if the new spec is not empty.
2136 if (end != it) fmt_ = {it, detail::to_unsigned(end - it)};
2137 return end;
2138 }
2139
2140 template <typename Duration, typename FormatContext>
2141 auto do_format(const std::tm& tm, FormatContext& ctx,
2142 const Duration* subsecs) const -> decltype(ctx.out()) {
2143 auto specs = specs_;
2144 auto buf = basic_memory_buffer<Char>();
2145 auto out = basic_appender<Char>(buf);
2146 detail::handle_dynamic_spec(specs.dynamic_width(), specs.width, width_ref_,
2147 ctx);
2148
2149 auto loc_ref = specs.localized() ? ctx.locale() : locale_ref();
2150 detail::get_locale loc(static_cast<bool>(loc_ref), loc_ref);
2151 auto w = detail::tm_writer<basic_appender<Char>, Char, Duration>(
2152 loc, out, tm, subsecs);
2153 detail::parse_chrono_format(fmt_.begin(), fmt_.end(), w);
2154 return detail::write(
2155 ctx.out(), basic_string_view<Char>(buf.data(), buf.size()), specs);
2156 }
2157
2158 public:
2159 FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
2161 }
2162
2163 template <typename FormatContext>
2164 auto format(const std::tm& tm, FormatContext& ctx) const
2165 -> decltype(ctx.out()) {
2166 return do_format<std::chrono::seconds>(tm, ctx, nullptr);
2167 }
2168};
2169
2170// DEPRECATED! Reversed order of template parameters.
2171template <typename Char, typename Duration>
2172struct formatter<sys_time<Duration>, Char> : private formatter<std::tm, Char> {
2173 FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
2174 return this->do_parse(ctx, true);
2175 }
2176
2177 template <typename FormatContext>
2178 auto format(sys_time<Duration> val, FormatContext& ctx) const
2179 -> decltype(ctx.out()) {
2180 std::tm tm = gmtime(val);
2181 using period = typename Duration::period;
2183 period::num == 1 && period::den == 1 &&
2184 !std::is_floating_point<typename Duration::rep>::value)) {
2186 return formatter<std::tm, Char>::format(tm, ctx);
2187 }
2188 Duration epoch = val.time_since_epoch();
2189 Duration subsecs = detail::duration_cast<Duration>(
2191 if (subsecs.count() < 0) {
2192 auto second = detail::duration_cast<Duration>(std::chrono::seconds(1));
2193 if (tm.tm_sec != 0) {
2194 --tm.tm_sec;
2195 } else {
2196 tm = gmtime(val - second);
2198 }
2199 subsecs += second;
2200 }
2201 return formatter<std::tm, Char>::do_format(tm, ctx, &subsecs);
2202 }
2203};
2204
2205template <typename Duration, typename Char>
2206struct formatter<utc_time<Duration>, Char>
2207 : formatter<sys_time<Duration>, Char> {
2208 template <typename FormatContext>
2209 auto format(utc_time<Duration> val, FormatContext& ctx) const
2210 -> decltype(ctx.out()) {
2212 detail::utc_clock::to_sys(val), ctx);
2213 }
2214};
2215
2216template <typename Duration, typename Char>
2217struct formatter<local_time<Duration>, Char>
2218 : private formatter<std::tm, Char> {
2219 FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
2220 return this->do_parse(ctx, false);
2221 }
2222
2223 template <typename FormatContext>
2224 auto format(local_time<Duration> val, FormatContext& ctx) const
2225 -> decltype(ctx.out()) {
2226 auto time_since_epoch = val.time_since_epoch();
2227 auto seconds_since_epoch =
2229 // Use gmtime to prevent time zone conversion since local_time has an
2230 // unspecified time zone.
2231 std::tm t = gmtime(seconds_since_epoch.count());
2232 using period = typename Duration::period;
2233 if (period::num == 1 && period::den == 1 &&
2234 !std::is_floating_point<typename Duration::rep>::value) {
2235 return formatter<std::tm, Char>::format(t, ctx);
2236 }
2237 auto subsecs =
2238 detail::duration_cast<Duration>(time_since_epoch - seconds_since_epoch);
2239 return formatter<std::tm, Char>::do_format(t, ctx, &subsecs);
2240 }
2241};
2242
2245
2246#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
constexpr T & get(wpi::util::array< T, N > &arr) noexcept
Definition array.hpp:66
#define FMT_ASSERT(condition, message)
Definition base.h:394
#define FMT_END_EXPORT
Definition base.h:267
std::integral_constant< bool, B > bool_constant
Definition base.h:310
#define FMT_PRAGMA_CLANG(x)
Definition base.h:224
basic_string_view< char > string_view
Definition base.h:620
constexpr auto min_of(T a, T b) -> T
Definition base.h:347
#define FMT_USE_LOCALE
Definition base.h:915
#define FMT_CONSTEXPR
Definition base.h:113
#define FMT_BEGIN_NAMESPACE
Definition base.h:256
#define FMT_ENABLE_IF(...)
Definition base.h:344
#define FMT_BEGIN_EXPORT
Definition base.h:266
void void_t
Definition base.h:331
#define FMT_NORETURN
Definition base.h:195
typename std::conditional< B, T, F >::type conditional_t
Definition base.h:309
@ general
Definition base.h:684
@ fixed
Definition base.h:683
#define FMT_END_NAMESPACE
Definition base.h:259
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
Definition base.h:2484
A dynamically growing memory buffer for trivially copyable/constructible types with the first SIZE el...
Definition format.h:797
An implementation of std::basic_string_view for pre-C++17.
Definition base.h:522
Definition chrono.h:1858
day()=default
constexpr day(unsigned d) noexcept
Definition chrono.h:1864
A contiguous memory buffer with an optional growing ability.
Definition base.h:1773
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:1605
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 -> iterator
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:1317
Definition format.h:1300
auto size() const -> size_t
Definition format.h:1309
auto c_str() const -> const wchar_t *
Definition format.h:1310
Definition base.h:2178
Definition base.h:919
Definition chrono.h:1869
constexpr month(unsigned m) noexcept
Definition chrono.h:1875
month()=default
Parsing context consisting of a format string range being parsed and an argument counter for automati...
Definition base.h:857
Definition chrono.h:1847
constexpr auto c_encoding() const noexcept -> unsigned
Definition chrono.h:1855
constexpr weekday(unsigned wd) noexcept
Definition chrono.h:1853
weekday()=default
Definition chrono.h:1890
constexpr auto year() const noexcept -> fmt::year
Definition chrono.h:1900
constexpr year_month_day(const year &y, const month &m, const day &d) noexcept
Definition chrono.h:1898
constexpr auto month() const noexcept -> fmt::month
Definition chrono.h:1901
year_month_day()=default
constexpr auto day() const noexcept -> fmt::day
Definition chrono.h:1902
Definition chrono.h:1880
year()=default
constexpr year(int y) noexcept
Definition chrono.h:1886
#define FMT_STRING(s)
Constructs a legacy compile-time format string from a string literal s.
Definition format.h:4251
FMT_INLINE auto format(locale_ref loc, format_string< T... > fmt, T &&... args) -> std::string
Definition format.h:4305
basic_memory_buffer< char > memory_buffer
Definition format.h:919
#define FMT_THROW(x)
Definition format.h:177
auto ptr(T p) -> const void *
Converts p to const void* for pointer formatting.
Definition format.h:3975
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:1022
auto get_iterator(Buf &buf, OutputIt) -> decltype(buf.out())
Definition base.h:2141
FMT_CONSTEXPR20 auto isfinite(T value) -> bool
Definition format.h:2629
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 void ignore_unused(const T &...)
Definition base.h:361
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:1452
FMT_CONSTEXPR auto get_units() -> const char *
Definition chrono.h:577
auto is_big_endian() -> bool
Definition format.h:290
pad_type
Definition chrono.h:609
@ none
Definition chrono.h:613
@ zero
Definition chrono.h:611
@ space
Definition chrono.h:615
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:427
FMT_CONSTEXPR auto to_unsigned(Int value) -> make_unsigned_t< Int >
Definition base.h:439
numeric_system
Definition chrono.h:602
@ alternative
Definition chrono.h:605
@ standard
Definition chrono.h:603
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 in(type t, int set) -> bool
Definition base.h:1040
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:1036
@ use_utf8
Definition base.h:459
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:557
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:380
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:1443
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:2083
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:2312
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:3712
auto format_duration_value(OutputIt out, Rep val, int) -> OutputIt
Definition chrono.h:1546
@ precision
Definition base.h:1467
@ width
Definition base.h:1467
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:2137
type
Definition base.h:985
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:2131
auto gmtime_s(...) -> null<>
Definition chrono.h:276
FMT_CONSTEXPR20 FMT_INLINE void write2digits(Char *out, size_t value)
Definition format.h:1206
constexpr auto count() -> int
Definition base.h:1081
FMT_CONSTEXPR20 auto count_digits(uint64_t n) -> int
Definition format.h:1096
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:1241
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:2616
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 StringMap.hpp:773
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
static constexpr int value
Definition chrono.h:963
Definition chrono.h:954
static constexpr int value
Definition chrono.h:955
Definition chrono.h:1614
void on_dec0_weekday(numeric_system)
Definition chrono.h:1720
void write(Rep value, int width, pad_type pad=pad_type::zero)
Definition chrono.h:1690
void on_datetime(numeric_system)
Definition chrono.h:1724
void write_nan()
Definition chrono.h:1702
void on_duration_unit()
Definition chrono.h:1834
void on_day_of_month(numeric_system, pad_type)
Definition chrono.h:1741
void on_day_of_year(pad_type)
Definition chrono.h:1743
void on_loc_time(numeric_system)
Definition chrono.h:1726
void on_tz_name()
Definition chrono.h:1730
void on_am_pm()
Definition chrono.h:1823
void on_24_hour_time()
Definition chrono.h:1804
auto minute() const -> Rep
Definition chrono.h:1671
void on_loc_date(numeric_system)
Definition chrono.h:1725
basic_appender< Char > iterator
Definition chrono.h:1615
tm_writer< iterator, Char > tm_writer_type
Definition chrono.h:1630
auto time() const -> std::tm
Definition chrono.h:1676
void on_second(numeric_system ns, pad_type pad)
Definition chrono.h:1775
void on_full_month()
Definition chrono.h:1723
void format_tm(const tm &time, Callback cb, Args... args)
Definition chrono.h:1705
duration_formatter(iterator o, std::chrono::duration< Rep, Period > d, locale_ref loc)
Definition chrono.h:1632
void on_dec_month(numeric_system, pad_type)
Definition chrono.h:1737
void on_year(numeric_system, pad_type)
Definition chrono.h:1731
auto second() const -> Rep
Definition chrono.h:1674
void on_iso_time()
Definition chrono.h:1816
void on_12_hour(numeric_system ns, pad_type pad)
Definition chrono.h:1757
bool localized
Definition chrono.h:1624
conditional_t< std::is_integral< Rep >::value &&sizeof(Rep)< sizeof(int), unsigned, typename make_unsigned_or_unchanged< Rep >::type > rep
Definition chrono.h:1618
void on_century(numeric_system)
Definition chrono.h:1734
void on_iso_date()
Definition chrono.h:1728
auto hour() const -> Rep
Definition chrono.h:1662
std::chrono::duration< rep, std::milli > milliseconds
Definition chrono.h:1627
void on_text(const Char *begin, const Char *end)
Definition chrono.h:1713
iterator out
Definition chrono.h:1616
void on_abbr_month()
Definition chrono.h:1722
void on_dec1_weekday(numeric_system)
Definition chrono.h:1721
void write_sign()
Definition chrono.h:1684
void on_dec0_week_of_year(numeric_system, pad_type)
Definition chrono.h:1738
void on_minute(numeric_system ns, pad_type pad)
Definition chrono.h:1766
int precision
Definition chrono.h:1622
void on_short_year(numeric_system)
Definition chrono.h:1732
auto hour12() const -> Rep
Definition chrono.h:1666
seconds s
Definition chrono.h:1626
locale_ref locale
Definition chrono.h:1623
void on_duration_value()
Definition chrono.h:1828
void on_dec1_week_of_year(numeric_system, pad_type)
Definition chrono.h:1739
auto days() const -> Rep
Definition chrono.h:1661
rep val
Definition chrono.h:1621
bool negative
Definition chrono.h:1628
void on_us_date()
Definition chrono.h:1727
void on_iso_week_of_year(numeric_system, pad_type)
Definition chrono.h:1740
auto handle_nan_inf() -> bool
Definition chrono.h:1647
void on_12_hour_time()
Definition chrono.h:1799
void on_24_hour(numeric_system ns, pad_type pad)
Definition chrono.h:1748
void on_iso_week_based_short_year()
Definition chrono.h:1736
void on_abbr_weekday()
Definition chrono.h:1718
std::chrono::duration< rep > seconds
Definition chrono.h:1625
void on_utc_offset(numeric_system)
Definition chrono.h:1729
void on_full_weekday()
Definition chrono.h:1719
void on_iso_week_based_year()
Definition chrono.h:1735
void on_offset_year()
Definition chrono.h:1733
Definition chrono.h:905
Definition chrono.h:909
Definition chrono.h:254
Definition format-inl.h:52
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:267
Definition chrono.h:238
Definition base.h:846
FMT_CONSTEXPR auto parse(parse_context< Char > &ctx) -> const Char *
Definition chrono.h:1940
auto format(day d, FormatContext &ctx) const -> decltype(ctx.out())
Definition chrono.h:1947
auto format(local_time< Duration > val, FormatContext &ctx) const -> decltype(ctx.out())
Definition chrono.h:2224
FMT_CONSTEXPR auto parse(parse_context< Char > &ctx) -> const Char *
Definition chrono.h:2219
auto format(month m, FormatContext &ctx) const -> decltype(ctx.out())
Definition chrono.h:1975
FMT_CONSTEXPR auto parse(parse_context< Char > &ctx) -> const Char *
Definition chrono.h:1964
auto format(std::chrono::duration< Rep, Period > d, FormatContext &ctx) const -> decltype(ctx.out())
Definition chrono.h:2074
FMT_CONSTEXPR auto parse(parse_context< Char > &ctx) -> const Char *
Definition chrono.h:2046
auto format(const std::tm &tm, FormatContext &ctx) const -> decltype(ctx.out())
Definition chrono.h:2164
FMT_CONSTEXPR auto do_parse(parse_context< Char > &ctx, bool has_timezone) -> const Char *
Definition chrono.h:2114
auto do_format(const std::tm &tm, FormatContext &ctx, const Duration *subsecs) const -> decltype(ctx.out())
Definition chrono.h:2141
FMT_CONSTEXPR void set_localized()
Definition chrono.h:2112
FMT_CONSTEXPR auto parse(parse_context< Char > &ctx) -> const Char *
Definition chrono.h:2159
auto localized() const -> bool
Definition chrono.h:2111
auto format(sys_time< Duration > val, FormatContext &ctx) const -> decltype(ctx.out())
Definition chrono.h:2178
FMT_CONSTEXPR auto parse(parse_context< Char > &ctx) -> const Char *
Definition chrono.h:2173
auto format(utc_time< Duration > val, FormatContext &ctx) const -> decltype(ctx.out())
Definition chrono.h:2209
FMT_CONSTEXPR auto parse(parse_context< Char > &ctx) -> const Char *
Definition chrono.h:1912
auto format(weekday wd, FormatContext &ctx) const -> decltype(ctx.out())
Definition chrono.h:1923
auto format(year y, FormatContext &ctx) const -> decltype(ctx.out())
Definition chrono.h:1999
FMT_CONSTEXPR auto parse(parse_context< Char > &ctx) -> const Char *
Definition chrono.h:1992
FMT_CONSTEXPR auto parse(parse_context< Char > &ctx) -> const Char *
Definition chrono.h:2016
auto format(year_month_day val, FormatContext &ctx) const -> decltype(ctx.out())
Definition chrono.h:2023
Definition base.h:1289