Добавьте один месяц к заданной дате (округленный день после) с помощью Python

Я хотел бы добавить один месяц к данной дате

import datetime
dt = datetime.datetime(year=2014, month=5, day=2)

так что я должен сделать

datetime.datetime(year=2014, month=6, day=2)

но с

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

Я должен получить

datetime.datetime(year=2015, month=3, day=1)

потому что нет 2015-02-31 (и я хочу, чтобы мой результат был круглым один день после)

некоторые месяцы имеют 31 день, некоторые другие 30, некоторые 29, некоторые 28 !

чтобы добавлять datetime.timedelta, вероятно, не очень хороший способ сделать (потому что мы не знаем номер дней, чтобы добавить)

я заметил, что у панд есть интересная концепция DateOffset

http://pandas.pydata.org/pandas-docs/stable/timeseries.html#dateoffset-objects

но я не нашел Month смещение, просто MonthBegin или MonthEnd

Я вижу этот пост Как рассчитать дату через шесть месяцев от текущей даты с помощью модуля datetime Python?

так я пробовал dateutil.relativedelta но!--14-->

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 месяцев (используя relativedelta(years=2, months=6))

4 ответов


можно использовать dateutil.relativedelta.relativedelta и вручную проверьте datetime.day атрибут, если исходный день больше, чем новый день, а затем добавить день.

функция, приведенная ниже, принимает datetime объект и


Это, кажется, работает. Он довольно чистый, но не красивый:

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), мы должны добавить еще один месяц и перейти к его первому дню.


быстрое решение:

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)

выход для первого входа (year=2014, month=5, day=2):

2014-06-02 00:00:00

выход для второго входа (year=2015, month=1, day=31):

2015-03-01 00:00:00

используйте метод bellow:

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)