Unix 时间戳转换器

当前 Unix 时间戳

0

Unix 时间到底在数什么(秒、毫秒、纳秒)

Unix 时间就是一个整数:自纪元 1970-01-01T00:00:00Z 起的秒数。这个日期本身是任意选定的 — 贝尔实验室的早期 Unix 需要一个能以合理分辨率装进 32 位值的零点,1970 年年初是一个方便的、离当时很近的整数。负值完全合法,表示 1970 年之前的时刻;-86400 就是 1969 年的最后一天。由于计数锚定在 UTC,首尔和圣保罗的两台机器在同一瞬间生成的时间戳数值相同:时间戳标识的是时刻,从来不是墙上时钟的读数。 这里的经典缺陷家族是单位混淆,因为各生态对分辨率意见不一。POSIX 的 time()、多数数据库和 JWT 声明用秒;JavaScript 的 Date.now() 和 Java 的 System.currentTimeMillis() 返回毫秒;许多 API 和数据库用微秒;Go 的 UnixNano 和可观测性领域大量使用纳秒。混用它们,日期要么落回 1970 年(把毫秒当秒,几乎全被除掉),要么飞到公元 56000 年以后(把秒当毫秒)。 对当前时代的值,数位数是最快的诊断:10 位是秒(1751414400 按秒算是 2025 年 7 月),13 位是毫秒,16 位是微秒,19 位是纳秒。相关的陷阱是浮点精度:把时间戳当浮点数走 JSON,秒级没问题,纳秒级会被破坏,因为 64 位 double 的整数精度只有 53 位 — 这是高分辨率 API 用字符串传时间戳的原因之一。
Same instant, four resolutions:
1751414400            seconds       (10 digits)
1751414400000         milliseconds  (13 digits)  Date.now()
1751414400000000      microseconds  (16 digits)
1751414400000000000   nanoseconds   (19 digits)  Go UnixNano

// The two classic unit bugs (JavaScript):
new Date(1751414400)        // 1970-01-21 — seconds fed as ms
new Date(1751414400 * 1000) // 2025-07-02 — correct

闰秒:每个时间戳里藏着的谎言

Unix 时间号称在数 1970 年以来的秒数,但这并非字面上的真话。地球自转不规则,UTC 为了与天文时间对齐会不时插入闰秒(1972 年以来共 27 次)。Unix 时间干脆假装闰秒不存在:按定义每天恰好 86400 秒。插入闰秒时,UTC 时钟读作 23:59:60,而 Unix 计数器无法表达那个瞬间 — 各实现要么重复一秒,要么冻结,这意味着两个不同的真实时刻可能共享同一个时间戳,跨越闰秒测量的间隔会差一秒。 这不是纸上谈兵。2012 年 6 月的闰秒通过内核定时器代码的 livelock 让全行业的 Linux 系统崩溃,连带压垮了航空订票系统;2016 年底的闰秒在 Cloudflare 引发生产事故 — 代码用时间戳相减得到无法处理的负时长。教训可以推广:永远不要假设后取的墙钟时间戳更大。测量时长要用单调时钟(JS 的 performance.now()、POSIX 的 CLOCK_MONOTONIC、Python 的 time.monotonic()),它对闰秒、NTP 跳变和手动改时都免疫。 大型运营商用"闰秒涂抹"绕开问题 — Google 和 AWS 在 24 小时窗口内把每一秒略微拉长,让闰秒消融进微观的减速里。终局则是废除:2022 年国际计量大会决议在 2035 年前停止插入闰秒。在那之前,时间戳仍是出色的时刻标识符,却是把测量时长时略不可靠的尺子。

2038 年问题已经到来

有符号 32 位整数的上限是 2,147,483,647。作为 Unix 时间戳,它对应 2038-01-19T03:14:07Z;一秒之后数值回绕为负,脆弱的系统会突然相信现在是 1901-12-13。还有十二年,听着像明天的问题 — 但任何计算未来日期的代码会提前几十年撞上这道边界。20 年期房贷的还款计划 2018 年就撞上了;15 年期证书和超长 TTL 今天正在撞。早在日期到来之前,系统就已经产出了真实的 2038 缺陷。 解决方案 — 64 位 time_t — 在新平台上早已是标准,64 位秒计数器可以安全使用约 2920 亿年。残留问题活在边缘地带:2038 年仍会在运行的 32 位 ABI 嵌入式与物联网设备、带 32 位时间字段的老文件格式和网络协议,还有数据库。MySQL 的 TIMESTAMP 列类型是著名的幸存者:它存储 32 位 epoch 秒,历史上无法表示 2038-01-19 之后的时间(请改用没有此限制的 DATETIME)。Linux 内核在 5.6 版(2020)为 32 位架构加入 64 位时间系统调用,glibc 以 _TIME_BITS=64 构建选项跟进;ext4 把时间戳扩展到 2446 年,XFS 到 2486 年。 还有两个相邻的溢出值得了解。把同样的 32 位重新解释为无符号来"修复" 2038 的系统,只是把期限推到 2106-02-07 — 是缓期,不是解决。毫秒世界也有自己的悬崖:32 位毫秒计数器(嵌入式运行时钟常用)每 49.7 天回绕一次,这个缺陷模式因 Windows 95 出名,后来还催生了要求波音 787 定期重启发电机控制单元的适航指令。
2^31 - 1 = 2147483647  →  2038-01-19T03:14:07Z  (signed 32-bit)
+1 second              →  -2147483648  =  1901-12-13T20:45:52Z

2^32 - 1 = 4294967295  →  2106-02-07T06:28:15Z  (unsigned 32-bit)
2^63 - 1 (64-bit)      →  ~292 billion years    (safe)

