Usando Date
, é complicado mesmo, porque a API antiga não fornece mecanismos adequados para cálculos com datas.
O ideal hoje em dia é usar a nova API java.time
, como já indicado acima. Esta API está disponível desde o Java 8 (março de 2014), então a menos que vc esteja mexendo em código legado que ainda depende de java.util.Date
, não há motivo para continuar sofrendo
Enfim, se quer mesmo continuar usando Date
, tem que fazer tudo na mão. E como vc faz o cálculo manualmente? Basicamente:
- subtrai o ano atual do ano de nascimento
- se ainda não chegou o aniversário, subtrai 1
Algo assim:
Date dataNascimento = // alguma data de nascimento qualquer
Calendar nasc = Calendar.getInstance();
nasc.setTime(dataNascimento);
// data atual
Calendar hoje = Calendar.getInstance();
int idade = hoje.get(Calendar.YEAR) - nasc.get(Calendar.YEAR);;
int mesAtual = hoje.get(Calendar.MONTH);
int mesNasc = nasc.get(Calendar.MONTH);
if (mesNasc > mesAtual) { // se o mês do aniversário ainda não chegou
idade--;
} else if (mesAtual == mesNasc) {
// é o mês do aniversário, mas o dia ainda não chegou
if (nasc.get(Calendar.DAY_OF_MONTH) > hoje.get(Calendar.DAY_OF_MONTH)) {
idade--;
}
}
System.out.printf("Idade=%d anos\n", idade);
Ou ainda, colocando todas as condições em um único if
:
int idade = hoje.get(Calendar.YEAR) - nasc.get(Calendar.YEAR);
int mesAtual = hoje.get(Calendar.MONTH);
int mesNasc = nasc.get(Calendar.MONTH);
if ((mesNasc > mesAtual) || (mesAtual == mesNasc && nasc.get(Calendar.DAY_OF_MONTH) > hoje.get(Calendar.DAY_OF_MONTH))) {
idade--;
}
Usando java.time
Com java.time
, é muito mais simples. Mas em vez de Date
, vc vai ter que usar as novas classes. No caso de data de nascimento, geralmente usa-se somente o dia, mês e ano, então a classe mais adequada é java.time.LocalDate
.
Se vc só quer o valor numérico da idade em anos, basta usar um java.time.temporal.ChronoUnit
:
LocalDate nascimento = LocalDate.of(2000, 2, 21);
LocalDate hoje = LocalDate.now();
long idade = ChronoUnit.YEARS.between(nascimento, hoje);
System.out.printf("Idade=%d anos\n", idade);
Se quer a idade quebrada em campos (anos, meses e dias), pode usar Period
como já indicado:
LocalDate nascimento = LocalDate.of(2000, 2, 21);
LocalDate hoje = LocalDate.now();
Period idade = Period.between(nascimento, hoje);
System.out.printf("idade=%d anos, %d meses, %d dias\n", idade.getYears(), idade.getMonths(), idade.getDays());
Só um detalhe, e se alguém nasceu em 29 de fevereiro?
// nasceu em 29 de fevereiro de 2000
LocalDate nascimento = LocalDate.of(2000, 2, 29);
// em 28 de fevereiro de 2001, qual será a idade?
LocalDate hoje = LocalDate.of(2001, 2, 28);
Period idade = Period.between(nascimento, hoje);
System.out.printf("idade=%d anos, %d meses, %d dias\n", idade.getYears(), idade.getMonths(), idade.getDays());
No exemplo acima, a data de nascimento é 29 de fevereiro de 2000. Nesse caso, em 28 de fevereiro de 2001, qual será a idade?
O resultado do código acima é idade=0 anos, 11 meses, 30 dias
. Isso porque a API entende que só completa-se 1 ano a partir do dia 29 de fevereiro. Mas como 2001 não é bissexto, então somente a partir de 1 de março de 2001 é que se completaria 1 ano.
Este é um corner case que precisa ser pensado caso a caso. Conheço pessoas que nasceram em 29 de fevereiro, e em anos não bissextos comemoram em 1 de março. Mas isso não quer dizer que seja uma regra universal. Aliás, nem sequer existe: aritmética de datas não tem definições precisas e oficiais como é na matemática, então cabe a vc decidir o que fazer nestes casos.