TL;DR: I am implementing custom formatter for fmt and Howard Hinnant's date library. With date::year_month_day d{};
, why does fmt::to_string(d)
return "{}"
while fmt::format("{}", d)
works fine, returning "0000-00-00"
? Example on godbolt.
I'm using date library and trying to switch from iostreams to fmt. I need to format date::year_month_day
in YYYY-MM-DD format so I wrote a custom formatter (template specialization of fmt::formatter for date::year_month_day
):
template<>
struct fmt::formatter<date::year_month_day> {
template<typename ParseContext>
auto parse(ParseContext & ctx) { return ctx.begin(); }
template<typename FormatContext>
auto format(const date::year_month_day & ymd, FormatContext & ctx) -> decltype(ctx.out()) {
const int year = (int)ymd.year();
const unsigned month = (unsigned)ymd.month();
const unsigned day = (unsigned)ymd.day();
return fmt::format_to(ctx.out(), "{:04}-{:02}-{:02}", year, month, day);
}
};
Complete minimal working example, with two working examples and one failing, is available on godbolt.
Using that custom formatter, fmt::format("{}", date::year_month_day{})
works as expected, returning "0000-00-00"
. fmt::to_string(date::year_month_day{})
is supposed to return the same result, but returns "{}"
instead.
What is the best way of formatting date::year_month_day
and other types from date
with fmt
, including fmt::to_string()
? Why do I get that "{}"
?
I can't use compiler with C++20 date support yet: as far as I know, there are no complete implementations of calendar and timezone parts of C++20's std::chrono as of June 2020.
Update: using custom formatter for custom empty struct works fine, giving the same result for format("{}", s)
and to_string(s)
, see examples on the godbolt link above. So there must be something special about date::year_month_day
which breaks fmt::to_string()
.
This is an unfortunate effect of the argument-dependent lookup: fmt::to_string
calls format
which ends up being resolved to date::format
instead of fmt::format
. The fix is to fully qualify the call to format
in fmt::to_string
since it depends on a user-defined type.
Update: this has been fixed in https://github.com/fmtlib/fmt/commit/2cac8a9d2e36cd920a9a60ec5b776c187e843fbb.