时间戳:为什么 1970 年 1 月 1 日成了计算机的"创世时刻"?(附 4 个高频翻车现场)

火力盒子技术专栏 · 本文提到的工具全部免费、在浏览器本地运行:https://www.ahotbox.com

你一定见过 1728000000 这样的数字出现在接口返回、日志、Cookie 的 Expires 里。它就是 Unix 时间戳——从 1970 年 1 月 1 日 00:00:00 UTC 到现在经过的秒数(或毫秒数)。

为什么是 1970?因为第一版 Unix 系统诞生在 1971 年前后,开发者把"纪元"定为系统诞生之前的整年起点:1970-01-01,简单、整、好记。这个约定被 C 语言、POSIX 规范一路继承下来,成了全球计算机的"创世时刻"。

在线转换工具:时间戳转换器(支持秒/毫秒、多时区、批量转换)

翻车现场 1:秒和毫秒混用

JS 的 Date.now() 返回毫秒,而很多后端(Go、Python 的 time.time()、PHP)返回秒。前端拿到秒级时间戳直接 new Date(ts),会得到 1970 年 1 月的日期:

// 错误:1680000000 是秒
new Date(1680000000); // 1970-01-20T06:40:00.000Z ❌

// 正确:先判断量级
const ts = 1680000000;
new Date(ts * (ts < 1e12 ? 1000 : 1)); // 2023-03-28 ✅

判断口诀:13 位是毫秒,10 位是秒。看到 10 位时间戳,先乘 1000。

翻车现场 2:时区归零

时间戳本身没有时区——它是从 UTC 纪元起算的绝对值。有问题的从来是"显示"环节:

// 同一时间戳,不同时区的显示不同
const d = new Date(0);
d.toISOString(); // "1970-01-01T00:00:00.000Z"(永远是 UTC 零区)
d.toString();    // 受本地时区影响

数据库里存时间戳,接口里传时间戳,只在展示层做时区转换——这是唯一的正确姿势。反过来,如果你在接口里传 "2024-03-28 10:00" 这种字符串,不同时区的机器解析结果就不同,Bug 从此常驻。

翻车现场 3:2038 年问题

32 位有符号整数最大值是 2147483647,如果用秒级时间戳存储,到 2038 年 1 月 19 日 03:14:07 UTC 就会溢出变成负数。这是 Y2K 的翻版。现在新项目一律用 64 位(JS 的 number 天然够用,Java 用 long),老系统的 int 字段要重点排查。

翻车现场 4:new Date('2024-03-28') 的时区陷阱

new Date('2024-03-28').getHours(); // 按零区解析,东八区显示 08:00
new Date('2024-03-28 10:00').getHours(); // 按本地时区解析 → 10:00

同一个函数,带不带 HH:mm 解析行为不同(ES 规范规定只有日期的 ISO 字符串按 UTC 解析)。日期字符串处理建议显式带时区或用库(dayjs/date-fns)。

常用速查

Date.now();                    // 当前毫秒时间戳
Math.floor(Date.now() / 1000); // 当前秒时间戳
new Date(ts).toISOString();    // 转 ISO 字符串(UTC)

不想手写?直接用 时间戳转换器,输入即转,支持秒/毫秒自动识别和时区切换。


关于火力盒子:ahotbox.com 是一个纯前端在线工具集,收录 1000+ 款免费工具(时间、开发、文本、转换、生成器等),所有数据在浏览器本地处理,无需注册、不上传数据。

发布建议:公众号直接使用本文;CSDN/掘金在文首加"本文首发于公众号 XX";知乎可在回答相关问题时引用第 1、4 节。
💡 关于火力盒子:ahotbox.com 收录 1000+ 款免费纯前端在线工具(开发、文本、时间、生成器、安全等),所有数据在浏览器本地处理,无需注册、不上传数据、支持离线使用。