开发 · 阅读约 4 分钟 ·

Unix 时间戳:秒还是毫秒?

每周都会被带进生产环境的“13 位数字”bug,以及区分这两种单位的一条简单规则。

JavaScript 使用毫秒,大多数后端使用秒。两者一旦混用,日期就会落到 1970 年 1 月,或者几万年后的未来。

数一数位数

当前以秒为单位的时间戳有 10 位(1790000000 是 2026 年 9 月 21 日)。同一时刻用毫秒表示有 13 位,微秒 16 位,纳秒 19 位。

判断规则

如果绝对值大于 10¹²,就是毫秒;否则按秒处理。这条规则适用于 2001 年 9 月之后的任何毫秒时间戳,以及 33658 年之前的任何秒级时间戳。

const ms = Math.abs(n) > 1e12 ? n : n * 1000;

时间戳没有时区

Unix 时间戳计算的是自 1970 年 1 月 1 日 00:00 UTC 以来的秒数。同一个数字在世界各地代表同一个瞬间,变的只是显示方式。当把本地时间当作 UTC 转换成时间戳时,就会出现 bug:所有日期都会偏移你所在时区的时差,往往是一两个小时,夏令时切换时还会再偏一次。请用 UTC 保存和传输时间戳,只在展示给人看时才转换成本地时间。

在常用语言中获取当前时间

JavaScript  Date.now()                        毫秒
JavaScript  Math.floor(Date.now() / 1000)     秒
Python      time.time()                       秒(带小数)
Java        System.currentTimeMillis()        毫秒
Go          time.Now().Unix()                 秒
PostgreSQL  EXTRACT(EPOCH FROM now())         秒
MySQL       UNIX_TIMESTAMP()                  秒

1970 年以前的日期和 2038 年问题

负的时间戳是有效的:−86400 就是 1969 年 12 月 31 日。一些旧系统和电子表格处理不了它们,所以出生日期和历史数据是常见的 bug 来源。另一头,有符号的 32 位整数到 2147483647 就用完了,也就是 2038 年 1 月 19 日 03:14:07 UTC。仍用 32 位存储时间戳的系统会回绕到 1901 年;用 64 位存储则能在数十亿年内避免这个问题。

闰秒

Unix 时间忽略闰秒:每天都恰好是 86,400 秒。这让计算保持简单,对几乎所有应用来说,这点差别都无关紧要。只有需要跨越闰秒精确计算时间间隔的系统,比如某些科学或金融系统,才需要考虑它。

快速排查清单

  • 日期落在 1970 年 1 月:把以秒为单位的值当成了毫秒。
  • 年份是五位数:把以毫秒为单位的值当成了秒。
  • 所有日期都偏移了相同的小时数:把本地时间当成了 UTC,或者反过来。
  • 一年中有一段时间日期偏了一小时:忽略了夏令时切换。
  • 日期跳到 1901 年:32 位溢出。

明确选择单位

4Dev 时间戳转换器不会猜测:"Unix Timestamp" 表示秒,"Unix Timestamp (ms)" 表示毫秒,旁边还有微秒和纳秒格式。一共支持 33 种格式,包括 ISO 8601、RFC 2822、SQL DATETIME 和 Excel 序列日期。

给人看的日期用 ISO 8601

时间戳非常适合存储和计算,但人很难读懂。在日志、API 和人会打开的文件里,像 2026-09-21T14:30:00Z 这样的 ISO 8601 格式没有歧义,按文本排序也正确,还会明确写出时区。在两者之间相互转换,正是时间戳转换器的用途。

打开时间戳转换器

LinkedInXFacebook