什么是 ISO 8601?
ISO 8601 是一个国际标准,用于以清晰、明确的格式表示日期和时间。该标准由国际标准化组织(ISO)发布,消除了世界各地不同日期格式(如 MM/DD/YYYY 与 DD/MM/YYYY)造成的混淆,并提供了一致的方式来交换日期和时间信息。
ISO 8601 格式在 API、数据库和 Web 应用程序中广泛使用,因为它:
- 明确无歧义:不会混淆日/月顺序
- 可排序:字典序排序也能正确工作
- 机器可读:计算机容易解析
- 人类可读:人们也能理解
- 通用:适用于所有时区和地区
为什么使用 ISO 8601 格式?
当你看到日期 03/04/2024 时,它是指 3 月 4 日还是 4 月 3 日?不同国家对此的解释不同。ISO 8601 通过使用 2024-04-03 格式解决了这个问题,它始终明确无歧义:年-月-日。
JAVASCRIPT1// 有歧义的格式(避免使用) 2"03/04/2024" // 这是 3 月 4 日还是 4 月 3 日? 3"4-3-24" // 这是 2024 年还是 1924 年? 4 5// ISO 8601 格式(推荐) 6"2024-04-03" // 始终是 2024 年 4 月 3 日 7"2024-04-03T14:30:00Z" // 2024 年 4 月 3 日下午 2:30(UTC)
ISO 8601 日期格式
基本日期格式
标准的 ISO 8601 日期格式遵循模式:YYYY-MM-DD
示例:
2024-01-15- 2024 年 1 月 15 日2024-12-31- 2024 年 12 月 31 日2025-06-07- 2025 年 6 月 7 日
PYTHON1# Python 示例 2from datetime import date 3 4today = date(2024, 4, 15) 5iso_date = today.isoformat() # "2024-04-15" 6print(f"ISO 8601 日期: {iso_date}")
扩展格式与基本格式
ISO 8601 支持两种格式:
- 扩展格式(带分隔符):
2024-04-15 - 基本格式(紧凑):
20240415
大多数应用程序使用扩展格式,因为它更易读。
JAVASCRIPT1// JavaScript 示例 2const date = new Date('2024-04-15'); 3 4// 扩展格式(推荐) 5const extended = date.toISOString().split('T')[0]; // "2024-04-15" 6 7// 基本格式(紧凑) 8const basic = extended.replace(/-/g, ''); // "20240415"
周日期
ISO 8601 还支持基于周的日期,格式为:YYYY-Www-D
YYYY:年份Www:周数(01-53)D:星期几(1=周一,7=周日)
示例: 2024-W15-3 表示 2024 年第 15 周的星期三。
序数日期
你也可以使用序数日期(一年中的第几天):YYYY-DDD
示例: 2024-366 表示 2024 年 12 月 31 日(闰年,共 366 天)。
ISO 8601 时间格式
基本时间格式
标准的 ISO 8601 时间格式遵循:HH:MM:SS 或 HH:MM:SS.sss
示例:
14:30:00- 下午 2:30:0009:05:30- 上午 9:05:3023:59:59.999- 晚上 11:59:59.999,带毫秒
JAVA1// Java 示例 2import java.time.LocalTime; 3import java.time.format.DateTimeFormatter; 4 5LocalTime time = LocalTime.of(14, 30, 0); 6String isoTime = time.format(DateTimeFormatter.ISO_LOCAL_TIME); 7System.out.println("ISO 8601 时间: " + isoTime); // "14:30:00"
小数秒
ISO 8601 支持不同精度的小数秒:
14:30:00.5- 半秒14:30:00.123- 毫秒(3 位数字)14:30:00.123456- 微秒(6 位数字)14:30:00.123456789- 纳秒(9 位数字)
GO1// Go 示例 2package main 3 4import ( 5 "fmt" 6 "time" 7) 8 9func main() { 10 now := time.Now() 11 // ISO 8601 带毫秒 12 iso := now.Format("15:04:05.000") 13 fmt.Println("ISO 8601 时间:", iso) 14}
ISO 8601 日期时间格式
日期和时间组合
要同时表示日期和时间,ISO 8601 使用 T 分隔符:YYYY-MM-DDTHH:MM:SS
示例:
2024-04-15T14:30:00- 2024 年 4 月 15 日下午 2:30(本地时间)2024-12-31T23:59:59- 2024 年 12 月 31 日晚上 11:59:59
RUBY1# Ruby 示例 2require 'time' 3 4datetime = Time.new(2024, 4, 15, 14, 30, 0) 5iso_datetime = datetime.iso8601 # "2024-04-15T14:30:00+00:00" 6puts "ISO 8601 日期时间: #{iso_datetime}"
"T" 分隔符
T 字符将日期与时间分开。它在标准格式中是必需的,尽管有些系统为了可读性也接受空格。
PHP1// PHP 示例 2<?php 3$datetime = new DateTime('2024-04-15 14:30:00'); 4$iso8601 = $datetime->format('c'); // "2024-04-15T14:30:00+00:00" 5echo "ISO 8601 日期时间: " . $iso8601; 6?>
ISO 8601 时区标识符
ISO 8601 最强大的功能之一是支持时区信息。
UTC 时间(Z 标识符)
Z 后缀表示 UTC(协调世界时),也称为"祖鲁时间":
2024-04-15T14:30:00Z- UTC 下午 2:30
Z 是 +00:00 的简写。
JAVASCRIPT1// JavaScript 示例 2const utcDate = new Date('2024-04-15T14:30:00Z'); 3console.log(utcDate.toISOString()); // "2024-04-15T14:30:00.000Z" 4 5// 对于 UTC 时间,始终优先使用带 Z 的 ISO 8601 6const timestamp = Date.now(); 7const isoString = new Date(timestamp).toISOString(); 8console.log(isoString); // "2024-04-15T14:30:00.123Z"
时区偏移量
对于非 UTC 时间,指定与 UTC 的偏移量:±HH:MM
示例:
2024-04-15T14:30:00+05:30- 印度时间下午 2:30(UTC+5:30)2024-04-15T14:30:00-04:00- 东部夏令时下午 2:30(UTC-4)2024-04-15T14:30:00+00:00- 与 Z 相同(UTC)
PYTHON1# Python 带时区示例 2from datetime import datetime, timezone, timedelta 3 4# UTC 时间 5utc_time = datetime(2024, 4, 15, 14, 30, 0, tzinfo=timezone.utc) 6print(utc_time.isoformat()) # "2024-04-15T14:30:00+00:00" 7 8# 自定义时区(UTC+5:30) 9ist = timezone(timedelta(hours=5, minutes=30)) 10ist_time = datetime(2024, 4, 15, 14, 30, 0, tzinfo=ist) 11print(ist_time.isoformat()) # "2024-04-15T14:30:00+05:30"
本地时间(无标识符)
如果未指定时区,则时间被视为本地时间:
2024-04-15T14:30:00- 本地时区的下午 2:30
警告: 避免在 API 和数据库中使用本地时间。始终指定时区以防止歧义。
ISO 8601 持续时间格式
ISO 8601 定义了使用前缀 P(表示"period")的持续时间特定表示法。
持续时间格式:P[n]Y[n]M[n]DT[n]H[n]M[n]S
P:持续时间标识符(必需)Y:年M:月(在 T 之前)D:日T:时间标识符(将日期与时间组件分开)H:小时M:分钟(在 T 之后)S:秒
持续时间示例
P3Y6M4DT12H30M5S = 3 年 6 个月 4 天 12 小时 30 分钟 5 秒
P1Y = 1 年
P6M = 6 个月
P7D = 7 天
PT2H30M = 2 小时 30 分钟
PT45S = 45 秒
P1DT12H = 1 天 12 小时
P0D = 0 天(零持续时间)
JAVASCRIPT1// JavaScript 示例(使用 date-fns 或自定义解析) 2function parseISO8601Duration(duration) { 3 const regex = /P(?:(\d+)Y)?(?:(\d+)M)?(?:(\d+)D)?(?:T(?:(\d+)H)?(?:(\d+)M)?(?:(\d+)S)?)?/; 4 const matches = duration.match(regex); 5 6 return { 7 years: parseInt(matches[1]) || 0, 8 months: parseInt(matches[2]) || 0, 9 days: parseInt(matches[3]) || 0, 10 hours: parseInt(matches[4]) || 0, 11 minutes: parseInt(matches[5]) || 0, 12 seconds: parseInt(matches[6]) || 0 13 }; 14} 15 16const duration = parseISO8601Duration("P1DT2H30M"); 17console.log(duration); // { years: 0, months: 0, days: 1, hours: 2, minutes: 30, seconds: 0 }
周持续时间
你还可以使用 W 表示以周为单位的持续时间:
P3W= 3 周(相当于P21D)
ISO 8601 时间间隔
ISO 8601 支持三种表示时间间隔的方式:
1. 开始和结束时间
<start>/<end>
示例:2024-04-15T09:00:00Z/2024-04-15T17:00:00Z(UTC 上午 9 点到下午 5 点)
2. 开始时间和持续时间
<start>/P<duration>
示例:2024-04-15T09:00:00Z/PT8H(UTC 上午 9 点开始,持续 8 小时)
3. 持续时间和结束时间
P<duration>/<end>
示例:PT8H/2024-04-15T17:00:00Z(8 小时,结束于 UTC 下午 5 点)
PYTHON1# Python 间隔示例 2from datetime import datetime, timedelta 3 4start = datetime(2024, 4, 15, 9, 0, 0) 5end = datetime(2024, 4, 15, 17, 0, 0) 6 7# 计算持续时间 8duration = end - start 9print(f"持续时间: {duration}") # 8:00:00 10 11# ISO 8601 间隔 12interval = f"{start.isoformat()}/{end.isoformat()}" 13print(f"间隔: {interval}")
ISO 8601 与 RFC 3339
RFC 3339 是 ISO 8601 的一个配置文件,通常在互联网上使用。主要区别:
| 特性 | ISO 8601 | RFC 3339 |
|---|---|---|
| 格式 | YYYY-MM-DDTHH:MM:SS±HH:MM | 相同 |
| UTC | Z 或 +00:00 | 两者都允许 |
| 小数秒 | 可选,任意精度 | 可选,任意精度 |
| 分隔符 | 可以省略(基本格式) | 必需(扩展格式) |
| 时间分隔符 | 必须使用 T | T 或空格都允许 |
示例:
- ISO 8601:
2024-04-15T14:30:00Z或20240415T143000Z - RFC 3339:
2024-04-15T14:30:00Z(仅扩展格式)
大多数现代 API 使用 RFC 3339,它是 ISO 8601 的严格子集。
ISO 8601 开发最佳实践
1. 始终使用 UTC 存储
使用 Z 标识符以 UTC 格式存储所有时间戳:
JAVASCRIPT1// ✅ 好 - 以 UTC 存储 2const timestamp = new Date().toISOString(); // "2024-04-15T14:30:00.123Z" 3 4// ❌ 差 - 存储本地时间 5const localTime = new Date().toString(); // "Mon Apr 15 2024 14:30:00 GMT+0500"
2. 包含时区信息
显示时间时,始终包含时区信息:
PYTHON1# ✅ 好 - 包含时区 2"2024-04-15T14:30:00+05:30" 3 4# ❌ 差 - 缺少时区 5"2024-04-15T14:30:00"
3. 使用扩展格式
为了可读性,优先使用扩展格式(带分隔符):
JAVA1// ✅ 好 - 扩展格式 2"2024-04-15T14:30:00Z" 3 4// ❌ 差 - 基本格式(难以阅读) 5"20240415T143000Z"
4. 精度很重要
根据使用情况使用适当的精度:
GO1// 日志记录的高精度 2"2024-04-15T14:30:00.123456789Z" 3 4// 大多数应用程序的标准精度 5"2024-04-15T14:30:00Z" 6 7// 当时间不重要时仅使用日期 8"2024-04-15"
5. 验证 ISO 8601 字符串
在解析之前始终验证 ISO 8601 字符串:
JAVASCRIPT1// JavaScript 验证 2function isValidISO8601(dateString) { 3 const iso8601Regex = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?(Z|[+-]\d{2}:\d{2})$/; 4 if (!iso8601Regex.test(dateString)) return false; 5 6 const date = new Date(dateString); 7 return !isNaN(date.getTime()); 8} 9 10console.log(isValidISO8601("2024-04-15T14:30:00Z")); // true 11console.log(isValidISO8601("2024-04-15 14:30:00")); // false
常见 ISO 8601 错误及避免方法
1. 缺少 T 分隔符
JAVASCRIPT1// ❌ 错误 2"2024-04-15 14:30:00Z" 3 4// ✅ 正确 5"2024-04-15T14:30:00Z"
2. 错误的时区格式
PYTHON1# ❌ 错误 - 偏移量中缺少冒号 2"2024-04-15T14:30:00+0530" 3 4# ✅ 正确 - 偏移量中有冒号 5"2024-04-15T14:30:00+05:30"
3. 混合日期格式
JAVA1// ❌ 错误 - 美国格式 2"04/15/2024T14:30:00Z" 3 4// ✅ 正确 - ISO 8601 5"2024-04-15T14:30:00Z"
4. 省略前导零
RUBY1# ❌ 错误 2"2024-4-5T9:5:0Z" 3 4# ✅ 正确 5"2024-04-05T09:05:00Z"
不同编程语言中的 ISO 8601
JavaScript / TypeScript
JAVASCRIPT1// ISO 8601 格式的当前时间 2const now = new Date().toISOString(); 3console.log(now); // "2024-04-15T14:30:00.123Z" 4 5// 解析 ISO 8601 字符串 6const date = new Date("2024-04-15T14:30:00Z"); 7 8// 自定义格式化(使用 Intl) 9const formatter = new Intl.DateTimeFormatter('zh-CN', { 10 year: 'numeric', 11 month: '2-digit', 12 day: '2-digit', 13 hour: '2-digit', 14 minute: '2-digit', 15 second: '2-digit', 16 timeZone: 'UTC', 17 hour12: false 18});
Python
PYTHON1from datetime import datetime, timezone 2 3# ISO 8601 格式的当前时间 4now = datetime.now(timezone.utc).isoformat() 5print(now) # "2024-04-15T14:30:00.123456+00:00" 6 7# 解析 ISO 8601 字符串 8dt = datetime.fromisoformat("2024-04-15T14:30:00+00:00") 9 10# 格式化为 ISO 8601 11formatted = dt.strftime("%Y-%m-%dT%H:%M:%S%z")
Java
JAVA1import java.time.Instant; 2import java.time.ZonedDateTime; 3import java.time.format.DateTimeFormatter; 4 5// ISO 8601 格式的当前时间 6String now = Instant.now().toString(); 7System.out.println(now); // "2024-04-15T14:30:00.123Z" 8 9// 解析 ISO 8601 字符串 10ZonedDateTime dt = ZonedDateTime.parse("2024-04-15T14:30:00Z"); 11 12// 格式化为 ISO 8601 13String formatted = dt.format(DateTimeFormatter.ISO_INSTANT);
使用 ISO 8601 的工具
在线转换器
- ISO 8601 转换器 - 在 ISO 8601 和人类可读格式之间转换
- Unix 时间戳转换器 - 在 Unix 时间戳和 ISO 8601 之间转换
- 时区转换器 - 在不同时区之间转换 ISO 8601 时间
常见问题
ISO 8601 中的"T"是什么意思?
T 是日期和时间组件之间的分隔符。它代表"Time"(时间),是 ISO 8601 标准所要求的,以避免歧义。
ISO 8601 与 RFC 3339 相同吗?
RFC 3339 是为互联网使用而设计的 ISO 8601 配置文件(子集)。RFC 3339 更严格,始终需要带分隔符的扩展格式,而 ISO 8601 允许基本格式和扩展格式。
为什么 ISO 8601 使用 YYYY-MM-DD 顺序?
这个顺序(从最大到最小单位)允许自然排序。当你按字母顺序对 ISO 8601 日期进行排序时,它们会自动按时间顺序排序。
我可以使用空格代替"T"吗?
虽然有些系统为了可读性接受空格,但 ISO 8601 标准要求使用 T 分隔符。为了最大兼容性,始终使用 T。
存储时间戳应该使用什么时区?
在数据库和 API 中始终以 UTC(带 Z 标识符)存储时间戳。仅在向用户显示时转换为本地时间。
如何处理夏令时?
以 UTC 存储所有时间以避免夏令时问题。转换为本地时间时,使用能够自动处理夏令时的适当时区库。
小数秒的最大精度是多少?
ISO 8601 没有指定最大精度。大多数系统支持毫秒(3 位数字)、微秒(6 位数字)或纳秒(9 位数字)。
如果秒为零,我可以省略秒吗?
虽然有些系统接受 2024-04-15T14:30Z,但严格的 ISO 8601 格式要求秒:2024-04-15T14:30:00Z。
相关资源
- 什么是 Unix 时间戳? - 了解 Unix 时间戳和 epoch 时间
- 理解时区 - 掌握时区概念和最佳实践
- 时间戳格式速查表 - 所有时间戳格式的快速参考
- 当前 Unix 时间戳 - 获取各种格式的当前时间戳
- 日期转时间戳转换器 - 将日期转换为时间戳
总结
ISO 8601 是软件系统中表示日期和时间的黄金标准。通过遵循 ISO 8601 格式,你可以确保你的时间戳明确无歧义、可排序且与全球系统兼容。
关键要点:
- 对 UTC 时间使用
YYYY-MM-DDTHH:MM:SSZ - 包含时区信息(
Z或±HH:MM) - 以 UTC 存储时间戳,以本地时间显示
- 在解析之前验证 ISO 8601 字符串
- 为了可读性使用扩展格式(带分隔符)
掌握 ISO 8601 格式对于任何处理日期和时间的开发人员来说都是必不可少的。无论你是构建 API、存储数据还是解析日志文件,ISO 8601 都提供了一种可靠、标准化的时间表示方法。
今天就开始在你的项目中使用 ISO 8601,永远消除日期/时间的歧义!🚀