我正在使用datetime Python模块。我希望从当前日期计算6个月的日期。有人能帮我一下吗?

我想从当前日期生成一个6个月后的日期的原因是为了生成一个回顾日期。如果用户在系统中输入数据,系统将有从输入数据之日起6个月的审查日期。


当前回答

我使用replace()方法并编写了这个递归函数。dt是一个日期时间。datetime对象:

def month_timedelta(dt, m):
    y = m // 12
    dm = m % 12
    if y == 0:
        if dt.month + m <= 12:
            return dt.replace(month = dt.month + m)
        else:
            dy = (dt.month + m) // 12
            ndt = dt.replace(year=dt.year + dy)
            return ndt.replace(month=(ndt.month + m) % 12)
    else:
        return month_timedelta(dt.replace(year=dt.year + y),dm)

其他回答

修改了Johannes Wei在1new_month = 121情况下的答案。这对我来说非常合适。月份可以是正的,也可以是负的。

def addMonth(d,months=1):
    year, month, day = d.timetuple()[:3]
    new_month = month + months
    return datetime.date(year + ((new_month-1) / 12), (new_month-1) % 12 +1, day)

我认为这样做会比手动添加天数更安全:

import datetime
today = datetime.date.today()

def addMonths(dt, months = 0):
    new_month = months + dt.month
    year_inc = 0
    if new_month>12:
        year_inc +=1
        new_month -=12
    return dt.replace(month = new_month, year = dt.year+year_inc)

newdate = addMonths(today, 6)

使用下面给出的函数,你可以得到x个月之后/之前的日期。

from datetime import date

def next_month(given_date, month):
    yyyy = int(((given_date.year * 12 + given_date.month) + month)/12)
    mm = int(((given_date.year * 12 + given_date.month) + month)%12)

    if mm == 0:
        yyyy -= 1
        mm = 12
    return given_date.replace(year=yyyy, month=mm)


if __name__ == "__main__":
    today = date.today()
    print(today)

    for mm in [-12, -1, 0, 1, 2, 12, 20 ]:
        next_date = next_month(today, mm)
        print(next_date)

还有另一个解决方案,希望有人会喜欢:

def add_months(d, months):
    return d.replace(year=d.year+months//12).replace(month=(d.month+months)%12)

这个解决方案并不适用于所有情况下的第29、30、31天,所以需要更健壮的解决方案(这已经不是那么好了:)):

def add_months(d, months):
    for i in range(4):
        day = d.day - i
        try:
            return d.replace(day=day).replace(year=d.year+int(months)//12).replace(month=(d.month+int(months))%12)
        except:
            pass
    raise Exception("should not happen")

下面是一个示例,它允许用户决定如何返回一个日期,其中一天大于一个月中的天数。

def add_months(date, months, endOfMonthBehaviour='RoundUp'):
    assert endOfMonthBehaviour in ['RoundDown', 'RoundIn', 'RoundOut', 'RoundUp'], \
        'Unknown end of month behaviour'
    year = date.year + (date.month + months - 1) / 12
    month = (date.month + months - 1) % 12 + 1
    day = date.day
    last = monthrange(year, month)[1]
    if day > last:
        if endOfMonthBehaviour == 'RoundDown' or \
            endOfMonthBehaviour == 'RoundOut' and months < 0 or \
            endOfMonthBehaviour == 'RoundIn' and months > 0:
            day = last
        elif endOfMonthBehaviour == 'RoundUp' or \
            endOfMonthBehaviour == 'RoundOut' and months > 0 or \
            endOfMonthBehaviour == 'RoundIn' and months < 0:
            # we don't need to worry about incrementing the year
            # because there will never be a day in December > 31
            month += 1
            day = 1
    return datetime.date(year, month, day)


>>> from calendar import monthrange
>>> import datetime
>>> add_months(datetime.datetime(2016, 1, 31), 1)
datetime.date(2016, 3, 1)
>>> add_months(datetime.datetime(2016, 1, 31), -2)
datetime.date(2015, 12, 1)
>>> add_months(datetime.datetime(2016, 1, 31), -2, 'RoundDown')
datetime.date(2015, 11, 30)