UUsefulCrate 你的文件永远不会离开浏览器

首页 › 指南 › 开发者

Unix 时间戳:秒、毫秒,以及日志为什么对不上

几乎所有让人困惑的时间戳问题,都逃不出三种原因:单位错了、时区丢了,或者时钟从一开始就不准。

2026-09-24 · 6 分钟阅读

直接给结论:Unix 时间戳数的是从 1970 年 1 月 1 日 00:00:00 UTC 起经过的秒数, 它本身不带任何时区。十位数字是秒,十三位是同一个时刻的毫秒表示。如果同一个事件的两个时间戳正好差一个你的 UTC 偏移量,那其中必有一个是用本地时间写下来的。

几乎所有让人困惑的时间戳问题,都逃不出三种原因:单位错了、时区丢了,或者时钟从一开始就不准。

Unix 时间戳到底数的是什么

一个 Unix 时间戳,是从 1970 年 1 月 1 日 00:00:00 UTC 起经过的秒数,不计闰秒。 它标记的那个时刻毫无歧义,因为它完全不带时区 —— 它是一个计数,不是一个日期。

整个设计就是这样。一个秒数在东京、拉各斯和圣保罗是同一个数字,这正是你在机器可读的「某事发生在何时」记录里 想要的性质。歧义只在有人把这个数转成人能读的东西、并且必须决定用哪个钟来显示的时候才出现。

0           → 1970-01-01T00:00:00Z
1735689600  → 2025-01-01T00:00:00Z
-86400      → 1969-12-31T00:00:00Z     (负值是合法的)

单位问题,最常见的那个

现代系统越来越多地记录毫秒。于是同一个时刻有了两种完全不同的表示:

那个时刻秒毫秒
2025-01-01 00:00:00 UTC17356896001735689600000
现在(2026 年,约)1.7 × 10⁹1.7 × 10¹²

知道了之后,失败的样子很好认。把一个毫秒值当秒读,你会落到公元 56000 年附近; 把一个秒值当毫秒读,你会落到 1970 年 1 月。两种都会给出一个自信、具体、但完全错误的日期。

数值过大也是 JavaScript 的 Date 构造函数出毛病的根源。它接受的是毫秒, 所以把一个以秒为单位的时间戳传进去,它会静悄悄地给你一个 1970 年的日期,而不是报错。

怎么不靠猜就分辨出来

不要去写死一个年份阈值 —— 那种做法会失效。可靠的判断基于数量级,它成立的原因是: 对任何合理的日期来说,这两个区间都不重叠。

所以 1735689600 是秒,1735689600000 是毫秒,同一条规则就能读对两者。 这里的转换工具用的正是这个判断,并且会告诉你它认定你给的是哪一种 —— 猜是被显示出来的,而不是静默进行的。

时区问题,更安静的那个

时间戳本身没有时区,但它的表示形式有,而这个表示形式经常缺东西。

看 2026-03-01 09:00:00。没有偏移量,这就不算一个时刻 —— 它只是一个墙上钟表的读数,你在不同地方站,它对应九个不同的时刻。 写完整的话,它要么是 2026-03-01T09:00:00+08:00,要么是 2026-03-01T01:00:00Z, 而这两个是同一个时刻。

两条做法能挡掉几乎所有由此产生的混乱:

本地时间是一个「展示层」的事。一旦被用作存储格式,你就引入了一个含义取决于读者所在位置的值, 而它迟早会在别的地方被读。

夏令时,那个特殊情况

在会调钟的时区里,每年都会发生两件会让天真日期算术崩掉的事:

所以「加 24 小时」和「加一天」不是同一个操作。给一个时刻加 86,400 秒定义明确; 加一个日历日跨越夏令时边界时含义不同。如果你在做排期,用懂时区数据库的库, 而不是自己对钟做算术。如果你只是在记录某事发生在何时,存 UTC,问题就消失了。

第三种问题:时钟本来就是错的

时间戳记录的是那台机器的时钟当时认为的时间。如果某台服务器漂了, 或者某个容器启动时宿主时钟没设好,那记录下来的时间就是「忠实地错了」—— 再怎么转换也修不回来。

日志里的几个典型信号:

系统应该从网络时间源同步;日志也应该区分「事件发生的时刻」和「它被写下来的时刻」—— 后者往往在前者拿不到的时候还拿得到。

闰秒,一句话说完

Unix 时间戳忽略它。地球自转并不完全规律,UTC 会偶尔插入一秒来补偿; Unix 时间有意不这么做,所以它会比严格的 UTC 时钟略慢一点。对几乎所有软件来说这都无关紧要, 它只对天文计算和原子时标准有意义,几乎不涉及别的场合。

遇到任何「像时间戳的东西」时的简短流程

  1. 转换之前先确定单位。用数量级判断,再检查得出的年份是否说得通。
  2. 确定有没有偏移量。如果没有,就从上下文推断原本想表达哪个时区,并把它写下来, 免得下一个读的人还得再猜一遍。
  3. 如果这些值来自日志,就用本地工具转换。日志行里通常同时带着主机名、内网 IP、会话标识和用户 ID, 所以最好不要把它们发到任何地方去。
  4. 跨机器比较时只用 UTC。

Unix 时间戳转换工具处理前面两步,把本地时间、ISO 8601 和 UTC 并排列出来, 所以你在读的是哪一种毫无歧义。它就在页面里运行,因此没有任何一行日志需要离开它本来就在的那台机器。

← 全部指南