
Python 的 strptime 在未指定年份时默认使用 1900 年,而 1900 年不是闰年,导致 “02-29” 被判定为非法日期;显式传入闰年(如 2024)并匹配 %Y 格式符即可解决。
python 的 `strptime` 在未指定年份时默认使用 1900 年,而 1900 年不是闰年,导致 “02-29” 被判定为非法日期;显式传入闰年(如 2024)并匹配 `%y` 格式符即可解决。
在使用 datetime.datetime.strptime() 解析形如 "02-29 13:34:57.041" 的日期时间字符串时,看似合法(例如在 2024 年 2 月 29 日运行),却抛出 ValueError: day is out of range for month 异常,其根本原因在于:strptime 在格式字符串中未包含年份(即缺少 %Y、%y 等年份占位符)时,会将缺失的年份默认设为 1900。
而 1900 年虽能被 4 整除,但根据格里高利历规则——“能被 100 整除但不能被 400 整除的年份不是闰年”——1900 ÷ 400 = 4.75(余数 ≠ 0),因此 1900 年不是闰年,2 月仅有 28 天。此时解析 "02-29" 就必然失败。
✅ 正确做法是:显式提供闰年年份,并在格式字符串中加入对应的年份解析指令。推荐使用 4 位年份 %Y,确保语义明确、无歧义:
import datetime tstr = "02-29-2024 13:34:57.041" # 显式包含年份 dt = datetime.datetime.strptime(tstr, '%m-%d-%Y %H:%M:%S.%f') print(dt) # 输出:2024-02-29 13:34:57.041000
⚠️ 注意事项:
- 若原始字符串不包含年份(如仅 "02-29 13:34:57.041"),不可强行解析;应先补全年份(例如根据业务上下文拼接当前年 f"{datetime.date.today().year}-02-29"),再解析;
- 避免使用 %y(2 位年份),因其会将 "24" 解释为 1924 年(而非 2024),而 1924 年虽是闰年,但易引发跨世纪逻辑错误;
- 对于需支持任意闰年场景的通用代码,建议始终要求输入含完整年份,或封装校验逻辑(如 try/except 捕获 ValueError 后回退到默认闰年处理)。
总结:日期解析的合法性不仅取决于字符串内容,更依赖于隐式补全规则。牢记 strptime 的年份默认值是 1900,并在设计格式模板时主动控制年份维度,是避免“2月29日陷阱”的关键实践。










