std::chrono::duration_cast 的本质是向零截断而非四舍五入,仅当源单位周期能被目标单位周期整除时才允许小单位转大单位,否则编译失败;反向转换恒安全但需注意 rep 溢出。

std::chrono::duration_cast 的本质是截断,不是四舍五入
它不会做任何数值近似,而是直接丢弃低位精度——比如把 std::chrono::nanoseconds 转成 std::chrono::milliseconds 时,末尾的 999 纳秒会被直接砍掉,不是向上或向下取整。
常见错误是以为转换后能“保留精度”,结果发现时间差变小了:
auto ns = 1234567ns; auto ms = std::chrono::duration_cast<:chrono::milliseconds>(ns); // 结果是 1ms,不是 2ms</:chrono::milliseconds>
- 只做整数除法(向零截断),不调用
round()、floor()或ceil() - 如果源 duration 的 tick_period 分母不能被目标单位整除,必然丢失精度
- 想四舍五入?得手动加半格:
std::chrono::duration_cast<ms>(ns + 500ns)</ms>
跨量级转换必须注意 tick_period 是否可整除
std::chrono::duration 内部由 rep(表示值)和 period(每个 tick 多少秒)组成。duration_cast 能安全转换的前提是:源 period 能被目标 period 整除(即目标单位更大),否则编译失败。
例如:nanoseconds(ratio)→ microseconds(ratio)可以,因为 1000000000 ÷ 1000000 = 1000;但反过来就不行:
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
auto us = 123us; auto ns = std::chrono::duration_cast<:chrono::nanoseconds>(us); // ✅ OK</:chrono::nanoseconds>
auto ns = 123ns; auto us = std::chrono::duration_cast<:chrono::microseconds>(ns); // ✅ OK(截断)</:chrono::microseconds>
auto s = 1s; auto ns = std::chrono::duration_cast<:chrono::nanoseconds>(s); // ✅ OK(精确)</:chrono::nanoseconds>
- 反向转换(大单位 → 小单位)总是安全的,只要
rep类型能容纳结果 - 正向转换(小单位 → 大单位)可能丢精度,且要求 period 可整除,否则编译报错:
error: no matching function for call to 'duration_cast' - 不确定 period 关系?优先用标准 typedef(如
milliseconds),别手写duration<long ratio>></long>
避免隐式转换陷阱:别依赖自动推导 rep 类型
当源 duration 的 rep 是 int,而目标单位需要更大范围(比如转成 hours),duration_cast 不会自动提升 rep 类型,溢出行为未定义。
using ms_t = std::chrono::duration<int std::milli>; ms_t x = std::chrono::duration_values<ms_t>::max(); // 最大 int 毫秒 auto h = std::chrono::duration_cast<:chrono::hours>(x); // ❌ 可能溢出,h 值未定义</:chrono::hours></ms_t></int>
- 显式指定目标
rep类型更安全:std::chrono::duration_cast<:chrono::duration long std::hour_ratio>>(x)</:chrono::duration> - 标准 typedef(如
std::chrono::milliseconds)默认用long long,但自定义 duration 很容易用int或short - 调试时打印
.count()前先确认类型:decltype(x)::rep和decltype(h)::rep可能不同
实际计时场景中该用 duration_cast 还是直接构造?
多数时候你不需要 duration_cast——尤其当只是“把一个 time_point 差值转成毫秒数”这种需求。直接用 .time_since_epoch().count() 更快,也更明确。
auto start = std::chrono::steady_clock::now(); /* ... work ... */ auto end = std::chrono::steady_clock::now(); auto dur = end - start; // type: steady_clock::duration <p>// ✅ 推荐:语义清晰,无转换开销 auto ms = dur.count() <em> dur.period::num / dur.period::den </em> 1000LL; // 不推荐这样算</p><p>// ✅ 更好:直接转成标准单位再取 count auto ms = std::chrono::duration_cast<:chrono::milliseconds>(dur).count();</:chrono::milliseconds></p><p>// ✅ 最佳实践(C++17 起): auto ms = std::chrono::round<:chrono::milliseconds>(dur).count(); // 显式表达四舍五入意图</:chrono::milliseconds></p>
-
duration_cast是唯一能做单位变换的工具,但它不是“格式化输出”的替代品 - 日志或 UI 显示毫秒?优先用
round<ms>()</ms>或floor<ms>()</ms>,而不是裸 cast - 性能敏感路径(如高频采样)中,避免反复 cast;缓存转换后的值,或用
auto保持原类型
精度丢失不是 bug,是设计选择;真正容易被忽略的是:duration_cast 不改变值的物理意义,只改变它的表达方式——而表达方式一旦选错单位,后续所有计算都跟着偏。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










