chrono.h 66 KB

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