同事贴了一个数字: 1752345678,问我这是哪一天。我看了一眼说 2025-07-12 大概。没过几秒他追问,到底是哪一天?是 13 位的 1752345678901 还是 10 位的 1752345678?这就是大多数人对 UNIX 时间戳的日常状态——见过、却读不出来。
这篇文章就是为了让你下次看到一串 10 位、13 位、16 位或者 19 位的数字时,能立刻说出它对应的是哪一天、哪个小时、哪一秒,顺便搞懂为什么 epoch 偏偏是 1970-01-01。
30 秒总览
- 1970-01-01 00:00:00 UTC 被选作 UNIX epoch 的起点,原因有三: 当时主流 UNIX 系统刚诞生; 用 32 位有符号整数装时间最方便; 选一个确定的过去时刻做原点,跨系统对齐最简单。
- UNIX 时间戳 = 自那一刻起的秒数(可以含小数表示亚秒精度),单位从秒到纳秒有四种常见精度。
- 数字长度本身就是精度的提示: 10 位 ≈ 秒、13 位 ≈ 毫秒、16 位 ≈ 微秒、19 位 ≈ 纳秒。这条规则够你在 90% 的场景里一眼判定。
- 想要在秒、毫秒、微秒、纳秒和人类可读日期之间随时切换,把 UNIX 时间戳转换器 收进书签。
5 个真实场景:时间戳在哪儿出现
场景 1:日志里的 13 位毫秒数
服务端日志里看到一行: 1752345678901 INFO request completed。这个数字几乎肯定是毫秒,不是秒。
为什么: 主流后端语言默认用 Date.now() (JavaScript) 、System.currentTimeMillis() (Java) 、time.time() * 1000 (Python),返回的都是 13 位毫秒。
正解: 在 UNIX 时间戳转换器 里粘贴 1752345678901,工具会自动识别为毫秒,直接给出对应的 UTC 和本地时间。如果手头没有工具,记住 13 位 ÷ 1000 ≈ 10 位,秒数大概是 1752345678,对到 2025-07-12 前后。
场景 2:API 响应里的 10 位秒数
REST API 返回一个 JSON: {"created_at": 1752345678, "expires_at": 1752346400}。这大概率是秒。
为什么: 部分老牌 API (尤其是 PHP 时代和部分 Unix 工具) 仍用秒;还有一些公共时间 API 直接吐秒。
正解: 看上下文。如果字段名叫 unix_timestamp、epoch_seconds,是秒;如果叫 created_time_ms、timestamp_ms,是毫秒。粘贴到 UNIX 时间戳转换器 时工具会同时输出秒、毫秒、微秒、纳秒四种精度,你可以反向核对单位用对没。
场景 3:JWT 里的 iat 和 exp 字段
JWT 的 payload 里经常看到: iat: 1752345678、exp: 1752349278。这两个都是秒,不是毫秒。
为什么: JWT 是 RFC 7519 标准,明文规定 NumericDate 用自 epoch 起的秒数 (可以含小数) 。所有合规的 JWT 库都是秒。
正解: 用 JWT 解码器 解码 token 后,默认按秒渲染 iat 和 exp;你如果看到 13 位的 iat,要警觉——可能是库把毫秒错填进去了,或者某些非标准实现。
场景 4:数据库里 ISO 8601 和 epoch 混用
表设计有个老坑: 一个字段存 ISO 8601 字符串 (比如 2025-07-12T10:30:00Z),另一个字段存 epoch 整数 (比如 1752345678)。JOIN 的时候忘了统一单位,慢查询就来了;比较的时候漏掉时区,数据对不齐。
为什么: 这是过去十年 ORM 和迁移脚本的常见遗留。不同团队、不同时期的代码风格不一样,数据库里就两种都有。
正解: 新表统一只存一种。绝对时间优先 epoch ms (13 位) 或带时区的 ISO 8601 (2025-07-12T10:30:00+08:00)。不要混存。
场景 5:跨时区协作,3 个工程师在 3 个时区
群里贴了一个时间: 2025-07-12 10:30:00,团队里有人解读成北京时间,有人解读成 UTC,有人解读成美西。事故就是这么发生的——会议推迟 8 小时,半夜开。
为什么: 没有时区信息的本地时间字符串,在跨时区协作里就是一个坑。
正解: 跨时区协作只用带时区的 ISO 8601 (2025-07-12T10:30:00+08:00) 或 epoch (10/13 位) 。两种都是绝对的,不依赖阅读者所在的时区。如果团队里要统一,优先用 epoch ms——它是一种语言、一种格式、一个数字,谁粘贴都不出错。
4 个常见坑
坑 1:把秒当毫秒 (Y2K 故事: 2000-01-01 = 946684800 秒,不是 946684800000)
最经典的踩坑: 2000 年那天,有些程序把 epoch 当毫秒用,得出来 946684800000,转回日期时溢出了 32 位有符号整数范围,导致部分系统崩溃或日期显示成 1970 年。
正解: 数字位数就是你的第一信号。10 位 ≈ 秒,13 位 ≈ 毫秒。如果你的代码里两个单位混用,先用一个常量定义 SECOND = 1、MILLISECOND = 1000,所有转换都走常量,不要写裸数字。
坑 2:跨时区比较两个 epoch 没问题,跨时区比较两个本地时间字符串可能错
两个 epoch 相减永远得到秒差,不依赖时区。两个本地时间字符串 2025-07-12 10:30:00 相减,如果你俩时区不一样,得到的是字面量减法而不是真实时间差。
正解: 跨时区协作和持久化只用 epoch 或带时区的 ISO 8601。本地时间字符串只用于 UI 渲染,不要用于比较或存储。
坑 3:精度丢失:16 位微秒和 19 位纳秒在 JavaScript 里都进 double,有损
JavaScript 的 Number 是 IEEE 754 双精度浮点数,安全整数上限是 Number.MAX_SAFE_INTEGER = 2^53 - 1 ≈ 9.007 × 10^15。16 位微秒 (最大约 10^16) 和 19 位纳秒 (最大约 10^19) 都超过安全整数范围,放进 JS number 就丢精度。
正解: 后端是 Go、Rust、Python int,精度没问题;前端展示可以,但要传回后端做持久化时,优先用字符串 ("1752345678901234567") 而不是 number。需要做差、做比较时,后端用 bigint 或库函数。
坑 4:32 位溢出——2038-01-19 03:14:07 UTC 之后,32 位有符号整数会回卷
32 位有符号整数最大能表示 2^31 - 1 = 2147483647 秒,正好对应 2038-01-19 03:14:07 UTC。再往后,32 位 time_t 会回卷成负数,系统日期会跳到 1901 年——这就是 Y2K38。
正解: 现代语言 (Go、Rust、Python 3、Node.js) 都用 64 位整数或更高精度,本身不是问题。但嵌入式系统、老 COBOL 主机、部分 IoT 设备和某些数据库驱动仍然用 32 位 time_t。这些设备的日期逻辑要在 2038 年前审计、升级,不然会跟千禧虫一样出事。
推荐做法
- 在你的代码里,统一用带时区的 ISO 8601 字符串表示绝对时间——比如
2025-07-12T10:30:00+08:00。人能读,机器能 parse,跨时区不歧义。 - 在传输和存储里,用 epoch ms (13 位) 表示绝对时间。一个数字、一种格式、跨语言无歧义。JSON payload、日志、数据库列、URL 参数都能用。
- 在用户面前,转成本地时间字符串。绝对时间 → 本地化展示靠
Intl.DateTimeFormat或类似库,不要让用户手动加时区。 - 调试和验证时,把 UNIX 时间戳转换器 收进书签。粘贴一串数字,1 秒看到 UTC、本地时间、ISO 8601、RFC 2822 和 4 种精度,比写代码快得多。配合 JWT 解码器 看 iat/exp、配合 Cron 表达式生成器 看 next-run 的 epoch,链路就完整了。
- 涉及 URL 编码或 Base64 编码的 timestamp,先用 Base64 编码解码器 转换,再粘到 UNIX 时间戳转换器 看人类时间——这种组合在你排查 OAuth state、签名 URL、带时间戳的 token 时很常见。
时间戳的难,不在计算,在于精度和时区的混用。一旦你在团队里定下 epoch ms + ISO 8601 的双向规范,90% 的时区事故都不会发生。
2038 年问题还要担心吗?
要分情况看。
桌面、服务器、移动端、云函数——64 位 time_t 已经是默认,Y2K38 在这些平台上不是问题。Linux、macOS、Windows、Go、Rust、Python 3、Node.js、Java 全是 64 位时间,2038 年那天啥也不会发生。
真正还有风险的,是嵌入式系统、老 COBOL 主机、部分 IoT 设备、以及某些数据库驱动或文件系统,它们仍然用 32 位有符号整数存 time_t。这些设备的固件升级往往滞后多年,真到 2038 年那天可能真出问题——摄像头、路由器、工业 PLC、汽车 ECU 都是高风险区。
正解: 如果你的业务依赖第三方设备或库,提前审计依赖链。看到 time_t、int32_t 存秒、MySQL 旧 schema、嵌入式 C 代码——这些都是要重点排查的。审计出来能升级就升级,不能升级要写 workaround,实在不行就 2038 年前更换设备。
就像 Y2K 之前那几年,工程界用几年时间批量修复;Y2K38 也会有自己的修复窗口,只是窗口比 Y2K 短(主要因为 32 位设备现在分散得多),需要从现在就开始注意。
打开 UNIX 时间戳转换器,粘贴一个 13 位毫秒数,看工具自动识别并同时输出秒、毫秒、微秒、纳秒四种精度,以及 UTC / 本地时间 / ISO 8601 / RFC 2822 四种格式——比手算和查表都靠谱。书签里加一个,下次再有人贴 1752345678,你就有答案了。