Je dois vérifier si un certain nombre d'années se sont écoulées depuis une date donnée. Actuellement, j'ai le module timedelta
du module datetime
et je ne sais pas comment le convertir en années.
Vous avez besoin de plus que timedelta
pour savoir combien d'années se sont écoulées; vous devez également connaître la date de début (ou de fin). (C'est une année bissextile.)
Votre meilleur pari est d'utiliser le dateutil.relativedelta
objet , mais c'est un module tiers. Si vous voulez connaître le datetime
qui était n
ans à compter de quelque date (par défaut à maintenant), vous pouvez procéder comme suit:
from dateutil.relativedelta import relativedelta
def yearsago(years, from_date=None):
if from_date is None:
from_date = datetime.now()
return from_date - relativedelta(years=years)
Si vous préférez vous en tenir à la bibliothèque standard, la réponse est un peu plus complexe:
from datetime import datetime
def yearsago(years, from_date=None):
if from_date is None:
from_date = datetime.now()
try:
return from_date.replace(year=from_date.year - years)
except ValueError:
# Must be 2/29!
assert from_date.month == 2 and from_date.day == 29 # can be removed
return from_date.replace(month=2, day=28,
year=from_date.year-years)
S'il s'agit de 2/29 et qu'il y a 18 ans, il n'y en avait pas 2/29, cette fonction renverra 2/28. Si vous préférez retourner 3/1, changez simplement la dernière instruction return
pour lire ::
return from_date.replace(month=3, day=1,
year=from_date.year-years)
Votre question disait à l'origine que vous vouliez savoir combien d'années cela fait depuis une date donnée. En supposant que vous souhaitiez un nombre entier d'années, vous pouvez deviner sur la base de 365,25 jours par an, puis vérifier en utilisant l'une des fonctions yearsago
définies ci-dessus:
def num_years(begin, end=None):
if end is None:
end = datetime.now()
num_years = int((end - begin).days / 365.25)
if begin > yearsago(num_years, end):
return num_years - 1
else:
return num_years
Si vous essayez de vérifier si une personne a 18 ans, utiliser timedelta
ne fonctionnera pas correctement sur certains cas Edge en raison des années bissextiles. Par exemple, une personne née le 1 er janvier 2000 aura 18 ans exactement 6575 jours plus tard le 1 er janvier 2018 (5 années bissextiles incluses), mais une personne née le 1 er janvier 2001 aura 18 ans exactement 6574 jours plus tard le 1 er janvier. 2019 (4 années bissextiles incluses). Ainsi, si une personne a exactement 6574 jours, vous ne pouvez pas déterminer si elle a 17 ou 18 ans sans connaître un peu plus d'informations sur sa date de naissance.
Pour ce faire, calculez l’âge directement à partir des dates, en soustrayant les deux années, puis en soustrayant une si le mois/jour en cours précède le mois/jour de naissance.
Tout d’abord, au niveau le plus détaillé, le problème ne peut pas être résolu exactement. La durée des années varie et il n’existe pas de "bon choix" pour la durée d’une année.
Cela dit, obtenez la différence en unités "naturelles" (probablement en secondes) et divisez-les par le rapport entre cela et les années. Par exemple.
delta_in_days / (365.25)
delta_in_seconds / (365.25*24*60*60)
...ou peu importe. Restez à l'écart des mois, car ils sont encore moins bien définis que les années.
Voici une fonction DOB mise à jour, qui calcule les anniversaires de la même manière que les humains:
import datetime
import locale
# Source: https://en.wikipedia.org/wiki/February_29
PRE = [
'US',
'TW',
]
POST = [
'GB',
'HK',
]
def get_country():
code, _ = locale.getlocale()
try:
return code.split('_')[1]
except IndexError:
raise Exception('Country cannot be ascertained from locale.')
def get_leap_birthday(year):
country = get_country()
if country in PRE:
return datetime.date(year, 2, 28)
Elif country in POST:
return datetime.date(year, 3, 1)
else:
raise Exception('It is unknown whether your country treats leap year '
+ 'birthdays as being on the 28th of February or '
+ 'the 1st of March. Please consult your country\'s '
+ 'legal code for in order to ascertain an answer.')
def age(dob):
today = datetime.date.today()
years = today.year - dob.year
try:
birthday = datetime.date(today.year, dob.month, dob.day)
except ValueError as e:
if dob.month == 2 and dob.day == 29:
birthday = get_leap_birthday(today.year)
else:
raise e
if today < birthday:
years -= 1
return years
print(age(datetime.date(1988, 2, 29)))
Obtenez le nombre de jours, puis divisez par 365.2425 (année moyenne grégorienne) pour les années. Divisez par 30,436875 (le mois grégorien moyen) pendant des mois.
C’est la solution que j’ai trouvée, j’espère pouvoir vous aider ;-)
def menor_edad_legal(birthday):
""" returns true if aged<18 in days """
try:
today = time.localtime()
fa_divuit_anys=date(year=today.tm_year-18, month=today.tm_mon, day=today.tm_mday)
if birthday>fa_divuit_anys:
return True
else:
return False
except Exception, ex_edad:
logging.error('Error menor de edad: %s' % ex_edad)
return True
Encore une autre bibliothèque tierce non mentionnée ici est mxDateTime (le prédécesseur de python datetime
et de tierce partie timeutil
pourrait être utilisé pour cette tâche.) Pourrait être utilisé pour cette tâche.
Le yearsago
mentionné ci-dessus serait:
from mx.DateTime import now, RelativeDateTime
def years_ago(years, from_date=None):
if from_date == None:
from_date = now()
return from_date-RelativeDateTime(years=years)
Le premier paramètre devrait être une instance DateTime
.
Pour convertir les datetime
ordinaires en DateTime
, vous pouvez utiliser ceci avec une précision de 1 seconde):
def DT_from_dt_s(t):
return DT.DateTimeFromTicks(time.mktime(t.timetuple()))
ou ceci pour une précision de 1 microseconde:
def DT_from_dt_u(t):
return DT.DateTime(t.year, t.month, t.day, t.hour,
t.minute, t.second + t.microsecond * 1e-6)
Et oui, ajouter la dépendance pour cette seule tâche en question serait certainement une surexploitation par rapport à l'utilisation de timeutil (suggéré par Rick Copeland).
En fin de compte, vous avez un problème de calcul. Si tous les 4 ans, nous avons un jour supplémentaire, nous plongerons le timedelta en jours, pas par 365, mais par 365 * 4 + 1, le montant sera de 4 ans. Puis divisez à nouveau par 4. timedelta/((365 * 4) +1)/4 = timedelta * 4/(365 * 4 +1)
def age(dob):
import datetime
today = datetime.date.today()
if today.month < dob.month or \
(today.month == dob.month and today.day < dob.day):
return today.year - dob.year - 1
else:
return today.year - dob.year
>>> import datetime
>>> datetime.date.today()
datetime.date(2009, 12, 1)
>>> age(datetime.date(2008, 11, 30))
1
>>> age(datetime.date(2008, 12, 1))
1
>>> age(datetime.date(2008, 12, 2))
0
Je vais suggérer Pyfdate
Qu'est-ce que pyfdate?
L'objectif de Python étant de devenir un langage de script puissant et facile à utiliser, les fonctionnalités permettant de travailler avec les dates et les heures ne sont pas aussi conviviales qu'elles le devraient. Pyfdate a pour but de remédier à cette situation en fournissant des fonctionnalités permettant de travailler avec des dates et des heures aussi puissantes et faciles à utiliser que le reste de Python.
le tutoriel
cette fonction renvoie la différence en années entre deux dates (prises sous forme de chaînes au format ISO, mais elle peut facilement être modifiée pour prendre n'importe quel format)
import time
def years(earlydateiso, laterdateiso):
"""difference in years between two dates in ISO format"""
ed = time.strptime(earlydateiso, "%Y-%m-%d")
ld = time.strptime(laterdateiso, "%Y-%m-%d")
#switch dates if needed
if ld < ed:
ld, ed = ed, ld
res = ld[0] - ed [0]
if res > 0:
if ld[1]< ed[1]:
res -= 1
Elif ld[1] == ed[1]:
if ld[2]< ed[2]:
res -= 1
return res
Quelle est l'exactitude dont vous avez besoin? td.days / 365.25
vous rapprochera si vous êtes inquiet pour les années bissextiles.