All Tools / Blog / 如何在时区之间转换时间

如何在时区之间转换时间

2 min read

时区转换以两种方式出错:偏移量算错,或者忽略夏令时(DST)。纽约冬季是 UTC−5,夏季是 UTC−4。2 月的"下午 5 点 EST"和 7 月的"下午 5 点 EDT"用的是不同的 UTC 偏移量。硬编码偏移量的工具和代码都会出错。

在浏览器中

在时区转换器中输入时间,选择两个时区,即可看到对应时间。转换器使用 IANA 时区数据,夏令时切换自动处理——无需手动调整偏移量。

常见时区的 UTC 偏移量

城市 IANA 时区 标准时间偏移 夏令时偏移
纽约 America/New_York UTC−5 UTC−4
伦敦 Europe/London UTC+0 UTC+1
巴黎 Europe/Paris UTC+1 UTC+2
迪拜 Asia/Dubai UTC+4 — (无夏令时)
孟买 Asia/Kolkata UTC+5:30 — (无夏令时)
新加坡 Asia/Singapore UTC+8 — (无夏令时)
东京 Asia/Tokyo UTC+9 — (无夏令时)
悉尼 Australia/Sydney UTC+10 UTC+11
北京/上海 Asia/Shanghai UTC+8 — (无夏令时)

使用 IANA 时区名称(America/New_York),而不是缩写(EST)。EST 有歧义——在北美和澳大利亚指不同的时区。

Python

Python 3.9+ 在标准库中内置了 zoneinfo,无需第三方包。

from datetime import datetime
from zoneinfo import ZoneInfo

# 创建带时区信息的 datetime
ny_time = datetime(2026, 3, 15, 14, 30, tzinfo=ZoneInfo('America/New_York'))

# 转换到其他时区
london = ny_time.astimezone(ZoneInfo('Europe/London'))
tokyo  = ny_time.astimezone(ZoneInfo('Asia/Tokyo'))

print(f'纽约:   {ny_time:%Y-%m-%d %H:%M %Z}')
print(f'伦敦:   {london:%Y-%m-%d %H:%M %Z}')
print(f'东京:   {tokyo:%Y-%m-%d %H:%M %Z}')
# 将当前 UTC 时间转换到多个时区
from datetime import datetime, timezone
from zoneinfo import ZoneInfo

now_utc = datetime.now(timezone.utc)
zones = ['America/New_York', 'Europe/London', 'Asia/Singapore', 'Asia/Shanghai']

for tz in zones:
    local = now_utc.astimezone(ZoneInfo(tz))
    print(f'{tz:<25} {local:%Y-%m-%d %H:%M %Z}')

JavaScript

// 将日期转换到指定时区
function convertToTimezone(date, timezone) {
    return new Intl.DateTimeFormat('zh-CN', {
        timeZone: timezone,
        year: 'numeric', month: '2-digit', day: '2-digit',
        hour: '2-digit', minute: '2-digit', second: '2-digit',
        hour12: false,
    }).format(date);
}

const now = new Date();
console.log(convertToTimezone(now, 'America/New_York'));
console.log(convertToTimezone(now, 'Asia/Shanghai'));
console.log(convertToTimezone(now, 'Asia/Tokyo'));
// 获取任意时区当前的 UTC 偏移量(分钟)
function getUtcOffsetMinutes(timezone, date = new Date()) {
    const utc = new Date(date.toLocaleString('en-US', { timeZone: 'UTC' }));
    const tz  = new Date(date.toLocaleString('en-US', { timeZone: timezone }));
    return (tz - utc) / 60000;
}

console.log(getUtcOffsetMinutes('America/New_York')); // -300 或 -240,取决于是否夏令时
console.log(getUtcOffsetMinutes('Asia/Shanghai'));     // 始终是 480

naive datetime 陷阱

没有时区信息的 Python datetimenaive 的——它不了解夏令时。在夏令时切换时对 naive datetime 做计算会得出错误结果。

from datetime import datetime, timedelta

# 错误——美国夏令时切换日的 naive datetime(凌晨 2 点时钟拨快 1 小时)
dt = datetime(2026, 3, 8, 1, 0)
print(dt + timedelta(hours=2))  # 显示 3:00 AM,但本地时间在 2:00 AM 就跳到了 3 AM

# 正确——带时区信息的 datetime
from zoneinfo import ZoneInfo
dt = datetime(2026, 3, 8, 1, 0, tzinfo=ZoneInfo('America/New_York'))
print(dt + timedelta(hours=2))  # 正确处理夏令时的空缺

创建需要做计算的 datetime 时,务必附加时区信息。

存储和传输时间

方式 问题
存储为 EST / PST 缩写有歧义,未编码夏令时
存储为 UTC 偏移(-05:00 无法表示未来的夏令时行为
存储为 UTC + IANA 时区名称 正确——无歧义,夏令时自动处理

数据库做法:存储 UTC 时间戳,如需展示本地时间则单独存储 IANA 时区名称,展示时再重建本地时间。

要点总结

  • 使用 IANA 时区名称(America/New_York)——EST 等缩写在不同大陆有歧义。
  • Python 3.9+ 的 zoneinfo 自动处理夏令时;现代项目无需 pytz
  • Naive datetime 在夏令时边界产生错误结果——务必附加时区信息。
  • 迪拜、孟买、新加坡和东京没有夏令时——偏移量全年不变。
  • 数据库存 UTC 时间戳;展示时用 IANA 时区名称重建本地时间。