@@ -991,16 +991,28 @@ inline auto tm_mon_short_name(int mon) -> const char* {
991991}
992992
993993template <typename T, typename = void >
994- struct has_member_data_tm_gmtoff : std::false_type {};
994+ struct has_tm_gmtoff : std::false_type {};
995995template <typename T>
996- struct has_member_data_tm_gmtoff <T, void_t <decltype (T::tm_gmtoff)>>
997- : std::true_type {};
996+ struct has_tm_gmtoff <T, void_t <decltype (T::tm_gmtoff)>> : std::true_type {};
998997
999- template <typename T, typename = void >
1000- struct has_member_data_tm_zone : std::false_type {};
998+ template <typename T, typename = void > struct has_tm_zone : std::false_type {};
1001999template <typename T>
1002- struct has_member_data_tm_zone <T, void_t <decltype (T::tm_zone)>>
1003- : std::true_type {};
1000+ struct has_tm_zone <T, void_t <decltype (T::tm_zone)>> : std::true_type {};
1001+
1002+ template <typename T, FMT_ENABLE_IF(has_tm_zone<T>::value)>
1003+ bool set_tm_zone (T& time, char * tz) {
1004+ time.tm_zone = tz;
1005+ return true ;
1006+ }
1007+ template <typename T, FMT_ENABLE_IF(!has_tm_zone<T>::value)>
1008+ bool set_tm_zone (T&, char *) {
1009+ return false ;
1010+ }
1011+
1012+ inline char * utc () {
1013+ static char tz[] = " UTC" ;
1014+ return tz;
1015+ }
10041016
10051017// Converts value to Int and checks that it's in the range [0, upper).
10061018template <typename T, typename Int, FMT_ENABLE_IF(std::is_integral<T>::value)>
@@ -1260,24 +1272,24 @@ class tm_writer {
12601272 write2 (static_cast <int >(offset % 60 ));
12611273 }
12621274
1263- template <typename T, FMT_ENABLE_IF(has_member_data_tm_gmtoff <T>::value)>
1264- void format_utc_offset_impl (const T& tm, numeric_system ns) {
1275+ template <typename T, FMT_ENABLE_IF(has_tm_gmtoff <T>::value)>
1276+ void format_utc_offset (const T& tm, numeric_system ns) {
12651277 write_utc_offset (tm.tm_gmtoff , ns);
12661278 }
1267- template <typename T, FMT_ENABLE_IF(!has_member_data_tm_gmtoff <T>::value)>
1268- void format_utc_offset_impl (const T&, numeric_system ns) {
1279+ template <typename T, FMT_ENABLE_IF(!has_tm_gmtoff <T>::value)>
1280+ void format_utc_offset (const T&, numeric_system ns) {
12691281 write_utc_offset (0 , ns);
12701282 }
12711283
1272- template <typename T, FMT_ENABLE_IF(has_member_data_tm_zone <T>::value)>
1273- void format_tz_name_impl (const T& tm) {
1284+ template <typename T, FMT_ENABLE_IF(has_tm_zone <T>::value)>
1285+ void format_tz_name (const T& tm) {
12741286 if (is_classic_)
12751287 out_ = write_tm_str<Char>(out_, tm.tm_zone , loc_);
12761288 else
12771289 format_localized (' Z' );
12781290 }
1279- template <typename T, FMT_ENABLE_IF(!has_member_data_tm_zone <T>::value)>
1280- void format_tz_name_impl (const T&) {
1291+ template <typename T, FMT_ENABLE_IF(!has_tm_zone <T>::value)>
1292+ void format_tz_name (const T&) {
12811293 format_localized (' Z' );
12821294 }
12831295
@@ -1389,8 +1401,8 @@ class tm_writer {
13891401 out_ = copy<Char>(std::begin (buf) + offset, std::end (buf), out_);
13901402 }
13911403
1392- void on_utc_offset (numeric_system ns) { format_utc_offset_impl (tm_, ns); }
1393- void on_tz_name () { format_tz_name_impl (tm_); }
1404+ void on_utc_offset (numeric_system ns) { format_utc_offset (tm_, ns); }
1405+ void on_tz_name () { format_tz_name (tm_); }
13941406
13951407 void on_year (numeric_system ns, pad_type pad) {
13961408 if (is_classic_ || ns == numeric_system::standard)
@@ -1987,16 +1999,14 @@ class year_month_day {
19871999template <typename Char>
19882000struct formatter <weekday, Char> : private formatter<std::tm, Char> {
19892001 private:
1990- bool localized_ = false ;
19912002 bool use_tm_formatter_ = false ;
19922003
19932004 public:
19942005 FMT_CONSTEXPR auto parse (parse_context<Char>& ctx) -> const Char* {
19952006 auto it = ctx.begin (), end = ctx.end ();
19962007 if (it != end && *it == ' L' ) {
19972008 ++it;
1998- localized_ = true ;
1999- return it;
2009+ this ->set_localized ();
20002010 }
20012011 use_tm_formatter_ = it != end && *it != ' }' ;
20022012 return use_tm_formatter_ ? formatter<std::tm, Char>::parse (ctx) : it;
@@ -2007,7 +2017,7 @@ struct formatter<weekday, Char> : private formatter<std::tm, Char> {
20072017 auto time = std::tm ();
20082018 time.tm_wday = static_cast <int >(wd.c_encoding ());
20092019 if (use_tm_formatter_) return formatter<std::tm, Char>::format (time, ctx);
2010- detail::get_locale loc (localized_ , ctx.locale ());
2020+ detail::get_locale loc (this -> localized () , ctx.locale ());
20112021 auto w = detail::tm_writer<decltype (ctx.out ()), Char>(loc, ctx.out (), time);
20122022 w.on_abbr_weekday ();
20132023 return w.out ();
@@ -2041,16 +2051,14 @@ struct formatter<day, Char> : private formatter<std::tm, Char> {
20412051template <typename Char>
20422052struct formatter <month, Char> : private formatter<std::tm, Char> {
20432053 private:
2044- bool localized_ = false ;
20452054 bool use_tm_formatter_ = false ;
20462055
20472056 public:
20482057 FMT_CONSTEXPR auto parse (parse_context<Char>& ctx) -> const Char* {
20492058 auto it = ctx.begin (), end = ctx.end ();
20502059 if (it != end && *it == ' L' ) {
20512060 ++it;
2052- localized_ = true ;
2053- return it;
2061+ this ->set_localized ();
20542062 }
20552063 use_tm_formatter_ = it != end && *it != ' }' ;
20562064 return use_tm_formatter_ ? formatter<std::tm, Char>::parse (ctx) : it;
@@ -2061,7 +2069,7 @@ struct formatter<month, Char> : private formatter<std::tm, Char> {
20612069 auto time = std::tm ();
20622070 time.tm_mon = static_cast <int >(static_cast <unsigned >(m)) - 1 ;
20632071 if (use_tm_formatter_) return formatter<std::tm, Char>::format (time, ctx);
2064- detail::get_locale loc (localized_ , ctx.locale ());
2072+ detail::get_locale loc (this -> localized () , ctx.locale ());
20652073 auto w = detail::tm_writer<decltype (ctx.out ()), Char>(loc, ctx.out (), time);
20662074 w.on_abbr_month ();
20672075 return w.out ();
@@ -2195,6 +2203,9 @@ template <typename Char> struct formatter<std::tm, Char> {
21952203 detail::string_literal<Char, ' %' , ' F' , ' ' , ' %' , ' T' >();
21962204
21972205 protected:
2206+ bool localized () const { return specs_.localized (); }
2207+ void set_localized () { specs_.set_localized (); }
2208+
21982209 FMT_CONSTEXPR auto do_parse (parse_context<Char>& ctx, bool has_timezone)
21992210 -> const Char* {
22002211 auto it = ctx.begin (), end = ctx.end ();
@@ -2209,6 +2220,11 @@ template <typename Char> struct formatter<std::tm, Char> {
22092220 if (it == end) return it;
22102221 }
22112222
2223+ if (*it == ' L' ) {
2224+ specs_.set_localized ();
2225+ ++it;
2226+ }
2227+
22122228 end = detail::parse_chrono_format (it, end,
22132229 detail::tm_format_checker (has_timezone));
22142230 // Replace the default format string only if the new spec is not empty.
@@ -2225,7 +2241,7 @@ template <typename Char> struct formatter<std::tm, Char> {
22252241 detail::handle_dynamic_spec (specs.dynamic_width (), specs.width , width_ref_,
22262242 ctx);
22272243
2228- auto loc_ref = ctx.locale ();
2244+ auto loc_ref = specs. localized () ? ctx.locale () : detail::locale_ref ();
22292245 detail::get_locale loc (static_cast <bool >(loc_ref), loc_ref);
22302246 auto w = detail::tm_writer<basic_appender<Char>, Char, Duration>(
22312247 loc, out, tm, subsecs);
@@ -2236,7 +2252,7 @@ template <typename Char> struct formatter<std::tm, Char> {
22362252
22372253 public:
22382254 FMT_CONSTEXPR auto parse (parse_context<Char>& ctx) -> const Char* {
2239- return do_parse (ctx, detail::has_member_data_tm_gmtoff <std::tm>::value);
2255+ return do_parse (ctx, detail::has_tm_gmtoff <std::tm>::value);
22402256 }
22412257
22422258 template <typename FormatContext>
@@ -2261,17 +2277,20 @@ struct formatter<sys_time<Duration>, Char> : private formatter<std::tm, Char> {
22612277 if (detail::const_check (
22622278 period::num == 1 && period::den == 1 &&
22632279 !std::is_floating_point<typename Duration::rep>::value)) {
2280+ detail::set_tm_zone (tm, detail::utc ());
22642281 return formatter<std::tm, Char>::format (tm, ctx);
22652282 }
22662283 Duration epoch = val.time_since_epoch ();
22672284 Duration subsecs = detail::duration_cast<Duration>(
22682285 epoch - detail::duration_cast<std::chrono::seconds>(epoch));
22692286 if (subsecs.count () < 0 ) {
22702287 auto second = detail::duration_cast<Duration>(std::chrono::seconds (1 ));
2271- if (tm.tm_sec != 0 )
2288+ if (tm.tm_sec != 0 ) {
22722289 --tm.tm_sec ;
2273- else
2290+ } else {
22742291 tm = gmtime (val - second);
2292+ detail::set_tm_zone (tm, detail::utc ());
2293+ }
22752294 subsecs += second;
22762295 }
22772296 return formatter<std::tm, Char>::do_format (tm, ctx, &subsecs);
0 commit comments