¿Cómo puedo encontrar una edad en Python desde la fecha de hoy y la fecha de nacimiento de una persona? La fecha de nacimiento es de un DateField en un modelo Django.
un punto crítico: date.today()devuelve la fecha en la zona horaria local que puede ser diferente del lugar de nacimiento. Es posible que necesite usar zonas horarias explícitamente
jfs
10
Eso probablemente depende de su definición de "edad". Para todos los propósitos prácticos, un cumpleaños generalmente se da como una fecha, no como fecha / hora (es decir, "nacido" no tiene los detalles). La mayoría de las personas no nacen a la medianoche en punto (por lo general, observan prematuramente :-)), y cuando están en una zona horaria diferente, supongo que la mayoría de las personas observan su cumpleaños en la hora local (eso es lo que hago, vivo 10-12h por delante de mi tiempo de lugar de nacimiento). Si "nacido" era una fecha y hora que reconoce la zona horaria, podría usar la aritmética de pytz y normalizar (), ¿tal vez sea de interés para un software de astrología?
Danny W. Adair
2
Estoy completamente de acuerdo en el contexto de las edades humanas, pero su fórmula puede usarse en un contexto más amplio. Aunque personalmente nunca celebro mi cumpleaños ni una hora antes debido a una tradición familiar y a ser un programador, es trivial calcular el tiempo donde quiera que esté.
jfs
@pyd: born is a date / datetime
kjagiello
68
from datetime import date
def calculate_age(born):
today = date.today()try:
birthday = born.replace(year=today.year)exceptValueError:# raised when birth date is February 29 and the current year is not a leap year
birthday = born.replace(year=today.year, month=born.month+1, day=1)if birthday > today:return today.year - born.year -1else:return today.year - born.year
Solo como una cuestión de principio, su exceptbloqueo debe detectar solo una excepción específica que podría generarse.
Daenyth
1
@Daenyth: Buena decisión ... creo que es una ValueError. Actualizado.
mpen
Incluso llego al extremo de probar el mensaje de la excepción para asegurarme de que sea lo que estoy esperando. Incluso con el código anterior, existe la posibilidad de que se arroje un ValueError, pero no es el ValueError lo que espera.
Randy Syring
+ por excepción pero, ¿hay algún problema en mi ? Creo que es bastante simple. def calculate_age(dob)
Grijesh Chauhan
1
@GrijeshChauhan: Sí, el tuyo no funciona. datetime.date(2014, 1, 1)da -1, debería dar 0. Tu today > dobestá comprobando si el DOB está en el pasado, no a principios de este mismo año. datetime.date.today()incluye información del año, por lo que lo reemplazo con el año actual en mi solución.
mpen
18
from datetime import date
days_in_year =365.2425
age = int((date.today()- birth_date).days / days_in_year)
En Python 3, puede realizar la división en datetime.timedelta:
from datetime import date, timedelta
age =(date.today()- birth_date)// timedelta(days=365.2425)
cada cuarto año es bisiesto, excepto que cada centésimo año no es bisiesto, excepto que cada cuatrocientos años es bisiesto. pruebe days_in_year = 365.2425
Dan
3
@Dan: la diferencia entre Julian ( 365.25) y el año calendario gregoriano ( 365.2425) es menos de un día si vives menos de 130 años.
jfs
44
Esto no funciona para algunas fechas: (date(2017, 3, 1) - date(2004, 3, 1)) / timedelta(days=365.2425)debería regresar 13, pero regresa 12. Sin piso, el resultado es 12.999582469181433.
href_
13
Según lo sugerido por @ [Tomasz Zielinski] y @Williams python-dateutil pueden hacerlo solo 5 líneas.
from dateutil.relativedelta import*from datetime import date
today = date.today()
dob = date(1982,7,5)
age = relativedelta(today, dob)>>relativedelta(years=+33, months=+11, days=+16)`
import datetime
import dateutil
def birthday(date):# Get the current date
now = datetime.datetime.utcnow()
now = now.date()# Get the difference between the current date and the birthday
age = dateutil.relativedelta.relativedelta(now, date)
age = age.years
return age
Esto no funciona correctamente cuando el cumpleaños es el 29 de febrero y la fecha de hoy es el 28 de febrero (actuará como si hoy fuera el 29 de febrero).
Trey Hunner
6
from datetime import date
def age(birth_date):
today = date.today()
y = today.year - birth_date.year
if today.month < birth_date.month or today.month == birth_date.month and today.day < birth_date.day:
y -=1return y
fecha de instancia o algún obj como ese, docs.python.org/3/library/datetime.html#datetime.date, error tipográfico corregido.
gzerone
5
Desafortunadamente, no puede simplemente usar timedelata ya que la unidad más grande que usa es el día y los años bisiestos harán que sus cálculos no sean válidos. Por lo tanto, busquemos el número de años y luego ajustemos por uno si el último año no está lleno:
from datetime import date
birth_date = date(1980,5,26)
years = date.today().year - birth_date.year
if(datetime.now()- birth_date.replace(year=datetime.now().year)).days >=0:
age = years
else:
age = years -1
Upd:
Esta solución realmente causa una excepción cuando entra en juego el 29 de febrero. Aquí está la verificación correcta:
from datetime import date
birth_date = date(1980,5,26)
today = date.today()
years = today.year - birth_date.year
if all((x >= y)for x,y in zip(today.timetuple(), birth_date.timetuple()):
age = years
else:
age = years -1
Upd2:
Llamar varias llamadas a now()un éxito en el rendimiento es ridículo, no importa en todos, sino en casos extremadamente especiales. La verdadera razón para usar una variable es el riesgo de incosistencia de datos.
Gracias, descubrí esto haciendo algunas pruebas y terminé un código similar encontrado en el enlace de AndiDog.
tkalve
3
Strike 1: estás usando datetime.datetime en lugar de datetime.date. Strike 2: tu código es feo e ineficiente. Llamando a datetime.now () TRES veces? Huelga 3: Fecha de nacimiento el 29 de febrero de 2004 y la fecha de hoy 28 de febrero de 2010 debería regresar a los 6 años, no morir gritando "ValueError: el día está fuera de rango para el mes". ¡Estás fuera!
John Machin
Lo sentimos, su código "Upd" es aún más barroco y roto que el primer intento, nada que ver con el 29 de febrero; falla en MUCHOS casos simples como el 15-06-2009 al 02/07/2010 ... la persona obviamente tiene poco más de 1 año, pero usted deduce un año porque la prueba en los días (2> = 15) falla. Y obviamente no lo ha probado, contiene un error de sintaxis.
John Machin
4
El clásico truco en este escenario es qué hacer con las personas nacidas el 29 de febrero. Ejemplo: debe tener 18 años para votar, conducir un automóvil, comprar alcohol, etc. Si nace el 29/02/2004, ¿cuál es el primer día en que se le permite hacer estas cosas? 2022-02 -28 o 2022-03-01? AFAICT, principalmente el primero, pero algunos killjoys podrían decir el último.
Aquí hay un código que atiende al 0.068% (aprox.) De la población nacida ese día:
No use Django's |timesincepara calcular un timedelta durante varios años porque no tiene en cuenta los años bisiestos y, por lo tanto, produce resultados inexactos. Vea el boleto Django # 19210 para más información sobre esto.
jnns
No lo sabia. Gracias.
Anoyz
2
Aquí hay una solución para encontrar la edad de una persona, ya sea en años, meses o días.
Digamos que la fecha de nacimiento de una persona es 2012-01-17T00: 00: 00
Por lo tanto, su edad en 2013-01-16T00: 00: 00 será 11 meses
o si nació el 2012-12-17T00: 00: 00 , su edad el 2013-01-12T00: 00: 00 será 26 días
o si nació el 2000-02-29T00: 00: 00 , su edad el 2012-02-29T00: 00: 00 será 12 años
Deberá importar fecha y hora .
Aquí está el código:
def get_person_age(date_birth, date_today):"""
At top level there are three possibilities : Age can be in days or months or years.
For age to be in years there are two cases: Year difference is one or Year difference is more than 1
For age to be in months there are two cases: Year difference is 0 or 1
For age to be in days there are 4 possibilities: Year difference is 1(20-dec-2012 - 2-jan-2013),
Year difference is 0, Months difference is 0 or 1
"""
years_diff = date_today.year - date_birth.year
months_diff = date_today.month - date_birth.month
days_diff = date_today.day - date_birth.day
age_in_days =(date_today - date_birth).days
age = years_diff
age_string = str(age)+" years"# age can be in months or days.if years_diff ==0:if months_diff ==0:
age = age_in_days
age_string = str(age)+" days"elif months_diff ==1:if days_diff <0:
age = age_in_days
age_string = str(age)+" days"else:
age = months_diff
age_string = str(age)+" months"else:if days_diff <0:
age = months_diff -1else:
age = months_diff
age_string = str(age)+" months"# age can be in years, months or days.elif years_diff ==1:if months_diff <0:
age = months_diff +12
age_string = str(age)+" months"if age ==1:if days_diff <0:
age = age_in_days
age_string = str(age)+" days"elif days_diff <0:
age = age-1
age_string = str(age)+" months"elif months_diff ==0:if days_diff <0:
age =11
age_string = str(age)+" months"else:
age =1
age_string = str(age)+" years"else:
age =1
age_string = str(age)+" years"# The age is guaranteed to be in years.else:if months_diff <0:
age = years_diff -1elif months_diff ==0:if days_diff <0:
age = years_diff -1else:
age = years_diff
else:
age = years_diff
age_string = str(age)+" years"if age ==1:
age_string = age_string.replace("years","year").replace("months","month").replace("days","day")return age_string
Algunas funciones adicionales utilizadas en los códigos anteriores son:
def get_todays_date():"""
This function returns todays date in proper date object format
"""return datetime.now()
Y
def get_date_format(str_date):"""
This function converts string into date type object
"""
str_date = str_date.split("T")[0]return datetime.strptime(str_date,"%Y-%m-%d")
Ahora, tenemos que alimentar get_date_format () con las cadenas como 2000-02-29T00: 00: 00
Lo convertirá en el objeto de tipo de fecha que se alimentará a get_person_age (date_birth, date_today) .
La función get_person_age (date_birth, date_today) devolverá la edad en formato de cadena.
Ampliando la solución de Danny , pero con todo tipo de formas de informar edades para personas más jóvenes (nota, hoy es datetime.date(2015,7,17)):
def calculate_age(born):'''
Converts a date of birth (dob) datetime object to years, always rounding down.
When the age is 80 years or more, just report that the age is 80 years or more.
When the age is less than 12 years, rounds down to the nearest half year.
When the age is less than 2 years, reports age in months, rounded down.
When the age is less than 6 months, reports the age in weeks, rounded down.
When the age is less than 2 weeks, reports the age in days.
'''
today = datetime.date.today()
age_in_years = today.year - born.year -((today.month, today.day)<(born.month, born.day))
months =(today.month - born.month -(today.day < born.day))%12
age = today - born
age_in_days = age.days
if age_in_years >=80:return80,'years or older'if age_in_years >=12:return age_in_years,'years'elif age_in_years >=2:
half ='and a half 'if months >6else''return age_in_years,'%syears'%half
elif months >=6:return months,'months'elif age_in_days >=14:return age_in_days/7,'weeks'else:return age_in_days,'days'
Código de muestra:
print'%d %s'%calculate_age(datetime.date(1933,6,12))# >=80 yearsprint'%d %s'%calculate_age(datetime.date(1963,6,12))# >=12 yearsprint'%d %s'%calculate_age(datetime.date(2010,6,19))# >=2 yearsprint'%d %s'%calculate_age(datetime.date(2010,11,19))# >=2 years with halfprint'%d %s'%calculate_age(datetime.date(2014,11,19))# >=6 monthsprint'%d %s'%calculate_age(datetime.date(2015,6,4))# >=2 weeksprint'%d %s'%calculate_age(datetime.date(2015,7,11))# days old80 years or older
52 years
5 years
4and a half years
7 months
6 weeks
7 days
Como no vi la implementación correcta, recodifiqué la mía de esta manera ...
def age_in_years(from_date, to_date=datetime.date.today()):if(DEBUG):
logger.debug("def age_in_years(from_date='%s', to_date='%s')"%(from_date, to_date))if(from_date>to_date):# swap when the lower bound is not the lower bound
logger.debug('Swapping dates ...')
tmp = from_date
from_date = to_date
to_date = tmp
age_delta = to_date.year - from_date.year
month_delta = to_date.month - from_date.month
day_delta = to_date.day - from_date.day
if(DEBUG):
logger.debug("Delta's are : %i / %i / %i "%(age_delta, month_delta, day_delta))if(month_delta>0or(month_delta==0and day_delta>=0)):return age_delta
return(age_delta-1)
La suposición de ser "18" el 28 de febrero cuando nació el 29 es simplemente errónea. Intercambiar los límites se puede omitir ... es solo una conveniencia personal para mi código :)
La solución de Danny ligeramente modificada para facilitar la lectura y comprensión
from datetime import date
def calculate_age(birth_date):
today = date.today()
age = today.year - birth_date.year
full_year_passed =(today.month, today.day)<(birth_date.month, birth_date.day)ifnot full_year_passed:
age -=1return age
datetime
módulo estándar no es suficiente, puede intentar: labix.org/python-dateutildateutil.relativedelta.relativedelta
Respuestas:
Eso se puede hacer mucho más simple considerando que int (True) es 1 e int (False) es 0:
fuente
date.today()
devuelve la fecha en la zona horaria local que puede ser diferente del lugar de nacimiento. Es posible que necesite usar zonas horarias explícitamenteActualización: use la solución de Danny , es mejor
fuente
except
bloqueo debe detectar solo una excepción específica que podría generarse.ValueError
. Actualizado.def calculate_age(dob)
datetime.date(2014, 1, 1)
da -1, debería dar 0. Tutoday > dob
está comprobando si el DOB está en el pasado, no a principios de este mismo año.datetime.date.today()
incluye información del año, por lo que lo reemplazo con el año actual en mi solución.En Python 3, puede realizar la división en
datetime.timedelta
:fuente
365.25
) y el año calendario gregoriano (365.2425
) es menos de un día si vives menos de 130 años.(date(2017, 3, 1) - date(2004, 3, 1)) / timedelta(days=365.2425)
debería regresar13
, pero regresa12
. Sin piso, el resultado es12.999582469181433
.Según lo sugerido por @ [Tomasz Zielinski] y @Williams python-dateutil pueden hacerlo solo 5 líneas.
fuente
La forma más simple es usar
python-dateutil
fuente
fuente
Desafortunadamente, no puede simplemente usar timedelata ya que la unidad más grande que usa es el día y los años bisiestos harán que sus cálculos no sean válidos. Por lo tanto, busquemos el número de años y luego ajustemos por uno si el último año no está lleno:
Upd:
Esta solución realmente causa una excepción cuando entra en juego el 29 de febrero. Aquí está la verificación correcta:
Upd2:
Llamar varias llamadas a
now()
un éxito en el rendimiento es ridículo, no importa en todos, sino en casos extremadamente especiales. La verdadera razón para usar una variable es el riesgo de incosistencia de datos.fuente
El clásico truco en este escenario es qué hacer con las personas nacidas el 29 de febrero. Ejemplo: debe tener 18 años para votar, conducir un automóvil, comprar alcohol, etc. Si nace el 29/02/2004, ¿cuál es el primer día en que se le permite hacer estas cosas? 2022-02 -28 o 2022-03-01? AFAICT, principalmente el primero, pero algunos killjoys podrían decir el último.
Aquí hay un código que atiende al 0.068% (aprox.) De la población nacida ese día:
Aquí está la salida:
fuente
Si está buscando imprimir esto en una página usando plantillas de django, entonces lo siguiente podría ser suficiente:
fuente
|timesince
para calcular un timedelta durante varios años porque no tiene en cuenta los años bisiestos y, por lo tanto, produce resultados inexactos. Vea el boleto Django # 19210 para más información sobre esto.Aquí hay una solución para encontrar la edad de una persona, ya sea en años, meses o días.
Digamos que la fecha de nacimiento de una persona es 2012-01-17T00: 00: 00 Por lo tanto, su edad en 2013-01-16T00: 00: 00 será 11 meses
o si nació el 2012-12-17T00: 00: 00 , su edad el 2013-01-12T00: 00: 00 será 26 días
o si nació el 2000-02-29T00: 00: 00 , su edad el 2012-02-29T00: 00: 00 será 12 años
Deberá importar fecha y hora .
Aquí está el código:
Algunas funciones adicionales utilizadas en los códigos anteriores son:
Y
Ahora, tenemos que alimentar get_date_format () con las cadenas como 2000-02-29T00: 00: 00
Lo convertirá en el objeto de tipo de fecha que se alimentará a get_person_age (date_birth, date_today) .
La función get_person_age (date_birth, date_today) devolverá la edad en formato de cadena.
fuente
Ampliando la solución de Danny , pero con todo tipo de formas de informar edades para personas más jóvenes (nota, hoy es
datetime.date(2015,7,17)
):Código de muestra:
fuente
Como no vi la implementación correcta, recodifiqué la mía de esta manera ...
La suposición de ser "18" el 28 de febrero cuando nació el 29 es simplemente errónea. Intercambiar los límites se puede omitir ... es solo una conveniencia personal para mi código :)
fuente
Extienda a Danny W. Adair Respuesta , para obtener mes también
fuente
Fecha
Tu fecha de nacimiento
Tu edad
fuente
fecha y hora de importación
En tu caso:
fuente
La solución de Danny ligeramente modificada para facilitar la lectura y comprensión
fuente