# How to Use safe_duration_cast in fmtlib for Safe Chrono Conversions

> Learn to use fmtlib's safe_duration_cast for safe chrono conversions. Prevent undefined behavior, overflow, and precision loss when converting std::chrono::duration types.

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

---

**The {fmt} library provides `safe_duration_cast` utilities in [`include/fmt/chrono.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/chrono.h) that prevent undefined behavior, overflow, and precision loss when converting between `std::chrono::duration` types.**

The fmtlib/fmt repository implements robust overflow-checked conversions for C++ chrono types. By using the `safe_duration_cast` facilities located in [`include/fmt/chrono.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/chrono.h), you can safely convert duration values without risking undefined behavior from standard `std::chrono::duration_cast` operations.

## Understanding the safe_duration_cast Implementation

The safe conversion machinery resides in [`include/fmt/chrono.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/chrono.h) within the `safe_duration_cast` namespace (lines 27-35). This code is conditionally compiled when `FMT_SAFE_DURATION_CAST` is defined as `1` (the default), providing three specialized template functions that handle different numeric representations.

### lossless_integral_conversion

The `lossless_integral_conversion<To, From>(from, ec)` template performs conversions between integral types without data loss. As implemented at lines 41-66, this function validates that the source value fits within the target type's range. If the value would overflow or underflow, the function sets the integer error code `ec` to indicate failure.

### safe_float_conversion

For floating-point transitions, `safe_float_conversion<To, From>(from, ec)` (lines 112-133) handles special IEEE 754 values while validating range constraints. This helper preserves NaN and infinity values and sets `ec` when a finite value exceeds the target type's representable range.

### safe_duration_cast for Floating-Point Representations

The `safe_duration_cast<To>(from, ec)` overload specifically handles floating-point durations (lines 56-70). It performs intermediate calculations in a widened "IntermediateRep" type to prevent overflow during the conversion arithmetic, then checks whether the final result fits safely within the target duration's representation.

## High-Level API: fmt::duration_cast

The public interface `fmt::duration_cast`, defined at lines 20-25 of [`include/fmt/chrono.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/chrono.h), provides a convenient throwing wrapper around the safe conversion logic. When `FMT_SAFE_DURATION_CAST` is enabled, this template function forwards to the safe helpers and throws `fmt::format_error` (defined in [`include/fmt/format.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/format.h)) when a conversion would overflow.

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

int main() {
    using namespace std::chrono;
    
    try {
        // Safe conversion from seconds to milliseconds
        auto ms = fmt::duration_cast<milliseconds>(seconds(5));
        std::cout << "5 s = " << ms.count() << " ms\n";
        
        // This throws fmt::format_error on overflow
        auto huge = duration<int64_t, std::ratio<1, 1000>>(1'000'000'000);
        auto result = fmt::duration_cast<milliseconds>(huge);
    } catch (const fmt::format_error& e) {
        std::cerr << "Overflow detected: " << e.what() << '\n';
    }
}

```

## Low-Level API: Error Code Interface

For applications requiring explicit error handling, the `fmt::safe_duration_cast` namespace exposes the underlying functions directly. These return an empty duration and set the integer error code `ec` to `1` on failure (or `0` on success) instead of throwing exceptions.

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

int main() {
    using namespace std::chrono;
    
    int ec = 0;
    
    // Non-throwing conversion with error code
    auto safe_ms = fmt::safe_duration_cast::safe_duration_cast<milliseconds>(
                      seconds(5), ec);
    if (ec) {
        std::cerr << "Conversion failed!\n";
    } else {
        std::cout << "5 s = " << safe_ms.count() << " ms\n";
    }
    
    // Floating-point duration handling
    auto fsec = duration<double>(0.00123);
    ec = 0;
    auto fms = fmt::safe_duration_cast::safe_duration_cast<milliseconds>(fsec, ec);
    if (!ec) {
        std::cout << "Floating-point: " << fms.count() << " ms\n";
    }
}

```

## Configuring FMT_SAFE_DURATION_CAST

The `FMT_SAFE_DURATION_CAST` preprocessor macro controls compilation of the safe conversion path. When set to `1` (default), `fmt::duration_cast` uses `lossless_integral_conversion` for integral types and widened intermediates for floating-point calculations. Set this macro to `0` before including headers to disable safety checks and use raw `std::chrono::duration_cast` behavior:

```cpp
#define FMT_SAFE_DURATION_CAST 0
#include <fmt/chrono.h>

```

## Summary

- **Include** [`include/fmt/chrono.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/chrono.h) from the fmtlib/fmt repository to access overflow-checked chrono conversions.
- **Use** `fmt::duration_cast<To>(duration)` for automatic validation that throws `fmt::format_error` when values overflow.
- **Use** `fmt::safe_duration_cast::safe_duration_cast<To>(duration, ec)` for manual error handling via integer error codes without exceptions.
- **Control** the feature through the `FMT_SAFE_DURATION_CAST` macro (default `1` enables safe conversions).
- **Handle** floating-point durations safely with preserved NaN/Infinity values through the internal `safe_float_conversion` helper.

## Frequently Asked Questions

### What happens when safe_duration_cast detects an overflow?

When using the high-level `fmt::duration_cast` API, the library throws `fmt::format_error` defined in [`include/fmt/format.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/format.h). When using the low-level `fmt::safe_duration_cast::safe_duration_cast` interface, the function sets the error code parameter `ec` to `1` and returns a default-constructed duration of the target type.

### How do I disable safe conversions and use standard duration_cast?

Define `FMT_SAFE_DURATION_CAST` as `0` before including [`include/fmt/chrono.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/chrono.h). This causes `fmt::duration_cast` to directly invoke `std::chrono::duration_cast` without performing overflow checks or using the safe helper functions.

### Does safe_duration_cast handle floating-point special values?

Yes. The implementation uses `safe_float_conversion` (lines 112-133 in [`include/fmt/chrono.h`](https://github.com/fmtlib/fmt/blob/main/include/fmt/chrono.h)) to preserve NaN and infinity values while checking that finite magnitude values fit within the target type's representable range before conversion.

### Which header file do I need to include?

Include `<fmt/chrono.h>` from the fmtlib/fmt repository. This header provides both the high-level `fmt::duration_cast` function and the low-level `fmt::safe_duration_cast` namespace containing the explicit error-code based conversion functions.