为何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可以正常格式化。
解决办法
- 自定义格式化器:为
std::chrono::time_point<std::chrono::steady_clock>编写fmt的formatter特化,但由于steady_clock没有固定起始时间点,格式化出的“时间”无实际日历意义,仅适合显示相对时间。 - 转换为可格式化类型:
- 若需表示日历时间,直接改用
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
相关产品推荐
相关产品推荐

