From 33cdfc648598a11290f7088f993749482f3611f3 Mon Sep 17 00:00:00 2001 From: Howard Hinnant Date: Fri, 24 Jun 2016 20:33:40 -0400 Subject: [PATCH] Fix bug in formatting zoned_times produced by ambiguous local times. --- tz.h | 92 +++++++++++++++++++++++++++++------------------------------- 1 file changed, 44 insertions(+), 48 deletions(-) diff --git a/tz.h b/tz.h index 17c15ec..4ce5928 100644 --- a/tz.h +++ b/tz.h @@ -455,7 +455,7 @@ time_zone::to_sys_impl(local_time tp, choose z, std::false_type) const } else if (i.result == local_info::ambiguous) { - if (z == choose::earliest) + if (z == choose::latest) return sys_time{tp.time_since_epoch()} - i.second.offset; } return sys_time{tp.time_since_epoch()} - i.first.offset; @@ -1336,8 +1336,8 @@ namespace detail template std::basic_string -format(const std::locale& loc, std::basic_string format, - local_time tp, const time_zone* zone = nullptr) +format(const std::locale& loc, std::basic_string fmt, + local_time tp, const sys_info* info = nullptr) { // Handle these specially // %S append fractional seconds if tp has precision finer than seconds @@ -1350,9 +1350,9 @@ format(const std::locale& loc, std::basic_string format, using namespace std::chrono; auto command = false; auto modified = false; - for (std::size_t i = 0; i < format.size(); ++i) + for (std::size_t i = 0; i < fmt.size(); ++i) { - switch (format[i]) + switch (fmt[i]) { case '%': command = true; @@ -1371,7 +1371,7 @@ format(const std::locale& loc, std::basic_string format, os << make_time(tp - floor(tp)); auto s = os.str(); s.erase(0, 8); - format.insert(i+1, s); + fmt.insert(i+1, s); i += s.size() - 1; } command = false; @@ -1380,12 +1380,11 @@ format(const std::locale& loc, std::basic_string format, case 'z': if (command) { - if (zone == nullptr) + if (info == nullptr) throw std::runtime_error("Can not format local_time with %z"); else { - auto info = zone->get_info(tp).first; - auto offset = duration_cast(info.offset); + auto offset = duration_cast(info->offset); basic_ostringstream os; if (offset >= minutes{0}) os << '+'; @@ -1393,7 +1392,7 @@ format(const std::locale& loc, std::basic_string format, auto s = os.str(); if (!modified) s.erase(s.find(':'), 1); - format.replace(i - 1 - modified, 2 + modified, s); + fmt.replace(i - 1 - modified, 2 + modified, s); i += s.size() - 1; } } @@ -1403,14 +1402,13 @@ format(const std::locale& loc, std::basic_string format, case 'Z': if (command && !modified) { - if (zone == nullptr) + if (info == nullptr) throw std::runtime_error("Can not format local_time with %z"); else { - auto info = zone->get_info(tp).first; - format.replace(i - 1, 2, std::basic_string - (info.abbrev.begin(), info.abbrev.end())); - i += info.abbrev.size() - 1; + fmt.replace(i - 1, 2, std::basic_string + (info->abbrev.begin(), info->abbrev.end())); + i += info->abbrev.size() - 1; } } command = false; @@ -1431,7 +1429,7 @@ format(const std::locale& loc, std::basic_string format, #else gmtime_s(&tm, &tt); #endif - f.put(os, os, os.fill(), &tm, format.data(), format.data() + format.size()); + f.put(os, os, os.fill(), &tm, fmt.data(), fmt.data() + fmt.size()); return os.str(); } @@ -1440,56 +1438,54 @@ format(const std::locale& loc, std::basic_string format, template inline std::basic_string -format(const std::locale& loc, std::basic_string format, +format(const std::locale& loc, std::basic_string fmt, local_time tp) { - return detail::format(loc, std::move(format), tp); + return detail::format(loc, std::move(fmt), tp); } template inline std::basic_string -format(std::basic_string format, local_time tp) +format(std::basic_string fmt, local_time tp) { - return detail::format(std::locale{}, std::move(format), tp); + return detail::format(std::locale{}, std::move(fmt), tp); } template inline std::basic_string -format(const std::locale& loc, std::basic_string format, +format(const std::locale& loc, std::basic_string fmt, const zoned_time& tp) { - return detail::format(loc, std::move(format), tp.get_local_time(), - tp.get_time_zone()); + auto const info = tp.get_info(); + return detail::format(loc, std::move(fmt), tp.get_local_time(), &info); } template inline std::basic_string -format(std::basic_string format, const zoned_time& tp) +format(std::basic_string fmt, const zoned_time& tp) { - return detail::format(std::locale{}, std::move(format), tp.get_local_time(), - tp.get_time_zone()); + auto const info = tp.get_info(); + return detail::format(std::locale{}, std::move(fmt), tp.get_local_time(), &info); } template inline std::basic_string -format(const std::locale& loc, std::basic_string format, +format(const std::locale& loc, std::basic_string fmt, sys_time tp) { - return detail::format(loc, std::move(format), - local_time{tp.time_since_epoch()}, locate_zone("UTC")); + return format(loc, std::move(fmt), make_zoned(locate_zone("UTC"), tp)); } template inline std::basic_string -format(std::basic_string format, sys_time tp) +format(std::basic_string fmt, sys_time tp) { - return detail::format(std::locale{}, std::move(format), - local_time{tp.time_since_epoch()}, locate_zone("UTC")); + return format(std::move(fmt), make_zoned(locate_zone("UTC"), tp)); } // const CharT* formats @@ -1497,53 +1493,53 @@ format(std::basic_string format, sys_time tp) template inline std::basic_string -format(const std::locale& loc, const CharT* format, local_time tp) +format(const std::locale& loc, const CharT* fmt, local_time tp) { - return detail::format(loc, std::basic_string(format), tp); + return detail::format(loc, std::basic_string(fmt), tp); } template inline std::basic_string -format(const CharT* format, local_time tp) +format(const CharT* fmt, local_time tp) { - return detail::format(std::locale{}, std::basic_string(format), tp); + return detail::format(std::locale{}, std::basic_string(fmt), tp); } template inline std::basic_string -format(const std::locale& loc, const CharT* format, const zoned_time& tp) +format(const std::locale& loc, const CharT* fmt, const zoned_time& tp) { - return detail::format(loc, std::basic_string(format), tp.get_local_time(), - tp.get_time_zone()); + auto const info = tp.get_info(); + return detail::format(loc, std::basic_string(fmt), tp.get_local_time(), + &info); } template inline std::basic_string -format(const CharT* format, const zoned_time& tp) +format(const CharT* fmt, const zoned_time& tp) { - return detail::format(std::locale{}, std::basic_string(format), - tp.get_local_time(), tp.get_time_zone()); + auto const info = tp.get_info(); + return detail::format(std::locale{}, std::basic_string(fmt), + tp.get_local_time(), &info); } template inline std::basic_string -format(const std::locale& loc, const CharT* format, sys_time tp) +format(const std::locale& loc, const CharT* fmt, sys_time tp) { - return detail::format(loc, std::basic_string(format), - local_time{tp.time_since_epoch()}, locate_zone("UTC")); + return format(loc, fmt, make_zoned(locate_zone("UTC"), tp)); } template inline std::basic_string -format(const CharT* format, sys_time tp) +format(const CharT* fmt, sys_time tp) { - return detail::format(std::locale{}, std::basic_string(format), - local_time{tp.time_since_epoch()}, locate_zone("UTC")); + return format(fmt, make_zoned(locate_zone("UTC"), tp)); } // parse