c++c++-chronofmt

How can I format a `std::chrono::year_month_day` with libfmt?


I am using gcc-13.3 with c++23 enabled.

I have the following code which uses std::format to format a std::chrono::year_month_day to a string:

#include <chrono>
#include <format>
#include <iostream>

int main()
{
    const std::chrono::time_point now {std::chrono::system_clock::now()};
    const std::chrono::year_month_day ymd {std::chrono::floor<std::chrono::days>(now)};

    std::cout << std::format("{}", ymd) << '\n';

    return 0;
}

This works as expected.

Now I want to replace std::format with libfmt. (I have fmtlib-11.2.0 installed.)

#include <fmt/chrono.h>
#include <fmt/core.h>
#include <chrono>
#include <iostream>

int main()
{
    const std::chrono::time_point now {std::chrono::system_clock::now()};
    const std::chrono::year_month_day ymd {std::chrono::floor<std::chrono::days>(now)};

    std::cout << fmt::format("{}", ymd) << '\n';

    return 0;
}

This fails to compile:

/usr/local/include/fmt/base.h:2262:45: error: \
‘fmt::v11::detail::type_is_unformattable_for< \
    std::chrono::year_month_day, char> _’ has incomplete type
 2262 |     type_is_unformattable_for<T, char_type> _;

I was (perhaps incorrectly?) under the impression that std::chrono types are directly formattable with fmtlib.

In addition, I can see formatter specialisations in fmt/chrono.h which I have included.

$ grep year_month_day /usr/local/include/include/fmt/chrono.h
using year_month_day = std::chrono::year_month_day;
class year_month_day {
  year_month_day() = default;
  constexpr year_month_day(const year& y, const month& m, const day& d) noexcept
struct formatter<year_month_day, Char> : private formatter<std::tm, Char> {
  auto format(year_month_day val, FormatContext& ctx) const

Solution

  • {fmt} uses the __cpp_lib_chrono feature-test macro to detect if chrono types are available. For std::chrono::year_month_day, which is a C++20 feature, it checks if the standard library sets this macro to 201907 or higher. One possible reason for it to not be set or set to a lower value is that you are compiling with an older standard. It is also possible that the standard library sets this macro to a lower value if it only provides a partial implementation of C++20 chrono features.

    Your example works on godbolt with gcc 15.1 (and a corresponding version of libstdc++) and -std=c++20: https://www.godbolt.org/z/o5fxEGMdn.