You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何编写Python函数实现datetime对象的指定月份偏移?

问题

如何编写一个Python函数,接收datetime对象和整数作为输入,返回偏移指定月份后的新datetime对象?

我此前尝试了如下代码:

from datetime import datetime, timedelta

def get_offset_datetime(source_date_time, month_offset):
    year, month, day = (source_date_time.year + month_offset // 12,
                       source_date_time.month + month_offset % 12,
                       source_date_time.day)
    if month>12:
        year+=1
        month-=12
    elif month<1:
        year-=1
        month+=12
    offset_datetime = datetime(year, month, day, source_date_time.hour, source_date_time.minute, source_date_time.second)
    return offset_datetime

但部分日期会报错,例如执行以下测试代码:

source_date_time = datetime(2022,1,31)
month_offset = 1
offset_datetime = get_offset_datetime(source_date_time, month_offset)
print(source_date_time)
print(offset_datetime)

期望输出为:

2022-02-28 00:00:00

但实际出现如下错误:

Traceback (most recent call last):
  File "/home/user/Desktop/exam/main.py", line 42, in <module>
    offset_datetime = get_offset_datetime2(source_date_time, month_offset)
  File "/home/user/Desktop/exam/main.py", line 27, in get_offset_datetime2
    offset_datetime = datetime(year, month, day, source_date_time.hour, source_date_time.minute, source_date_time.second)
ValueError: day is out of range for month
解决方案

方法一:使用第三方库 python-dateutil

python-dateutil 的 relativedelta 专门处理这类日期偏移问题,能自动识别月末日期的边界情况,无需手动处理:

先安装依赖库:

pip install python-dateutil

编写函数:

from datetime import datetime
from dateutil.relativedelta import relativedelta

def get_offset_datetime(source_date_time, month_offset):
    return source_date_time + relativedelta(months=month_offset)

测试示例:

source_date_time = datetime(2022,1,31)
month_offset = 1
offset_datetime = get_offset_datetime(source_date_time, month_offset)
print(offset_datetime)  # 输出 2022-02-28 00:00:00

方法二:纯标准库实现

如果不想依赖第三方库,可以通过计算目标月份的最后一天来规避日期越界问题:

from datetime import datetime, timedelta

def get_offset_datetime(source_date_time, month_offset):
    # 计算目标年份和月份
    target_year = source_date_time.year + month_offset // 12
    target_month = source_date_time.month + month_offset % 12
    
    # 调整跨年度的月份
    if target_month > 12:
        target_year += 1
        target_month -= 12
    elif target_month < 1:
        target_year -= 1
        target_month += 12
    
    # 获取目标月份的最后一天:取下个月第一天再减1天
    try:
        next_month_first = datetime(target_year, target_month + 1, 1)
    except ValueError:
        # 处理12月的情况,下个月是次年1月
        next_month_first = datetime(target_year + 1, 1, 1)
    target_last_day = next_month_first - timedelta(days=1)
    
    # 取原日期日数和目标月最后一天的较小值,避免越界
    target_day = min(source_date_time.day, target_last_day.day)
    
    # 返回新的datetime对象
    return datetime(
        target_year, target_month, target_day,
        source_date_time.hour, source_date_time.minute, source_date_time.second
    )

测试多场景:

# 原测试用例
source_date_time = datetime(2022,1,31)
month_offset = 1
print(get_offset_datetime(source_date_time, month_offset))  # 2022-02-28 00:00:00

# 闰年2月29日偏移
source_date_time = datetime(2020,2,29)
month_offset = 1
print(get_offset_datetime(source_date_time, month_offset))  # 2020-03-29 00:00:00

# 反向偏移月份
source_date_time = datetime(2022,3,31)
month_offset = -1
print(get_offset_datetime(source_date_time, month_offset))  # 2022-02-28 00:00:00

内容的提问来源于stack exchange,提问作者Hossein Vejdani

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 15:25:33