Unix 时间戳格式详解
一份所有 Unix 时间戳格式的完整参考 —— 秒、毫秒、微秒、ISO 8601 和 RFC 2822 —— 配有示例显示每种语言和数据库使用哪种格式,以及如何一眼区分它们。
一眼看尽每种 Unix 时间戳格式
Unix 时间戳只是一个数字,而它的格式其实只是它的单位 —— 它从 1970 年 1 月 1 日 UTC 起数得有多细。单位几乎总能从位数读出:10 位是秒,13 是毫秒,16 是微秒,19 是纳秒。两种字符串格式 ISO 8601 和 RFC 2822 则是自描述的。下表是全貌;其后的各节讲解每种格式以及如何区分它们。
| 格式 | 位数 | 示例 | 使用者 |
|---|---|---|---|
| 秒 | 10 | 1700000000 | Python, PHP, Go, Ruby, C, SQL |
| 毫秒 | 13 | 1700000000000 | JavaScript, Java, .NET |
| 微秒 | 16 | 1700000000000000 | PostgreSQL, Rust |
| 纳秒 | 19 | 1700000000000000000 | Go UnixNano, 追踪系统 |
| ISO 8601 | 字符串 | 2023-11-15T06:13:20Z | API、日志(自描述) |
| RFC 2822 | 字符串 | Wed, 15 Nov 2023 06:13:20 GMT | 邮件、HTTP 头 |
秒级 Unix 时间 —— 通用格式
最常见的格式:一个 32 位或 64 位整数,计自 1970 年 1 月 1 日 00:00:00 UTC 起的整秒数。当前是约 17 亿的 10 位数字。
- 示例:1700000000 = 2023-11-15 06:13:20 UTC
- 使用者:Python time.time(), PHP time(), Go time.Now().Unix(), Ruby Time.now.to_i, C time(NULL)
- 存储为:32 位 int(旧式,最大年份 2038)、64 位 int(现代,数十亿年内安全)
- 数据库:MySQL UNIX_TIMESTAMP(), PostgreSQL EXTRACT(EPOCH FROM NOW())::BIGINT
毫秒级 Unix 时间 —— JavaScript 的格式
自 Unix 纪元起的毫秒:一个提供毫秒精度的 13 位整数。这是 JavaScript 的 Date 对象内部使用的格式。
- 示例:1700000000000 = 2023-11-15 06:13:20.000 UTC
- 使用者:JavaScript Date.now(), Java System.currentTimeMillis(), .NET DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()
- 转换为秒:Math.floor(ms / 1000)
- 从秒转换:seconds * 1000
ISO 8601 —— 可读的标准
ISO 8601 是把日期和时间表示为字符串的国际标准。与 Unix 时间戳不同,它是自描述的:格式同时编码了日期/时间和时区偏移。
- 2023-11-15T06:13:20Z —— UTC(Z 后缀表示 UTC)
- 2023-11-15T01:13:20-05:00 —— 带显式 UTC 偏移(EST)
- 2023-11-15T06:13:20.000Z —— 带毫秒
- JavaScript:date.toISOString() 总是返回带 Z 后缀的 UTC
- Python:datetime.isoformat(),Go:time.Format(time.RFC3339)
RFC 2822 —— 邮件与 HTTP 日期格式
RFC 2822(邮件由 RFC 5322 更新,HTTP 由 RFC 9110 沿用)是邮件头和 HTTP 响应中使用的可读日期格式。JavaScript 的 Date.toUTCString() 返回这种格式。
- 示例:Wed, 15 Nov 2023 06:13:20 GMT
- 用于:HTTP 响应头(Last-Modified, Date, Expires)、邮件头(Date:)
- JavaScript:date.toUTCString()
- 在现代 API 中较少见,但在 Web 基础设施中仍广泛遇到
如何检测时间戳格式
当你收到一个未知的时间戳值时,这些规则能识别它的格式。位数决定每一种数值情形;两种字符串格式一看便知。
| 线索 | 格式 |
|---|---|
| 10 位 | Unix 秒 |
| 13 位 | Unix 毫秒 |
| 16 位 | 微秒 |
| 19 位 | 纳秒 |
| 含 T 或 Z | ISO 8601 |
| 逗号或星期名 | RFC 2822 |
| 负整数 | 1970 年之前的秒或毫秒 |
- 常识检查:任何数值都应解码为当前时代的可信日期(10 位秒大致是 2001—2038 年)
- 靠近 1970 年或数千年之外的日期意味着单位读错了
微秒与纳秒
一些高精度系统使用比毫秒更小的单位。它们在应用层代码中很少见,但出现在底层系统、数据库内部和可观测性工具里。
- 微秒(µs):16 位整数 —— Rust SystemTime as_micros(), PostgreSQL clock_gettime()
- 纳秒(ns):19 位整数 —— Go time.Now().UnixNano(), Rust SystemTime as_nanos()
- PostgreSQL EXTRACT(EPOCH) 返回一个以微秒为小数部分的浮点数
- 把纳秒转换为秒:除以 1,000,000,000(1e9)
分辨率与亚秒精度
上面每种格式承载不同的时间分辨率。选择一种格式就是选择你能多精细地区分两个时刻 —— 从一秒到一纳秒。
- 1 秒分辨率:Unix 秒(10 位)、传统 POSIX time_t
- 1 毫秒:JavaScript Date, MongoDB BSON Date, Java Instant.toEpochMilli()
- 1 微秒:Chrome/WebKit 时间戳, Python datetime.timestamp(), PostgreSQL timestamp precision 6
- 100 纳秒:Windows FILETIME, .NET DateTime.Ticks
- 1 纳秒:Java Instant(完整精度), Go time.UnixNano(), JS Temporal.Instant.epochNanoseconds(BigInt)
- 皮秒及以下:PTP/IEEE 1588 线缆格式(一秒的 1/2^32)、NTP 小数字段
- 选择满足你需求的最粗分辨率 —— 亚秒精度常在 JSON 序列化或字符串往返时丢失
- 在格式间转换时,经由 Unix 毫秒或纳秒(通过 BigInt)—— 那是保留精度的最小公分母
时间戳格式转换器
在 Unix 时间与你在实践中遇到的平台专用时间戳格式之间转换:
FAQ
- Unix 时间戳是多少位?
- 现代的秒级 Unix 时间戳是 10 位(约 17 亿);毫秒级是 13 位。微秒是 16 位,纳秒是 19 位。
- JavaScript 使用哪种时间戳格式?
- JavaScript 的 Date 以毫秒工作 —— Date.now() 返回一个 13 位的毫秒时间戳,new Date(ms) 期望毫秒。把 Unix 秒乘以 1000 再传给 Date。
- Unix 时间和 ISO 8601 有什么区别?
- Unix 时间是自 1970 年 UTC 起的单个秒数或毫秒数,不带时区。ISO 8601 是一个自描述字符串,如 2023-11-15T06:13:20Z,它编码了日期、时间和偏移。
- RFC 2822 日期格式是什么?
- RFC 2822(由 RFC 5322 更新)是邮件和 HTTP 头中使用的可读日期格式,如 "Wed, 15 Nov 2023 06:13:20 GMT"。JavaScript 用 date.toUTCString() 生成它。
- 我怎么检测一个时间戳是秒还是毫秒?
- 数位数:10 位的值是秒,13 位的值是毫秒。如果一个值转换出靠近 1970 年或远在未来的日期,就是单位读错了。