# How to Format std::chrono Time Points with fmtlib: A Complete Guide

> Learn to format std::chrono time points with fmtlib. Easily convert time points to strings using strftime-style specifiers and the fmt/chrono.h header. Get started today.

- Repository: [Hello World Foundation/fmt](https://github.com/fmtlib/fmt)
- Tags: how-to-guide
- Published: 2026-09-12

---

**You can format any `std::chrono` time point or duration by including `<fmt/chrono.h>` and using standard strftime-style format specifiers like `%Y-%m-%d %H:%M:%S` inside your format string.**

The `fmtlib/fmt` repository provides native support for C++11 and C++20 chrono types through the dedicated header [`include/fmt/chrono.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/chrono.h). This implementation eliminates the need for manual `std::tm` conversions or `<iomanip>` manipulators by offering type-safe formatter specializations that handle `system_clock::time_point`, `utc_time`, `local_time`, and high-resolution durations with compile-time validation.

## Include the Chrono Header

To access chrono formatting capabilities, include the specialized header after your core fmt include:

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

```

This header defines the `formatter<std::chrono::duration>` and time-point alias specializations that teach `fmt::format` how to parse and display temporal data.

## Format System Clock Time Points

The most common use case is formatting `std::chrono::system_clock::time_point`. The library treats this as `sys_time` internally and converts it to a broken-down time representation automatically.

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

int main() {
    auto now = std::chrono::system_clock::now();
    
    // Default formatting uses strftime-style specifiers
    std::cout << fmt::format("{:%Y-%m-%d %H:%M:%S}\n", now);
}

```

According to the source code in [`include/fmt/chrono.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/chrono.h), the conversion path involves `detail::to_time_t` at **line 481** to cast the time point to `std::time_t`, followed by a `gmtime` call at **line 535** to obtain the `std::tm` structure for formatting.

## Format UTC and Local Time (C++20)

For C++20 code using distinct clock types, the header provides type aliases at **lines 262-265** for `utc_time` and `local_time`. These enable explicit formatting of UTC-based or local-time-based points using the same specifier syntax.

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

int main() {
    using namespace std::chrono;
    
    // UTC time point
    utc_time<seconds> utc_now{system_clock::now()};
    fmt::print("{:%Y-%m-%d %H:%M:%S} UTC\n", utc_now);
    
    // Local time point  
    local_time<seconds> local_now{system_clock::now()};
    fmt::print("{:%Y-%m-%d %H:%M:%S} local\n", local_now);
}

```

## Format Durations

Durations are handled by the same generic `formatter<std::chrono::duration>` specialization that begins at **line 2033**. The library interprets format specifiers like `%H`, `%M`, and `%S` as a time-of-day breakdown when formatting durations.

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

int main() {
    auto duration = std::chrono::minutes{123} + std::chrono::seconds{45};
    
    // Outputs 02:03:45
    fmt::print("{:%H:%M:%S}\n", duration);
}

```

## Sub-Second Precision

To display fractional seconds, use the `%f` specifier. The implementation extracts the sub-second component using the fractional part extraction logic found at **lines 971-978** of [`include/fmt/chrono.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/chrono.h).

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

int main() {
    auto ms = std::chrono::milliseconds{1234};
    
    // Outputs 01.234 (1 second and 234 milliseconds)
    fmt::print("{:%S.%f}\n", ms);
}

```

## How the Formatter Works Internally

When you pass a chrono type to `fmt::format`, the library executes a three-phase pipeline defined in [`include/fmt/chrono.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/chrono.h):

1. **Parsing**: The format string is analyzed by `parse_chrono_format`, starting at **line 630**, which builds a `chrono_format_checker` to validate specifiers like `%Y`, `%m`, `%d`, `%H`, `%M`, and `%S`.

2. **Conversion**: For time points, the formatter invokes `detail::to_time_t` to convert the duration-since-epoch to `std::time_t`, then uses `gmtime` to create a `std::tm` representation.

3. **Output**: The formatter writes each field according to the parsed specifiers. For durations, it calculates hours, minutes, and seconds directly from the tick count without calendar conversion.

This architecture ensures that **formatting `std::chrono` time points with fmtlib** requires no manual temporaries or error-prone pointer handling.

## Summary

- Include `<fmt/chrono.h>` to enable chrono support alongside the core library.
- Use strftime-style format specifiers (e.g., `%Y-%m-%d %H:%M:%S`) inside your format string braces.
- The formatter specializations begin at **line 2033** in [`include/fmt/chrono.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/chrono.h), handling both durations and time points.
- C++20 `utc_time` and `local_time` aliases are supported via definitions at **lines 262-265**.
- Sub-second precision is available through the `%f` specifier, implemented at **lines 971-978**.

## Frequently Asked Questions

### Do I need to link against a separate library for chrono support?

No. Chrono formatting is header-only functionality. Including `<fmt/chrono.h>` provides all necessary templates and specializations without requiring additional linker flags, as confirmed by the implementation in [`include/fmt/chrono.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/chrono.h).

### What format specifiers are supported for std::chrono types?

The library supports standard strftime specifiers including `%Y` (year), `%m` (month), `%d` (day), `%H` (hour), `%M` (minute), `%S` (second), and `%f` (fractional seconds). The `parse_chrono_format` function at **line 630** validates these specifiers at runtime.

### Does fmtlib require C++20 to format time points?

No. Basic formatting for `std::chrono::system_clock::time_point` works with C++11. However, explicit `utc_time` and `local_time` types require C++20's extended `<chrono>` library, as these type aliases depend on C++20 clock features defined at **lines 262-265**.

### How does fmtlib handle timezone conversions?

By default, time points are formatted as UTC using the `gmtime` conversion path at **line 535**. To display local time, you must explicitly use `std::chrono::local_time` (C++20), which triggers the local clock formatting path in the formatter specializations.