Add platform-specific 'z' formatter

This commit is contained in:
Vladislav Shchapov 2021-11-13 14:31:57 +05:00 committed by Victor Zverovich
parent be3a3a5aed
commit 5abe9e8266
3 changed files with 64 additions and 1 deletions

View File

@ -13,6 +13,7 @@
#include <ctime> #include <ctime>
#include <locale> #include <locale>
#include <sstream> #include <sstream>
#include <type_traits>
#include "format.h" #include "format.h"
@ -871,6 +872,22 @@ inline const char* tm_mon_short_name(int mon) {
return mon >= 0 && mon <= 11 ? short_name_list[mon] : "???"; return mon >= 0 && mon <= 11 ? short_name_list[mon] : "???";
} }
template <typename T, typename = void>
struct has_member_data_tm_gmtoff : std::false_type {};
template <typename T>
struct has_member_data_tm_gmtoff<T, void_t<decltype(T::tm_gmtoff)>>
: std::true_type {};
#if defined(_WIN32)
inline void tzset_once() {
static bool init = []() -> bool {
_tzset();
return true;
}();
ignore_unused(init);
}
#endif
template <typename OutputIt, typename Char> class tm_writer { template <typename OutputIt, typename Char> class tm_writer {
private: private:
static constexpr int days_per_week = 7; static constexpr int days_per_week = 7;
@ -988,6 +1005,36 @@ template <typename OutputIt, typename Char> class tm_writer {
} }
} }
void write_utc_offset(long offset) {
if (offset < 0) {
*out_++ = '-';
offset = -offset;
} else {
*out_++ = '+';
}
offset /= 60;
write2(static_cast<int>(offset / 60));
write2(static_cast<int>(offset % 60));
}
void format_utc_offset_impl(std::true_type) {
write_utc_offset(tm_.tm_gmtoff);
}
void format_utc_offset_impl(std::false_type) {
#if defined(_WIN32)
tzset_once();
long offset = 0;
_get_timezone(&offset);
if (tm_.tm_isdst) {
long dstbias = 0;
_get_dstbias(&dstbias);
offset += dstbias;
}
write_utc_offset(-offset);
#else
format_localized('z');
#endif
}
void format_localized(char format, char modifier = 0) { void format_localized(char format, char modifier = 0) {
out_ = write<Char>(out_, tm_, loc_, format, modifier); out_ = write<Char>(out_, tm_, loc_, format, modifier);
} }
@ -1094,7 +1141,9 @@ template <typename OutputIt, typename Char> class tm_writer {
out_ = copy_str<Char>(std::begin(buf) + offset, std::end(buf), out_); out_ = copy_str<Char>(std::begin(buf) + offset, std::end(buf), out_);
} }
void on_utc_offset() { format_localized('z'); } void on_utc_offset() {
format_utc_offset_impl(has_member_data_tm_gmtoff<std::tm>{});
}
void on_tz_name() { format_localized('Z'); } void on_tz_name() { format_localized('Z'); }
void on_year(numeric_system ns) { void on_year(numeric_system ns) {

View File

@ -49,7 +49,14 @@ std::string system_strftime(const std::string& format, const std::tm* timeptr,
os.imbue(loc); os.imbue(loc);
facet.put(os, os, ' ', timeptr, format.c_str(), facet.put(os, os, ' ', timeptr, format.c_str(),
format.c_str() + format.size()); format.c_str() + format.size());
#ifdef _WIN32
// Workaround a bug in older versions of Universal CRT.
auto str = os.str();
if (str == "-0000") str = "+0000";
return str;
#else
return os.str(); return os.str();
#endif
} }
FMT_CONSTEXPR std::tm make_tm(int year, int mon, int mday, int hour, int min, FMT_CONSTEXPR std::tm make_tm(int year, int mon, int mday, int hour, int min,

View File

@ -277,7 +277,14 @@ std::wstring system_wcsftime(const std::wstring& format, const std::tm* timeptr,
os.imbue(loc); os.imbue(loc);
facet.put(os, os, L' ', timeptr, format.c_str(), facet.put(os, os, L' ', timeptr, format.c_str(),
format.c_str() + format.size()); format.c_str() + format.size());
#ifdef _WIN32
// Workaround a bug in older versions of Universal CRT.
auto str = os.str();
if (str == L"-0000") str = L"+0000";
return str;
#else
return os.str(); return os.str();
#endif
} }
TEST(chrono_test, time_point) { TEST(chrono_test, time_point) {