J'ai une application python qui doit tracer des dates tous les trois mois pendant plusieurs années. Il est important que les dates soient exactement 4 fois par an, le plus souvent possible le même jour chaque année, et le plus souvent possible le même jour du mois, et que ces dates soient aussi proches que possible de "3 mois" (cible mobile, en particulier pour les années bissextiles). Malheureusement, datetime.timedelta
ne prend pas en charge les mois!
Existe-t-il une méthode "standard" pour effectuer ce calcul en python ???
Si le pire venait à se dégrader, je demanderai à mon application de demander à PostgreSQL, qui dispose du support intégré de Nice pour les calculs de date, de répondre comme ceci:
# select ('2010-11-29'::date + interval '3 months')::date;
date
------------
2011-02-28
(1 row)
Si vous recherchez des dates exactes ou "plus précises", vous feriez probablement mieux de consulter dateutil .
Exemple rapide:
>>> from dateutil.relativedelta import relativedelta
>>> import datetime
>>> TODAY = datetime.date.today()
>>> TODAY
datetime.date(2012, 3, 6)
Ajoutez 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. Veillez à utiliser months
pour ces exemples!).
>>> three_mon_rel = relativedelta(months=3)
>>> TODAY + three_mon_rel
datetime.date(2012, 6, 6)
Et cela reste constant tout au long de l'année. Littéralement tous les trois mois, le jour (il fallait continuer à ajouter car, pour une raison quelconque, multiplier une relativedelta
et l'ajouter à un objet datetime.date
génère une 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 la solution suggérée par les mVChr , bien qu’elle soit "assez bonne", dérive légèrement dans le temps:
>>> three_mon_timedelta = datetime.timedelta(days=3 * 365/12)
>>> TODAY + three_mon_timedelta
datetime.date(2012, 6, 5)
Et au cours d'une année, le jour du mois continue de glisser:
>>> 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 nouvelle année à la date de la date originale (sauf le 29 février)
voici une bonne solution http://www.voidspace.org.uk/python/weblog/Arch_d7_2012_02_25.shtml#e1235
modifier ah moyen standard désolé ...
En utilisant les bibliothèques standard Python, c'est-à-dire sans dateutil
ou autres, et en résolvant le 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
Essai:
>>>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))