在 JavaScript 中处理 Unix 时间戳
在 JavaScript 中处理 Unix 时间戳所需的一切 —— 获取当前时间、从时间戳创建 Date、为任意时区格式化、避免常见错误 —— 附一份可复制粘贴的速查表和深入指南的链接。
JavaScript 时间戳速查表
JavaScript 以毫秒工作:Date.now() 和 Date 构造函数都使用自 Unix 纪元起的毫秒,而其他大多数系统使用秒 —— 所以几乎每个 JavaScript 时间戳任务都归结为记住一个 × 1000 或 ÷ 1000。下表是快速参考;其后的各节解释每个操作,深入指南则完整讲解时区和 Temporal API。
| 任务 | 代码 | 结果 |
|---|---|---|
| 当前时间(毫秒) | Date.now() | 1700000000000 |
| 当前时间(秒) | Math.floor(Date.now() / 1000) | 1700000000 |
| 秒 → Date | new Date(s * 1000) | Date 对象 |
| 毫秒 → Date | new Date(ms) | Date 对象 |
| Date → 毫秒 | date.getTime() | 1700000000000 |
| Date → ISO 8601 | date.toISOString() | 2023-11-15T06:13:20.000Z |
| ISO 字符串 → 毫秒 | Date.parse(str) | 1700000000000 |
获取当前 Unix 时间戳
JavaScript 提供了几种等价的方式把当前时间获取为数字时间戳。它们都返回自 Unix 纪元起的毫秒数。
- Date.now() → 最快也最易读 —— 1700000000000(毫秒)
- Math.floor(Date.now() / 1000) → 秒级 Unix 时间戳 —— 1700000000
- +new Date() → 与 Date.now() 相同,使用一元加运算符
- new Date().getTime() → 显式方法调用,结果与 Date.now() 相同
从 Unix 时间戳创建 Date 对象
Date 构造函数接受自纪元起的毫秒。把秒级时间戳传给构造函数之前,务必先乘以 1000。
- new Date(1700000000 * 1000) → 从秒(最常见的情形)
- new Date(1700000000000) → 从毫秒(JavaScript 的 API、Java)
- new Date(Date.now()) → 当前时间作为 Date 对象
- new Date(0) → Unix 纪元:1970 年 1 月 1 日 00:00:00 UTC
格式化日期 —— 内置字符串方法
Date 对象有几个内置的字符串转换方法。每个都生成不同的格式。
- .toISOString() → '2023-11-15T06:13:20.000Z' — ISO 8601,始终 UTC,机器可读
- .toUTCString() → 'Wed, 15 Nov 2023 06:13:20 GMT' — RFC 7231,人类可读的 UTC
- .toString() → 带完整时区名的本地时区字符串
- .toLocaleString() → 在用户本地时区下感知区域设置的格式
感知时区的格式化
对于感知时区的格式化,用带显式 timeZone 的 Intl.DateTimeFormat —— 它会自动应用 DST,且不需要库。时区本身就是一个深入的主题;专门的 JavaScript 时区指南讲解 formatToParts、检测用户时区,以及困难的挂钟→UTC 方向。
- new Intl.DateTimeFormat('en-US', { timeZone: 'America/New_York', dateStyle: 'full', timeStyle: 'long' }).format(date)
- date.toLocaleString('en-GB', { timeZone: 'Europe/London', hour12: false })
把日期字符串转换回 Unix 时间戳
要走相反方向 —— 从日期字符串到 Unix 时间戳 —— 用 Date.parse(),或把字符串传给 Date 构造函数。
- new Date('2023-11-15T06:13:20Z').getTime() / 1000 → 从 ISO 8601 UTC 得到 Unix 秒
- new Date('2023-11-15T01:13:20-05:00').getTime() → 从带偏移的 ISO 得到 Unix 毫秒
- Date.parse('2023-11-15T06:13:20Z') → 与 new Date(...).getTime() 相同
- 为了可预测的解析,始终使用带显式时区的 ISO 8601 格式
常见陷阱
这些是 JavaScript 开发者在日期和时间戳上最常犯的错误:
- new Date(1700000000) —— 缺少 × 1000 会转换到约 1970 年而非 2023 年
- getMonth() 返回 0–11 而非 1–12 —— 显示时务必加 1
- new Date('2024-01-01') 是 UTC 午夜;new Date('2024/01/01') 是本地午夜
- new Date(2024, 0, 1) = 1 月 1 日(构造函数里月份也是从 0 开始)
- 用加 86400000 毫秒来得到“明天”可能在 DST 边界失败 —— 改用 setDate(d.getDate() + 1)
Temporal API —— Date 的现代替代
TC39 的 Temporal API 已达到 Stage 4,并在现代浏览器和 Node.js 中发布。它修复了 Date 的核心缺陷 —— 不可变、纳秒精度、感知时区 —— 而 Temporal.Instant 就是它的 Unix 时间戳类型。发布的 API 以毫秒或纳秒转换纪元(较旧的 fromEpochSeconds 已被移除),所以把 Unix 秒乘以 1000。完整 API 见 Temporal 完整指南。
- Temporal.Now.instant() —— 纳秒精度的当前瞬间
- Temporal.Instant.fromEpochMilliseconds(Date.now()) —— 从 JS 毫秒时间戳
- Temporal.Instant.fromEpochMilliseconds(1700000000 * 1000) —— 从 Unix 秒(× 1000)
- Temporal.ZonedDateTime —— 瞬间 + IANA 时区,Date 本该是的类型
- 已在 Firefox 139+、Chrome 144+、Node.js 26+ 发布;Safari 在 Technology Preview;其余用 polyfill
进一步阅读
FAQ
- 在 JavaScript 中如何获取秒级 Unix 时间戳?
- 用 Math.floor(Date.now() / 1000)。Date.now() 返回毫秒,所以除以 1000 再向下取整即可得到整数 Unix 秒。
- 在 JavaScript 中如何把 Unix 时间戳转换为可读日期?
- 把秒乘以 1000,传给 Date 构造函数,再格式化:new Date(1700000000 * 1000).toISOString() 得到 "2023-11-14T22:13:20.000Z"。对于特定时区,用带 timeZone 选项的 Intl.DateTimeFormat。
- 为什么用 Unix 时间戳调用 new Date() 会显示 1970?
- Date 构造函数期望毫秒。10 位的秒级时间戳必须乘以 1000:new Date(seconds * 1000)。
- 如何为特定时区格式化 JavaScript 日期?
- 用带显式 timeZone 选项的 Intl.DateTimeFormat,例如 new Intl.DateTimeFormat('en-US', { timeZone: 'America/New_York' })。它会自动应用夏令时,且不需要外部库。
- 我该用 Date 还是 Temporal?
- 对于运行时支持的新代码,优先用 Temporal —— 它不可变、感知时区,并能避开 Date 的坑。Date 对简单的 epoch 毫秒工作仍然没问题,而且依旧是支持最广的。