Unix 时间戳完全指南:秒与毫秒、时区陷阱与常见错值
最后更新:2026-09-14
Unix 时间戳是从 1970-01-01 00:00:00 UTC 起经过的秒数(或毫秒数)。它最大的优点是「不含时区」——时间戳本身是一个绝对时刻,与时区无关;时区只在把它显示成人类可读格式时才参与运算。
围绕这个定义产生的误解,构成了后端与前端时间处理事故的绝大多数。
一、先解决最常见的一件事:秒还是毫秒
同一个时刻,秒级与毫秒级时间戳相差 1000 倍。判断方法很简单——看位数:
- 10 位 → 秒级,可表示的区间大约是 2001 年至 2286 年;
- 13 位 → 毫秒级,可表示的区间远超实际需要;
- 16 位 → 微秒级;19 位 → 纳秒级,多出现在语言默认或高精度采集场景;
- 若一个 13 位数值被按秒解析,会得到公元 5 万年以上的日期;反之 10 位被按毫秒解析,会得到 1970 年 1 月的日期。
二、时区陷阱:转换发生在哪一步
时间戳转日期时的正确流程是:时间戳 → 绝对时刻 → 按目标时区格式化。出错通常发生在第三步——把「服务器本地时区」当成了「用户时区」,或者反过来。
更隐蔽的是「库里存字符串日期、应用按 UTC 生成」的组合:数据库的 CURRENT_DATE 按数据库时区计算,应用生成日期按应用时区计算,两者相差 8 小时时,同一天的 0 点到 8 点之间会产生跨日错位,表现为统计数字总是差一点。解决办法是把日期口径收敛到一处计算,而不是在 SQL 与应用里各算一次。
三、夏令时:没有夏令时的地方也要小心
不是所有地区都有夏令时,但代码可能被部署到有的地方。夏令时切换日的两个特殊时刻(跳过的一小时、重复的一小时)会让「本地时间」与「绝对时刻」不再一一对应:用本地时间做定时任务会出现某个时刻任务跑了两次或一次没跑。
可靠做法是:调度与存储一律用绝对时刻(时间戳或带偏移的 ISO 8601),只在展示时转成本地时间。中国标准时间不使用夏令时,因此国内业务通常感受不到这个问题,但跨时区的用户或服务器会立刻暴露它。
四、为什么推荐 ISO 8601 而不是本地格式
像 03/04/2026 这样的写法存在根本歧义:可能是 3 月 4 日,也可能是 4 月 3 日,取决于书写者所在地区。ISO 8601 采用从大到小的顺序并显式标注时区偏移,解析无歧义、可排序、可比较。
实践建议:接口与日志一律使用带时区偏移的 ISO 8601(或直接用时间戳),只在用户界面按用户时区格式化成本地习惯格式。
五、2038 问题与负时间戳
用 32 位有符号整数存储秒级时间戳的平台,会在 2038-01-19 溢出为负数。现代系统多已改用 64 位整数,但老设备、嵌入式系统与部分文件格式仍受影响,做长期归档时要留意。
另外,1970 年之前的时刻会得到负时间戳,这是合法值而非错误;但如果代码里对时间戳做了「必须为正」的校验,就会把历史数据判为非法。
六、常见错值反查
- 日期显示为 1970-01-01 或 1970-01-02 → 时间戳为 0 或接近 0,通常是字段缺失或解析失败后落成了默认值;
- 日期显示为遥远的未来 → 毫秒值被当成秒,或单位混用;
- 同一个时刻在两端显示相差整小时 → 时区未统一,且大概率相差的正是标准偏移;
- 统计按天分组总是差几小时的数据 → 日期口径分别由数据库与应用计算,需收敛到一处。
七、工具与延伸
需要即时换算可用 Unix 时间戳转换工具,它同时显示秒级与毫秒级解析结果,便于识别单位错配。若问题出在定时任务的执行时间,请继续阅读《Cron 表达式速查表》。