直接相减两个 time_point 得到 duration 类型,无需手动转毫秒;错误做法是强转 long long 计算,会丢失精度;正确做法是用 duration_cast 提取毫秒值。

std::chrono::duration 直接相减就能算时差,别手动转毫秒
两个 std::chrono::time_point 相减,结果就是 std::chrono::duration 类型,本质是“时间间隔”的强类型封装。不需要先转成毫秒或秒再做减法——那反而会丢失精度、引入截断误差。
常见错误是把 time_point 强制转成 long long 再计算:
auto t1 = std::chrono::steady_clock::now(); std::this_thread::sleep_for(std::chrono::milliseconds(10)); auto t2 = std::chrono::steady_clock::now(); // ❌ 错误:强行转 long long 丢精度,且语义不清 auto diff_ms = (t2.time_since_epoch().count() - t1.time_since_epoch().count()) * std::chrono::steady_clock::period::num / std::chrono::steady_clock::period::den;
✅ 正确做法是直接相减,让类型系统帮你处理单位转换:
auto diff = t2 - t1; // 类型是 std::chrono::duration<..., ...> auto ms = std::chrono::duration_cast(diff).count();
-
duration支持直接 +、-、==、 - 不同 clock(如
steady_clock和system_clock)的time_point不能直接相减,编译报错 - 用
duration_cast转换时,向下取整(向零截断),若需四舍五入可先加半格再 cast
std::chrono::duration_cast 不是函数调用,是模板显式特化
std::chrono::duration_cast 是一个模板,不是普通函数。它在编译期决定如何缩放底层计数值,不涉及运行时开销。但写错模板参数会导致静默精度损失或编译失败。
立即学习“C++免费学习笔记(深入)”;
典型陷阱:
- 把
duration_cast当成合法写法 —— 实际必须是duration类型,比如duration_cast - 从高精度往低精度 cast(如纳秒 → 毫秒)会截断,但反向 cast(毫秒 → 纳秒)是安全的,只是补零
- 用
auto接收 cast 结果时,类型仍是duration,不是原始整数;要取数值必须调用.count()
示例:
auto ns = std::chrono::nanoseconds(123456789); auto ms = std::chrono::duration_cast(ns); // 123ms auto count = ms.count(); // 类型是 long long,值为 123
跨单位转换容易踩的坑:ratio 和浮点精度
std::chrono::duration 的模板参数是 Rep(表示类型)和 Period(一个 std::ratio)。比如 milliseconds 是 duration,其中 milli = ratio。
当你自定义 duration 或混用单位时,要注意:
-
ratio(微秒)和ratio(毫秒)之间转换,如果Rep是整数,除不尽就会截断 - 用
double作Rep可保留小数,但会引入浮点误差,比如duration在长时间累加后可能失准 - 避免用
duration_cast在整数Rep和浮点Rep之间来回转,容易隐式溢出或精度坍塌
推荐做法:内部统一用整数 Rep(如 long long),只在最终输出或 ui 层才转成浮点秒或带小数的毫秒。
实际性能影响:duration 运算几乎零开销,但 cast 和 count 有隐含成本
duration 是纯类型包装,所有算术操作在编译期确定缩放逻辑,生成的汇编通常就是几条整数加减或移位指令。但以下操作有真实开销:
-
duration_cast若目标单位与源单位不可整除(如纳秒 → 毫秒),需做整数除法(非移位),在某些嵌入式平台较慢 -
.count()是 trivial 成员函数,但若后续拿这个值做大量浮点运算,要注意类型转换延迟 - 频繁创建临时
duration对象(尤其模板实例多时)可能略微增加编译时间和二进制体积,但对运行时无影响
高频场景(如游戏循环、实时日志打点)建议提前 cast 好并缓存,而不是每次都要 duration_cast。
真正难的是理解 period 的 rational 缩放关系,而不是写法本身。多数问题出在想当然地“除1000”或“乘1e6”,而忽略了 ratio 是编译期有理数,不是运行时浮点系数。