C++ std::chrono::tai_clock用法实战 _ C++20处理国际原子时【详解】

阿宇同学_9660

阿宇同学_9660

2026-04-28

627人浏览

原创

tai_clock不是更准的system_clock,而是独立于utc、无闰秒、与utc偏移量随历史闰秒插入动态变化的时间标度;其now()返回以1970-01-01 tai为起点的time_point,跨时钟转换必须通过from_utc/to_utc查闰秒表,不可手动加减固定秒数。

c++ std::chrono::tai_clock用法实战 _ c++20处理国际原子时【详解】

tai_clock 不是“更准的 system_clock”,它是完全独立的时间标度——没有闰秒、不随地球自转调整、与 UTC 固定偏移 37 秒(截至 2026 年 4 月)。直接用 system_clock::now() 加减 37 秒来模拟 TAI 是错的,因为闰秒插入历史会影响回溯转换。

为什么不能手动加减 37 秒?

TAI 和 UTC 的差值不是常量:1972 年初为 +10 秒,之后每次插入闰秒就 +1。截至 2026 年 4 月,已累计插入 27 次闰秒(含 1972 年那 10 秒),所以当前差值为 +37 秒。但 tai_clock::from_utc() 和 tai_clock::to_utc() 会查闰秒数据库,自动处理历史跳变点。手动硬编码 37 秒只对“现在”近似成立,对过去或未来时间点会出错。

  • 错误示例:auto taitp = std::chrono::time_point<tai_clock>(utc_tp.time_since_epoch() + std::chrono::seconds(37));</tai_clock> —— 这忽略所有闰秒插入时刻的不连续性
  • 正确路径必须走 tai_clock::from_utc(utc_tp) 或 tai_clock::to_utc(tai_tp)
  • 闰秒数据库依赖系统时区数据(Windows 10 1809+/Linux glibc ≥2.30),旧系统可能 fallback 到静态表,结果不一致

tai_clock::now() 返回的是什么?

tai_clock::now() 返回的是当前国际原子时对应的时间点,类型为 std::chrono::time_point<tai_clock></tai_clock>,其 epoch 是 1970-01-01 00:00:00 TAI(注意:不是 UTC)。这个时间点内部用纳秒级 tai_clock::duration 表示,和 system_clock 的 epoch 起始不同,不能直接比较或算术运算。

C++ Code Review Master
C++ Code Review Master

组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。

下载
  • 不能写:tai_clock::now() > system_clock::now() —— 编译失败,类型不兼容
  • 如需比较,必须先转换:tai_clock::to_utc(tai_tp) > system_clock::now()
  • tai_clock::now() 在多数实现中基于硬件原子钟信号或 NTP 校准的 TAI 源,但标准不保证精度,实际取决于平台支持

跨时钟转换必须用 from_utc / to_utc

TAI 与其他时钟(system_clock、utc_clock、gps_clock)之间没有隐式转换,所有转换都必须显式调用静态成员函数。这些函数会触发闰秒表查询,失败时抛出 std::runtime_error(例如数据库缺失或时间超出已知闰秒范围)。

  • UTC → TAI:auto tai_tp = tai_clock::from_utc(utc_tp);
  • TAI → UTC:auto utc_tp = tai_clock::to_utc(tai_tp);
  • system_clock → TAI:先转 utc_clock,再转 tai_clock:tai_clock::from_utc(utc_clock::from_sys(sys_tp))
  • 转换失败常见于 Windows 7 或未更新 tzdb 的嵌入式系统,建议加 try/catch

file_clock 和 tai_clock 没有直接关系

有人误以为 file_clock 时间戳可直接喂给 tai_clock,这是错的。file_clock 映射的是文件系统原生时间(如 NTFS 的 UTC 微秒、ext4 的纳秒 since epoch),它本身不携带时区或闰秒语义。它的 to_sys() 返回 system_clock::time_point,再经 utc_clock::from_sys() → tai_clock::from_utc() 才能进 TAI 域。

  • 错误链:file_clock::now() → tai_clock::from_utc(...) —— 类型不匹配,编译不过
  • 正确链:auto fc = file_clock::now(); auto sc = file_clock::to_sys(fc); auto uc = utc_clock::from_sys(sc); auto tc = tai_clock::from_utc(uc);
  • 每一步都可能失败,尤其在 FAT32 等无纳秒精度的文件系统上,file_clock::to_sys() 可能截断精度

