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)
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)
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)
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é...
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))