Python datetime 模块
date, time, datetime, timedelta and timezone — the object model behind date handling.
Key PointsFour types, one rule: keep everything timezone-aware in UTC inside the system, convert only at the edges.
Four Core Types
| Type | Holds | Example |
|---|---|---|
| date | Year-month-day | date(2026, 10, 31) |
| time | Hour-minute-second | time(9, 30) |
| datetime | Both | datetime(2026, 10, 31, 9, 30) |
| timedelta | A duration | timedelta(days=7) |
Python
from datetime import date, datetime, time, timedelta
d = date(2026, 10, 31)
print(d.year, d.month, d.day, d.weekday()) # 2026 10 31 5(周六)
dt = datetime(2026, 10, 31, 9, 30, 15)
print(dt.isoformat())
print(dt.date(), dt.time())Output
2026 10 31 5
2026-10-31T09:30:15
2026-10-31 09:30:15Arithmetic
datetime - datetime gives a timedelta; adding one shifts the date. Month arithmetic needs dateutil.relativedelta.
Python
from datetime import datetime, timedelta
start = datetime(2026, 10, 1)
print(start + timedelta(days=30))
print((datetime(2026, 12, 31) - start).days)
from dateutil.relativedelta import relativedelta
print(start + relativedelta(months=1)) # 11-01Output
2026-10-31 00:00:00
91
2026-11-01 00:00:00Timezone
A datetime without tzinfo is naive — it does not know which zone it is in. In multi-zone systems that is the classic data incident.
Python
from datetime import datetime, timezone, timedelta
utc = datetime.now(timezone.utc)
cst = utc.astimezone(timezone(timedelta(hours=8)))
print(utc.strftime("%H:%M"), cst.strftime("%H:%M"))
naive = datetime(2026, 10, 31, 1, 30)
aware = naive.replace(tzinfo=timezone.utc)
print(aware.astimezone(timezone(timedelta(hours=8))).hour)Output
02:40 10:40
9Store aware UTC in the database; convert only for display. Comparing aware with naive raises TypeError.
四个核心类型
| 类型 | 表示 | 示例 |
|---|---|---|
| date | 年月日 | date(2026, 10, 31) |
| time | 时分秒 | time(9, 30) |
| datetime | 日期 + 时间 | datetime(2026, 10, 31, 9, 30) |
| timedelta | 时间间隔 | timedelta(days=7) |
Python
from datetime import date, datetime, time, timedelta
d = date(2026, 10, 31)
print(d.year, d.month, d.day, d.weekday()) # 2026 10 31 5(周六)
dt = datetime(2026, 10, 31, 9, 30, 15)
print(dt.isoformat())
print(dt.date(), dt.time())Output
2026 10 31 5
2026-10-31T09:30:15
2026-10-31 09:30:15日期运算
datetime - datetime 得到 timedelta,datetime + timedelta 得到新时间。月份加减没有内置支持,需要 dateutil.relativedelta。
Python
from datetime import datetime, timedelta
start = datetime(2026, 10, 1)
print(start + timedelta(days=30))
print((datetime(2026, 12, 31) - start).days)
from dateutil.relativedelta import relativedelta
print(start + relativedelta(months=1)) # 11-01Output
2026-10-31 00:00:00
91
2026-11-01 00:00:00时区
不带 tzinfo 的 datetime 叫 naive,它没有「这是哪个时区」的信息。跨时区系统里 naive 时间是最常见的数据事故来源。
Python
from datetime import datetime, timezone, timedelta
utc = datetime.now(timezone.utc)
cst = utc.astimezone(timezone(timedelta(hours=8)))
print(utc.strftime("%H:%M"), cst.strftime("%H:%M"))
naive = datetime(2026, 10, 31, 1, 30)
aware = naive.replace(tzinfo=timezone.utc)
print(aware.astimezone(timezone(timedelta(hours=8))).hour)Output
02:40 10:40
9入库统一存 UTC 的 aware datetime;只在展示层转本地时区。比较 aware 与 naive 会直接抛 TypeError。