Guide

ISO 8601格式指南:日期时间与时区标准完全解析

什么是 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 格式解决了这个问题,它始终明确无歧义:年-月-日。

// 有歧义的格式(避免使用)
"03/04/2024"  // 这是 3 月 4 日还是 4 月 3 日?
"4-3-24"      // 这是 2024 年还是 1924 年?

// ISO 8601 格式(推荐)
"2024-04-03"  // 始终是 2024 年 4 月 3 日
"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 日
# Python 示例
from datetime import date

today = date(2024, 4, 15)
iso_date = today.isoformat()  # "2024-04-15"
print(f"ISO 8601 日期: {iso_date}")

扩展格式与基本格式

ISO 8601 支持两种格式:

  1. 扩展格式(带分隔符):2024-04-15
  2. 基本格式(紧凑):20240415

大多数应用程序使用扩展格式,因为它更易读。

// JavaScript 示例
const date = new Date('2024-04-15');

// 扩展格式(推荐)
const extended = date.toISOString().split('T')[0];  // "2024-04-15"

// 基本格式(紧凑)
const 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:SSHH:MM:SS.sss

示例:

  • 14:30:00 - 下午 2:30:00
  • 09:05:30 - 上午 9:05:30
  • 23:59:59.999 - 晚上 11:59:59.999,带毫秒
// Java 示例
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;

LocalTime time = LocalTime.of(14, 30, 0);
String isoTime = time.format(DateTimeFormatter.ISO_LOCAL_TIME);
System.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 位数字)
// Go 示例
package main

import (
    "fmt"
    "time"
)

func main() {
    now := time.Now()
    // ISO 8601 带毫秒
    iso := now.Format("15:04:05.000")
    fmt.Println("ISO 8601 时间:", iso)
}

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
# Ruby 示例
require 'time'

datetime = Time.new(2024, 4, 15, 14, 30, 0)
iso_datetime = datetime.iso8601  # "2024-04-15T14:30:00+00:00"
puts "ISO 8601 日期时间: #{iso_datetime}"

"T" 分隔符

T 字符将日期与时间分开。它在标准格式中是必需的,尽管有些系统为了可读性也接受空格。

// PHP 示例
<?php
$datetime = new DateTime('2024-04-15 14:30:00');
$iso8601 = $datetime->format('c');  // "2024-04-15T14:30:00+00:00"
echo "ISO 8601 日期时间: " . $iso8601;
?>

ISO 8601 时区标识符

ISO 8601 最强大的功能之一是支持时区信息。

UTC 时间(Z 标识符)

Z 后缀表示 UTC(协调世界时),也称为"祖鲁时间":

  • 2024-04-15T14:30:00Z - UTC 下午 2:30

Z+00:00 的简写。

// JavaScript 示例
const utcDate = new Date('2024-04-15T14:30:00Z');
console.log(utcDate.toISOString());  // "2024-04-15T14:30:00.000Z"

// 对于 UTC 时间,始终优先使用带 Z 的 ISO 8601
const timestamp = Date.now();
const isoString = new Date(timestamp).toISOString();
console.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)
# Python 带时区示例
from datetime import datetime, timezone, timedelta

# UTC 时间
utc_time = datetime(2024, 4, 15, 14, 30, 0, tzinfo=timezone.utc)
print(utc_time.isoformat())  # "2024-04-15T14:30:00+00:00"

# 自定义时区(UTC+5:30)
ist = timezone(timedelta(hours=5, minutes=30))
ist_time = datetime(2024, 4, 15, 14, 30, 0, tzinfo=ist)
print(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 天(零持续时间)
// JavaScript 示例(使用 date-fns 或自定义解析)
function parseISO8601Duration(duration) {
    const regex = /P(?:(\d+)Y)?(?:(\d+)M)?(?:(\d+)D)?(?:T(?:(\d+)H)?(?:(\d+)M)?(?:(\d+)S)?)?/;
    const matches = duration.match(regex);

    return {
        years: parseInt(matches[1]) || 0,
        months: parseInt(matches[2]) || 0,
        days: parseInt(matches[3]) || 0,
        hours: parseInt(matches[4]) || 0,
        minutes: parseInt(matches[5]) || 0,
        seconds: parseInt(matches[6]) || 0
    };
}

const duration = parseISO8601Duration("P1DT2H30M");
console.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 点)

# Python 间隔示例
from datetime import datetime, timedelta

start = datetime(2024, 4, 15, 9, 0, 0)
end = datetime(2024, 4, 15, 17, 0, 0)

# 计算持续时间
duration = end - start
print(f"持续时间: {duration}")  # 8:00:00

# ISO 8601 间隔
interval = f"{start.isoformat()}/{end.isoformat()}"
print(f"间隔: {interval}")

ISO 8601 与 RFC 3339

RFC 3339ISO 8601 的一个配置文件,通常在互联网上使用。主要区别:

特性ISO 8601RFC 3339
格式YYYY-MM-DDTHH:MM:SS±HH:MM相同
UTCZ+00:00两者都允许
小数秒可选,任意精度可选,任意精度
分隔符可以省略(基本格式)必需(扩展格式)
时间分隔符必须使用 TT 或空格都允许

