How to Use safe_duration_cast in fmtlib for Safe Chrono Conversions

The {fmt} library provides safe_duration_cast utilities in 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, 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 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, 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) when a conversion would overflow.

#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.

#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:

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

Summary

  • Include 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. 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. 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) 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.

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 →