mirror of
https://github.com/fmtlib/fmt.git
synced 2024-11-25 03:30:05 +00:00
Implement %Ez, %Oz for chrono formatter
Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>
This commit is contained in:
parent
f1733afd49
commit
1bf302a4ea
@ -427,14 +427,33 @@ inline void do_write(buffer<Char>& buf, const std::tm& time,
|
|||||||
os.imbue(loc);
|
os.imbue(loc);
|
||||||
using iterator = std::ostreambuf_iterator<Char>;
|
using iterator = std::ostreambuf_iterator<Char>;
|
||||||
const auto& facet = std::use_facet<std::time_put<Char, iterator>>(loc);
|
const auto& facet = std::use_facet<std::time_put<Char, iterator>>(loc);
|
||||||
|
// std::time_put may not support '%Ez', '%Oz'.
|
||||||
|
bool modified_z = false;
|
||||||
|
if (format == 'z' && modifier != '\0') {
|
||||||
|
modified_z = true;
|
||||||
|
modifier = '\0';
|
||||||
|
}
|
||||||
auto end = facet.put(os, os, Char(' '), &time, format, modifier);
|
auto end = facet.put(os, os, Char(' '), &time, format, modifier);
|
||||||
if (end.failed()) FMT_THROW(format_error("failed to format time"));
|
if (end.failed()) FMT_THROW(format_error("failed to format time"));
|
||||||
|
if (modified_z) {
|
||||||
|
// Insert ':' into ISO 8601 formatted timezone
|
||||||
|
auto size = buf.size();
|
||||||
|
buf.push_back(*(buf.end() - 1));
|
||||||
|
Char* p = buf.data();
|
||||||
|
p[size - 1] = p[size - 2];
|
||||||
|
p[size - 2] = Char(':');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char, typename OutputIt,
|
template <typename Char, typename OutputIt,
|
||||||
FMT_ENABLE_IF(!std::is_same<Char, char>::value)>
|
FMT_ENABLE_IF(!std::is_same<Char, char>::value)>
|
||||||
auto write(OutputIt out, const std::tm& time, const std::locale& loc,
|
auto write(OutputIt out, const std::tm& time, const std::locale& loc,
|
||||||
char format, char modifier = 0) -> OutputIt {
|
char format, char modifier = 0) -> OutputIt {
|
||||||
|
if (format == 'z' && modifier != '\0') {
|
||||||
|
auto&& buf = basic_memory_buffer<Char>();
|
||||||
|
do_write<Char>(buf, time, loc, format, modifier);
|
||||||
|
return copy_str<Char>(buf.begin(), buf.end(), out);
|
||||||
|
}
|
||||||
auto&& buf = get_buffer<Char>(out);
|
auto&& buf = get_buffer<Char>(out);
|
||||||
do_write<Char>(buf, time, loc, format, modifier);
|
do_write<Char>(buf, time, loc, format, modifier);
|
||||||
return get_iterator(buf, out);
|
return get_iterator(buf, out);
|
||||||
@ -747,7 +766,7 @@ FMT_CONSTEXPR const Char* parse_chrono_format(const Char* begin,
|
|||||||
handler.on_duration_unit();
|
handler.on_duration_unit();
|
||||||
break;
|
break;
|
||||||
case 'z':
|
case 'z':
|
||||||
handler.on_utc_offset();
|
handler.on_utc_offset(numeric_system::standard);
|
||||||
break;
|
break;
|
||||||
case 'Z':
|
case 'Z':
|
||||||
handler.on_tz_name();
|
handler.on_tz_name();
|
||||||
@ -775,6 +794,9 @@ FMT_CONSTEXPR const Char* parse_chrono_format(const Char* begin,
|
|||||||
case 'X':
|
case 'X':
|
||||||
handler.on_loc_time(numeric_system::alternative);
|
handler.on_loc_time(numeric_system::alternative);
|
||||||
break;
|
break;
|
||||||
|
case 'z':
|
||||||
|
handler.on_utc_offset(numeric_system::alternative);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
FMT_THROW(format_error("invalid format"));
|
FMT_THROW(format_error("invalid format"));
|
||||||
}
|
}
|
||||||
@ -823,6 +845,9 @@ FMT_CONSTEXPR const Char* parse_chrono_format(const Char* begin,
|
|||||||
case 'S':
|
case 'S':
|
||||||
handler.on_second(numeric_system::alternative);
|
handler.on_second(numeric_system::alternative);
|
||||||
break;
|
break;
|
||||||
|
case 'z':
|
||||||
|
handler.on_utc_offset(numeric_system::alternative);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
FMT_THROW(format_error("invalid format"));
|
FMT_THROW(format_error("invalid format"));
|
||||||
}
|
}
|
||||||
@ -874,7 +899,7 @@ template <typename Derived> struct null_chrono_spec_handler {
|
|||||||
FMT_CONSTEXPR void on_am_pm() { unsupported(); }
|
FMT_CONSTEXPR void on_am_pm() { unsupported(); }
|
||||||
FMT_CONSTEXPR void on_duration_value() { unsupported(); }
|
FMT_CONSTEXPR void on_duration_value() { unsupported(); }
|
||||||
FMT_CONSTEXPR void on_duration_unit() { unsupported(); }
|
FMT_CONSTEXPR void on_duration_unit() { unsupported(); }
|
||||||
FMT_CONSTEXPR void on_utc_offset() { unsupported(); }
|
FMT_CONSTEXPR void on_utc_offset(numeric_system) { unsupported(); }
|
||||||
FMT_CONSTEXPR void on_tz_name() { unsupported(); }
|
FMT_CONSTEXPR void on_tz_name() { unsupported(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -915,7 +940,7 @@ struct tm_format_checker : null_chrono_spec_handler<tm_format_checker> {
|
|||||||
FMT_CONSTEXPR void on_24_hour_time() {}
|
FMT_CONSTEXPR void on_24_hour_time() {}
|
||||||
FMT_CONSTEXPR void on_iso_time() {}
|
FMT_CONSTEXPR void on_iso_time() {}
|
||||||
FMT_CONSTEXPR void on_am_pm() {}
|
FMT_CONSTEXPR void on_am_pm() {}
|
||||||
FMT_CONSTEXPR void on_utc_offset() {}
|
FMT_CONSTEXPR void on_utc_offset(numeric_system) {}
|
||||||
FMT_CONSTEXPR void on_tz_name() {}
|
FMT_CONSTEXPR void on_tz_name() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1218,7 +1243,7 @@ class tm_writer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void write_utc_offset(long offset) {
|
void write_utc_offset(long offset, numeric_system ns) {
|
||||||
if (offset < 0) {
|
if (offset < 0) {
|
||||||
*out_++ = '-';
|
*out_++ = '-';
|
||||||
offset = -offset;
|
offset = -offset;
|
||||||
@ -1227,14 +1252,15 @@ class tm_writer {
|
|||||||
}
|
}
|
||||||
offset /= 60;
|
offset /= 60;
|
||||||
write2(static_cast<int>(offset / 60));
|
write2(static_cast<int>(offset / 60));
|
||||||
|
if (ns != numeric_system::standard) *out_++ = ':';
|
||||||
write2(static_cast<int>(offset % 60));
|
write2(static_cast<int>(offset % 60));
|
||||||
}
|
}
|
||||||
template <typename T, FMT_ENABLE_IF(has_member_data_tm_gmtoff<T>::value)>
|
template <typename T, FMT_ENABLE_IF(has_member_data_tm_gmtoff<T>::value)>
|
||||||
void format_utc_offset_impl(const T& tm) {
|
void format_utc_offset_impl(const T& tm, numeric_system ns) {
|
||||||
write_utc_offset(tm.tm_gmtoff);
|
write_utc_offset(tm.tm_gmtoff, ns);
|
||||||
}
|
}
|
||||||
template <typename T, FMT_ENABLE_IF(!has_member_data_tm_gmtoff<T>::value)>
|
template <typename T, FMT_ENABLE_IF(!has_member_data_tm_gmtoff<T>::value)>
|
||||||
void format_utc_offset_impl(const T& tm) {
|
void format_utc_offset_impl(const T& tm, numeric_system ns) {
|
||||||
#if defined(_WIN32) && defined(_UCRT)
|
#if defined(_WIN32) && defined(_UCRT)
|
||||||
# if FMT_USE_TZSET
|
# if FMT_USE_TZSET
|
||||||
tzset_once();
|
tzset_once();
|
||||||
@ -1246,10 +1272,10 @@ class tm_writer {
|
|||||||
_get_dstbias(&dstbias);
|
_get_dstbias(&dstbias);
|
||||||
offset += dstbias;
|
offset += dstbias;
|
||||||
}
|
}
|
||||||
write_utc_offset(-offset);
|
write_utc_offset(-offset, ns);
|
||||||
#else
|
#else
|
||||||
ignore_unused(tm);
|
ignore_unused(tm);
|
||||||
format_localized('z');
|
format_localized('z', ns == numeric_system::standard ? '\0' : 'E');
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1375,7 +1401,7 @@ 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_utc_offset_impl(tm_); }
|
void on_utc_offset(numeric_system ns) { format_utc_offset_impl(tm_, ns); }
|
||||||
void on_tz_name() { format_tz_name_impl(tm_); }
|
void on_tz_name() { format_tz_name_impl(tm_); }
|
||||||
|
|
||||||
void on_year(numeric_system ns) {
|
void on_year(numeric_system ns) {
|
||||||
@ -1807,7 +1833,7 @@ struct chrono_formatter {
|
|||||||
void on_loc_time(numeric_system) {}
|
void on_loc_time(numeric_system) {}
|
||||||
void on_us_date() {}
|
void on_us_date() {}
|
||||||
void on_iso_date() {}
|
void on_iso_date() {}
|
||||||
void on_utc_offset() {}
|
void on_utc_offset(numeric_system) {}
|
||||||
void on_tz_name() {}
|
void on_tz_name() {}
|
||||||
void on_year(numeric_system) {}
|
void on_year(numeric_system) {}
|
||||||
void on_short_year(numeric_system) {}
|
void on_short_year(numeric_system) {}
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
#include "fmt/chrono.h"
|
#include "fmt/chrono.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@ -290,6 +291,21 @@ TEST(chrono_test, time_point) {
|
|||||||
EXPECT_EQ(sys_output, fmt::format(fmt::runtime(fmt_spec), t1));
|
EXPECT_EQ(sys_output, fmt::format(fmt::runtime(fmt_spec), t1));
|
||||||
EXPECT_EQ(sys_output, fmt::format(fmt::runtime(fmt_spec), tm));
|
EXPECT_EQ(sys_output, fmt::format(fmt::runtime(fmt_spec), tm));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (std::find(spec_list.cbegin(), spec_list.cend(), "%z") !=
|
||||||
|
spec_list.cend()) {
|
||||||
|
auto t = std::chrono::system_clock::to_time_t(t1);
|
||||||
|
auto tm = *std::localtime(&t);
|
||||||
|
|
||||||
|
auto sys_output = system_strftime("%z", &tm);
|
||||||
|
sys_output.insert(sys_output.end() - 2, 1, ':');
|
||||||
|
|
||||||
|
EXPECT_EQ(sys_output, fmt::format("{:%Ez}", t1));
|
||||||
|
EXPECT_EQ(sys_output, fmt::format("{:%Ez}", tm));
|
||||||
|
|
||||||
|
EXPECT_EQ(sys_output, fmt::format("{:%Oz}", t1));
|
||||||
|
EXPECT_EQ(sys_output, fmt::format("{:%Oz}", tm));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef FMT_STATIC_THOUSANDS_SEPARATOR
|
#ifndef FMT_STATIC_THOUSANDS_SEPARATOR
|
||||||
|
Loading…
Reference in New Issue
Block a user