Unix 时间戳的时区坑:你以为的"现在"不是真的"现在"

· 约 2 分钟 🕐 时间戳

“服务器记录的下单时间戳是 1713772800,用户说他是下午 5 点下的单,但我本地转出来是上午 9 点,谁错了?“——都没错。这是时区。

Unix 时间戳是什么

UTC 1970-01-01 00:00:00 开始经过的秒数。这个定义里有两个关键点:

  1. 起点是 UTC 零点(不是北京时间)
  2. 时间戳本身是一个数字,不带时区信息

所以 1713772800 这个数字在地球上任何地方都代表同一个绝对时刻。只是显示成”人类看得懂的时间”时,才需要加上时区才能算出 几点几分

同一时间戳在不同时区

1713772800 这个数字:

时区显示
UTC2024-04-22 08:00:00
北京 (UTC+8)2024-04-22 16:00:00
纽约 (UTC-4)2024-04-22 04:00:00
东京 (UTC+9)2024-04-22 17:00:00

没有哪个是”正确”的,只是观察角度不同。

秒 vs 毫秒:两位之差多 1000 倍

  • 10 位数字(1713772800)= 秒级时间戳,PHP/Python 默认
  • 13 位数字(1713772800000)= 毫秒级,JavaScript/Java 默认

写代码时踩坑:JavaScript 的 Date.now() 返回毫秒,而 Python 的 time.time() 返回秒(浮点)。两边接口对接时必须对齐单位。

一秒差对比一年时长

  • 如果你把秒级戳当毫秒用:显示的时间是 1970-01-20 左右(起点后几千秒)
  • 如果你把毫秒级戳当秒用:显示的时间是 56000 年之后

出现”离谱时间”基本就是这个错误。

常见踩坑清单

1. 数据库存字符串 2024-04-22 16:00:00,没记时区 别人来读这个值,不知道是北京时间还是服务器本地时间。最佳实践:永远存 UTC 时间戳(或带时区的 ISO 8601 字符串)

2. JavaScript new Date('2024-04-22') 这个写法会被解析成 UTC 零点(2024-04-22T00:00:00Z),在北京时区显示成 4 月 22 日早 8 点。要表达”本地的 4 月 22 日零点”得写 new Date('2024-04-22T00:00:00')(注意没有 Z)。

3. 夏令时 UTC+8 的中国不用夏令时,但美国欧洲一年两次切换。同一个”本地时间 9:00”在夏令时和冬令时对应的时间戳不一样。后端处理国际用户时别按本地时间做调度,全部换成 UTC 再运算。

时间戳永远是 UTC 秒

当你看到时间戳 1713772800,它就是一个绝对时刻。想看北京时间还是纽约时间,是显示层的问题,不是数据本身的问题。这个认知到位了,90% 的时区 bug 就不会再出现。

互转 + 多时区对照

输入时间戳一次性显示 UTC、北京、纽约、东京等多个时区的结果;反过来输入本地时间指定时区也能算出对应时间戳。

❓ 常见问题

时间戳是 10 位还是 13 位?

都有,取决于单位。10 位数字 = 秒级时间戳(Python/PHP 默认),13 位 = 毫秒级(JavaScript/Java 默认)。接口对接时务必对齐单位,把 10 位当 13 位用会得到 1970 年初的时间,反之得到 56000 年后。

2038 年问题会导致时间戳溢出吗?

会。32 位有符号整数最大值对应 2038-01-19 03:14:07 UTC,之后会溢出。64 位系统和现代软件(Linux 64 位、大部分语言的 int64)已解决。但嵌入式系统、老旧数据库、32 位 Unix 服务仍可能受影响,是 Y2K 之后最值得关注的时间问题。

同一个时间戳在不同时区显示的时间一样吗?

不一样。时间戳是绝对时刻(UTC 零点起的秒数),显示出来的"几点几分"依赖本地时区。时间戳 1713772800 在北京显示为 16:00,在纽约显示为 04:00,是同一瞬间。数据库存时间戳(整数)比存字符串更不容易出错。

JavaScript 里 `new Date('2024-04-22')` 是什么时区?

按 ISO 8601 规范,只有日期无时间的字符串被解析为 UTC 零点。所以在北京时区显示会是 2024-04-22 08:00。要表达"本地的零点"用 `new Date('2024-04-22T00:00:00')`(没有 Z 后缀),会按本地时区解析。

🕐 打开 时间戳 秒/毫秒互转 · 多时区切换