std::chrono 不能直接处理闰秒。它将 utc 视为线性时间轴,使用固定偏移(tai−37s),不集成闰秒表,也不响应 iers 公告;需借助 howard hinnant 的 date 库等外部方案手动加载和解析 leap-seconds.list 才能实现真实 utc 对齐。

std::chrono 能不能直接处理闰秒
不能。C++20 的 std::chrono(包括 sys_time、utc_time、tai_time)**不包含闰秒表,也不自动插入或跳过闰秒**。它把 UTC 当作“平滑连续的线性时间轴”来建模,和 IERS 实际发布的闰秒公告脱钩。
这意味着:如果你用 std::chrono::utc_clock::now() 获取当前 UTC 时间,返回值是基于 C++ 标准定义的“理想化 UTC”(即 TAI − 37s,固定偏移),不是真实世界中可能因闰秒而暂停/跳变的广播 UTC。
- 真实 UTC 在 2016-12-31 23:59:60 插入一秒 → 你的程序不会感知这个额外的 “60” 秒
-
utc_clock::from_sys(…)和utc_clock::to_sys(…)的转换只依赖编译时硬编码的闰秒数(C++20 初始为 37),不会查系统时区数据库或网络公告 - 所有标准库时间点运算(加减、比较)都按“无闰秒”假设进行,结果在高精度授时场景下会漂移
想对齐真实 UTC,得自己加载闰秒表
必须显式引入外部闰秒数据源,并重写时间转换逻辑。主流做法是用 Howard Hinnant 的 date 库(已作为 <chrono></chrono> 扩展被 C++20 采纳部分接口,但闰秒支持仍需手动集成)。
关键步骤:
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
- 下载并解析 IERS 官方
leap-seconds.list(路径如/usr/share/zoneinfo/leap-seconds.list或从 ietf.org 获取) - 用
date::parse("%Y-%m-%d %H:%M:%S", …)解析闰秒生效时间(注意:IERS 给的是 TAI 时间戳) - 构建
std::vector<:sys_seconds></:sys_seconds>记录每个闰秒插入点(转成系统时间) - 封装自己的
real_utc_clock,在now()中查表修正
示例片段(需 date 库):
auto ls = date::get_leap_second_info(); // 需提前 load_leap_seconds() auto tai = date::tai_clock::now(); auto utc = date::utc_clock::from_tai(tai); // 仍用标准转换 // 但若要映射到广播 UTC,则需:if (tai >= ls.last_tai) utc += 1s;
Linux 系统级闰秒处理其实也不可靠
别指望 clock_gettime(CLOCK_REALTIME, ...) 或 gettimeofday() 自动处理闰秒——Linux 默认采用“ smear ”(涂抹)策略(如 NTPd 的 -x 模式),把闰秒差值摊到数小时均匀调整;或者直接忽略(多数容器/云环境默认)。
-
CLOCK_TAI是唯一保证线性的时钟,但它返回的是 TAI,不是广播 UTC -
/proc/sys/kernel/time/ntp_tick_shift等参数只影响内核 tick,不改变用户态时间 API 行为 - systemd-timesyncd、chrony 等工具是否启用闰秒支持,取决于配置(如 chrony 的
leapsectz指令),且需要定期更新leapseconds文件
业务代码里要不要主动处理闰秒
绝大多数应用不需要。日志打点、定时任务、HTTP 请求超时、数据库事务时间戳——这些都不依赖秒级精度对齐 IERS UTC。
- 金融交易系统:通常用 TAI 或自增序列号做事件排序,UTC 仅作可读标注
- 分布式追踪:依赖
std::chrono::steady_clock(单调、无闰秒)做 span duration - 只有卫星导航、射电天文、原子钟同步等场景才真需要闰秒对齐
- 如果真要支持,别自己解析
leap-seconds.list—— 用成熟封装如libfixposix或abseil的TimeZone::Lookup(带闰秒上下文)
最常被忽略的一点:闰秒发生时刻,strftime("%H:%M:%S", ...) 可能输出 "23:59:60",但你的 struct tm 解析器大概率没实现这个扩展,会崩或回绕。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










