这份常见问题汇总了转换时间戳时最要紧的几个判断:这个数字从哪一刻起算、用的是什么单位,以及是哪个时区把一个本地钟面读数变成了确定的瞬间。

先把边界弄清楚

  • Unix 时间戳通常是从 1970-01-01T00:00:00Z 起算的秒数。
  • JavaScript Date 用毫秒,而大量接口和命令行工具用秒。
  • UTC 确定的是一条共享的时间轴;具名时区决定这个瞬间在本地怎么显示。
  • 一个不带时区的日历日期,还不足以确定全球唯一的某一刻。

具体要转换时,请用对应的工具,别对着格式化后的字符串猜。明确的单位和时区,比一个看起来很唬人的数字有用得多。

Frequent questions:

Q: 什么是 Unix 时间戳?
A: Unix 时间戳是从 Unix 纪元(1970 年 1 月 1 日 00:00:00 UTC)算起经过的秒数。它是一个与语言无关、与时区无关的整数,可以唯一地标识时间轴上的任意一刻。
Q: 什么是 Unix 纪元?
A: Unix 纪元指 1970 年 1 月 1 日 00:00:00 UTC。所有 Unix 时间戳都是以这个固定参考点为起算——正数往后,负数往前。选 1970 纯粹是出于实用:贝尔实验室设计 Unix 的那会儿,它是个刚过去不久的整年份。
Q: 10 位和 13 位的时间戳有什么区别?
A: 10 位(比如 1700000000)是纪元以来的秒数,13 位(比如 1700000000000)是毫秒数。JavaScript 的 Date.now() 返回毫秒;大多数 Unix 系统调用,以及 Python、Go、PHP 这些语言,默认返回秒。
Q: JavaScript 为什么用毫秒而不是秒?
A: JavaScript 的 Date API 是照着 1995 年那会儿系统定时器的精度设计的。用毫秒可以避免亚秒级时长的精度损失。所以拿到服务端给的秒级 Unix 时间戳时,记得先乘 1000 再传给 new Date()。
Q: JavaScript 里怎么把 Unix 时间戳转成可读日期?
A: 秒级时间戳:new Date(1700000000 * 1000).toISOString()。毫秒级:new Date(1700000000000).toISOString()。两者都会得到形如 '2023-11-15T06:13:20.000Z' 的 ISO 8601 字符串。要本地化显示,用 toLocaleString() 并带上 timeZone 选项。
Q: Unix 时间戳自带时区信息吗?
A: 不带。Unix 时间戳始终表示 UTC 时间轴上的一个瞬间,时区只在格式化显示的时候才起作用。身处不同时区的两台设备,对同一瞬间会算出完全相同的 Unix 时间戳。
Q: 什么是 2038 年问题?
A: 用 32 位有符号整数存 Unix 时间戳的系统,最大只能表示到 2,147,483,647,对应 2038 年 1 月 19 日 03:14:07 UTC。过了那一刻,整数会溢出成一个很大的负数。现代 64 位系统不受影响,但嵌入式设备和老数据库仍可能中招。
Q: 负的 Unix 时间戳是什么意思?
A: 表示 Unix 纪元之前的时刻。比如 -86400 就是 1969 年 12 月 31 日 00:00:00 UTC。现在主流的日期 API 都能正确处理负时间戳,但一些老系统和老数据库不支持。
Q: Python 里怎么取 Unix 时间戳?
A: 秒:import time; int(time.time())。想要明确的 UTC datetime:import datetime; int(datetime.datetime.now(datetime.timezone.utc).timestamp())。毫秒:int(time.time() * 1000)。
Q: Unix 时间戳的精度有多高?
A: 标准的 Unix 时间戳精确到秒。需要亚秒精度时,Web API 和 JavaScript 里常用 13 位的毫秒时间戳。也有系统用微秒(16 位)甚至纳秒。用哪个单位,取决于你的应用真正需要多高的精度。
Q: Unix 时间戳最大能到多少?
A: 在如今标配的 64 位有符号整数下,Unix 时间戳能覆盖从大约 2920 亿年前到 2920 亿年后的任意时刻。那个著名的 32 位上限(2038 年问题)只影响老系统。
Q: 为什么我的时间戳显示成了 1970 年?
A: 通常是三种原因之一:值本身就是 0(正好是纪元);值其实是毫秒却被当成了秒(于是缩成一个接近 0 的秒数);或者值是 null/undefined,被你的代码兜底成了 0。
Q: UTC 和 GMT 有什么区别?
A: 日常用途下两者可以互换。UTC(协调世界时)是现代的原子钟标准;GMT(格林尼治标准时间)是零偏移时区的历史叫法。英国和绝大多数软件把它们视作等价。
Q: 日期该存成 Unix 时间戳还是 ISO 8601 字符串?
A: 都可以。整数紧凑、比较方便;ISO 8601 字符串自解释、人能直接读懂。不过在数据库里,通常还是原生的日期时间类型最好(Postgres 的 TIMESTAMP WITH TIME ZONE、MySQL 的 DATETIME(6)),因为它们保留了时区语义,索引效率也更高。
Q: 直接存服务器的本地时间可以吗?
A: 不建议。不带偏移地存本地时间,一旦服务器迁移、夏令时切换,或者另一个时区的服务器来读这个值,信息就丢了。请存 UTC(Unix 时间戳或带时区的 datetime),只在展示层再转成本地时间。
Q: Unix 时间戳包含闰秒吗?
A: POSIX 的 Unix 时间刻意忽略闰秒——即使 UTC 插入了额外的一秒,Unix 的每一天也恰好是 86,400 秒。具体表现是某个秒数被重复一次,还是把这一秒抹平摊到一段时间里,取决于系统的实现。