真正难的不是调用 tai_clock::now(),而是理解它不提供“绝对真实时间”——它只是 TAI 标度上的一个点;所有跨标度转换都依赖外部闰秒数据,而这份数据在不同平台、不同 libc 版本、不同 Windows 更新状态下差异很大。别绕过 from_utc 直接手算,那是给自己埋定时精度 bug。

C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!

相关专题

更多
C语言变量命名
C语言变量命名

c语言变量名规则是:1、变量名以英文字母开头;2、变量名中的字母是区分大小写的;3、变量名不能是关键字;4、变量名中不能包含空格、标点符号和类型说明符。php中文网还提供c语言变量的相关下载、相关课程等内容,供大家免费下载使用。

2023.06.20

2989

3

c语言入门自学零基础
c语言入门自学零基础

C语言是当代人学习及生活中的必备基础知识,应用十分广泛,本专题为大家c语言入门自学零基础的相关文章,以及相关课程,感兴趣的朋友千万不要错过了。

2023.07.25

2228

9

c语言运算符的优先级顺序
c语言运算符的优先级顺序

c语言运算符的优先级顺序是括号运算符 > 一元运算符 > 算术运算符 > 移位运算符 > 关系运算符 > 位运算符 > 逻辑运算符 > 赋值运算符 > 逗号运算符。本专题为大家提供c语言运算符相关的各种文章、以及下载和课程。

2023.08.02

1200

5

c语言数据结构
c语言数据结构

数据结构是指将数据按照一定的方式组织和存储的方法。它是计算机科学中的重要概念,用来描述和解决实际问题中的数据组织和处理问题。数据结构可以分为线性结构和非线性结构。线性结构包括数组、链表、堆栈和队列等,而非线性结构包括树和图等。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.08.09

1138

4

c语言random函数用法
c语言random函数用法

c语言random函数用法:1、random.random,随机生成(0,1)之间的浮点数;2、random.randint,随机生成在范围之内的整数,两个参数分别表示上限和下限;3、random.randrange,在指定范围内,按指定基数递增的集合中获得一个随机数;4、random.choice,从序列中随机抽选一个数;5、random.shuffle,随机排序。

2023.09.05

1336

5

c语言const用法
c语言const用法

const是关键字,可以用于声明常量、函数参数中的const修饰符、const修饰函数返回值、const修饰指针。详细介绍:1、声明常量,const关键字可用于声明常量,常量的值在程序运行期间不可修改,常量可以是基本数据类型,如整数、浮点数、字符等,也可是自定义的数据类型;2、函数参数中的const修饰符,const关键字可用于函数的参数中,表示该参数在函数内部不可修改等等。

2023.09.20

2078

7

c语言get函数的用法
c语言get函数的用法

get函数是一个用于从输入流中获取字符的函数。可以从键盘、文件或其他输入设备中读取字符,并将其存储在指定的变量中。本文介绍了get函数的用法以及一些相关的注意事项。希望这篇文章能够帮助你更好地理解和使用get函数 。

2023.09.20

3280

8

c数组初始化的方法
c数组初始化的方法

c语言数组初始化的方法有直接赋值法、不完全初始化法、省略数组长度法和二维数组初始化法。详细介绍:1、直接赋值法,这种方法可以直接将数组的值进行初始化;2、不完全初始化法,。这种方法可以在一定程度上节省内存空间;3、省略数组长度法,这种方法可以让编译器自动计算数组的长度;4、二维数组初始化法等等。

2023.09.22

14695

6

c语言中null和NULL的区别
c语言中null和NULL的区别

c语言中null和NULL的区别是:null是C语言中的一个宏定义,通常用来表示一个空指针,可以用于初始化指针变量,或者在条件语句中判断指针是否为空;NULL是C语言中的一个预定义常量,通常用来表示一个空值,用于表示一个空的指针、空的指针数组或者空的结构体指针。

2023.09.22

549

3

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程