日期时间格式对照表
日期时间格式对照:Unix 时间戳、ISO 8601、RFC 3339、RFC 2822 等标准格式,以及常见展示写法的含义与示例,处理时间字段时快速查阅。
实践注解
- Unix 时间戳是 UTC,但「当前时区」不是时间戳本身与时区无关,展示时才需要时区。把时间戳存库、用本地时区渲染是正确的做法;反过来把「本地时间」当成时间戳存储,跨时区就会出现几小时偏移。
- ISO 8601 的 Z 与 +08:00 不能省2026-10-01T12:00:00 不带偏移量时,不同运行环境会按各自的本地时区解析,同一字符串得到不同瞬间。API 一律返回带 Z 或显式偏移的完整写法。
- MySQL 的 DATETIME 不存时区,TIMESTAMP 会转换DATETIME 原样存取,TIMESTAMP 在写入时按会话时区转成 UTC、读取时再转回。同一份数据在会话时区不同的连接里会显示不同值,选型时必须先明确这一语义差异。
数据来源
- ISO 8601-1:2019
- RFC 3339
- RFC 5322 (Internet message date)
- RFC 9557 (IXDTF)
上述编号、名称与定义均来自公开规范,本站不主张对规范数据本身的独创性;本页的编排方式、中文释义与实践注解由本站撰写。
原理解析
时间表示分两层:一是「绝对时刻」——时间线上唯一的点(如 Unix 时间戳 1693564800),与展示无关;二是「展示格式」——人类可读的写法,受地区、历法、时区影响。同一绝对时刻在不同地区显示为不同字符串,因此存储时优先保留绝对时刻加时区,展示时再按用户 locale 格式化。
各格式来源不同:Unix 时间戳是 1970-01-01 UTC 起的秒/毫秒,最适合计算;ISO 8601 / RFC 3339 是人类可读且机器无歧义的标准,适合 API 与日志;RFC 2822 常见于邮件与 HTTP 头。混用时务必确认单位(秒 vs 毫秒)与时区,否则会差出 1000 倍或偏移到错误时区。
什么时候该查这张表
这张表在你要为接口、日志或存储选时间格式时有用。它把 Unix 时间戳、ISO 8601、RFC 3339、RFC 2822、SQL 格式、本地化格式放在一起对照,标出各自的可读性、时区处理与适用场景。
不该查的情况:你在处理时区转换的业务语义,或做跨时区的调度与日历运算。格式只是表示法,「用户说的下午三点是哪个时区的三点」是业务规则问题,表里没有答案。
判断标准:按用途选。机器之间传输与存储用 ISO 8601 或 Unix 时间戳;给人看的日志与界面用可读格式;HTTP 头必须用 RFC 7231 规定的 IMF-fixdate。不要用自定义格式——手写的 YYYY-MM-DD HH:mm 在时区与跨平台上问题不断。
特别注意 Unix 时间戳的三个坑:它是秒级还是毫秒级各家不统一(JavaScript 的 Date.now() 是毫秒,数据库常用秒);它本身不含时区,约定为 UTC 但常被当本地时间用;2038 年问题在 32 位系统上仍存在。
边界与常见陷阱
秒与毫秒混用是最常见的接口故障源
前端传 1717171717(秒),后端按毫秒解析得到 1970 年 1 月;反过来发 1717171717000,Go/Java 的某些库按秒解析直接溢出。症状是「时间显示成 1970 年」或「时间在未来几百年」。防御做法:在契约里显式写单位(字段名带 Ms 或 S,或用 ISO 8601),并在服务端做量级校验——超过 1e11 的时间戳一定不是秒级。
本地时区与 UTC 混存导致时间错位
写入时用本地时间、读取时当 UTC(或反过来),是最隐蔽的时区 bug:同一批数据在开发机(UTC+8)与生产机(UTC)上结果差 8 小时,且不报错。规则要单一:存储层一律 UTC,展示层再按用户时区渲染;绝不在数据库里存不带时区信息的本地时间字符串(「2024-06-01 12:00:00」 这种字符串无法推断时区)。
夏令时切换当天的时间是不连续的
在多数时区,春季跳表时存在一个从未发生过的本地时间(如 02:30),秋季回拨时存在一个出现两次的本地时间(如 01:30)。这会导致「按本地时间调度任务」在切换日执行两次或完全没执行。规避方式:调度用 UTC 或「本地时间 + 时区名」表达(cron 的 CRON_TZ),不要用纯本地时刻;跨时区的日程用带时区的 IANA 名称而非固定偏移量。
与相邻内容的分工
要查某个码点或字符的编码形式,用站内「字符编码」页;本页关注时间格式的选择与转换。
要计算两个时刻之间的间隔或做日期加减,用站内时间相关工具;本页是格式对照,不含日期算术。
要处理定时任务的调度语义(cron 表达式、错过窗口、抖动),属调度系统范畴,本表不覆盖。
若目的是排查某个时间显示错乱的问题,通常需要同时看存储格式、服务端时区配置与前端渲染三处,仅看格式表不足以定位。
实战片段
要点:① 时间戳单位必须在契约里显式声明,服务端做量级校验——超过 1e11 一定不是秒;② 存储层一律用 UTC 的 ISO 字符串或数字,绝不存 2024-06-01 12:00:00 这类无时区信息的字符串;③ Date.toString() 结果带本地时区与英文月份且不可逆解析,不能用于持久化;④ HTTP 头日期必须用 toUTCString() 对应的 IMF-fixdate;⑤ 夏令时切换日纯本地时间不连续,调度请用 UTC 或 CRON_TZ。
const d = new Date()
// ① 三种输出,各自的用途
console.log(d.toISOString()) // 2024-06-01T12:00:00.000Z ← 存储/传输用这个
console.log(d.toJSON()) // 同上(Date 专有)
console.log(d.getTime()) // 1717243200000 毫秒,注意是 13 位
// ② 🔴 单位混用的防御:量级校验
function toDate(v) {
if (typeof v === 'number') {
if (v < 1e11) return new Date(v * 1000) // 看着像秒 ⇒ 当秒处理
if (v > 1e14) throw new Error('不像毫秒时间戳: ' + v)
return new Date(v) // 13 位 ⇒ 毫秒
}
if (typeof v === 'string') {
if (/^d{10}$/.test(v)) return new Date(Number(v) * 1000)
return new Date(v) // ISO 字符串直接解析
}
throw new TypeError('不支持的类型')
}
console.log(toDate(1717171717).toISOString()) // 秒 ⇒ 正常
console.log(toDate(1717171717000).toISOString()) // 毫秒 ⇒ 正常
// ③ 存储一律 UTC,展示再本地化(不要存本地时间字符串)
const record = { createdAt: d.toISOString() } // ✅
const LOCAL = '2024-06-01 12:00:00' // ❌ 不带时区,无法推断
// ④ 手动格式化(仅用于展示;库更省事)
const pad = n => String(n).padStart(2, '0')
const fmtLocal = x => x.getFullYear() + '-' +
pad(x.getMonth() + 1) + '-' + pad(x.getDate()) + ' ' +
pad(x.getHours()) + ':' + pad(x.getMinutes())
// ⑤ RFC 7231 的 HTTP 头日期(必须用 UTC 的英文格式)
console.log(new Date().toUTCString())
// Mon, 01 Jun 2024 12:00:00 GMT
// ⑥ 陷阱:toString() 结果不可解析,不要用于持久化
console.log(d.toString()) // 本地时区 + 空格分隔 + 英文月份,不可逆| 格式 | 含义 | 示例 |
|---|---|---|
| Unix 时间戳 | 自 1970-01-01 UTC 起的秒数(或毫秒) | 1693564800 |
| ISO 8601 | 国际标准化组织日期时间格式 | 2023-09-01T12:00:00Z |
| ISO 8601(含时区偏移) | 带 +08:00 等偏移的本地时间 | 2023-09-01T20:00:00+08:00 |
| RFC 3339 | ISO 8601 的严格子集,常用于 API | 2023-09-01T12:00:00+00:00 |
| RFC 2822 / 1123 | HTTP 头常用的日期格式 | Fri, 01 Sep 2023 12:00:00 GMT |
| YYYY-MM-DD | 仅日期(ISO 日期) | 2023-09-01 |
| YYYY/MM/DD | 斜杠分隔日期(中文习惯) | 2023/09/01 |
| YYYY年M月D日 | 中文长日期 | 2023年9月1日 |
| HH:mm:ss | 24 小时制时间 | 12:00:00 |
| hh:mm A | 12 小时制带 AM/PM | 12:00 PM |
| YYYY-MM-DD HH:mm:ss | 常用数据库 datetime | 2023-09-01 12:00:00 |
| 相对时间 | 如 "3 分钟前",用于社交/日志展示 | 3 minutes ago |
| 季度 Qn-YYYY | 财季/季度表示 | Q3-2023 |
| ISO 周 Www-yyyy | ISO 周编号 | W35-2023 |
| Duration(ISO 8601) | 时间段表示法 | P1Y2M3DT4H5M6S |
| 毫秒时间戳 | JavaScript Date.now() 返回值 | 1693564800000 |
常见问题
Unix 时间戳是秒还是毫秒?
通常是秒(如 1693564800),但 JavaScript 的 Date.now() 与很多前端库返回毫秒(13 位)。互操作时要确认单位,必要时 ×1000 或 ÷1000 转换,否则会差出 1000 倍导致时间远到 1970 或 50000 年。
ISO 8601 和 RFC 3339 有什么区别?
RFC 3339 是 ISO 8601 的一个严格子集:要求完整的日期时间、必须带时区(Z 或 ±hh:mm)、不允许空格分隔日期与时间。写 API 时优先 RFC 3339,可读性最好。
UTC、GMT 和时区偏移 +08:00 是什么关系?
UTC 与 GMT 在日常使用中可视为等同(GMT 是时区名,UTC 是时间标准)。+08:00 表示比 UTC 早 8 小时(如中国标准时间)。存时间建议统一用 UTC(或带偏移),展示时再按用户时区转换。
数据库该存哪种时间格式?
关系型数据库优先用原生 datetime/timestamp 类型(由数据库保证时区与格式);若以字符串存储,统一用 ISO 8601/RFC 3339 并明确时区,避免 "2023-09-01 12:00" 这类无时区歧义写法。