pd.to_datetime()报错或返回nat主因是默认格式识别能力弱且不启用模糊匹配;应优先用format参数精准解析,混合格式时结合dateutil.parser兜底,并务必验证清洗结果。

为什么 pd.to_datetime() 直接报错或返回 NaT
多数人一上来就用 pd.to_datetime(df['date_col']),结果大量日期变成 NaT,或者抛出 ParserError。根本原因是:Pandas 默认只尝试少数几种常见格式(如 '2023-01-01'、'01/01/2023'),遇到像 '2023年01月01日'、'23/01/01'、'Jan 1st, 2023' 这类混合格式,直接放弃解析。
- 默认不启用模糊匹配,
infer_datetime_format=False时性能差且容错低 - 中文、缩写、序数词(如 “1st”)、空格不一致等,都会导致失败
-
errors='coerce'虽能避免报错,但把错误全转成NaT,你根本不知道哪条坏了
用 format 参数精准控制解析规则
当你清楚原始数据的规律(比如全是 'YYYY年MM月DD日' 或全是 'YY/MM/DD'),硬编码 format 是最快最稳的方式,比让 Pandas 猜快 5–10 倍,且零误判。
- 中文日期:用
pd.to_datetime(df['date_col'], format='%Y年%m月%d日') - 两位年份:用
format='%y/%m/%d'(注意是小写y),而非%Y - 带英文月份缩写:
format='%b %d, %Y'可解析'Jan 01, 2023';%B对应完整月份名 - 含毫秒但没冒号:
format='%Y-%m-%d %H:%M:%S.%f'—— 注意.%f必须紧挨着秒,不能有空格
混合格式太多?用 dateutil.parser + 自定义函数兜底
当一列里混着 '2023-01-01'、'01/01/2023'、'20230101'、'23.01.01' 几种格式,pd.to_datetime(..., infer_datetime_format=True) 往往失效。这时要自己写解析逻辑,靠 dateutil.parser.parse 更鲁棒。
- 先试
pd.to_datetime主流格式,失败再交给dateutil -
dateutil.parser.parse(x, default=datetime(1900, 1, 1))可设默认值补缺失年份 - 加
dayfirst=True处理欧洲习惯(如'01/02/03'当 2003-02-01) - 务必用
try/except包裹,否则单个坏字符串会让整列失败
def safe_parse_date(x):
if pd.isna(x):
return pd.NaT
try:
return pd.to_datetime(x, format='%Y-%m-%d')
except (ValueError, TypeError):
try:
return dateutil.parser.parse(x)
except (ValueError, TypeError):
return pd.NaT
转换后验证和清洗不能跳过
哪怕解析成功,也常藏坑:时区未统一、未来日期异常、2月30日这种非法日期被强行转成下月(如 '2023-02-30' → 2023-03-02),而 pd.to_datetime 默认 errors='raise' 才会暴露问题。
- 检查是否真转成功:
df['date_col'].dt.year.count()比df['date_col'].count()少?说明有NaT - 查非法日期:
df[df['date_col'].dt.day > 31]或用.is_valid(需pd.api.types.is_datetime64_any_dtype配合手动校验) - 统一时区:
df['date_col'] = df['date_col'].dt.tz_localize('Asia/Shanghai'),避免后续计算跨时区出错 - 别忘了
.dt.date或.dt.normalize()—— 有时你只要日期,不要时间部分
真实场景里,日期脏、格式杂、业务含义模糊(比如“截止日期”字段里混着“待定”“无期限”字符串),光靠一个函数解决不了。得先看分布、再分组处理、最后人工抽检——自动化只是帮你筛出 95%,剩下的 5% 得靠人盯。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











