You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何C++ fmt库不支持显示std::chrono::steady_clock获取的时间?

为什么fmt库无法格式化std::chrono::steady_clock的时间点?

我可以用C++ fmt库配合std::chrono::system_clock和std::chrono::high_resolution_clock正常显示当前时间,但使用std::chrono::steady_clock时会报错。

最小复现示例

#include <iostream>
#include <fmt/core.h>
#include <fmt/chrono.h>
#include <fmt/format.h>
#include <fmt/std.h>

int main()
{
    fmt::print("current time: {:%Y-%m-%d %H:%M:%S.%z}\n", std::chrono::system_clock::now());
    fmt::print("current time: {:%Y-%m-%d %H:%M:%S.%z}\n", std::chrono::high_resolution_clock::now());
    // fmt::print("current time: {:%Y-%m-%d %H:%M:%S.%z}\n", std::chrono::steady_clock::now());
}

正常运行输出

current time: 2023-02-25 11:08:43.+0000
current time: 2023-02-25 11:08:43.+0000

取消注释后报错信息

In file included from <source>:12:
/opt/compiler-explorer/libs/fmt/9.1.0/include/fmt/core.h:1756:3: error: static assertion failed due to requirement 'formattable': Cannot format an argument. To make type T formattable provide a formatter<T> specialization: https://fmt.dev/latest/api.html#udt
  static_assert(
  ^
/opt/compiler-explorer/libs/fmt/9.1.0/include/fmt/core.h:1777:10: note: in instantiation of function template specialization 'fmt::detail::make_value<fmt::basic_format_context<fmt::appender, char>, std::chrono::time_point<std::chrono::steady_clock, std::chrono::duration<long, std::ratio<1, 1000000000>>> &>' requested here
  return make_value<Context>(val);
         ^
/opt/compiler-explorer/libs/fmt/9.1.0/include/fmt/core.h:1899:23: note: in instantiation of function template specialization 'fmt::detail::make_arg<true, fmt::basic_format_context<fmt::appender, char>, fmt::detail::type::custom_type, std::chrono::time_point<std::chrono::steady_clock, std::chrono::duration<long, std::ratio<1, 1000000000>>> &, 0>' requested here
        data_{detail::make_arg<
                      ^
/opt/compiler-explorer/libs/fmt/9.1.0/include/fmt/core.h:1918:10: note: in instantiation of function template specialization 'fmt::format_arg_store<fmt::basic_format_context<fmt::appender, char>, std::chrono::time_point<std::chrono::steady_clock, std::chrono::duration<long, std::ratio<1, 1000000000>>>>::format_arg_store<std::chrono::time_point<std::chrono::steady_clock, std::chrono::duration<long, std::ratio<1, 1000000000>>> &>' requested here
  return {FMT_FORWARD(args)...};
         ^
/opt/compiler-explorer/libs/fmt/9.1.0/include/fmt/core.h:3294:28: note: in instantiation of function template specialization 'fmt::make_format_args<fmt::basic_format_context<fmt::appender, char>, std::chrono::time_point<std::chrono::steady_clock, std::chrono::duration<long, std::ratio<1, 1000000000>>> &>' requested here
  const auto& vargs = fmt::make_format_args(args...);
                           ^
<source>:23:10: note: in instantiation of function template specialization 'fmt::print<std::chrono::time_point<std::chrono::steady_clock, std::chrono::duration<long, std::ratio<1, 1000000000>>>>' requested here
    fmt::print("current time: {:%Y-%m-%d %H:%M:%S.%z}\n", std::chrono::steady_clock::now());
         ^
1 error generated.

核心原因

std::chrono::steady_clock的设计目标是测量时间间隔,而非表示实际的日历时间。它不提供将时间点转换为std::time_t的接口(即没有to_time_t静态成员函数),而fmt库的chrono格式化支持依赖这一转换能力来解析%Y-%m-%d这类日历时间格式。

对比另外两个时钟:

  • std::chrono::system_clock:明确绑定系统日历时间,提供to_time_t和from_time_t接口,用于在时间点与Unix时间戳间转换。
  • std::chrono::high_resolution_clock:通常是system_clock或steady_clock的别名(取决于实现),但多数平台上会继承system_clock的日历时间转换能力,因此fmt可以正常格式化。

解决办法

  1. 自定义格式化器:为std::chrono::time_point<std::chrono::steady_clock>编写fmt的formatter特化,但由于steady_clock没有固定起始时间点,格式化出的“时间”无实际日历意义,仅适合显示相对时间。
  2. 转换为可格式化类型:
    • 若需表示日历时间,直接改用system_clock或high_resolution_clock;
    • 若仅需记录相对时间,计算与某个起始steady_clock时间点的间隔,格式化这个时长(fmt支持格式化std::chrono::duration)。

示例:格式化steady_clock的时间间隔

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

int main()
{
    auto start = std::chrono::steady_clock::now();
    // 模拟耗时操作
    std::this_thread::sleep_for(std::chrono::milliseconds(150));
    auto end = std::chrono::steady_clock::now();
    
    fmt::print("elapsed time: {:%H:%M:%S.%3}\n", end - start);
}

内容的提问来源于stack exchange,提问作者DailyLearner

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 03:25:23