Comment ajouter "3 mois" à une datetime.date object en python?

Python date calculs, where are thou?

j'ai une application python qui doit tracer des dates tous les trois mois pendant plusieurs années. Il est important que les dates se produisent exactement 4 fois par année, et que les dates se produisent le même jour chaque année autant que possible, et que les dates se produisent le même jour du mois autant que possible, et que les dates soient aussi proches de "3 mois" d'intervalle qu'ils peuvent l'être (ce qui est une cible mobile, en particulier l'année bissextile). Malheureusement, datetime.timedelta ne supporte pas les mois!

Est-il une façon "standard" de faire ce calcul en python???

<!-La voie SQL?

Si le pire arrive au pire, je vais punt et mon app demander PostgreSQL, qui n'ont de belles prise en charge intégrée pour les calculs de date, pour la réponse comme ceci:

# select ('2010-11-29'::date + interval '3 months')::date;
    date    
------------
 2011-02-28
(1 row)
22
demandé sur Nathan 2012-03-07 04:54:57

4 réponses

si vous cherchez des dates exactes ou "plus précises", vous feriez mieux de vérifier dateutil.

petit exemple:

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

ajouter Maintenant 3 mois à TODAY, observez qu'il correspond exactement au jour (notez que relativedelta(months=3) et relativedelta(month=3) ont des comportements différents. Assurez-vous d'utiliser months pour ces exemples!).

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

Et il reste cohérent tout au long de l'année. Littéralement tous les trois mois, le jour (a dû continuer à ajouter parce que pour une raison quelconque multipliant un relativedelta et en l'ajoutant à un datetime.date l'objet lance un 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)

alors que le mVChr's solution proposée, bien que certainement assez "bon", les dérives légèrement au fil du temps:

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

Et, au cours de l'année, le jour du mois nous glisse:

>>> 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)
51
répondu jathanism 2017-05-23 11:47:20
import datetime

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

Puis "normaliser" chaque année à la date du jour (sauf si Fév 29)

6
répondu mVChr 2012-03-07 01:11:13

voici une bonne solution http://www.voidspace.org.uk/python/weblog/arch_d7_2012_02_25.shtml#e1235

modifier ah façon standard désolé...

1
répondu heinzderaugust 2012-03-07 01:33:49

utiliser les bibliothèques standard de Python, c'est-à-dire sans dateutil ou d'autres, et la résolution du problème du "31 février":

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

Test:

>>>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
répondu David Ragazzi 2018-08-17 14:27:18