c++标准库不支持闰秒,所有时间类型均跳过23:59:60;判断闰秒需手动解析iana的leap-seconds.list文件,将目标utc时间转为自1972年起的秒数后查表比对。

闰秒在C++标准库中根本不存在
标准C++(包括std::chrono、std::tm、std::time_t)**不建模闰秒**,所有时间类型都基于“平滑的TAI–UTC差值忽略模型”,即把UTC当作连续秒流处理。这意味着:std::chrono::system_clock返回的纪元以来的秒数,和POSIX时间一样,**跳过闰秒**——23:59:60这个时刻在C++标准时间类型里无法表示,也不会被解析或生成。
你遇到的“闰秒判断”需求,实际来自外部数据源
真正需要判断闰秒的场景,通常是你在解析外部输入(如NTP日志、ICAO/ITU公告文本、leap-seconds.list文件),或对接高精度授时系统。此时不是让C++“计算”闰秒,而是查表比对:
-
leap-seconds.list由IANA维护,每半年更新一次,明确列出每次闰秒发生的UTC日期和方向(正闰秒即插入1秒) - 每一行形如:
#@ 4217817600(TAI–UTC偏移生效时间,单位为TAI秒)和2272060800 37(UTC秒数 + 当前TAI–UTC值) - 关键转换:需将你手头的UTC日期(年月日时分秒)转为对应的UTC秒数(自1972-01-01 00:00:00起),再与列表中各条目的UTC时间戳比对
用C++做闰秒检查,必须自己解析并缓存leap-seconds.list
没有标准API,只能手动实现查找逻辑。核心步骤:
- 下载最新
leap-seconds.list(URL:https://data.iana.org/time-zones/tzdata/leap-seconds.list),注意校验其#@行签名和末尾哈希 - 逐行解析,跳过注释,提取每条记录的UTC时间戳(第二列)和对应TAI–UTC值;注意:该时间戳是“从1900年起的秒数”,需减去
2208988800ULL转为Unix纪元(1970)秒数 - 将目标UTC时间(例如
2016-12-31 23:59:60)按规则转为Unix秒数:先当作普通时间算出2017-01-01 00:00:00的秒数,再减1 —— 因为闰秒发生在23:59:60,它紧邻下一分钟的起点 - 二分查找该秒数是否落在某次闰秒生效时间点(即是否等于某条记录的UTC时间戳);若相等,且下一条记录的TAI–UTC值更大,则为正闰秒发生时刻
示例片段(简化):
// 假设已解析出 leap_seconds = { {1483228800, 37}, {1483228801, 38} } // 2017-01-01 00:00:00 对应 1483228800
std::time_t target = 1483228799; // 2016-12-31 23:59:59 → 但闰秒是 23:59:60,即同一秒级时间戳下多出1秒
// 实际判断:target == 1483228800 表示该秒是闰秒秒(23:59:60),因为下个TAI–UTC值变了
别碰std::put_time和strptime解析23:59:60
几乎所有C/C++标准时间解析函数都会拒绝60作为秒值:
-
std::get_time、strptime在遇到%S=60时直接失败或截断为0 -
std::mktime传入tm_sec=60会规范化为下一分钟(即tm_sec=0, tm_min+=1),完全丢失闰秒语义 - 试图用
std::chrono::parse(C++20)解析"2016-12-31 23:59:60"同样失败,标准未定义该格式支持
所以,任何想靠“解析字符串→转时间对象→判断”的路都走不通。闰秒只能通过外部元数据(leap-seconds.list)+ 手动时间戳对齐来识别,且必须清楚:C++运行时本身对此一无所知。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











