
本文详解如何在 Pandas 中安全、准确地计算两个日期列之间的月数差,避开 Timedelta('1 month') 引发的 ValueError,并提供基于 to_period("M") 的可靠方案及注意事项。
本文详解如何在 pandas 中安全、准确地计算两个日期列之间的月数差,避开 `timedelta('1 month')` 引发的 valueerror,并提供基于 `to_period("m")` 的可靠方案及注意事项。
在 Pandas 中直接对 datetime64 类型列做“除以 1 个月”(如 // pd.Timedelta('1 month'))会报错 ValueError: invalid unit abbreviation: month,这是因为 pd.Timedelta 不支持 'month' 这类非固定长度的时间单位(月份天数不恒定,无法映射为精确纳秒数)。
✅ 推荐解决方案:使用 .dt.to_period("M")
to_period("M") 将时间戳转换为以“日历月”为单位的周期(如 2022-01、2023-06),其底层是自 Unix 纪元(1970-01)起的整数月序号。相减后即得自然月数差(四舍五入到整月,忽略日/时分秒):
import pandas as pd
data = {
'id_number': ['000001000', '000009795', '000011722'],
'first_date': ['2022-01-08 13:41:00', '2022-11-07 09:16:00', '2022-02-15 12:46:00'],
'last_date': ['2023-06-13 16:33:00', '2022-11-30 12:59:00', '2022-06-21 11:42:00']
}
df_test = pd.DataFrame(data)
# 转换为 datetime
df_test['first_date'] = pd.to_datetime(df_test['first_date'])
df_test['last_date'] = pd.to_datetime(df_test['last_date'])
# ✅ 正确计算月数差(按日历月)
df_test['months_difference'] = (
df_test['last_date'].dt.to_period("M").astype(int)
- df_test['first_date'].dt.to_period("M").astype(int)
)
print(df_test[['id_number', 'first_date', 'last_date', 'months_difference']])输出:
id_number first_date last_date months_difference 0 000001000 2022-01-08 13:41:00 2023-06-13 16:33:00 17 1 000009795 2022-11-07 09:16:00 2022-11-30 12:59:00 0 2 000011722 2022-02-15 12:46:00 2022-06-21 11:42:00 4
? 补充说明与注意事项:
- ✅ 语义清晰:to_period("M") 按年月对齐(如 2022-01-31 和 2022-02-28 均属 2022-01 和 2022-02),结果为严格日历月差;
- ⚠️ 不考虑天数比例:该方法返回整月数,不反映“30天≈1月”的近似值,也不支持小数月(如 1.5 个月需用其他方式);
- ? 避免 relativedelta 在向量化场景:dateutil.relativedelta 虽可精确计算年/月/日,但不支持 Pandas Series 向量化运算,需 apply() 循环,性能差且易出错;
- ? 若需带小数的“平均月”(如按 30.44 天/月折算):可用 (last_date - first_date) / np.timedelta64(1, 'D') / 30.44,但请明确业务是否接受此近似。
总结:对于绝大多数需要“X 年 Y 月”式统计分析的场景,dt.to_period("M").astype(int) 是最简洁、高效、语义正确的月数差计算方式。


















