Как добавить «3 месяца» к объекту datetime.date в python? - PullRequest
25 голосов
/ 07 марта 2012

вычисления даты Python, где ты?

У меня есть приложение на python, которое должно составлять даты каждые три месяца в течение нескольких лет. Важно, чтобы даты встречались ровно 4 раза в год, чтобы даты встречались в один и тот же день каждого года как можно дольше, и чтобы даты встречались в один и тот же день месяца как можно дольше, и чтобы даты были как можно ближе к «3 месяцам» (что является движущейся целью, особенно в високосный год). К сожалению, datetime.timedelta не поддерживает месяцы!

Есть ли "стандартный" способ сделать это вычисление в Python ???

Путь SQL?

Если худшее приходит к худшему, я разбираюсь, и мое приложение попросит PostgreSQL, у которого есть хорошая встроенная поддержка для вычисления даты, получить такой ответ:

# select ('2010-11-29'::date + interval '3 months')::date;
    date    
------------
 2011-02-28
(1 row)

Ответы [ 4 ]

56 голосов
/ 07 марта 2012

Если вы ищете точные или «более точные» даты, вам, вероятно, лучше проверить dateutil .

Быстрый пример:

>>> from dateutil.relativedelta import relativedelta
>>> import datetime
>>> TODAY = datetime.date.today()
>>> TODAY
datetime.date(2012, 3, 6)

Теперь добавьте 3 месяца к TODAY, обратите внимание, что он точно соответствует дню (обратите внимание, что relativedelta(months=3) и relativedelta(month=3) ведут себя по-разному. Обязательно используйте months для этих примеров!).

>>> three_mon_rel = relativedelta(months=3)
>>> TODAY + three_mon_rel
datetime.date(2012, 6, 6)

И он остается неизменным в течение года. Буквально каждые три месяца, в день (пришлось продолжать добавлять, потому что по какой-то причине умножение relativedelta и добавление его к объекту datetime.date приводит к TypeError):

>>> TODAY + three_mon_rel + three_mon_rel
datetime.date(2012, 9, 6)
>>> TODAY + three_mon_rel + three_mon_rel + three_mon_rel
datetime.date(2012, 12, 6)
>>> TODAY + three_mon_rel + three_mon_rel + three_mon_rel + three_mon_rel
datetime.date(2013, 3, 6)

Принимая во внимание, что предлагаемое решение мВч , хотя и определенно «достаточно хорошее», с течением времени слегка дрейфует:

>>> three_mon_timedelta = datetime.timedelta(days=3 * 365/12)
>>> TODAY + three_mon_timedelta
datetime.date(2012, 6, 5)

И в течение года день месяца продолжает скользить:

>>> TODAY + three_mon_timedelta * 2
datetime.date(2012, 9, 4)
>>> TODAY + three_mon_timedelta * 3
datetime.date(2012, 12, 4)
>>> TODAY + three_mon_timedelta * 4
datetime.date(2013, 3, 5)
7 голосов
/ 07 марта 2012
import datetime

some_date = datetime.date.today()
three_months = datetime.timedelta(3*365/12)
print (some_date + three_months).isoformat()
# => '2012-06-01'

Затем "нормализуйте" каждый новый год до дня исходной даты (если не 29 февраля)

1 голос
/ 12 мая 2018

Использование стандартных библиотек Python, т.е. без dateutil или других, и решение проблемы «31 февраля»:

import datetime
import calendar

def add_months(date, months):
    months_count = date.month + months

    # Calculate the year
    year = date.year + int(months_count / 12)

    # Calculate the month
    month = (months_count % 12)
    if month == 0:
        month = 12

    # Calculate the day
    day = date.day
    last_day_of_month = calendar.monthrange(year, month)[1]
    if day > last_day_of_month:
        day = last_day_of_month

    new_date = datetime.date(year, month, day)
    return new_date

Тестирование:

>>>date = datetime.date(2018, 11, 30)

>>>print(date, add_months(date, 3))
(datetime.date(2018, 11, 30), datetime.date(2019, 2, 28))

>>>print(date, add_months(date, 14))
(datetime.date(2018, 12, 31), datetime.date(2020, 2, 29))
1 голос
/ 07 марта 2012

вот хорошее решение http://www.voidspace.org.uk/python/weblog/arch_d7_2012_02_25.shtml#e1235

редактировать ах стандартным способом извините ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...