How to Format std::chrono Types Using fmtlib

fmtlib provides full formatting support for C++ chrono types through the fmt/chrono.h header, allowing you to format std::chrono::duration with specifiers like %Q and %q, and std::chrono::time_point using standard strftime-compatible patterns.

Formatting time values in C++ typically requires verbose stream manipulators or C-style format strings, but the fmtlib library eliminates this complexity with dedicated chrono support. By including the fmt/chrono.h header from the fmtlib/fmt repository, you gain access to type-safe formatting for durations, time points, and clocks. This guide demonstrates how to format std::chrono types using fmtlib with practical examples derived from the source code.

Include the fmt/chrono.h Header

All chrono formatting capabilities reside in a single header. Add the following include to your source file:

#include <fmt/chrono.h>

This header provides specializations of formatter<T> for std::chrono::duration and std::chrono::time_point types. When you pass chrono objects to fmt::format, the library automatically selects the appropriate formatter, parses the format string, and drives the output generation.

Format std::chrono::duration Values

Durations represent time intervals. The implementation in include/fmt/chrono.h provides the %Q specifier for the numeric value and %q for the unit suffix.

Basic Duration Formatting

Use {:%Q} to extract just the numeric value, or {:%Q %q} to include the unit:

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

int main() {
    using namespace std::chrono_literals;
    std::chrono::duration<double> d = 1.2345s;

    // Numeric value only
    std::cout << fmt::format("{:%Q}", d) << '\n';     // 1.2345
    
    // Value with unit
    std::cout << fmt::format("{:%Q %q}", d) << '\n';  // 1.2345 s
}

Precision and Fixed Formatting

For floating-point durations, you can specify precision within the format string. The library handles safe duration conversions internally through safe_duration_cast utilities (lines 200–260 in chrono.h) to prevent overflow:

// Fixed precision with 3 decimal places
std::cout << fmt::format("{:%Q.3f}", d) << '\n';  // 1.235

Format std::chrono::time_point Objects

Time points represent specific moments in time. The formatting implementation uses strftime-compatible specifiers processed by the tm_writer class (starting at line 440 in chrono.h).

System Clock Time Points

Format std::chrono::system_clock::now() using standard date and time specifiers:

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

int main() {
    using namespace std::chrono;
    auto now = system_clock::now();

    // ISO-8601 format
    std::cout << fmt::format("{:%F %T}", now) << '\n';  
    // Output: 2026-09-10 14:23:07
    
    // Custom format with weekday and month name
    std::cout << fmt::format("{:%a, %b %d %Y %H:%M}", now) << '\n';
    // Output: Sat, Sep 10 2026 14:23
}

UTC and Local Time with Subseconds

The library supports utc_clock and local time variants. For subsecond precision, the implementation uses write_fractional_seconds and write_floating_seconds (lines 660–720 in chrono.h):

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

int main() {
    using namespace std::chrono;
    utc_time<microseconds> utc_tp = utc_clock::now();

    // Include microseconds
    std::cout << fmt::format("{:%F %T.%Q}", utc_tp) << '\n';
    // Output: 2026-09-10 14:23:07.123456
}

Implementation Overview

The chrono formatting system in include/fmt/chrono.h relies on several key components to ensure safety and performance:

  • parse_chrono_format (lines 28–73): Parses %-based format strings and delegates conversions to handler callbacks.
  • tm_writer (line ~440): Receives callbacks like on_year, on_month, and on_second to write formatted characters into the output buffer.
  • safe_duration_cast (lines 200–260): Ensures conversions between different duration types never overflow or lose precision during formatting.

These components work together within the generic formatter<T> specializations to provide zero-overhead, type-safe formatting.

Summary

  • Include fmt/chrono.h to enable chrono formatting support in fmtlib.
  • Use %Q for duration values and %q for unit suffixes when formatting std::chrono::duration.
  • Apply standard strftime specifiers (like %Y, %m, %d, %H, %M, %S) to std::chrono::time_point objects.
  • Access subsecond precision through fractional second specifiers supported by the internal write_fractional_seconds implementation.
  • The formatting system prevents overflow through safe_duration_cast utilities during type conversions.

Frequently Asked Questions

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

You must include <fmt/chrono.h>. This header provides the necessary formatter specializations for all std::chrono types including durations and time points. The rest of the fmtlib infrastructure is pulled in automatically when you include this file.

Can I format std::chrono::duration with custom precision?

Yes. For floating-point durations, you can specify precision directly in the format string using syntax like {:%Q.3f}. The library uses internal utilities like write_floating_seconds (located around lines 660–720 in include/fmt/chrono.h) to handle the fractional part formatting safely.

Does fmtlib support UTC and local time points?

Yes. The library provides full support for std::chrono::utc_time, std::chrono::local_time, and std::chrono::system_clock::time_point. All time point types use the same strftime-compatible formatting specifiers processed by the tm_writer class in chrono.h.

How does fmtlib prevent overflow when formatting durations?

The implementation uses safe_duration_cast utilities (located around lines 200–260 in include/fmt/chrono.h) to ensure conversions between different duration types maintain precision and avoid overflow during the formatting process.

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 →