Support fill, align & width for time point (#3260)
This commit is contained in:
parent
2622cd23e6
commit
dda53082be
@ -2115,9 +2115,7 @@ template <typename Char, typename Duration>
|
|||||||
struct formatter<std::chrono::time_point<std::chrono::system_clock, Duration>,
|
struct formatter<std::chrono::time_point<std::chrono::system_clock, Duration>,
|
||||||
Char> : formatter<std::tm, Char> {
|
Char> : formatter<std::tm, Char> {
|
||||||
FMT_CONSTEXPR formatter() {
|
FMT_CONSTEXPR formatter() {
|
||||||
basic_string_view<Char> default_specs =
|
this->format_str = detail::string_literal<Char, '%', 'F', ' ', '%', 'T'>{};
|
||||||
detail::string_literal<Char, '%', 'F', ' ', '%', 'T'>{};
|
|
||||||
this->do_parse(default_specs.begin(), default_specs.end());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename FormatContext>
|
template <typename FormatContext>
|
||||||
@ -2145,9 +2143,7 @@ template <typename Char, typename Duration>
|
|||||||
struct formatter<std::chrono::local_time<Duration>, Char>
|
struct formatter<std::chrono::local_time<Duration>, Char>
|
||||||
: formatter<std::tm, Char> {
|
: formatter<std::tm, Char> {
|
||||||
FMT_CONSTEXPR formatter() {
|
FMT_CONSTEXPR formatter() {
|
||||||
basic_string_view<Char> default_specs =
|
this->format_str = detail::string_literal<Char, '%', 'F', ' ', '%', 'T'>{};
|
||||||
detail::string_literal<Char, '%', 'F', ' ', '%', 'T'>{};
|
|
||||||
this->do_parse(default_specs.begin(), default_specs.end());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename FormatContext>
|
template <typename FormatContext>
|
||||||
@ -2190,51 +2186,51 @@ struct formatter<std::chrono::time_point<std::chrono::utc_clock, Duration>,
|
|||||||
|
|
||||||
template <typename Char> struct formatter<std::tm, Char> {
|
template <typename Char> struct formatter<std::tm, Char> {
|
||||||
private:
|
private:
|
||||||
enum class spec {
|
format_specs<Char> specs;
|
||||||
unknown,
|
detail::arg_ref<Char> width_ref;
|
||||||
year_month_day,
|
|
||||||
hh_mm_ss,
|
|
||||||
};
|
|
||||||
spec spec_ = spec::unknown;
|
|
||||||
basic_string_view<Char> specs;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
template <typename It> FMT_CONSTEXPR auto do_parse(It begin, It end) -> It {
|
basic_string_view<Char> format_str;
|
||||||
if (begin != end && *begin == ':') ++begin;
|
|
||||||
|
FMT_CONSTEXPR auto do_parse(basic_format_parse_context<Char>& ctx)
|
||||||
|
-> decltype(ctx.begin()) {
|
||||||
|
auto begin = ctx.begin(), end = ctx.end();
|
||||||
|
if (begin == end || *begin == '}') return end;
|
||||||
|
|
||||||
|
begin = detail::parse_align(begin, end, specs);
|
||||||
|
if (begin == end) return end;
|
||||||
|
|
||||||
|
begin = detail::parse_dynamic_spec(begin, end, specs.width, width_ref, ctx);
|
||||||
|
if (begin == end) return end;
|
||||||
|
|
||||||
end = detail::parse_chrono_format(begin, end, detail::tm_format_checker());
|
end = detail::parse_chrono_format(begin, end, detail::tm_format_checker());
|
||||||
// Replace default spec only if the new spec is not empty.
|
// Replace default format_str only if the new spec is not empty.
|
||||||
if (end != begin) specs = {begin, detail::to_unsigned(end - begin)};
|
if (end != begin) format_str = {begin, detail::to_unsigned(end - begin)};
|
||||||
return end;
|
return end;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename FormatContext, typename Duration>
|
template <typename FormatContext, typename Duration>
|
||||||
auto do_format(const std::tm& tm, FormatContext& ctx,
|
auto do_format(const std::tm& tm, FormatContext& ctx,
|
||||||
const Duration* subsecs) const -> decltype(ctx.out()) {
|
const Duration* subsecs) const -> decltype(ctx.out()) {
|
||||||
|
auto specs_copy = specs;
|
||||||
|
basic_memory_buffer<Char> buf;
|
||||||
|
auto out = std::back_inserter(buf);
|
||||||
|
detail::handle_dynamic_spec<detail::width_checker>(specs_copy.width,
|
||||||
|
width_ref, ctx);
|
||||||
|
|
||||||
const auto loc_ref = ctx.locale();
|
const auto loc_ref = ctx.locale();
|
||||||
detail::get_locale loc(static_cast<bool>(loc_ref), loc_ref);
|
detail::get_locale loc(static_cast<bool>(loc_ref), loc_ref);
|
||||||
auto w = detail::tm_writer<decltype(ctx.out()), Char, Duration>(
|
auto w =
|
||||||
loc, ctx.out(), tm, subsecs);
|
detail::tm_writer<decltype(out), Char, Duration>(loc, out, tm, subsecs);
|
||||||
if (spec_ == spec::year_month_day)
|
detail::parse_chrono_format(format_str.begin(), format_str.end(), w);
|
||||||
w.on_iso_date();
|
return detail::write(
|
||||||
else if (spec_ == spec::hh_mm_ss)
|
ctx.out(), basic_string_view<Char>(buf.data(), buf.size()), specs_copy);
|
||||||
w.on_iso_time();
|
|
||||||
else
|
|
||||||
detail::parse_chrono_format(specs.begin(), specs.end(), w);
|
|
||||||
return w.out();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
FMT_CONSTEXPR auto parse(basic_format_parse_context<Char>& ctx)
|
FMT_CONSTEXPR auto parse(basic_format_parse_context<Char>& ctx)
|
||||||
-> decltype(ctx.begin()) {
|
-> decltype(ctx.begin()) {
|
||||||
auto end = this->do_parse(ctx.begin(), ctx.end());
|
return this->do_parse(ctx);
|
||||||
// basic_string_view<>::compare isn't constexpr before C++17.
|
|
||||||
if (specs.size() == 2 && specs[0] == Char('%')) {
|
|
||||||
if (specs[1] == Char('F'))
|
|
||||||
spec_ = spec::year_month_day;
|
|
||||||
else if (specs[1] == Char('T'))
|
|
||||||
spec_ = spec::hh_mm_ss;
|
|
||||||
}
|
|
||||||
return end;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename FormatContext>
|
template <typename FormatContext>
|
||||||
|
@ -462,7 +462,7 @@ TEST(chrono_test, format_default) {
|
|||||||
fmt::format("{}", std::chrono::duration<int, std::ratio<15, 4>>(42)));
|
fmt::format("{}", std::chrono::duration<int, std::ratio<15, 4>>(42)));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(chrono_test, align) {
|
TEST(chrono_test, duration_align) {
|
||||||
auto s = std::chrono::seconds(42);
|
auto s = std::chrono::seconds(42);
|
||||||
EXPECT_EQ("42s ", fmt::format("{:5}", s));
|
EXPECT_EQ("42s ", fmt::format("{:5}", s));
|
||||||
EXPECT_EQ("42s ", fmt::format("{:{}}", s, 5));
|
EXPECT_EQ("42s ", fmt::format("{:{}}", s, 5));
|
||||||
@ -478,6 +478,35 @@ TEST(chrono_test, align) {
|
|||||||
fmt::format("{:{}%H:%M:%S}", std::chrono::seconds(12345), 12));
|
fmt::format("{:{}%H:%M:%S}", std::chrono::seconds(12345), 12));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(chrono_test, tm_align) {
|
||||||
|
auto t = make_tm(1975, 12, 29, 12, 14, 16);
|
||||||
|
EXPECT_EQ("1975-12-29 12:14:16", fmt::format("{:%F %T}", t));
|
||||||
|
EXPECT_EQ("1975-12-29 12:14:16 ", fmt::format("{:30%F %T}", t));
|
||||||
|
EXPECT_EQ("1975-12-29 12:14:16 ", fmt::format("{:{}%F %T}", t, 30));
|
||||||
|
EXPECT_EQ("1975-12-29 12:14:16 ", fmt::format("{:<30%F %T}", t));
|
||||||
|
EXPECT_EQ(" 1975-12-29 12:14:16 ", fmt::format("{:^30%F %T}", t));
|
||||||
|
EXPECT_EQ(" 1975-12-29 12:14:16", fmt::format("{:>30%F %T}", t));
|
||||||
|
|
||||||
|
EXPECT_EQ("1975-12-29 12:14:16***********", fmt::format("{:*<30%F %T}", t));
|
||||||
|
EXPECT_EQ("*****1975-12-29 12:14:16******", fmt::format("{:*^30%F %T}", t));
|
||||||
|
EXPECT_EQ("***********1975-12-29 12:14:16", fmt::format("{:*>30%F %T}", t));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(chrono_test, tp_align) {
|
||||||
|
auto tp = std::chrono::time_point_cast<std::chrono::microseconds>(
|
||||||
|
std::chrono::system_clock::from_time_t(0));
|
||||||
|
EXPECT_EQ("00:00.000000", fmt::format("{:%M:%S}", tp));
|
||||||
|
EXPECT_EQ("00:00.000000 ", fmt::format("{:15%M:%S}", tp));
|
||||||
|
EXPECT_EQ("00:00.000000 ", fmt::format("{:{}%M:%S}", tp, 15));
|
||||||
|
EXPECT_EQ("00:00.000000 ", fmt::format("{:<15%M:%S}", tp));
|
||||||
|
EXPECT_EQ(" 00:00.000000 ", fmt::format("{:^15%M:%S}", tp));
|
||||||
|
EXPECT_EQ(" 00:00.000000", fmt::format("{:>15%M:%S}", tp));
|
||||||
|
|
||||||
|
EXPECT_EQ("00:00.000000***", fmt::format("{:*<15%M:%S}", tp));
|
||||||
|
EXPECT_EQ("*00:00.000000**", fmt::format("{:*^15%M:%S}", tp));
|
||||||
|
EXPECT_EQ("***00:00.000000", fmt::format("{:*>15%M:%S}", tp));
|
||||||
|
}
|
||||||
|
|
||||||
TEST(chrono_test, format_specs) {
|
TEST(chrono_test, format_specs) {
|
||||||
EXPECT_EQ("%", fmt::format("{:%%}", std::chrono::seconds(0)));
|
EXPECT_EQ("%", fmt::format("{:%%}", std::chrono::seconds(0)));
|
||||||
EXPECT_EQ("\n", fmt::format("{:%n}", std::chrono::seconds(0)));
|
EXPECT_EQ("\n", fmt::format("{:%n}", std::chrono::seconds(0)));
|
||||||
|
Loading…
Reference in New Issue
Block a user