使用Python将一个月添加到给定日期(四舍五入后的第二天)

使用Python将一个月添加到给定日期(四舍五入后的第二天),python,pandas,calendar,timedelta,python-dateutil,Python,Pandas,Calendar,Timedelta,Python Dateutil,我想在给定日期的基础上再加一个月 import datetime dt = datetime.datetime(year=2014, month=5, day=2) 所以我应该 datetime.datetime(year=2014, month=6, day=2) datetime.datetime(year=2015, month=3, day=1) 但是 dt = datetime.datetime(year=2015, month=1, day=31) 我应该 datetime.

我想在给定日期的基础上再加一个月

import datetime
dt = datetime.datetime(year=2014, month=5, day=2)
所以我应该

datetime.datetime(year=2014, month=6, day=2)
datetime.datetime(year=2015, month=3, day=1)
但是

dt = datetime.datetime(year=2015, month=1, day=31)
我应该

datetime.datetime(year=2014, month=6, day=2)
datetime.datetime(year=2015, month=3, day=1)
因为没有2015-02-31(我希望我的结果在一天之后是圆的)

有些月有31天,有些月有30天,有些月有29天,有些月有28天

因此,添加一个
datetime.timedelta
可能不是一个好方法(因为我们不知道要添加的天数)

我注意到熊猫有一个有趣的
DateOffset

但是我没有找到一个
偏移量,只是

我也看到了这个帖子

所以我尝试了
dateutil.relativedelta
但是

from dateutil.relativedelta import relativedelta
datetime.datetime(year=2015, month=1, day=31)+relativedelta(months=1)
返回

datetime.datetime(2015, 2, 28, 0, 0)
所以结果在之前的一天被四舍五入

有没有一种(干净的)方法可以在之后一整天

编辑: 我给出了一个要添加一个月的示例,但我也希望能够添加例如:2年6个月(使用
相对LTA(年=2,月=6)

快速解决方案:

import datetime
import calendar
dt = datetime.datetime(year=2014, month=5, day=2)
d = calendar.monthrange(dt.year,dt.month+1)[1] 
print dt+datetime.timedelta(days=d+1)
第一次输入的输出
(年=2014,月=5,日=2)

第二次输入的输出
(年=2015,月=1,日=31)

您可以使用并手动检查该属性,如果原始日期大于新日期,则添加一天

下面的函数接受一个
datetime
对象和
relativedelta
对象。请注意,下面的代码只能工作数年和数月,我认为如果您使用低于该值的任何东西(天、小时等),它都不会工作。您可以很容易地修改此函数,将
作为参数,然后在函数本身内部构造
relativedelta

from datetime import datetime
from dateutil.relativedelta import relativedelta

def add_time(d, rd):
    day = relativedelta(days=+1)

    out = d + rd
    if d.day > out.day:
        out = out + day

    return out    

# Check that it "rolls over"
print(add_time(datetime(year=2015, month=1, day=29), relativedelta(years=+4, months=+1))) # 2019-03-01 00:00:00
print(add_time(datetime(year=2015, month=3, day=31), relativedelta(years=+0, months=+2))) # 2015-05-01 00:00:00

# Check that it handles "normal" scenarios
print(add_time(datetime(year=2015, month=6, day=19), relativedelta(months=+1))) # 2015-07-19 00:00:00
print(add_time(datetime(year=2015, month=6, day=30), relativedelta(years=+2, months=+1))) # 2017-07-30 00:00:00

# Check across years
print(add_time(datetime(year=2015, month=12, day=25), relativedelta(months=+1))) # 2016-01-25 00:00:00

# Check leap years
print(add_time(datetime(year=2016, month=1, day=29), relativedelta(years=+4, months=+1))) # 2020-02-29 00:00:00

这似乎奏效了。它很干净,但并不漂亮:

def add_month(now):
    try:
        then = (now + relativedelta(months=1)).replace(day=now.day)
    except ValueError:
        then = (now + relativedelta(months=2)).replace(day=1)
    return then

for now in [datetime(2015, 1, 20), datetime(2015, 1, 31), datetime(2015, 2, 28)]:
    print now, add_month(now)
印刷品:

2015-01-20 00:00:00 2015-02-20 00:00:00
2015-01-31 00:00:00 2015-03-01 00:00:00
2015-02-28 00:00:00 2015-03-28 00:00:00
它会增加一个月,并尝试将该天替换为原来的一天。如果它成功了,就不是特例。如果失败(ValueError),我们必须再添加一个月,并转到第一天。

使用下面的方法:

def datetime_offset_by_months(datetime_origin, n=1):
    """
    datetime offset by months
    :param datetime_origin: the original datetime
    :param n: count of months
    :return: after offset datetime
    """
    # create a shortcut object for one day
    one_day = datetime.timedelta(days=1)

    # first use div and mod to determine year cycle
    q, r = divmod(datetime_origin.month + n, 12)

    # create a datetime_offset
    # to be the last day of the target month
    datetime_offset = datetime.datetime(
        datetime_origin.year + q, r + 1, 1) - one_day

    '''
       if input date is the last day of this month
       then the output date should also be the last
       day of the target month, although the day
       www.iplaypy.com
       may be different.
       for example:
       datetime_origin = 8.31
       datetime_offset = 9.30
    '''

    if datetime_origin.month != (datetime_origin + one_day).month:
        return datetime_offset

    '''
        if datetime_origin day is bigger than last day of
        target month, then, use datetime_offset
        for example:
        datetime_origin = 10.31
        datetime_offset = 11.30
    '''

    if datetime_origin.day >= datetime_offset.day:
        return datetime_offset

    '''
     then, here, we just replace datetime_offset's day
     with the same of datetime_origin, that's ok.
    '''

    return datetime_offset.replace(day= datetime_origin.day)
资讯科技的使用:

import datetime
now_date = datetime.datetime.now()

off_set_datetime = datetime_offset_by_months(now_date, -2)
print(off_set_datetime)

您是否希望添加,例如,2年、6个月和5天?你能更具体地回答你的问题吗?我只需要在datetime中加上年和月(但我希望结果是后天“圆”的,而不是像relativedelta那样的前一天),我编辑了下面的答案,以便它接受一个
relativedelta
参数。这将允许你使用任何你想要的时间。请注意,如果包括天、小时等,它将不起作用。