Python 的 datetime:别再用字符串算时间
算时间这件事,最容易顺手写成字符串操作:把 "2026-11-09 09:44" 切开取小时,或者拿两个时间字符串直接比大小。本地跑起来好像没问题,可一旦涉及时区、夏令时或者跨天计算,字符串就原形毕露了:"09:44" 比 "10:05" 小没错,但 "9:44" 和 "10:05" 按字符串比就反了;更不用说把北京时间和 UTC 混在一起比较,差出来的 8 小时能让定时任务整整错开一天。时间值得交给一个专门的类型来管,那就是 datetime。
from datetime import datetime, timezone, timedelta
now = datetime.now(timezone.utc) # 带时区的现在
local = now.astimezone(timezone(timedelta(hours=8))) # 转成北京时间
第一个要分清的概念是 naive 和 aware。没有时区信息的 datetime 叫 naive,它不知道自己代表哪个时区的时间;带了 tzinfo 的叫 aware。两者不能直接相减或比较,混用会直接抛 TypeError,这其实是好事——比起静悄悄算出一个错 8 小时的结果,报错至少不会让你带着错误结果继续跑。规则很简单:要比较、要相减,先统一成 aware,datetime.now(timezone.utc) 就是最稳的起点。
第二个要点是加减时间用 timedelta,而不是自己算天数再拼字符串:
deadline = now + timedelta(days=7) # 一周后
yesterday = now - timedelta(hours=24) # 24 小时前
print((deadline - now).days) # 7
两个 aware 时间相减直接得到 timedelta,.days、.seconds、.total_seconds() 各取所需;想判断“是否过期”,直接比两个 datetime,不用再把时间转成字符串比字典序,也不用担心 "9:44" 这种位数不一致的坑。
第三个容易踩的坑是解析和格式化。strptime 把字符串解析成时间,strftime 把时间格式化成字符串,进出各走各的路:
text = "2026-11-09 09:44"
dt = datetime.strptime(text, "%Y-%m-%d %H:%M")
print(dt.strftime("%Y年%m月%d日 %H:%M")) # 2026年11月09日 09:44
解析时格式串和输入必须对得上,%m 是补零的月份,%H 是 24 小时制,写错一个字母就会解析失败;Python 3.11 起 datetime.fromisoformat 还能直接解析 ISO 格式,少写一层格式串。存时间优先存 ISO 字符串或时间戳,展示时再按需格式化,存和用的职责分开,就不会出现“存的时候是字符串、算的时候又得现解析”的尴尬。
最后记住一条底线:涉及时区的计算,永远先统一时区再运算。拿 UTC 存、拿本地时区展示,是最不容易出错的分工;astimezone 只做转换不改变那一刻本身,同一个瞬间在哪个时区看都一样。字符串只能描述时间,datetime 才能计算时间。
- 点赞
- 收藏
- 关注作者
评论(0)