17370845950

c++的std::chrono库如何处理闰秒? (UTC vs TAI)
std::chrono不处理闰秒,所有标准时钟均忽略闰秒,依赖外部库(如date)或手动查表实现UTC/TAI转换。

std::chrono 不处理闰秒,它基于系统时钟(通常是 UTC),但完全不感知闰秒存在。

std::chrono 的时钟类型都不支持闰秒

所有标准时钟 —— std::chrono::system_clockstd::chrono::steady_clockstd::chrono::high_resolution_clock —— 都是单调或近似 UTC 的实现,但 C++ 标准明确回避了闰秒语义:

  • system_clock 通常映射到 POSIX clock_gettime(CLOCK_REALTIME, ...) 或 Windows GetSystemTimeAsFileTime(),二者都跳过闰秒(即“smear”或直接忽略)
  • 没有 std::chrono::tai_clockstd::chrono::utc_clock(C++20 及之前标准)
  • 即使系统底层使用 TAI(如某些 NTP 服务器),system_clock::time_point 仍按“Unix 时间戳”解释

    :自 1970-01-01T00:00:00 UTC 起的秒数(不含闰秒)

闰秒发生时 std::chrono 的实际行为

以 2016 年末的闰秒(UTC 23:59:60)为例:

  • Linux 系统通常采用“重复秒”策略:23:59:6023:59:6000:00:00,但 clock_gettime(CLOCK_REALTIME) 多数发行版会“抹平”(smear),让这一秒被拉长或跳过
  • system_clock::to_time_t()system_clock::from_time_t() 无法表示 23:59:60 —— 它们只接受 struct tmtm_sec ∈ [0, 60),而 60 是 POSIX 允许的闰秒值,但 std::chrono 的转换函数不校验或处理该值
  • 若你用 std::put_time 格式化一个恰好落在闰秒窗口内的 time_t,结果取决于 libc 实现(glibc 支持 tm_sec == 60,但 std::chrono 不保证传入合法值)

需要 TAI/UTC 对齐时怎么办?

标准库无解,必须依赖外部数据和手动校正:

  • 闰秒表是离散、人工发布的(如 IERS Bulletin C),需定期更新本地数据库(如 leap-seconds.list
  • 可用第三方库辅助:  – date 库(Howard Hinnant)提供 dateutc_clock,并内置截至编译时的闰秒表  – 示例:将 TAI 时间转为带闰秒的 UTC 字符串需显式调用 tai_clock(内部查表)
  • 自行实现需注意:TAI = UTC + 总闰秒数;而总闰秒数随时间分段变化(不是固定偏移),必须做时间点查表而非简单加减
#include "date/tz.h"
using namespace date;
auto tai_tp = tai_clock::now();
auto utc_tp = utc_clock::from_tai(tai_tp); // 查表计算 UTC 偏移
std::cout << utc_tp << '\n'; // 输出含闰秒语义的 UTC 时间

真正棘手的不是“怎么转”,而是“谁负责更新闰秒表”和“系统时钟是否已 smear”。生产环境若需亚秒级 UTC 对齐(如天文、金融时间戳),不能只靠 date::utc_clock::to_sys()