J'ai besoin de vérifier si un certain nombre d'années se sont écoulées depuis une certaine date. Actuellement, j'ai timedeltadu datetimemodule et je ne sais pas comment le convertir en années.
Vous avez besoin de plus d'un timedeltapour dire 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 l' dateutil.relativedeltaobjet , mais c'est un module tiers. Si vous voulez connaître la datetimequi a été des nannées d' une certaine date (par défaut à l' heure actuelle), vous pouvez faire ce qui suit ::
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 isNone:
from_date = datetime.now()try:return from_date.replace(year=from_date.year - years)exceptValueError:# Must be 2/29!assert from_date.month ==2and from_date.day ==29# can be removedreturn from_date.replace(month=2, day=28,
year=from_date.year-years)
Si c'est 2/29, et il y a 18 ans il n'y avait pas 2/29, cette fonction renverra 2/28. Si vous préférez retourner 3/1, changez simplement la dernière returninstruction en read ::
Votre question indiquait à l'origine que vous vouliez savoir combien d'années cela faisait depuis une certaine date. En supposant que vous vouliez 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 yearsagofonctions définies ci-dessus:
def num_years(begin, end=None):if end isNone:
end = datetime.now()
num_years = int((end - begin).days /365.25)if begin > yearsago(num_years, end):return num_years -1else:return num_years
Vous pouvez être totalement précis avec 365,2425 (au lieu de 365,25), qui prend en compte l'exception de 400 ans pour le calendrier grégorien.
brianary
3
Votre fonction est légalement interrompue pour des pays comme le Royaume-Uni et Hong Kong, car ils «arrondissent» au 1er mars pour les années bissextiles.
voir aussi ceci et cela. Les deux sont d'excellentes listes de choses qui ne sont pas vraies sur le temps.
gvoysey
49
Si vous essayez de vérifier si quelqu'un a 18 ans, l'utilisation timedeltane fonctionnera pas correctement dans certains cas extrêmes en raison des années bissextiles. Par exemple, une personne née le 1er janvier 2000 aura 18 ans exactement 6575 jours plus tard le 1er janvier 2018 (5 années bissextiles incluses), mais une personne née le 1er janvier 2001 aura 18 ans exactement 6574 jours plus tard le 1er janvier, 2019 (4 années bissextiles incluses). Ainsi, vous si quelqu'un a exactement 6574 jours, vous ne pouvez pas déterminer s'il a 17 ou 18 ans sans connaître un peu plus d'informations sur sa date de naissance.
La bonne façon de faire est de calculer l'âge directement à partir des dates, en soustrayant les deux années, puis en soustrayant un si le mois / jour actuel 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. Les années varient en longueur et il n'y a pas de «bon choix» clair pour la durée de l'année.
Cela dit, obtenez la différence entre les unités "naturelles" (probablement secondes) et divisez par le rapport entre cela et les années. Par exemple
Ce n'est PAS ce que quiconque veut dire ou utiliser lorsqu'il s'agit de savoir combien d'années de service ou une personne a-t-elle atteint un âge particulier.
John Machin
3
Votre 365,25 doit être 365,2425 pour prendre en compte l'exception de 400 ans du calendrier grégorien.
brianary
1
Eh bien, le problème peut être résolu correctement - vous pouvez dire à l'avance quelles années ont des jours bissextiles et des secondes intercalaires et tout cela. C'est juste qu'il n'y a pas de manière extrêmement élégante de le faire sans soustraire les années, puis les mois, puis les jours, etc ... dans les deux dates formatées
Litherum
7
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]exceptIndexError:raiseException('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:raiseException('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)exceptValueErroras e:if dob.month ==2and dob.day ==29:
birthday = get_leap_birthday(today.year)else:raise e
if today < birthday:
years -=1return years
print(age(datetime.date(1988,2,29)))
Cela se rompt lorsque dob est le 29 février et que l'année en cours n'est pas une année bissextile.
Trey Hunner
4
Obtenez le nombre de jours, puis divisez par 365,2425 (l'année grégorienne moyenne) pendant des années. Divisez par 30,436875 (le mois grégorien moyen) pendant des mois.
Une personne née le 29 février sera considérée comme ayant atteint l'âge de 1 an le 28 février suivant.
John Machin
D'accord. Corrigé pour tenir compte des 0,08% de la population née le 29 en inversant le test de «est anniversaire après aujourd'hui» à «est anniversaire avant aujourd'hui». Est-ce que cela résout le problème?
John Mee
Cela fonctionne correctement pour votre exemple!?! Si je mets «aujourd'hui» au 28 février 2009 et la date de naissance au 29 février 2008, cela renvoie zéro - du moins pour moi; pas 1 comme vous le suggérez (Python 2.5.2). Il n'y a pas besoin de grossier M. Machin. Avec quelles deux dates avez-vous des problèmes?
John Mee
Je vais réessayer: une personne née le 29 février sera considérée par la plupart des gens pour la plupart des raisons juridiques comme ayant atteint l'âge de 1 an le 28 février suivant. Votre code produit 0, à la fois avant et après votre "correction". En fait, les deux versions de votre code produisent EXACTEMENT la même sortie pour TOUTES les 9 possibilités d'entrée (mois <==> X jour <==>). BTW, 100,0 / (4 * 365 + 1) produit 0,068 et non 0,08.
John Machin
2
Soupir. (0) La résolution des problèmes du 29 février est essentielle dans toute arithmétique de date; vous l'avez simplement ignoré. (1) Votre code n'était pas mieux la première fois; que ne comprenez-vous pas dans «produire exactement le même résultat»? (2) Trois résultats atomiques possibles (<, ==,>) comparant today.month et dob.month; trois résultats atomiques possibles comparant today.day et dob.day; 3 * 3 == 9 (3) stackoverflow.com/questions/2217488/…
John Machin
1
Dans quelle mesure avez-vous besoin que ce soit exact? td.days / 365.25vous rapprochera, si vous vous inquiétez des années bissextiles.
Je suis vraiment inquiet pour les années bissextiles. Il devrait vérifier si la personne a plus de 18 ans.
Migol
Ensuite, il n'y a pas de one-liner facile, vous allez devoir analyser les deux dates et déterminer si la personne a passé son 18e anniversaire ou non.
eduffy
1
Une autre bibliothèque tierce non mentionnée ici est mxDateTime (prédécesseur de python datetimeet de tierstimeutil ) pourrait être utilisée pour cette tâche.
Et oui, ajouter la dépendance pour cette seule tâche en question serait certainement une exagération par rapport à l'utilisation de timeutil (suggéré par Rick Copeland).
En fin de compte, vous avez un problème de mathématiques. Si tous les 4 ans nous avons un jour supplémentaire, puis plonger le chronomètre en jours, pas par 365 mais 365 * 4 + 1, cela vous donnerait le montant de 4 ans. Puis divisez-le à nouveau par 4. timedelta / ((365 * 4) +1) / 4 = timedelta * 4 / (365 * 4 +1)
La chose des années bissextiles ne s'applique pas lorsque les années sont divisibles par 100, sauf quand elles sont divisibles par 400. Donc, pour l'année 2000: - elle est divisible par quatre, donc elle devrait être bissextile mais ... - elle est également divisible par cent, donc ça ne devrait pas être bissextile mais ... - il est divisible par 400, donc c'était en fait une année bissextile. Pour 1900: - il est divisible par 4 donc ça devrait être bond. - il est divisible par 100, il ne doit donc pas être bondi. - il n'est PAS divisible par 400, donc cette règle ne s'applique pas. 1900 n'était pas une année bissextile.
Jblasco
1
C'est la solution que j'ai élaboré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:returnTrueelse:returnFalseexceptException, ex_edad:
logging.error('Error menor de edad: %s'% ex_edad)returnTrue
Même si ce fil est déjà mort, puis-je suggérer une solution de travail pour ce même problème auquel je faisais face. Le voici (la date est une chaîne au format jj-mm-aaaa):
def validatedate(date):
parts = date.strip().split('-')if len(parts)==3andFalsenotin[x.isdigit()for x in parts]:
birth = datetime.date(int(parts[2]), int(parts[1]), int(parts[0]))
today = datetime.date.today()
b =(birth.year *10000)+(birth.month *100)+(birth.day)
t =(today.year *10000)+(today.month *100)+(today.day)if(t -18*10000)>= b:returnTruereturnFalse
cette fonction renvoie la différence en années entre deux dates (prise 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 neededif ld < ed:
ld, ed = ed, ld
res = ld[0]- ed [0]if res >0:if ld[1]< ed[1]:
res -=1elif ld[1]== ed[1]:if ld[2]< ed[2]:
res -=1return res
Étant donné l'objectif de Python d'être un langage de script puissant et facile à utiliser, ses fonctionnalités pour travailler avec les dates et les heures ne sont pas aussi conviviales qu'elles devraient l'être. Le but de pyfdate est de remédier à cette situation en fournissant des fonctionnalités pour travailler avec des dates et des heures qui sont aussi puissantes et faciles à utiliser que le reste de Python.
J'ai aimé la solution de John Mee pour sa simplicité, et je ne suis pas très préoccupé par la façon dont, le 28 février ou le 1er mars, quand ce n'est pas une année bissextile, déterminer l'âge des personnes nées le 29 février. Mais voici un ajustement de son code qui, je pense, répond aux plaintes:
def age(dob):import datetime
today = datetime.date.today()
age = today.year - dob.year
if( today.month == dob.month ==2and
today.day ==28and dob.day ==29):passelif today.month < dob.month or \
(today.month == dob.month and today.day < dob.day):
age -=1return age
Réponses:
Vous avez besoin de plus d'un
timedelta
pour dire 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 l'
dateutil.relativedelta
objet , mais c'est un module tiers. Si vous voulez connaître ladatetime
qui a été desn
années d' une certaine date (par défaut à l' heure actuelle), vous pouvez faire ce qui suit ::Si vous préférez vous en tenir à la bibliothèque standard, la réponse est un peu plus complexe:
Si c'est 2/29, et il y a 18 ans il n'y avait pas 2/29, cette fonction renverra 2/28. Si vous préférez retourner 3/1, changez simplement la dernière
return
instruction en read ::Votre question indiquait à l'origine que vous vouliez savoir combien d'années cela faisait depuis une certaine date. En supposant que vous vouliez 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
yearsago
fonctions définies ci-dessus:la source
datetime.now()
) est supérieure à la différence entre les années juliennes (365.25
) et grégoriennes (365.2425
) moyennes . . La bonne approche est suggérée dans la réponse de @Adam RosenfieldSi vous essayez de vérifier si quelqu'un a 18 ans, l'utilisation
timedelta
ne fonctionnera pas correctement dans certains cas extrêmes en raison des années bissextiles. Par exemple, une personne née le 1er janvier 2000 aura 18 ans exactement 6575 jours plus tard le 1er janvier 2018 (5 années bissextiles incluses), mais une personne née le 1er janvier 2001 aura 18 ans exactement 6574 jours plus tard le 1er janvier, 2019 (4 années bissextiles incluses). Ainsi, vous si quelqu'un a exactement 6574 jours, vous ne pouvez pas déterminer s'il a 17 ou 18 ans sans connaître un peu plus d'informations sur sa date de naissance.La bonne façon de faire est de calculer l'âge directement à partir des dates, en soustrayant les deux années, puis en soustrayant un si le mois / jour actuel précède le mois / jour de naissance.
la source
Tout d'abord, au niveau le plus détaillé, le problème ne peut pas être résolu exactement. Les années varient en longueur et il n'y a pas de «bon choix» clair pour la durée de l'année.
Cela dit, obtenez la différence entre les unités "naturelles" (probablement secondes) et divisez par le rapport entre cela et les années. Par exemple
...ou peu importe. Évitez les mois, car ils sont encore moins bien définis que les années.
la source
Voici une fonction DOB mise à jour, qui calcule les anniversaires de la même manière que les humains:
la source
Obtenez le nombre de jours, puis divisez par 365,2425 (l'année grégorienne moyenne) pendant des années. Divisez par 30,436875 (le mois grégorien moyen) pendant des mois.
la source
la source
Dans quelle mesure avez-vous besoin que ce soit exact?
td.days / 365.25
vous rapprochera, si vous vous inquiétez des années bissextiles.la source
Une autre bibliothèque tierce non mentionnée ici est mxDateTime (prédécesseur de python
datetime
et de tierstimeutil
) pourrait être utilisée pour cette tâche.Ce qui précède
yearsago
serait:Le premier paramètre devrait être un
DateTime
instance.Pour convertir ordinaire
datetime
enDateTime
vous pouvez utiliser ceci pour une précision d'une seconde):ou ceci pour une précision de 1 microseconde:
Et oui, ajouter la dépendance pour cette seule tâche en question serait certainement une exagération par rapport à l'utilisation de timeutil (suggéré par Rick Copeland).
la source
En fin de compte, vous avez un problème de mathématiques. Si tous les 4 ans nous avons un jour supplémentaire, puis plonger le chronomètre en jours, pas par 365 mais 365 * 4 + 1, cela vous donnerait le montant de 4 ans. Puis divisez-le à nouveau par 4. timedelta / ((365 * 4) +1) / 4 = timedelta * 4 / (365 * 4 +1)
la source
C'est la solution que j'ai élaborée, j'espère pouvoir vous aider ;-)
la source
Même si ce fil est déjà mort, puis-je suggérer une solution de travail pour ce même problème auquel je faisais face. Le voici (la date est une chaîne au format jj-mm-aaaa):
la source
cette fonction renvoie la différence en années entre deux dates (prise sous forme de chaînes au format ISO, mais elle peut facilement être modifiée pour prendre n'importe quel format)
la source
Je suggérerai Pyfdate
le tutoriel
la source
C'est le code que l'opérateur du Carrousel exécutait dans le film Logan's Run;)
https://en.wikipedia.org/wiki/Logan%27s_Run_(film)
la source
Je suis tombé sur cette question et j'ai trouvé la réponse d'Adams la plus utile https://stackoverflow.com/a/765862/2964689
Mais il n'y avait pas d'exemple python de sa méthode mais voici ce que j'ai fini par utiliser.
entrée: objet datetime
sortie: âge entier en années entières
la source
J'ai aimé la solution de John Mee pour sa simplicité, et je ne suis pas très préoccupé par la façon dont, le 28 février ou le 1er mars, quand ce n'est pas une année bissextile, déterminer l'âge des personnes nées le 29 février. Mais voici un ajustement de son code qui, je pense, répond aux plaintes:
la source