relativedelta 是一个非常强大且灵活的日期和时间计算工具,它存在于 dateutil 库中,而不是 Python 标准库,相比于标准库中的 datetime.timedelta,relativedelta 的功能要强大得多,尤其是在处理月份、年份等不固定时间长度的单位时。

relativedelta 是什么?
relativedelta 是一个用于表示日期和时间之间差异的类,它可以被加到或从一个 datetime 或 date 对象中减去,以生成一个新的日期。
核心优势:
- 处理月份和年份:
timedelta无法直接处理“增加一个月”或“增加一年”,因为它不知道每个月有多少天。relativedelta可以完美解决这个问题,1月31日加一个月是2月28日(或29日),而1月31日加31天是3月3日,两者结果完全不同。 - 处理相对日期: 可以轻松计算“下个星期三”、“上个月的最后一个工作日”等。
- 处理时区: 可以处理时区相关的操作。
安装
relativedelta 不是 Python 标准库的一部分,所以你需要先安装 python-dateutil 库。
pip install python-dateutil
基本用法
导入必要的模块。

from datetime import datetime from dateutil.relativedelta import relativedelta
1 创建 relativedelta 对象
你可以通过多种方式创建一个 relativedelta 对象:
# 1. 创建一个空的 relativedelta (表示0时间差)
delta_empty = relativedelta()
print(f"空的 delta: {delta_empty}") # 输出: relativedelta()
# 2. 创建一个包含天、秒、微秒的 delta (类似 timedelta)
delta_simple = relativedelta(days=10, seconds=30)
print(f"简单的 delta: {delta_simple}") # 输出: relativedelta(days=+10, seconds=+30)
# 3. 创建一个包含年份、月份的 delta (这是 relativedelta 的核心优势)
delta_year_month = relativedelta(years=2, months=3)
print(f"年月 delta: {delta_year_month}") # 输出: relativedelta(years=+2, months=+3)
# 4. 创建一个包含星期几的 delta
# weekday 参数: MO(周一), TU(周二), ..., SU(周日)
# 1 * MO 表示下下个周一 (1 * 下一个周一)
# -1 * MO 表示上个周一
delta_weekday = relativedelta(weekday=1 * datetime.MONDAY) # 下下个周一
print(f"工作日 delta: {delta_weekday}") # 输出: relativedelta(weekday=MO(+1))
# 5. 创建一个相对日期的 delta (相对于某个基准日)
# 相对于 2025-10-31,"下个月的最后一个星期日"
# 这里的 day=31 是基准日,weekday=SU(-1) 表示基准日所在月份的最后一个星期日
delta_relative = relativedelta(day=31, weekday=1 * datetime.SU) # 注意:这里的 weekday=1*SU 表示下个周日,需要特殊处理
# 更好的方式是使用 SU(-1) 表示上个月最后一个周日
delta_relative_correct = relativedelta(day=31, weekday=datetime.SU(-1))
print(f"相对日期 delta (基准31日,上月最后一个周日): {delta_relative_correct}") # 输出: relativedelta(day=31, weekday=SU(-1))
2 在 datetime 对象上使用 relativedelta
这是最常见的用法,将 relativedelta 加到 datetime 对象上或从中减去。
# 定义一个基准日期
d = datetime(2025, 1, 31, 10, 30, 0)
# --- 加法 ---
# 加上 2 年 3 个月
d_plus = d + relativedelta(years=2, months=3)
print(f"原日期: {d}")
print(f"加 2 年 3 个月后: {d_plus}") # 输出: 2025-04-30 10:30:00
# 加上 10 天
d_plus_days = d + relativedelta(days=10)
print(f"加 10 天后: {d_plus_days}") # 输出: 2025-02-10 10:30:00
# 加上 1 个月
# 1月有31天,加1个月会自动调整到2月的最后一天
d_plus_month = d + relativedelta(months=1)
print(f"加 1 个月后: {d_plus_month}") # 输出: 2025-02-28 10:30:00
# --- 减法 ---
# 减去 1 年 5 天
d_minus = d - relativedelta(years=1, days=5)
print(f"减 1 年 5 天后: {d_minus}") # 输出: 2025-01-26 10:30:00
# 减去 1 个月
# 1月31日减1个月是12月31日
d_minus_month = d - relativedelta(months=1)
print(f"减 1 个月后: {d_minus_month}") # 输出: 2025-12-31 10:30:00
relativedelta vs. timedelta 的核心区别
这是理解 relativedelta 价值的关键。
| 特性 | relativedelta |
timedelta |
|---|---|---|
| 主要用途 | 处理日历相关的日期偏移 | 处理固定的时间间隔 |
| 支持单位 | 年、月、日、周、小时、分钟、秒、微秒 | 天、秒、微秒 |
| 月份/年份 | 智能处理,知道2月有28/29天,能正确计算月末。 | 不支持,只能通过天数来模拟,结果不准确。 |
| 示例 | datetime(2025, 1, 31) + relativedelta(months=1) -> 2025-02-28 |
datetime(2025, 1, 31) + timedelta(days=31) -> 2025-03-03 |
| 相对日期 | 支持,可以计算“下个周一”、“上个月的最后一天”等。 | 不支持。 |
代码对比:

from datetime import datetime, timedelta
from dateutil.relativedelta import relativedelta
d = datetime(2025, 1, 31)
# 使用 relativedelta 加一个月 (日历逻辑)
# 结果是 2 月的最后一日
result_rd = d + relativedelta(months=1)
print(f"relativedelta 加一个月: {result_rd}") # 输出: 2025-02-28 00:00:00
# 使用 timedelta 加一个月 (通过天数模拟)
# 假设一个月是31天,结果就是 3 月 3 日
# 这是错误的日历计算
result_td = d + timedelta(days=31)
print(f"timedelta 加31天: {result_td}") # 输出: 2025-03-03 00:00:00
高级用法:处理相对日期
relativedelta 的一个强大功能是它可以基于一个基准日期来定义偏移量。
from dateutil.relativedelta import relativedelta
from datetime import datetime
# 定义基准日
base_date = datetime(2025, 10, 15)
# --- 获取特定日期 ---
# 获取下个月的同一天 (2025-11-15)
next_month_same_day = base_date + relativedelta(months=1)
print(f"下个月的同一天: {next_month_same_day}") # 2025-11-15 00:00:00
# 获取上个月的同一天 (2025-09-15)
last_month_same_day = base_date + relativedelta(months=-1)
print(f"上个月的同一天: {last_month_same_day}") # 2025-09-15 00:00:00
# 获取去年的今天 (2025-10-15)
last_year_today = base_date + relativedelta(years=-1)
print(f"去年的今天: {last_year_today}") # 2025-10-15 00:00:00
# --- 获取相对工作日 ---
# 获取基准日所在月份的最后一个星期日
# weekday=SU(-1) 表示“-1个星期日”,即上一个星期日,相对于月末就是最后一个
last_sunday_of_month = base_date + relativedelta(day=31, weekday=datetime.SU(- 