Python3 日期和时间
Aware vs naive datetimes, parsing, formatting, and timestamp conversion.
Key PointsStore UTC, convert at the edges; a naive datetime is a bug waiting to happen.
Now and Construct
Python
from datetime import datetime, date, timedelta, timezone
now = datetime.now() # naive,本机时区,不推荐入库
utc = datetime.now(timezone.utc) # aware,推荐
today = date.today()
dt = datetime(2026, 10, 31, 9, 30, 0)Aware vs Naive
An aware datetime carries a tzinfo, so arithmetic across DST and conversions are correct. A naive datetime has no idea where it is — comparing the two raises TypeError.
Python
from datetime import datetime, timezone, timedelta
cst = timezone(timedelta(hours=8))
local = datetime.now(cst)
print(local.utcoffset()) # 8:00:00
print(local.astimezone(timezone.utc)) # 转到 UTC
# 从数据库取出的 naive 时间,补上时区
stored = datetime(2026, 10, 31, 1, 30)
aware = stored.replace(tzinfo=timezone.utc)Format and Parse
| Code | Meaning | Example |
|---|---|---|
| %Y | 4-digit year | 2026 |
| %m | Month 01-12 | 10 |
| %d | Day 01-31 | 31 |
| %H:%M:%S | 24h time | 09:30:00 |
| %f | Microseconds | 000000 |
| %z / %Z | UTC offset / zone name | +0800 / CST |
Python
dt = datetime(2026, 10, 31, 9, 30)
print(dt.strftime("%Y-%m-%d %H:%M")) # 2026-10-31 09:30
print(dt.isoformat()) # 2026-10-31T09:30:00
parsed = datetime.strptime("2026-10-31 09:30", "%Y-%m-%d %H:%M")
print(parsed.year) # 2026Arithmetic and Timestamps
Python
from datetime import datetime, timedelta, timezone
start = datetime(2026, 10, 1, tzinfo=timezone.utc)
end = start + timedelta(days=30, hours=2)
print(end - start) # 30 days, 2:00:00
print((end - start).total_seconds() / 86400) # 30.083...
ts = end.timestamp() # 秒(float)
print(datetime.fromtimestamp(ts, timezone.utc))Never do date math by adding 86400 seconds — DST days are 23 or 25 hours. Use
timedelta(days=1) on aware datetimes.当前时间与构造
Python
from datetime import datetime, date, timedelta, timezone
now = datetime.now() # naive,本机时区,不推荐入库
utc = datetime.now(timezone.utc) # aware,推荐
today = date.today()
dt = datetime(2026, 10, 31, 9, 30, 0)带时区与不带时区
aware datetime 带 tzinfo,跨夏令时的运算与转换才正确;naive 完全不知道自己在哪个时区,两者直接比较会抛 TypeError。
Python
from datetime import datetime, timezone, timedelta
cst = timezone(timedelta(hours=8))
local = datetime.now(cst)
print(local.utcoffset()) # 8:00:00
print(local.astimezone(timezone.utc)) # 转到 UTC
# 从数据库取出的 naive 时间,补上时区
stored = datetime(2026, 10, 31, 1, 30)
aware = stored.replace(tzinfo=timezone.utc)格式化与解析
| 占位符 | 含义 | 示例 |
|---|---|---|
| %Y | 四位年 | 2026 |
| %m | 月 01-12 | 10 |
| %d | 日 01-31 | 31 |
| %H:%M:%S | 24 小时制时间 | 09:30:00 |
| %f | 微秒 | 000000 |
| %z / %Z | 时区偏移 / 名称 | +0800 / CST |
Python
dt = datetime(2026, 10, 31, 9, 30)
print(dt.strftime("%Y-%m-%d %H:%M")) # 2026-10-31 09:30
print(dt.isoformat()) # 2026-10-31T09:30:00
parsed = datetime.strptime("2026-10-31 09:30", "%Y-%m-%d %H:%M")
print(parsed.year) # 2026运算与时间戳
Python
from datetime import datetime, timedelta, timezone
start = datetime(2026, 10, 1, tzinfo=timezone.utc)
end = start + timedelta(days=30, hours=2)
print(end - start) # 30 days, 2:00:00
print((end - start).total_seconds() / 86400) # 30.083...
ts = end.timestamp() # 秒(float)
print(datetime.fromtimestamp(ts, timezone.utc))不要用「加 86400 秒」做日期运算 —— 夏令时那天是 23 或 25 小时。对 aware datetime 用
timedelta(days=1)。