c++20起std::chrono::days才成为标准类型,c++17及更早需用hours或seconds模拟;使用时须注意隐式转换限制、时区与日历语义差异,避免时间逻辑偏差。

chrono 里没有内置的 days 类型?先确认标准版本
从 C++20 开始,std::chrono::days 才正式进入标准库;C++17 及更早版本中,std::chrono 没有原生“天”单位——你直接写 std::chrono::days(3) 会编译失败。
所以第一件事是检查编译器和标准:用 -std=c++20(GCC/Clang)或 /std:c++20(MSVC),并确认头文件已包含:#include <chrono></chrono>。
- Clang 10+、GCC 10+、MSVC 19.28+ 支持 C++20
std::chrono::days - 若必须用 C++17,只能手动用
std::chrono::hours(24)或std::chrono::seconds(86400)模拟,但语义模糊、易出错
用 std::chrono::days 做算术时要注意隐式转换陷阱
std::chrono::days 是一个“日历天”类型,底层基于 std::chrono::duration,但它的 rep 类型是 int(不是 long long),且不与 std::chrono::hours 等自动转换。
常见错误:直接把 days 和 hours 相加,比如 2d + 3h —— 这在 C++20 中不合法,因为没有定义跨类型运算符。
- 正确做法:显式转换,如
2d + std::chrono::hours(3)会触发隐式转换为std::chrono::hours,结果是std::chrono::hours(51) - 更安全的做法是统一转成同一精度,例如都转成
std::chrono::seconds:2d.count() * 86400s + 3h - 注意:
2d + 3h看似自然,但实际依赖用户定义字面量(2d)和标准提供的operator+重载,而后者只对同类型或可隐式提升的 duration 生效
和 std::chrono::system_clock::time_point 配合使用时别忽略时区
std::chrono::days 表示的是纯时间长度(duration),不是日历上的某一天。它和 time_point 相加时,只是机械地增加秒数(按 24×3600 秒/天),不考虑夏令时、闰秒或本地时区偏移。
例如:auto tp = std::chrono::system_clock::now() + 1d; 得到的是 UTC 时间加 86400 秒后的点,不是“明天同一时刻”(如果当地有 DST 切换,真实墙钟可能差 1 小时)。
- 若需日历语义(如“2024-03-10 加 1 天 = 2024-03-11”),应使用
<chrono></chrono>的日历扩展(C++20std::chrono::year_month_day)配合std::chrono::sys_days -
std::chrono::sys_days{2024y/3/10d} + 1d才真正表示日历加一天,结果是sys_days{2024y/3/11d} - 混淆
days和日历日期,是线上服务做定时任务时常见的逻辑偏差来源
自定义 days 字面量(C++14 起可用,但慎用)
C++14 引入了用户定义字面量,标准库在 C++20 中为 days 提供了 d 后缀(如 3d),但它是 std::chrono::days 类型,不是 int。
如果你在 C++17 项目中想提前用 3d,可以自己定义:
constexpr std::chrono::hours operator"" _d(unsigned long long d) {
return std::chrono::hours(d * 24);
}
但这只是模拟,返回的是 hours,不是真正的 days,且无法参与 C++20 日历类型运算。
- 真要兼容旧标准,建议封装一个
struct days { int val; }并提供显式转换方法,比魔改字面量更可控 - 所有自定义字面量必须声明在全局命名空间,且不能与标准冲突;C++20 后再用自定义
_d可能导致 ODR 违规
真正麻烦的从来不是“怎么写 1 天”,而是“这 1 天到底指什么”——是 86400 秒,还是日历上跳过一个 year_month_day,抑或本地时钟显示的下一个 00:00?选错类型,后面所有时间计算都会漂移。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











