必须先用pd.to_datetime()将两列转为datetime64[ns]类型,再相减得timedelta并用.dt.days提取整数天数;注意处理nat、非法日期、格式不统一及性能优化。

确保两列是 datetime 类型
直接对字符串或 object 类型的日期列做减法会报 TypeError: unsupported operand type(s) for -: 'str' and 'str',或者返回奇怪的 Timedelta 但数值为 NaT。必须先用 pd.to_datetime() 转换:
- 用
errors='coerce'把非法日期转成NaT(避免中断) - 检查转换结果:
df['date1'].dt.year不报错说明成功;若报AttributeError: Can only use .dt accessor with datetimelike values就还没转好 - 常见坑:含空格、中文“年/月/日”、时区符号(如 “2023-01-01 UTC”)会导致部分失败,建议加
format参数明确格式(如format='%Y-%m-%d')提升稳定性
用减法得到 Timedelta 并提取天数
两列都是 datetime64[ns] 后,相减得 Timedelta 类型,再用 .dt.days 提取整数天数(忽略小时/分钟):
df['days_diff'] = (df['end_date'] - df['start_date']).dt.days
注意点:
-
.dt.days返回的是int64,遇到NaT自动变成NaN(浮点型),不是报错 - 如果需要包含小数天(比如 1.5 天),改用
.dt.total_seconds() / 86400 - 顺序很重要:后减前才是“结束减开始”,反了会得负数 —— 这不是 bug,是预期行为
处理缺失值和边界情况
只要任意一列是 NaT,结果就是 NaT → .dt.days 后为 NaN。别指望它自动跳过或填充:
- 想填 0?用
.fillna(0).astype('int64'),但要确认业务上“缺日期=0天”是否合理 - 想只保留有效行:
df.dropna(subset=['start_date', 'end_date'])再计算 - 警惕
2023-02-30这类非法日期:to_datetime默认转成NaT,但不报错,容易被忽略 - 跨年、闰年、月末(如 2023-01-31 到 2023-02-28)都自动按真实日历算,Pandas 已处理好
性能提示:大表别反复调用 to_datetime
如果在循环里或多次重复对同一列调用 pd.to_datetime(),会严重拖慢速度。正确做法是:
- 一次性转换:
df[['start_date', 'end_date']] = df[['start_date', 'end_date']].apply(pd.to_datetime, errors='coerce') - 或分别赋值:
df['start_date'] = pd.to_datetime(df['start_date'], errors='coerce') - 用
infer_datetime_format=True可提速 2–5 倍(当格式高度统一时) - 超过百万行,考虑用
dtype={'start_date': 'datetime64[ns]'}在read_csv阶段就指定类型
日期差本身计算极快,瓶颈几乎总在类型转换这一步。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