-- MySQL: TIMESTAMP is 32-bit, DATETIME is not
CREATE TABLE t (
  ts TIMESTAMP,   -- max 2038-01-19 03:14:07 UTC
  dt DATETIME     -- max 9999-12-31 23:59:59
);

时区与夏令时:时间戳缺陷的诞生地

Unix 时间戳是绝对时刻;时区是呈现规则。把这两种角色分开,是对日期缺陷最有效的单一防御:存储和传输用 UTC 时间戳,只在展示边缘转换为本地时间。一旦"时间戳"悄悄经过了本地时间解释 — Python 的 naive datetime、被填入服务器本地时间的 DATETIME 列、datetime-local 表单输入 — 同一个值在不同机器上就代表不同的时刻。 夏令时是本地时间即使在单一时区内也危机四伏的原因。春季拨快时,本地时间的一个小时凭空消失(美国东部三月切换日的凌晨 2:30 不存在);秋季拨回时,一个小时出现两次,不知道是哪一遍,"凌晨 1:30" 就是歧义的。调度代码两种情况都会踩:每天 02:30 的任务一年两次要么不触发要么触发两次;朴素的"加 24 小时"算术在切换日漂移,因为那天只有 23 或 25 个小时。 再记两条规则。其一,偏移量不是时区:+09:00 只告诉你如何渲染某一个时刻,只有 Asia/Seoul、America/Sao_Paulo 这样的 IANA 时区名才承载完整的夏令时与政治历史 — 而历史会变,这正是 tzdata 包每年更新数次的原因(巴西 2019 年废除夏令时;埃及 2023 年恢复)。其二,了解你的语言的解析怪癖:在 JavaScript 里,new Date('2026-07-02') 按 UTC 午夜解析,而 new Date('2026-07-02T00:00') 按本地时间解析 — 一个字符的差异,给格林尼治以东或以西的所有用户制造经典的"差一天"缺陷。
// JavaScript parsing quirk (machine in UTC+9):
new Date('2026-07-02')        // date-only → parsed as UTC
  .toString()                 // Thu Jul 02 2026 09:00 GMT+0900
new Date('2026-07-02T00:00')  // date-time → parsed as LOCAL
  .toString()                 // Thu Jul 02 2026 00:00 GMT+0900

// Same string minus one 'T00:00' = 9 hours apart.

// DST gap: 2:30 AM does not exist on spring-forward day
// America/New_York, 2026-03-08: 01:59:59 → 03:00:00

ISO 8601 与 RFC 3339:写给人类和排序器的时间戳

当时间戳需要可读时,答案是 ISO 8601 家族:2026-07-02T09:30:00+09:00。实践中 API 实现的是 RFC 3339 — 一个刻意收窄、面向互联网的 ISO 8601 子集。完整的 ISO 标准允许一些你在 API 里永远见不到的东西 — 2026-W27-4 这样的周日期、2026-183 这样的序数日期、截断形式、不带连字符的基本格式。RFC 3339 把这些全部砍掉:完整的年-月-日、T 分隔符、强制的 UTC 偏移,以及作为 +00:00 简写的 Z。设计 API 时,"带 Z 的 RFC 3339" 是互操作性最高的选择;JavaScript 的 toISOString() 和 Python 的 datetime.isoformat() 都输出合规结果。 这个格式的杀手级特性是字典序等于时间序 — 但仅当所有值使用相同偏移和相同字段宽度时成立。对混合偏移的字符串按字母排序是错的(+09:00 的上午会排在它其实早于的 Z 后缀下午之后),这是把一切归一化为 Z 的又一个理由。正是这种可排序性,让日志文件、S3 对象键和备份名习惯性以 UTC ISO 时间戳开头。 容易咬人的细节:RFC 3339 允许 -00:00(历史上表示"偏移未知",不同于断言 UTC 的 +00:00);小数秒可选且宽度可变,解析器必须同时接受 .5、.500 和 .500000;而只有日期的 2026-07-02 根本不是时间戳 — 如上一节所示,不同解析器会给它配上不同的午夜。跨系统交换时刻时,要么发整数 epoch 值,要么发带显式偏移的完整 RFC 3339 字符串;任何更含糊的形式,都是在邀请两个系统各执一词。
最后更新:

关于此工具

Unix 时间戳转换器在 1970-01-01 UTC 起的整数秒(Unix epoch)与可读日期时间之间互转。JWT 的 iat/exp、数据库 created_at、日志、文件 mtime 等到处都是,免去每次心算。

使用方法

  1. Read the live "now" timestamp at the top of the page.
  2. Type a Unix timestamp into the input — the human date below updates instantly.
  3. Or pick a date with the picker — the Unix value updates instantly.
  4. Click Now to grab the current timestamp.
  5. Copy whichever representation you need into your code, log query, or test fixture.

常见用例

  • Converting a Stripe charge’s created field into a human date.
  • Decoding the iat / exp claim of a JWT to debug expiration issues.
  • Translating a log file timestamp into your local time zone.
  • Producing a Unix timestamp for an "expires in N seconds" cache entry.
  • Filling out a database test fixture with a known date.
  • Sanity-checking that a server clock matches the expected epoch.

常见问题

Q. Are timestamps in seconds or milliseconds?

A. Both are common. Unix tools and most databases use seconds; JavaScript Date.now() returns milliseconds. A 13-digit number is almost always milliseconds; 10 digits is seconds.

Q. What about time zones?

A. Unix timestamps are always UTC by definition. Display formatting is what introduces local time — store UTC, show local.

Q. Will Unix timestamps overflow in 2038?

A. Signed 32-bit timestamps overflow on 2038-01-19. Modern systems use 64-bit timestamps and are safe for billions of years.

Q. Why do JWT exp values look strange?

A. They are seconds since the epoch. iat is when the token was issued; exp is when it expires. Both are in UTC.