datetime.now() 默认返回无时区信息的“天真时间”,不自动适配系统本地时区;需显式传入 tz=zoneinfo.zoneinfo("asia/shanghai") 获取本地感知时间,naive datetime 调用 astimezone() 会报错。

datetime.now() 为什么总拿不到本地时区?
因为 datetime.now() 默认返回“天真时间”(naive datetime),不带时区信息,哪怕你系统设了上海时区,它也只按 UTC+0 算——不是它错了,是它根本没看你的系统时区。
真正要本地时间,得显式传入 tz 参数:
from datetime import datetime
import zoneinfo # Python 3.9+
dt = datetime.now(tz=zoneinfo.ZoneInfo("Asia/Shanghai"))常见错误现象:datetime.now().astimezone() 看似能转,但前提是原对象必须是“感知时间”(aware),否则直接报 ValueError: astimezone() cannot be applied to a naive datetime。
- Python pytz,但别用
pytz.timezone("Asia/Shanghai").localize(...)去包装now(),容易错位;推荐用pytz.timezone("Asia/Shanghai").now() -
time.time()和datetime.fromtimestamp(time.time())会读系统时区,但结果仍是 naive 对象,别误以为它“自动带时区” - Django 或 Flask 项目里,如果设置了
TIME_ZONE = "Asia/Shanghai",不代表datetime.now()就自动生效——框架只管自己的 ORM 字段和模板渲染逻辑
strptime 解析字符串失败的三个高频原因
不是格式写错了才报 ValueError: time data ... does not match format,更多时候是隐藏细节没对上。
立即学习“Python免费学习笔记(深入)”;
典型场景:从日志、API 返回或 CSV 里读到类似 "2024-03-15 14:22:08.123" 的字符串,用 %Y-%m-%d %H:%M:%S 死活解析不了。
- 微秒部分要显式写
%f,且它匹配的是 6 位数字;"123"是毫秒,得先补零成"000123"或改用正则截断 - 中文星期/月份名(如“三月”“星期五”)无法被默认 locale 解析,必须提前调
locale.setlocale(locale.LC_TIME, "zh_CN.UTF-8"),且该设置进程级生效,多线程下不安全 - 年份用
%y(两位)时,"01会被解释为 1901 而非 2001;datetime.strptime("01", "%y")永远不会是你以为的“今年或明年”
timedelta 相减结果负数却看不出?
timedelta 对象本身支持负值,但打印出来像 -1 day, 23:59:59.999999,这不是 bug,是它的标准表示法:内部只存 days、seconds、microseconds 三个字段,且 seconds 永远在 [0, 86399] 区间内,负数全折进 days。
所以 (d1 - d2).total_seconds() 才是唯一靠谱的数值化方式;直接看 td.days 或 td.seconds 容易误判。
- 比如两个时间差 -1 秒,
td显示为-1 day, 23:59:59,但td.total_seconds() == -1.0 - 做时间窗口判断时,别写
if td.days ,而应统一用 <code>if td.total_seconds() -
timedelta不支持乘除标量以外的运算,td * 1.5会报错,得先转成秒再算:timedelta(seconds=td.total_seconds() * 1.5)
time.sleep() 在循环里越睡越不准?
不是 sleep() 本身不准,而是每次循环体执行有耗时,sleep(1) 只保证“至少停 1 秒”,实际间隔 = 执行耗时 + 1 秒。跑久了就明显漂移。
需要严格等间隔(比如每秒查一次 API),就得用“锚点时间”校准:
import time
anchor = time.time()
for i in range(10):
# do work
now = time.time()
sleep_time = max(0, anchor + (i+1)*1 - now)
time.sleep(sleep_time)更稳妥的做法是用 asyncio.sleep() 配合事件循环,或者引入 schedule / APScheduler 这类带补偿机制的调度库。
- Windows 下
time.sleep(0.001)实际最小粒度约 15ms,Linux 一般 1–10ms,别指望毫秒级精度 - 信号中断(如 Ctrl+C)会让
sleep()提前退出并抛InterruptedError,生产环境必须捕获 - 在 Jupyter 或某些 IDE 的调试器里,
sleep()可能被暂停或跳过,测定时别依赖 notebook 单元格运行时间
事情说清了就结束。时区、解析、差值、休眠——这四块最常被当成“基础操作”跳过深究,结果卡住时反而最难定位。










