How to Format std::chrono Types with fmtlib: A Complete Guide to Date and Time Output in C++

Include <fmt/chrono.h> and use strftime-style specifiers like {:%Y-%m-%d} to format std::chrono::system_clock::now() and other chrono types with fmtlib.

The {fmt} library provides first-class support for C++ chrono types through specialized formatters defined in the fmtlib/fmt repository. To format chrono types like std::chrono::system_clock::now(), you include the <fmt/chrono.h> header, which exposes formatters for std::chrono::duration, std::chrono::time_point, and std::tm structures. This integration enables type-safe, high-performance date and time formatting using familiar strftime syntax directly within fmtlib's format strings.

Enabling Chrono Support

Before formatting any chrono types, you must include the <fmt/chrono.h> header. This header, located at include/fmt/chrono.h in the source tree, provides the necessary template specializations that teach fmtlib how to convert temporal types into strings. Without this header, attempts to format chrono objects will result in compilation errors because the primary formatter template lacks the required specializations.

Formatting std::chrono::time_point

The formatter for std::chrono::time_point implementations works by converting the time point to a broken-down calendar representation. In include/fmt/chrono.h (lines 68-78), the library defines a formatter<sys_time<Duration>, Char> specialization that handles any time_point whose clock provides a time_since_epoch() conversion to std::chrono::duration.

When you pass std::chrono::system_clock::now() to fmt::print, the library performs three internal steps:

  1. Instantiates the formatter<sys_time<Duration>, Char> for the specific system_clock::time_point type.
  2. Calls gmtime to convert the duration since epoch into a std::tm structure (lines 70-86).
  3. Delegates to the formatter<std::tm, Char> specialization to parse the strftime-style format string.
#include <fmt/chrono.h>
#include <chrono>

int main() {
    auto now = std::chrono::system_clock::now();
    fmt::print("Full timestamp: {}\n", now);           // Default ISO-like output
    fmt::print("Date only:      {:%Y-%m-%d}\n", now);  // 2024-09-04
    fmt::print("Time only:      {:%H:%M:%S}\n", now);  // 14:23:07
}

Handling Sub-Second Precision

For time points with sub-second precision, the implementation extracts the remainder of the duration after converting to seconds (lines 86-99 in include/fmt/chrono.h). This remainder passes to the do_format helper, which appends fractional seconds when you use the %f specifier.

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

int main() {
    using namespace std::chrono_literals;
    auto precise = std::chrono::system_clock::now() + 1234ms;
    fmt::print("Precise: {:%Y-%m-%d %H:%M:%S.%f}\n", precise);
    // %f prints fractional seconds (microseconds)
}

Formatting std::chrono::duration

Durations format automatically without requiring explicit specifiers, though you can combine them with time points in the same format string. The library handles safe duration casting internally to prevent precision loss.

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

int main() {
    using namespace std::chrono_literals;
    fmt::print("Elapsed: {} {}\n", 42s, 150ms);  // Output: Elapsed: 42s 150ms
}

Format Specifier Reference

According to doc/syntax.md in the fmtlib repository, chrono format specifications follow standard strftime conventions. Place specifiers after the % character inside the format braces:

  • %Y: Four-digit year (e.g., 2024).
  • %m: Zero-padded month (01-12).
  • %d: Zero-padded day of month (01-31).
  • %H: Hour in 24-hour format (00-23).
  • %M: Minute (00-59).
  • %S: Second (00-59).
  • %f: Fractional seconds (microseconds).

The doc/api.md file (section Date and Time Formatting) documents additional usage patterns and examples for these specifiers.

Implementation Details

The chrono formatting system relies on several template specializations in include/fmt/chrono.h:

  • formatter<sys_time<Duration>, Char>: Handles system clock time points (lines 68-78).
  • formatter<utc_time<Duration>, Char>: Supports UTC-specific formatting.
  • formatter<local_time<Duration>, Char>: Formats local time representations.

All specializations convert time points to std::tm using gmtime for consistent UTC output, then delegate to the generic std::tm formatter. This architecture ensures that any std::chrono::time_point compatible with time_since_epoch() works correctly, including steady_clock and high_resolution_clock time points (though the calendar date for non-system clocks represents time since their respective epochs).

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

int main() {
    auto steady = std::chrono::steady_clock::now();
    fmt::print("Steady clock (seconds): {:%S}\n", steady);
}

Summary

  • Include <fmt/chrono.h> to enable formatting for all std::chrono::duration and std::chrono::time_point types.
  • Use strftime-style specifiers (e.g., %Y, %m, %d, %H, %M, %S, %f) inside format strings like {:%Y-%m-%d}.
  • Access sub-second precision using the %f specifier, which relies on the internal do_format helper to extract fractional components from lines 86-99 of include/fmt/chrono.h.
  • Format any compatible clock because the formatter<sys_time<Duration>, Char> template works with any time point convertible to duration since epoch.
  • Reference doc/syntax.md for the complete list of chrono format specifications and doc/api.md for official usage examples.

Frequently Asked Questions

Which header do I need to include to format chrono types with fmtlib?

You must include <fmt/chrono.h> in addition to the standard fmt headers. This header defines the required formatter specializations in include/fmt/chrono.h (lines 68-78) that handle std::chrono::time_point, std::chrono::duration, and std::tm objects. Without this header, the compiler cannot resolve formatting for chrono types.

Can I format time points from clocks other than system_clock?

Yes. The formatter<sys_time<Duration>, Char> specialization works with any std::chrono::time_point whose clock provides a time_since_epoch() conversion to std::chrono::duration. This includes steady_clock and high_resolution_clock, though the calendar dates produced represent time elapsed since those clocks' specific epochs rather than actual calendar dates.

How do I display fractional seconds when formatting system_clock::now()?

Use the %f format specifier in your format string, such as {:%Y-%m-%d %H:%M:%S.%f}. Internally, the library extracts the sub-second remainder from the duration (lines 86-99 in include/fmt/chrono.h) and passes it to the do_format helper, which outputs the fractional component as microseconds.

What format syntax does fmtlib use for chrono types?

fmtlib uses standard strftime-style syntax where format specifiers begin with %. Supported specifiers include %Y (year), %m (month), %d (day), %H (hour), %M (minute), %S (second), and %f (fractional seconds), as documented in doc/syntax.md. Everything inside the {:%...} braces is interpreted as a chrono format specifier and processed by the specialized formatter templates.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →