前言

很多 Python 新手(甚至老手)都踩过这几个坑:

  • 模块太多:你需要同时和 datetimetimecalendar 三个模块打交道。想获取时间戳?去 time。想做日期加减?回 datetime
  • Naive vs Aware(时区陷阱): 这是最坑的地方。Python 默认生成的 datetime 对象是不带时区信息的(Naive)。如果把一个带时区的对象和一个不带时区的对象进行比较或相加,程序会直接抛出 TypeError 崩溃。
  • API 的破碎感: 为了做一个“减去 3 天”的操作,需要导入 timedelta,写 datetime.now() - timedelta(days=3);为了解析ISO字符串,得写很长的 strptime 格式化字符串。
  • 不支持“人类语言”:没法直接处理“昨天”、“两周后”这种逻辑,必须手动计算 timedelta

相比之下,Go 语言虽然要背 2006-01-02 15:04:05 这个神奇的时间点,但至少逻辑是自洽的。而 Python 的原生体验更像是不断缝补丁。

新工具推荐

时间来到 2026 年,社区生态和 python 标准库都在进化,来看看这些现代化的时间处理方式。

库名 角色 推荐理由
ZoneInfo 标准库 Python 3.9+ 内置,彻底取代 pytz,处理 IANA 时区。
Pendulum 核心逻辑 Datetime 的子类,语法极其优雅,处理“几天后”、“下周一”信手拈来。
Arrow 采集器 爬虫必备。它对凌乱字符串的兼容性极强,.get() 一下就搞定。

在 Python 3.9 之前,pytz 是时区处理的唯一选择,但它的 API 设计极其反人类(比如著名的 localize 陷阱)。

2026 年的今天,ZoneInfo 配合 IANA 时区数据库已经非常成熟。如果你在 Windows 上运行,记得装一下 tzdata 这个包;在 Linux 上,它直接读取系统数据库。这才是真正的 Pythonic

如何选择?

  • 追求“零依赖”且只需要处理时区转换:ZoneInfo (标准库)。
  • 需要处理复杂的日期加减(比如“下个月的第三个周五”):Pendulum
  • 正在写爬虫,面对的是各种奇怪的字符串时间:Arrow
  • 在用 Django: 坚持用 Django 内置的 timezone 工具类(它底层已经全面拥抱 ZoneInfo 了)。

代码例子

处理复杂的时区转换与加减(使用 Pendulum)

import pendulum

# 1. 语义化创建
now = pendulum.now('Asia/Shanghai')
future = now.add(months=2).end_of('week')

# 2. 极简的“人类化”显示
print(future.diff_for_humans()) # "2 months from now"

# 3. 彻底解决时区比对崩溃
dt_utc = pendulum.now('UTC')
if now > dt_utc: # Pendulum 会自动处理比对逻辑
    print("安全比对,不再报错")

从 API 或爬虫中解析凌乱时间(使用 Arrow)

import arrow

# 不管是时间戳、ISO 8601 还是特定格式,统统 get
raw_date = "2026-03-24T10:13:35+08:00"
t = arrow.get(raw_date)

# 转换成北京时间并格式化
print(t.to('Asia/Shanghai').format('YYYY-MM-DD HH:mm:60'))

标准库提供的时区转换(ZoneInfo)

如果在写一个轻量级脚本,不想添加额外依赖,可以直接用标准库的 ZoneInfo

from datetime import datetime
from zoneinfo import ZoneInfo

# 1. 创建一个带时区的 UTC 时间(2026 年的标配起点)
utc_now = datetime.now(ZoneInfo("UTC"))
print(f"UTC 时间: {utc_now}")

# 2. 一行代码转成本地时间(比如北京时间)
# 再也不需要 pytz.timezone('...').localize(...) 这种阴间操作了
beijing_time = utc_now.astimezone(ZoneInfo("Asia/Shanghai"))
print(f"北京时间: {beijing_time}")

# 3. 甚至可以处理极其冷门的时区,比如你想看看纽约的开发者在干嘛
ny_time = beijing_time.astimezone(ZoneInfo("America/New_York"))
print(f"纽约时间: {ny_time}")

# 4. 获取简写的时区名称(如 CST, EST)
print(f"当前时区缩写: {ny_time.tzname()}")

小结

永远不要使用 datetime.now() 养成使用 datetime.now(ZoneInfo("UTC"))pendulum.now() 的习惯。

数据库存储统一 UTC: 无论用户在哪里,数据库里存的一定要是 UTC。

前端交付 ISO 8601: 别传时间戳,传 2026-03-25T11:30:00Z 这种标准字符串,前端解析起来最省心。