# How to Format Dates and Times with fmtlib: A Complete Guide to {fmt} Chrono Features

> Master fmtlib chrono features for type-safe date and time formatting. Learn to format std::chrono and std::tm with strftime-like syntax. Avoid C formatting pitfalls today.

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

---

**fmtlib provides type-safe date and time formatting through the `<fmt/chrono.h>` header, supporting `std::chrono` types and `std::tm` with a strftime-like syntax that avoids the pitfalls of traditional C formatting.**

The fmtlib/fmt repository implements high-performance chrono formatting in [`include/fmt/chrono.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/chrono.h), offering a modern C++ alternative to `strftime` with full compile-time safety and locale support. This implementation handles everything from nanosecond-precision durations to zoned time points without requiring manual buffer management or format string validation.

## Core Architecture of fmtlib Chrono Formatting

The heart of date and time formatting resides in [`include/fmt/chrono.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/chrono.h), which defines template specializations of `formatter<T>` for chrono types. When you call `fmt::format` with a duration or time point, the library instantiates these specializations to parse and format the input.

The formatting pipeline follows three distinct phases implemented in the source:

1. **Parsing**: The `parse_chrono_format` function (around line 3028 in [`chrono.h`](https://github.com/fmtlib/fmt/blob/main/chrono.h)) tokenizes the format string, recognizing specifiers like `%Y`, `%S`, and modifiers for padding and locale.
2. **Handling**: The `tm_writer` class (line 1313) translates parsed specifiers into concrete output, handling fractional seconds and locale-aware conversions.
3. **Conversion**: Safe arithmetic operations use `safe_duration_cast` utilities (line 56) to prevent overflow when converting between duration types.

## Supported Date and Time Types

fmtlib can format three primary categories of temporal data:

- **`std::chrono::duration`**: Both integral and floating-point representations, from nanoseconds to years.
- **`std::chrono::time_point`**: For any clock type including system, steady, UTC, local, and zoned clocks.
- **`std::tm`**: The classic C-time structure, with thread-safe utilities like `fmt::gmtime`.

## Chrono Format Syntax and Specifiers

The formatting syntax follows a strftime-like mini-language documented in [`doc/syntax.md`](https://github.com/fmtlib/fmt/blob/main/doc/syntax.md). A chrono format specifier begins with `%` and supports optional padding and locale modifiers:

```

%[padding][locale]type

```

- **Padding modifiers**: `-` for space-padding, `_` for zero-padding.
- **Locale modifiers**: `E` for alternative representations (e.g., locale-dependent year), `O` for alternative numeric symbols.
- **Precision**: For fractional seconds, use `%.<n>S` where *n* specifies decimal places.

Common specifiers include `%Y` (4-digit year), `%m` (month), `%d` (day), `%H` (hour), `%M` (minute), `%S` (second), `%z` (offset), and `%Z` (timezone). Duration-specific specifiers `%Q` (numeric value) and `%q` (unit suffix) provide intuitive output like "42min".

## Practical Examples: Formatting Dates and Times with fmtlib

The following examples demonstrate usage patterns from the fmtlib implementation:

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

int main() {
    using namespace std::chrono_literals;

    // System clock time points
    auto now = std::chrono::system_clock::now();
    std::cout << fmt::format("Default: %c\n", now);
    std::cout << fmt::format("ISO: %Y-%m-%d %H:%M:%S\n", now);
    
    // Duration with fractional seconds
    std::chrono::microseconds us = 1234567us;
    std::cout << fmt::format("Seconds: %S, Milliseconds: %.3S\n", us, us);
    
    // Duration unit suffixes
    std::chrono::minutes mins = 42min;
    std::cout << fmt::format("Duration: %Q%q\n", mins);  // Output: 42min
    
    // Thread-safe tm formatting
    std::time_t t = std::time(nullptr);
    std::tm tm = fmt::gmtime(t);
    std::cout << fmt::format("UTC: %Y-%m-%d %H:%M:%S\n", tm);
}

```

### Formatting Time Points

System clock time points accept any valid chrono format string. The default `%c` produces a locale-appropriate date-time representation, while explicit specifiers like `%Y-%m-%d` generate ISO 8601 compliant output. Locale modifiers such as `%EC` and `%Ex` switch to alternative calendar representations when the locale supports them.

### Handling Fractional Seconds

When formatting `std::chrono::duration` types with sub-second precision, the `%S` specifier automatically includes fractional digits. For explicit control, use precision syntax: `%.3S` limits output to milliseconds, while `%.6S` shows microseconds. The `tm_writer` implementation in [`chrono.h`](https://github.com/fmtlib/fmt/blob/main/chrono.h) (line 1313) handles these conversions without floating-point precision loss.

### Duration Unit Suffixes

The `%Q` specifier extracts the numeric count from a duration, and `%q` appends the appropriate unit suffix (e.g., "min", "s", "ms"). This eliminates manual string concatenation when displaying human-readable durations.

## Locale Support and Performance

For the classic "C" locale, `tm_writer` uses optimized direct digit writing to minimize overhead. When a specific locale is active, the formatter delegates to `std::use_facet<std::time_put<char>>(loc)` (around line 3880 in [`chrono.h`](https://github.com/fmtlib/fmt/blob/main/chrono.h)) to generate locale-aware month names, day names, and numeric formats. This dual-path approach ensures both speed for the common case and correctness for internationalized applications.

## Summary

- **Header**: Include `<fmt/chrono.h>` to access date and time formatting capabilities.
- **Type Safety**: The library supports `std::chrono::duration`, `std::chrono::time_point`, and `std::tm` through template specializations.
- **Syntax**: Use strftime-like format specifiers with extensions for fractional seconds (`%.3S`) and duration units (`%Q%q`).
- **Safety**: `safe_duration_cast` utilities prevent overflow during conversions, and `fmt::gmtime` provides thread-safe calendar conversions.
- **Performance**: Optimized fast paths exist for the "C" locale, with fallback to standard locale facets for internationalization.

## Frequently Asked Questions

### How do I format dates and times with locale support in fmtlib?

fmtlib automatically uses the current locale for chrono formatting unless specified otherwise. Use locale modifiers like `%EY` or `%Ex` in your format string to access alternative calendar representations, or rely on the default behavior which invokes `std::time_put` facets from the standard library for locale-aware output.

### What is the difference between %S and %.3S when formatting durations?

`%S` prints the total seconds including any fractional component derived from the duration's precision. `%.3S` specifically limits the fractional output to three decimal places (milliseconds). According to the implementation in [`include/fmt/chrono.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/chrono.h), this precision modifier works for any duration with sub-second granularity.

### How do I include the chrono formatting header correctly?

Add `#include <fmt/chrono.h>` to your source file after installing the fmtlib library. This header pulls in all necessary definitions for `formatter` specializations of chrono types. The repository structure places this in [`include/fmt/chrono.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/chrono.h), consistent with other fmtlib modular headers like `<fmt/format.h>`.

### Does fmtlib provide thread-safe alternatives to std::gmtime?

Yes, fmtlib provides `fmt::gmtime` and `fmt::localtime` functions that wrap the standard C library functions in a thread-safe manner. These utilities return `std::tm` structures directly and are declared in [`include/fmt/chrono.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/chrono.h), allowing safe calendar conversions without static buffer concerns.