时间基础:UTC时间、系统时间、硬件时间、时间戳的本质

做多传感器融合,第一个绕不开的坎儿就是时间。

说实话,我早年做项目时,在这上面栽过不少跟头。两台设备明明同时采集数据,回放一看,时间轴对不上。你说气不气人?后来我才明白——时间这东西,看似简单,其实门道很深。

UTC时间:全球统一的“尺子”

先聊聊UTC。全称是Coordinated Universal Time,协调世界时。

说白了,它就是全世界通用的时间基准。不管你在北京、纽约还是南极,UTC时间都是一样的。我习惯把它想象成一把“国际标准尺”——各地的时间都是拿这把尺子量出来的。

关键点:UTC不依赖时区。北京时间是UTC+8,纽约时间是UTC-5。但UTC本身,永远不变。

我在项目中遇到过一个问题:两个传感器,一个设了北京时间,一个设了格林威治时间。结果数据对齐时差了8个小时。嗯,从那以后,我所有设备都强制用UTC记录原始时间,显示时再转换。

系统时间:操作系统里的“钟”

系统时间,就是你的Linux或Windows系统当前认为的时间。

它从1970年1月1日0点(UTC)开始计数,单位是秒。这个起点,我们叫它Unix纪元。你想想看,每次你调用time()函数,拿到的就是一个从那个时刻到现在的秒数。

// 获取系统时间示例
#include <time.h>
time_t now = time(NULL);
printf("当前系统时间戳: %ld\n", now);
// 输出类似: 当前系统时间戳: 1698765432

系统时间有个特点——它可以被修改。用户手动调时间、NTP同步、甚至程序里用settimeofday()都能改。所以,它不太可靠。

注意:系统时间可能发生跳变。如果NTP发现系统时间偏差太大,会直接“咔”一下调回来。你的时间戳可能突然倒退或前进几秒。这在传感器融合里是灾难。

硬件时间:主板上的“守夜人”

硬件时间,也叫RTC时间。它由主板上的纽扣电池供电,独立运行。

哪怕你关机、拔电源,它还在走。我经常把它比作一个“守夜人”——不管系统怎么折腾,它默默记着时间。

在嵌入式设备里,硬件时间通常是一个独立的RTC芯片。比如DS3231、PCF8563这些。它们精度不错,但也会漂移。我测过一块DS3231,常温下一天漂个1-2秒,温度变化大时更明显。

时间类型 存储位置 断电保持 可修改性 典型精度
UTC时间 标准定义 原子钟级
系统时间 内存/内核 容易 微秒级
硬件时间 RTC芯片 较难 秒级

系统启动时,会从硬件时间读取初始值。之后,系统时间靠CPU定时器维持。所以你会发现:刚开机时系统时间和硬件时间一致,跑着跑着就有偏差了。

时间戳的本质:一个数字而已

时间戳是什么?说白了,就是一个数字。

它代表从某个固定起点到现在的时长。最常见的是Unix时间戳——从1970-01-01 00:00:00 UTC到现在的秒数。

// 时间戳示例
// 1698765432 这个数字代表什么?
// 它代表:从1970年1月1日0点,到2023年10月31日12点37分12秒,一共过去了1698765432秒

时间戳的好处是:它是一个单调递增的数字。比较两个时间戳,谁大谁就晚。做差值,就知道间隔多久。非常适合计算机处理。

但要注意精度问题。我见过有人用float存时间戳,结果精度不够,两个相邻事件的时间戳居然相等。你想想看,这数据还能用吗?

我的建议:时间戳尽量用64位整数存储。微秒级精度的话,用uint64_t,单位选微秒。这样到公元2920年都不会溢出。

它们之间的关系

画个图就清楚了。我习惯用这个逻辑来理解:

时间体系关系图 UTC 时间(基准) 系统时间(软件) 硬件时间(RTC) 时间戳(数字表示) 关键说明 • UTC是绝对基准 • 系统时间可被修改 • 硬件时间断电保持 • 时间戳是数值化表达 • 系统启动时从RTC读初值 • 运行中系统时间独立计时 • 传感器融合建议用UTC • 时间戳用64位整数存储

你看这个图就明白了。UTC在最上面,是基准。系统时间从硬件时间初始化,然后独立运行。时间戳则是所有时间的数字表达形式。

做传感器融合时,我个人的习惯是:

  • 所有传感器原始数据,统一用UTC时间戳记录
  • 系统内部处理,用单调递增的本地时间戳
  • 硬件时间只做备份和启动初始化

避坑指南

我曾经踩过一个坑:用gettimeofday()获取时间戳做同步,结果NTP一跳,时间戳往回走了几百毫秒。两个传感器的数据直接乱套了。

后来我改用clock_gettime(CLOCK_MONOTONIC, ...)。这个时钟是单调递增的,不受系统时间调整影响。虽然它不直接对应UTC,但做相对时间同步足够了。

重要提醒:绝对不要用系统时间做高精度同步。用单调时钟(CLOCK_MONOTONIC)做相对时间,用PTP或GPS的PPS信号做绝对时间对齐。

嗯,时间基础就聊这么多。记住一句话:UTC是尺子,系统时间是显示器,硬件时间是备份,时间戳是数字。搞清楚了这些,后面做同步采样才不至于翻车。

小技巧:调试时,我习惯在日志里同时打印系统时间和单调时钟。一旦发现两者差值异常增大,就知道NTP又跳了。这招帮我抓过不少bug。