@@ -420,14 +420,11 @@ auto write(OutputIt out, const std::tm& time, const std::locale& loc,
420420 return write_encoded_tm_str (out, string_view (buf.data (), buf.size ()), loc);
421421}
422422
423- template <typename Rep1, typename Rep2>
424- struct is_same_arithmetic_type
425- : public std::integral_constant<bool ,
426- (std::is_integral<Rep1>::value &&
427- std::is_integral<Rep2>::value) ||
428- (std::is_floating_point<Rep1>::value &&
429- std::is_floating_point<Rep2>::value)> {
430- };
423+ template <typename T, typename U>
424+ using is_similar_arithmetic_type =
425+ bool_constant<(std::is_integral<T>::value && std::is_integral<U>::value) ||
426+ (std::is_floating_point<T>::value &&
427+ std::is_floating_point<U>::value)>;
431428
432429FMT_NORETURN inline void throw_duration_error () {
433430 FMT_THROW (format_error (" cannot format duration" ));
@@ -486,9 +483,9 @@ auto duration_cast(std::chrono::duration<FromRep, FromPeriod> from) -> To {
486483#endif
487484}
488485
489- template <
490- typename To, typename FromRep, typename FromPeriod,
491- FMT_ENABLE_IF (!is_same_arithmetic_type <FromRep, typename To::rep>::value)>
486+ template <typename To, typename FromRep, typename FromPeriod,
487+ FMT_ENABLE_IF (
488+ !is_similar_arithmetic_type <FromRep, typename To::rep>::value)>
492489auto duration_cast (std::chrono::duration<FromRep, FromPeriod> from) -> To {
493490 // Mixed integer <-> float cast is not supported by safe_duration_cast.
494491 return std::chrono::duration_cast<To>(from);
@@ -520,6 +517,7 @@ template <typename... T> auto current_zone(T...) -> time_zone* {
520517template <typename ... T> void _tzset (T...) {}
521518} // namespace tz
522519
520+ // DEPRECATED!
523521inline void tzset_once () {
524522 static bool init = []() {
525523 using namespace tz ;
@@ -915,11 +913,11 @@ template <typename Derived> struct null_chrono_spec_handler {
915913
916914class tm_format_checker : public null_chrono_spec_handler <tm_format_checker> {
917915 private:
918- bool no_timezone_ = false ;
916+ bool has_timezone_ = false ;
919917
920918 public:
921- constexpr explicit tm_format_checker (bool no_timezone = false )
922- : no_timezone_(no_timezone ) {}
919+ constexpr explicit tm_format_checker (bool has_timezone )
920+ : has_timezone_(has_timezone ) {}
923921
924922 FMT_NORETURN inline void unsupported () {
925923 FMT_THROW (format_error (" no format" ));
@@ -959,10 +957,10 @@ class tm_format_checker : public null_chrono_spec_handler<tm_format_checker> {
959957 FMT_CONSTEXPR void on_iso_time () {}
960958 FMT_CONSTEXPR void on_am_pm () {}
961959 FMT_CONSTEXPR void on_utc_offset (numeric_system) {
962- if (no_timezone_ ) FMT_THROW (format_error (" no timezone" ));
960+ if (!has_timezone_ ) FMT_THROW (format_error (" no timezone" ));
963961 }
964962 FMT_CONSTEXPR void on_tz_name () {
965- if (no_timezone_ ) FMT_THROW (format_error (" no timezone" ));
963+ if (!has_timezone_ ) FMT_THROW (format_error (" no timezone" ));
966964 }
967965};
968966
@@ -1128,7 +1126,7 @@ class tm_writer {
11281126 static constexpr int days_per_week = 7 ;
11291127
11301128 const std::locale& loc_;
1131- const bool is_classic_;
1129+ bool is_classic_;
11321130 OutputIt out_;
11331131 const Duration* subsecs_;
11341132 const std::tm& tm_;
@@ -1164,8 +1162,8 @@ class tm_writer {
11641162 }
11651163
11661164 auto tm_hour12 () const noexcept -> int {
1167- const auto h = tm_hour ();
1168- const auto z = h < 12 ? h : h - 12 ;
1165+ auto h = tm_hour ();
1166+ auto z = h < 12 ? h : h - 12 ;
11691167 return z == 0 ? 12 : z;
11701168 }
11711169
@@ -1181,11 +1179,11 @@ class tm_writer {
11811179
11821180 // Algorithm: https://en.wikipedia.org/wiki/ISO_week_date.
11831181 auto iso_year_weeks (long long curr_year) const noexcept -> int {
1184- const auto prev_year = curr_year - 1 ;
1185- const auto curr_p =
1182+ auto prev_year = curr_year - 1 ;
1183+ auto curr_p =
11861184 (curr_year + curr_year / 4 - curr_year / 100 + curr_year / 400 ) %
11871185 days_per_week;
1188- const auto prev_p =
1186+ auto prev_p =
11891187 (prev_year + prev_year / 4 - prev_year / 100 + prev_year / 400 ) %
11901188 days_per_week;
11911189 return 52 + ((curr_p == 4 || prev_p == 3 ) ? 1 : 0 );
@@ -1195,15 +1193,15 @@ class tm_writer {
11951193 days_per_week;
11961194 }
11971195 auto tm_iso_week_year () const noexcept -> long long {
1198- const auto year = tm_year ();
1199- const auto w = iso_week_num (tm_yday (), tm_wday ());
1196+ auto year = tm_year ();
1197+ auto w = iso_week_num (tm_yday (), tm_wday ());
12001198 if (w < 1 ) return year - 1 ;
12011199 if (w > iso_year_weeks (year)) return year + 1 ;
12021200 return year;
12031201 }
12041202 auto tm_iso_week_of_year () const noexcept -> int {
1205- const auto year = tm_year ();
1206- const auto w = iso_week_num (tm_yday (), tm_wday ());
1203+ auto year = tm_year ();
1204+ auto w = iso_week_num (tm_yday (), tm_wday ());
12071205 if (w < 1 ) return iso_year_weeks (year - 1 );
12081206 if (w > iso_year_weeks (year)) return 1 ;
12091207 return w;
@@ -1240,9 +1238,8 @@ class tm_writer {
12401238 uint32_or_64_or_128_t <long long > n = to_unsigned (year);
12411239 const int num_digits = count_digits (n);
12421240 if (negative && pad == pad_type::zero) *out_++ = ' -' ;
1243- if (width > num_digits) {
1241+ if (width > num_digits)
12441242 out_ = detail::write_padding (out_, pad, width - num_digits);
1245- }
12461243 if (negative && pad != pad_type::zero) *out_++ = ' -' ;
12471244 out_ = format_decimal<Char>(out_, n, num_digits);
12481245 }
@@ -1467,11 +1464,10 @@ class tm_writer {
14671464 void on_day_of_year (pad_type pad) {
14681465 auto yday = tm_yday () + 1 ;
14691466 auto digit1 = yday / 100 ;
1470- if (digit1 != 0 ) {
1467+ if (digit1 != 0 )
14711468 write1 (digit1);
1472- } else {
1469+ else
14731470 out_ = detail::write_padding (out_, pad);
1474- }
14751471 write2 (yday % 100 , pad);
14761472 }
14771473
@@ -1608,18 +1604,16 @@ template <typename Rep, typename Period,
16081604 FMT_ENABLE_IF (std::is_integral<Rep>::value)>
16091605inline auto get_milliseconds(std::chrono::duration<Rep, Period> d)
16101606 -> std::chrono::duration<Rep, std::milli> {
1611- // this may overflow and/or the result may not fit in the
1612- // target type.
1607+ // This may overflow and/or the result may not fit in the target type.
16131608#if FMT_SAFE_DURATION_CAST
1614- using CommonSecondsType =
1609+ using common_seconds_type =
16151610 typename std::common_type<decltype (d), std::chrono::seconds>::type;
1616- const auto d_as_common = detail::duration_cast<CommonSecondsType >(d);
1617- const auto d_as_whole_seconds =
1611+ auto d_as_common = detail::duration_cast<common_seconds_type >(d);
1612+ auto d_as_whole_seconds =
16181613 detail::duration_cast<std::chrono::seconds>(d_as_common);
1619- // this conversion should be nonproblematic
1620- const auto diff = d_as_common - d_as_whole_seconds;
1621- const auto ms =
1622- detail::duration_cast<std::chrono::duration<Rep, std::milli>>(diff);
1614+ // This conversion should be nonproblematic.
1615+ auto diff = d_as_common - d_as_whole_seconds;
1616+ auto ms = detail::duration_cast<std::chrono::duration<Rep, std::milli>>(diff);
16231617 return ms;
16241618#else
16251619 auto s = detail::duration_cast<std::chrono::seconds>(d);
@@ -1730,19 +1724,16 @@ struct chrono_formatter {
17301724
17311725 // returns true if nan or inf, writes to out.
17321726 auto handle_nan_inf () -> bool {
1733- if (isfinite (val)) {
1734- return false ;
1735- }
1727+ if (isfinite (val)) return false ;
17361728 if (isnan (val)) {
17371729 write_nan ();
17381730 return true ;
17391731 }
17401732 // must be +-inf
1741- if (val > 0 ) {
1742- write_pinf ();
1743- } else {
1744- write_ninf ();
1745- }
1733+ if (val > 0 )
1734+ std::copy_n (" inf" , 3 , out);
1735+ else
1736+ std::copy_n (" -inf" , 4 , out);
17461737 return true ;
17471738 }
17481739
@@ -1770,10 +1761,9 @@ struct chrono_formatter {
17701761 }
17711762
17721763 void write_sign () {
1773- if (negative) {
1774- *out++ = ' -' ;
1775- negative = false ;
1776- }
1764+ if (!negative) return ;
1765+ *out++ = ' -' ;
1766+ negative = false ;
17771767 }
17781768
17791769 void write (Rep value, int width, pad_type pad = pad_type::zero) {
@@ -1789,8 +1779,6 @@ struct chrono_formatter {
17891779 }
17901780
17911781 void write_nan () { std::copy_n (" nan" , 3 , out); }
1792- void write_pinf () { std::copy_n (" inf" , 3 , out); }
1793- void write_ninf () { std::copy_n (" -inf" , 4 , out); }
17941782
17951783 template <typename Callback, typename ... Args>
17961784 void format_tm (const tm& time, Callback cb, Args... args) {
@@ -1872,9 +1860,8 @@ struct chrono_formatter {
18721860 write_floating_seconds (buf, std::chrono::duration<rep, Period>(val),
18731861 precision);
18741862 if (negative) *out++ = ' -' ;
1875- if (buf.size () < 2 || buf[1 ] == ' .' ) {
1863+ if (buf.size () < 2 || buf[1 ] == ' .' )
18761864 out = detail::write_padding (out, pad);
1877- }
18781865 out = copy<char_type>(buf.begin (), buf.end (), out);
18791866 } else {
18801867 write (second (), 2 , pad);
@@ -1995,7 +1982,7 @@ class year_month_day {
19951982 constexpr auto month () const noexcept -> fmt::month { return month_; }
19961983 constexpr auto day () const noexcept -> fmt::day { return day_; }
19971984};
1998- #endif
1985+ #endif // __cpp_lib_chrono >= 201907
19991986
20001987template <typename Char>
20011988struct formatter <weekday, Char> : private formatter<std::tm, Char> {
@@ -2204,31 +2191,12 @@ template <typename Char> struct formatter<std::tm, Char> {
22042191 private:
22052192 format_specs specs_;
22062193 detail::arg_ref<Char> width_ref_;
2207-
2208- protected:
22092194 basic_string_view<Char> fmt_ =
22102195 detail::string_literal<Char, ' %' , ' F' , ' ' , ' %' , ' T' >();
22112196
2212- template <typename Duration, typename FormatContext>
2213- auto do_format (const std::tm& tm, FormatContext& ctx,
2214- const Duration* subsecs) const -> decltype(ctx.out()) {
2215- auto specs = specs_;
2216- auto buf = basic_memory_buffer<Char>();
2217- auto out = basic_appender<Char>(buf);
2218- detail::handle_dynamic_spec (specs.dynamic_width (), specs.width , width_ref_,
2219- ctx);
2220-
2221- auto loc_ref = ctx.locale ();
2222- detail::get_locale loc (static_cast <bool >(loc_ref), loc_ref);
2223- auto w =
2224- detail::tm_writer<decltype (out), Char, Duration>(loc, out, tm, subsecs);
2225- detail::parse_chrono_format (fmt_.begin (), fmt_.end (), w);
2226- return detail::write (
2227- ctx.out (), basic_string_view<Char>(buf.data (), buf.size ()), specs);
2228- }
2229-
2197+ protected:
22302198 FMT_CONSTEXPR auto do_parse (parse_context<Char>& ctx,
2231- bool no_timezone = false ) -> const Char* {
2199+ bool has_timezone ) -> const Char* {
22322200 auto it = ctx.begin (), end = ctx.end ();
22332201 if (it == end || *it == ' }' ) return it;
22342202
@@ -2242,15 +2210,33 @@ template <typename Char> struct formatter<std::tm, Char> {
22422210 }
22432211
22442212 end = detail::parse_chrono_format (it, end,
2245- detail::tm_format_checker (no_timezone ));
2213+ detail::tm_format_checker (has_timezone ));
22462214 // Replace the default format string only if the new spec is not empty.
22472215 if (end != it) fmt_ = {it, detail::to_unsigned (end - it)};
22482216 return end;
22492217 }
22502218
2219+ template <typename Duration, typename FormatContext>
2220+ auto do_format (const std::tm& tm, FormatContext& ctx,
2221+ const Duration* subsecs) const -> decltype(ctx.out()) {
2222+ auto specs = specs_;
2223+ auto buf = basic_memory_buffer<Char>();
2224+ auto out = basic_appender<Char>(buf);
2225+ detail::handle_dynamic_spec (specs.dynamic_width (), specs.width , width_ref_,
2226+ ctx);
2227+
2228+ auto loc_ref = ctx.locale ();
2229+ detail::get_locale loc (static_cast <bool >(loc_ref), loc_ref);
2230+ auto w =
2231+ detail::tm_writer<decltype (out), Char, Duration>(loc, out, tm, subsecs);
2232+ detail::parse_chrono_format (fmt_.begin (), fmt_.end (), w);
2233+ return detail::write (
2234+ ctx.out (), basic_string_view<Char>(buf.data (), buf.size ()), specs);
2235+ }
2236+
22512237 public:
22522238 FMT_CONSTEXPR auto parse (parse_context<Char>& ctx) -> const Char* {
2253- return do_parse (ctx);
2239+ return do_parse (ctx, detail::has_member_data_tm_gmtoff<std::tm>::value );
22542240 }
22552241
22562242 template <typename FormatContext>
@@ -2260,8 +2246,13 @@ template <typename Char> struct formatter<std::tm, Char> {
22602246 }
22612247};
22622248
2249+ // DEPRECATED! Reversed order of template parameters.
22632250template <typename Char, typename Duration>
2264- struct formatter <sys_time<Duration>, Char> : formatter<std::tm, Char> {
2251+ struct formatter <sys_time<Duration>, Char> : private formatter<std::tm, Char> {
2252+ FMT_CONSTEXPR auto parse (parse_context<Char>& ctx) -> const Char* {
2253+ return this ->do_parse (ctx, true );
2254+ }
2255+
22652256 template <typename FormatContext>
22662257 auto format (sys_time<Duration> val, FormatContext& ctx) const
22672258 -> decltype(ctx.out()) {
@@ -2299,9 +2290,10 @@ struct formatter<utc_time<Duration>, Char>
22992290};
23002291
23012292template <typename Duration, typename Char>
2302- struct formatter <local_time<Duration>, Char> : formatter<std::tm, Char> {
2293+ struct formatter <local_time<Duration>, Char>
2294+ : private formatter<std::tm, Char> {
23032295 FMT_CONSTEXPR auto parse (parse_context<Char>& ctx) -> const Char* {
2304- return this ->do_parse (ctx, true );
2296+ return this ->do_parse (ctx, false );
23052297 }
23062298
23072299 template <typename FormatContext>
@@ -2310,7 +2302,7 @@ struct formatter<local_time<Duration>, Char> : formatter<std::tm, Char> {
23102302 auto time_since_epoch = val.time_since_epoch ();
23112303 auto seconds_since_epoch =
23122304 detail::duration_cast<std::chrono::seconds>(time_since_epoch);
2313- // Use gmtime to prevent time conversion since local_time has an
2305+ // Use gmtime to prevent time zone conversion since local_time has an
23142306 // unspecified time zone.
23152307 auto t = gmtime (seconds_since_epoch.count ());
23162308 using period = typename Duration::period;
0 commit comments