You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2267 lines
72 KiB

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