Como posso encontrar uma idade em python a partir da data de hoje e a data de nascimento de uma pessoa? A data de nascimento é a partir de um DateField em um modelo do Django.
um nitpick: date.today()retorna a data no fuso horário local que pode ser diferente do local de nascimento. Você pode precisar usar fusos horários explicitamente
jfs
10
Isso provavelmente depende da sua definição de "idade". Para todos os fins práticos, geralmente um aniversário é dado como uma data, e não no horário e no horário do fuso horário (ou seja, "nascido" está faltando os detalhes). A maioria das pessoas não nasce à meia-noite em ponto (geralmente observam prematuramente :-)) e, quando em um fuso horário diferente, eu suponho que a maioria das pessoas observa seu aniversário na hora local (é isso que eu faço, vivo 10 a 12 horas à frente) do meu local de nascimento). Se "nascido" fosse um datetime com reconhecimento de fuso horário, você poderia usar a aritmética de pytz e normalizar () - talvez de interesse para um software de astrologia?
Danny W. Adair
2
Concordo plenamente no contexto da era humana, mas sua fórmula pode ser usada em um contexto mais amplo. Embora eu pessoalmente nunca comemore meu aniversário nem uma hora antes, devido a uma tradição familiar e como programador, é trivial calcular o tempo onde quer que eu esteja.
JFS
@pyd: nascido é uma data / 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
Por uma questão de princípio, seu exceptbloco deve capturar apenas a única exceção específica que pode ser gerada.
Daenyth
1
@ Daenyth: Boa ligação ... Eu acho que é uma ValueError. Atualizada.
MPEN
Chego ao ponto de testar a mensagem da exceção para garantir que é o que estou esperando. Mesmo com o código acima, existe a possibilidade de um ValueError ser lançado, mas não é o ValueError que você está esperando.
Randy Syring
+ por exceção, mas, existe algum problema no meu ? Eu acho que é bem simples. def calculate_age(dob)
Grijesh Chauhan
1
@GrijeshChauhan: Sim, o seu não funciona. datetime.date(2014, 1, 1)dá -1, deve dar 0. Você today > dobestá verificando se o DOB está no passado, não no início deste mesmo ano. datetime.date.today()inclui informações de ano, e é por isso que a substituo pelo ano atual em minha solução.
MPEN
18
from datetime import date
days_in_year =365.2425
age = int((date.today()- birth_date).days / days_in_year)
No Python 3, você pode executar a divisão em datetime.timedelta:
from datetime import date, timedelta
age =(date.today()- birth_date)// timedelta(days=365.2425)
todo quarto ano é um ano bissexto, exceto oitocentos anos, não é um ano bissexto, exceto que todo quatrocentos anos é um ano bissexto. tente days_in_year = 365.2425
Dan
3
@ Dan: a diferença entre o 365.25ano civil juliano ( ) e gregoriano ( 365.2425) é inferior a um dia se você vive menos de 130 anos.
JFS
4
Isso não funciona em algumas datas: (date(2017, 3, 1) - date(2004, 3, 1)) / timedelta(days=365.2425)deve retornar 13, mas retorna 12. Sem piso, o resultado é 12.999582469181433.
href_
13
Conforme sugerido por @ [Tomasz Zielinski] e @Williams python-dateutil, é possível fazer apenas 5 linhas.
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
Isso não funciona corretamente quando o aniversário é 29 de fevereiro e a data de hoje é 28 de fevereiro (agirá como se hoje fosse 29 de fevereiro).
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
date instance ou algum objeto como esse, docs.python.org/3/library/datetime.html#datetime.date, erro de digitação corrigido.
Gzerone 12/11
5
Infelizmente, você não pode simplesmente usar os dados de tempo, pois a maior unidade usada por dia e anos bissextos invalida seus cálculos. Portanto, vamos encontrar o número de anos e ajustar em um se o último ano não estiver cheio:
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 solução realmente causa uma exceção quando 29 de fevereiro entra em jogo. Aqui está a verificação correta:
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:
Fazer várias chamadas para now()uma ocorrência de desempenho é ridículo, isso não importa em todos, exceto em casos extremamente especiais. O verdadeiro motivo para usar uma variável é o risco de incosistência dos dados.
Obrigado, eu descobri isso fazendo alguns testes - e acabei com um código semelhante encontrado no link do AndiDog.
precisa saber é o seguinte
3
Greve 1: você está usando datetime.datetime em vez de datetime.date. Greve 2: seu código é feio e ineficiente. Chamando datetime.now () TRÊS vezes ?? Greve 3: data de nascimento em 29 de fevereiro de 2004 e data de hoje em 28 de fevereiro de 2010 deve retornar a idade de 6 anos, não morrer gritando "ValueError: o dia está fora do intervalo por mês". Você está fora!
John Machin
Desculpe, seu código "Upd" é ainda mais barroco e quebrado do que a primeira tentativa - nada a ver com 29 de fevereiro; ele falha em MUITOS casos simples, como 15/06/2009 a 02/07/2010 ... obviamente a pessoa tem pouco mais de 1 ano, mas você deduz um ano porque o teste nos dias (2> = 15) falha. E, obviamente, você não o testou - ele contém um erro de sintaxe.
John Machin
4
A pegadinha clássica nesse cenário é o que fazer com as pessoas nascidas no dia 29 de fevereiro. Exemplo: você precisa ter 18 anos para votar, dirigir um carro, comprar álcool, etc ... se você nasceu em 29-02-2004, qual é o primeiro dia em que você pode fazer isso: 2022-02 -28 ou 2022-03-01? AFAICT, principalmente o primeiro, mas alguns killjoys podem dizer o último.
Aqui está o código que atende a 0,068% (aproximadamente) da população nascida naquele dia:
Não use o Django |timesincepara calcular um intervalo de tempo ao longo de vários anos, porque ele não conta anos bissextos e, portanto, produz resultados imprecisos. Veja o ticket do Django nº 19210 para mais informações sobre isso.
jnns
Não sabia disso. Obrigado.
Anoyz
2
Aqui está uma solução para encontrar a idade de uma pessoa em anos, meses ou dias.
Digamos que a data de nascimento de uma pessoa seja 2012-01-17T00: 00: 00
Portanto, sua idade em 2013-01-16T00: 00: 00 será de 11 meses
ou se ele nasceu em 2012-12-17T00: 00: 00 , sua idade em 2013-01-12T00: 00: 00 será de 26 dias
ou se ele nasceu em 2000-02-29T00: 00: 00 , sua idade em 2012-02-29T00: 00: 00 será de 12 anos
Você precisará importar data e hora .
Aqui está o 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
Algumas funções extras usadas nos códigos acima são:
def get_todays_date():"""
This function returns todays date in proper date object format
"""return datetime.now()
E
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")
Agora, temos que alimentar get_date_format () com as strings como 2000-02-29T00: 00: 00
Ele será convertido no objeto de tipo de data que será alimentado em get_person_age (date_birth, date_today) .
A função get_person_age (date_birth, date_today) retornará idade no formato de string.
Expandindo a solução de Danny , mas com todo tipo de formas de relatar idades para pessoas mais jovens (observe que hoje é 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 amostra:
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 não vi a implementação correta, recodifiquei a minha dessa maneira ...
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)
A suposição de ter 18 anos no dia 28 de fevereiro, quando nasceu no dia 29, está errada. Trocar os limites pode ser deixado de fora ... é apenas uma conveniência pessoal para o meu código :)
Solução Danny ligeiramente modificada para facilitar a leitura e a compreensão
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 padrão não é suficiente, você pode tentar: labix.org/python-dateutildateutil.relativedelta.relativedelta
Respostas:
Isso pode ser muito mais simples, considerando que int (True) é 1 e int (False) é 0:
fonte
date.today()
retorna a data no fuso horário local que pode ser diferente do local de nascimento. Você pode precisar usar fusos horários explicitamenteAtualização: use a solução de Danny , é melhor
fonte
except
bloco deve capturar apenas a única exceção específica que pode ser gerada.ValueError
. Atualizada.def calculate_age(dob)
datetime.date(2014, 1, 1)
dá -1, deve dar 0. Vocêtoday > dob
está verificando se o DOB está no passado, não no início deste mesmo ano.datetime.date.today()
inclui informações de ano, e é por isso que a substituo pelo ano atual em minha solução.No Python 3, você pode executar a divisão em
datetime.timedelta
:fonte
365.25
ano civil juliano ( ) e gregoriano (365.2425
) é inferior a um dia se você vive menos de 130 anos.(date(2017, 3, 1) - date(2004, 3, 1)) / timedelta(days=365.2425)
deve retornar13
, mas retorna12
. Sem piso, o resultado é12.999582469181433
.Conforme sugerido por @ [Tomasz Zielinski] e @Williams python-dateutil, é possível fazer apenas 5 linhas.
fonte
A maneira mais simples é usar
python-dateutil
fonte
fonte
Infelizmente, você não pode simplesmente usar os dados de tempo, pois a maior unidade usada por dia e anos bissextos invalida seus cálculos. Portanto, vamos encontrar o número de anos e ajustar em um se o último ano não estiver cheio:
Upd:
Esta solução realmente causa uma exceção quando 29 de fevereiro entra em jogo. Aqui está a verificação correta:
Upd2:
Fazer várias chamadas para
now()
uma ocorrência de desempenho é ridículo, isso não importa em todos, exceto em casos extremamente especiais. O verdadeiro motivo para usar uma variável é o risco de incosistência dos dados.fonte
A pegadinha clássica nesse cenário é o que fazer com as pessoas nascidas no dia 29 de fevereiro. Exemplo: você precisa ter 18 anos para votar, dirigir um carro, comprar álcool, etc ... se você nasceu em 29-02-2004, qual é o primeiro dia em que você pode fazer isso: 2022-02 -28 ou 2022-03-01? AFAICT, principalmente o primeiro, mas alguns killjoys podem dizer o último.
Aqui está o código que atende a 0,068% (aproximadamente) da população nascida naquele dia:
Aqui está a saída:
fonte
Se você deseja imprimir isso em uma página usando modelos de django, o seguinte pode ser suficiente:
fonte
|timesince
para calcular um intervalo de tempo ao longo de vários anos, porque ele não conta anos bissextos e, portanto, produz resultados imprecisos. Veja o ticket do Django nº 19210 para mais informações sobre isso.Aqui está uma solução para encontrar a idade de uma pessoa em anos, meses ou dias.
Digamos que a data de nascimento de uma pessoa seja 2012-01-17T00: 00: 00 Portanto, sua idade em 2013-01-16T00: 00: 00 será de 11 meses
ou se ele nasceu em 2012-12-17T00: 00: 00 , sua idade em 2013-01-12T00: 00: 00 será de 26 dias
ou se ele nasceu em 2000-02-29T00: 00: 00 , sua idade em 2012-02-29T00: 00: 00 será de 12 anos
Você precisará importar data e hora .
Aqui está o código:
Algumas funções extras usadas nos códigos acima são:
E
Agora, temos que alimentar get_date_format () com as strings como 2000-02-29T00: 00: 00
Ele será convertido no objeto de tipo de data que será alimentado em get_person_age (date_birth, date_today) .
A função get_person_age (date_birth, date_today) retornará idade no formato de string.
fonte
Expandindo a solução de Danny , mas com todo tipo de formas de relatar idades para pessoas mais jovens (observe que hoje é
datetime.date(2015,7,17)
):Código de amostra:
fonte
Como não vi a implementação correta, recodifiquei a minha dessa maneira ...
A suposição de ter 18 anos no dia 28 de fevereiro, quando nasceu no dia 29, está errada. Trocar os limites pode ser deixado de fora ... é apenas uma conveniência pessoal para o meu código :)
fonte
Estenda para Danny W. Adair Answer , para obter o mês também
fonte
Data de hoje
Sua data de nascimento
Sua idade
fonte
data e hora da importação
No seu caso:
fonte
Solução Danny ligeiramente modificada para facilitar a leitura e a compreensão
fonte