示例:

  • ISO 8601:2024-04-15T14:30:00Z20240415T143000Z
  • RFC 3339:2024-04-15T14:30:00Z(仅扩展格式)

大多数现代 API 使用 RFC 3339,它是 ISO 8601 的严格子集。


ISO 8601 开发最佳实践

1. 始终使用 UTC 存储

使用 Z 标识符以 UTC 格式存储所有时间戳:

// ✅ 好 - 以 UTC 存储
const timestamp = new Date().toISOString();  // "2024-04-15T14:30:00.123Z"

// ❌ 差 - 存储本地时间
const localTime = new Date().toString();  // "Mon Apr 15 2024 14:30:00 GMT+0500"

2. 包含时区信息

显示时间时,始终包含时区信息:

# ✅ 好 - 包含时区
"2024-04-15T14:30:00+05:30"

# ❌ 差 - 缺少时区
"2024-04-15T14:30:00"

3. 使用扩展格式

为了可读性,优先使用扩展格式(带分隔符):

// ✅ 好 - 扩展格式
"2024-04-15T14:30:00Z"

// ❌ 差 - 基本格式(难以阅读)
"20240415T143000Z"

4. 精度很重要

根据使用情况使用适当的精度:

// 日志记录的高精度
"2024-04-15T14:30:00.123456789Z"

// 大多数应用程序的标准精度
"2024-04-15T14:30:00Z"

// 当时间不重要时仅使用日期
"2024-04-15"

5. 验证 ISO 8601 字符串

在解析之前始终验证 ISO 8601 字符串:

// JavaScript 验证
function isValidISO8601(dateString) {
    const iso8601Regex = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?(Z|[+-]\d{2}:\d{2})$/;
    if (!iso8601Regex.test(dateString)) return false;

    const date = new Date(dateString);
    return !isNaN(date.getTime());
}

console.log(isValidISO8601("2024-04-15T14:30:00Z"));  // true
console.log(isValidISO8601("2024-04-15 14:30:00"));   // false

常见 ISO 8601 错误及避免方法

1. 缺少 T 分隔符

// ❌ 错误
"2024-04-15 14:30:00Z"

// ✅ 正确
"2024-04-15T14:30:00Z"

2. 错误的时区格式

# ❌ 错误 - 偏移量中缺少冒号
"2024-04-15T14:30:00+0530"

# ✅ 正确 - 偏移量中有冒号
"2024-04-15T14:30:00+05:30"

3. 混合日期格式

// ❌ 错误 - 美国格式
"04/15/2024T14:30:00Z"

// ✅ 正确 - ISO 8601
"2024-04-15T14:30:00Z"

4. 省略前导零

# ❌ 错误
"2024-4-5T9:5:0Z"

# ✅ 正确
"2024-04-05T09:05:00Z"

不同编程语言中的 ISO 8601

JavaScript / TypeScript

// ISO 8601 格式的当前时间
const now = new Date().toISOString();
console.log(now);  // "2024-04-15T14:30:00.123Z"

// 解析 ISO 8601 字符串
const date = new Date("2024-04-15T14:30:00Z");

// 自定义格式化(使用 Intl)
const formatter = new Intl.DateTimeFormatter('zh-CN', {
    year: 'numeric',
    month: '2-digit',
    day: '2-digit',
    hour: '2-digit',
    minute: '2-digit',
    second: '2-digit',
    timeZone: 'UTC',
    hour12: false
});

Python

from datetime import datetime, timezone

# ISO 8601 格式的当前时间
now = datetime.now(timezone.utc).isoformat()
print(now)  # "2024-04-15T14:30:00.123456+00:00"

# 解析 ISO 8601 字符串
dt = datetime.fromisoformat("2024-04-15T14:30:00+00:00")

# 格式化为 ISO 8601
formatted = dt.strftime("%Y-%m-%dT%H:%M:%S%z")

Java

import java.time.Instant;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;

// ISO 8601 格式的当前时间
String now = Instant.now().toString();
System.out.println(now);  // "2024-04-15T14:30:00.123Z"

// 解析 ISO 8601 字符串
ZonedDateTime dt = ZonedDateTime.parse("2024-04-15T14:30:00Z");

// 格式化为 ISO 8601
String formatted = dt.format(DateTimeFormatter.ISO_INSTANT);

使用 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


相关资源


总结

ISO 8601 是软件系统中表示日期和时间的黄金标准。通过遵循 ISO 8601 格式,你可以确保你的时间戳明确无歧义、可排序且与全球系统兼容。

关键要点:

  • 对 UTC 时间使用 YYYY-MM-DDTHH:MM:SSZ
  • 包含时区信息(Z±HH:MM
  • 以 UTC 存储时间戳,以本地时间显示
  • 在解析之前验证 ISO 8601 字符串
  • 为了可读性使用扩展格式(带分隔符)

掌握 ISO 8601 格式对于任何处理日期和时间的开发人员来说都是必不可少的。无论你是构建 API、存储数据还是解析日志文件,ISO 8601 都提供了一种可靠、标准化的时间表示方法。

今天就开始在你的项目中使用 ISO 8601,永远消除日期/时间的歧义!🚀