o que todas as respostas até o momento não entenderam é que depende de onde a pessoa nasceu e de onde está agora.
Yaur
40
@Yaur: Basta converter a hora do agora + nascimento em GMT / UTC, a idade é apenas um valor relativo, portanto, os fusos horários são irrelevantes. Para determinar o fuso horário atual do usuário, você pode usar o GeoLocating.
Se estivermos levando em consideração a sugestão de @Yaur de cálculos de fuso horário, o horário de verão deve afetar o cálculo de alguma maneira?
DDM
6
Voto negativo porque esta é claramente uma pergunta de lição de casa e nenhuma tentativa existente foi fornecida.
677 Marie
Respostas:
2122
Uma solução fácil de entender e simples.
// Save today's date.var today =DateTime.Today;// Calculate the age.var age = today.Year- birthdate.Year;// Go back to the year the person was born in case of a leap yearif(birthdate.Date> today.AddYears(-age)) age--;
No entanto, isso pressupõe que você esteja procurando a idéia ocidental de idade e não esteja usando o cálculo da Ásia Oriental .
Só queria comentar sobre o desempenho do DateTime.Now. Se você não precisar de um valor preciso de fuso horário, use DateTime.UtcNow, é muito mais rápido.
JAG
104
Dado que estamos falando de aniversários, você pode simplesmente usar DateTime. Hoje, uma vez que a parte do tempo não tem relevância.
24511 Tristan Warner-Smith
78
Esta resposta não funciona com todos os locais e todas as idades. Vários países pularam datas após o nascimento das pessoas que vivem atualmente, incluindo Rússia (1918), Grécia (1924) e Turquia (1926).
Lars D
30
Na verdade, ainda não está totalmente correto. Esse código presume que 'bday' é a parte da data de um DateTime. É um caso extremo (acho que a maioria das pessoas passará datas e não datas e horários), mas se você passar o aniversário como uma data e hora em que a hora é maior que 00:00:00, então você ' Vou encontrar o bug que Danvil apontou. Definir bday = bday.Date corrige isso.
Øyvind
119
A última linha me fez pensar demais. Em vez disso, que tal: if (bday.AddYears (age)> now) age--; Esta parece ser uma expressão mais intuitiva.
Cdggins
1015
Essa é uma maneira estranha de fazê-lo, mas se você formatar a data yyyymmdde subtrair a data de nascimento da data atual, solte os últimos 4 dígitos da idade :)
Não sei c #, mas acredito que isso funcione em qualquer idioma.
20080814-19800703=280111
Solte os últimos 4 dígitos 28.
Código C #:
int now =int.Parse(DateTime.Now.ToString("yyyyMMdd"));int dob =int.Parse(dateOfBirth.ToString("yyyyMMdd"));int age =(now - dob)/10000;
Ou, alternativamente, sem toda a conversão de tipo na forma de um método de extensão. Verificação de erro omitida:
publicstaticInt32GetAge(thisDateTime dateOfBirth){var today =DateTime.Today;var a =(today.Year*100+ today.Month)*100+ today.Day;var b =(dateOfBirth.Year*100+ dateOfBirth.Month)*100+ dateOfBirth.Day;return(a - b)/10000;}
Na verdade, esta é excelente para utilização em MS-SQL com datetime-campos (total de dias desde 01-011900)
Patrik
5
@ numerek Por favor, poste suas modificações sugeridas como sua própria resposta. Pelo que vale, o ano atual em 10000 não chega nem perto de um estouro inteiro, em duas ordens de magnitude. 20150000 2147483648 vs
GalacticCowboy
7
@LongChalk 20180101 - 20171231 = 8870. Solte os últimos 4 dígitos e você terá (um implícito) 0para a idade. Como você conseguiu 1?
Rufus L
4
Sei que essa é uma resposta antiga, mas não usaria um método de extensão, não é o lugar certo para definir essas lógicas.
Enquanto esse código funciona, ele afirma que uma pessoa nascida em um dia bissexto atinge o próximo ano de idade em 1º de março em anos não bissextos, em vez de em 28 de fevereiro. Na realidade, qualquer uma das opções pode estar correta . A Wikipedia tem algo a dizer sobre isso . Portanto, embora seu código não esteja "errado", a solução aceita também não.
Matt Johnson-Pint
18
@ MattJohnson Eu acho que isso é realmente correto. Se meu aniversário era 29 de fevereiro, então 28 de fevereiro ainda não havia passado, e eu ainda deveria ter a mesma idade que 27 de fevereiro. No entanto, em 1º de março, passamos o meu aniversário e eu devo ter a próxima idade. Nos EUA, uma empresa que vende álcool terá uma placa que diz algo como "Se você nasceu depois deste dia em AAAA, não pode comprar álcool" (onde AAAA muda todos os anos). Isso significa que alguém nascido em 29 de fevereiro não podem comprar álcool em 28 de fevereiro no ano em que completar 21 (a maioria dos lugares), e dá suporte à idéia de que eles não são um ano mais velho até março 1.
jfren484
4
@ jfren484 - leia o artigo da Wikipedia. Varia consideravelmente entre jurisdições.
Matt Johnson-Pint
9
@ jfren484 Sua reivindicação não tem absolutamente nada a ver com filosofia; mas tudo a ver com o seu próprio sentimento pessoal . Quando uma pessoa nascida em 29 de fevereiro "envelhece" não tem importância, a menos que a idade constitua um 'limite de idade legal' (por exemplo, pode comprar álcool, votar, obter pensão, ingressar no exército, obter carteira de motorista). Considere a idade de beber nos EUA (21 anos): para a maioria das pessoas, isso corresponde a 7670 dias. São 7671 dias se nascermos antes de 29 de fevereiro no ano bissexto ou a partir de 1 de março antes do ano bissexto. Se nascido em 29 de fevereiro: 28 de fevereiro é 7670 dias e 1 de março é 7671 dias. A escolha é arbitrária , pode ser de qualquer maneira.
desiludido
4
@ CraigYoung Você não entende o que eu quis dizer com filosoficamente. Eu usei esse termo como um contraste legalmente. Se alguém está escrevendo um aplicativo que precisa saber a idade legal de uma pessoa, tudo o que eles precisam saber é como as jurisdições legais em que seu aplicativo é usado / tratam as pessoas nascidas em 29 de fevereiro. Se, no entanto, estamos falando sobre como isso deve ser tratado, então isso é por definição, filosofia. E sim, a opinião que eu dei é a minha própria opinião, mas como eu disse, eu acho que seria mais fácil para defender primeiro marco do que seria para fevereiro 28.
jfren484
110
A resposta simples para isso é aplicar AddYearscomo mostrado abaixo, porque este é o único método nativo para adicionar anos ao dia 29 de fevereiro dos anos bissextos e obter o resultado correto do dia 28 de fevereiro para os anos comuns.
Alguns acham que 1º de março é o aniversário dos pulos, mas nem o .Net nem nenhuma regra oficial apóiam isso, nem a lógica comum explica por que alguns nascidos em fevereiro devem ter 75% de seus aniversários em outro mês.
Além disso, um método Age se presta a ser adicionado como uma extensão para DateTime. Com isso, você pode obter a idade da maneira mais simples possível:
Item da lista
int idade = birthDate.Age ();
publicstaticclassDateTimeExtensions{/// <summary>/// Calculates the age in years of the current System.DateTime object today./// </summary>/// <param name="birthDate">The date of birth</param>/// <returns>Age in years today. 0 is returned for a future date of birth.</returns>publicstaticintAge(thisDateTime birthDate){returnAge(birthDate,DateTime.Today);}/// <summary>/// Calculates the age in years of the current System.DateTime object on a later date./// </summary>/// <param name="birthDate">The date of birth</param>/// <param name="laterDate">The date on which to calculate the age.</param>/// <returns>Age in years on a later day. 0 is returned as minimum.</returns>publicstaticintAge(thisDateTime birthDate,DateTime laterDate){int age;
age = laterDate.Year- birthDate.Year;if(age >0){
age -=Convert.ToInt32(laterDate.Date< birthDate.Date.AddYears(age));}else{
age =0;}return age;}}
Agora, execute este teste:
classProgram{staticvoidMain(string[] args){RunTest();}privatestaticvoidRunTest(){DateTime birthDate =newDateTime(2000,2,28);DateTime laterDate =newDateTime(2011,2,27);string iso ="yyyy-MM-dd";for(int i =0; i <3; i++){for(int j =0; j <3; j++){Console.WriteLine("Birth date: "+ birthDate.AddDays(i).ToString(iso)+" Later date: "+ laterDate.AddDays(j).ToString(iso)+" Age: "+ birthDate.AddDays(i).Age(laterDate.AddDays(j)).ToString());}}Console.ReadKey();}}
O exemplo da data crítica é este:
Data de nascimento: 2000-02-29 Data posterior: 2011-02-28 Idade: 11
Um comentário sobre o aniversário de 29 de fevereiro no dia 1º de março, tecnicamente, no dia 28 de fevereiro é muito cedo (um dia antes). No dia 1 é tarde demais. Mas como o aniversário termina, usar o 1º para calcular a idade em anos não bissextos faz mais sentido para mim, pois essa pessoa é realmente tão velha em 1º de março (e 2º e 3º) todos os anos, mas não em 28 de fevereiro.
24418 CyberClaw
1
Do ponto de vista do design de software, escrever isso como um método de extensão não faz muito sentido para mim. date.Age(other)?
Marsze # 12/18
90
Minha sugestão
int age =(int)((DateTime.Now- bday).TotalDays/365.242199);
Parece que o ano está mudando na data certa. (Eu testei até 107 anos de idade.)
A duração média de um ano no calendário gregoriano é 365,2425 dias.
dan04
4
Eu diria que esta é uma das soluções mais simples e é boa o suficiente . Quem se importa se eu tenho meio dia antes do meu aniversário de X e o programa diz que eu tenho X anos? O programa está mais ou menos certo, embora não matematicamente. Eu realmente gosto desta solução.
Peter Perháč
13
^^ Porque às vezes é importante. Nos meus testes, isso falha no aniversário das pessoas, informa-as mais jovens do que são.
ChadT
76
Outra função, não por mim, mas encontrada na web e refinada um pouco:
publicstaticintGetAge(DateTime birthDate){DateTime n =DateTime.Now;// To avoid a race condition around midnightint age = n.Year- birthDate.Year;if(n.Month< birthDate.Month||(n.Month== birthDate.Month&& n.Day< birthDate.Day))
age--;return age;}
Apenas duas coisas que me vêm à cabeça: E as pessoas de países que não usam o calendário gregoriano? DateTime.Now está na cultura específica do servidor, eu acho. Não tenho absolutamente nenhum conhecimento sobre como trabalhar com calendários asiáticos e não sei se há uma maneira fácil de converter datas entre calendários, mas, caso você esteja se perguntando sobre os chineses do ano 4660 :-)
Isso parece lidar melhor com diferentes regiões (formatos de data).
precisa saber é o seguinte
53
2 Os principais problemas a serem resolvidos são:
1. Calcule a idade exata - em anos, meses, dias etc.
2. Calcular a idade geralmente percebida - as pessoas geralmente não se importam com a idade exata, apenas se importam com o aniversário do ano atual.
A solução para 1 é óbvia:
DateTime birth =DateTime.Parse("1.1.2000");DateTime today =DateTime.Today;//we usually don't care about birth timeTimeSpan age = today - birth;//.NET FCL should guarantee this as precisedouble ageInDays = age.TotalDays;//total number of days ... also precisedouble daysInYear =365.2425;//statistical value for 400 yearsdouble ageInYears = ageInDays / daysInYear;//can be shifted ... not so precise
A solução para 2 é a que não é tão precisa na determinação da idade total, mas é percebida como precisa pelas pessoas. As pessoas também costumam usá-lo, quando calculam sua idade "manualmente":
DateTime birth =DateTime.Parse("1.1.2000");DateTime today =DateTime.Today;int age = today.Year- birth.Year;//people perceive their age in yearsif(today.Month< birth.Month||((today.Month== birth.Month)&&(today.Day< birth.Day))){
age--;//birthday in current year not yet reached, we are 1 year younger ;)//+ no birthday for 29.2. guys ... sorry, just wrong date for birth}
Notas 2:
Esta é a minha solução preferida
Não podemos usar DateTime.DayOfYear ou TimeSpans, pois eles mudam o número de dias nos anos bissextos
Coloquei pouco mais linhas para facilitar a leitura
Apenas mais uma observação ... Eu criaria dois métodos estáticos sobrecarregados, um para uso universal e outro para facilidade de uso:
Isto está quebrado. Tornado testável: estático público int CalculateAge (DateTime dateOfBirth, DateTime dateToCalculateAge) {retorna novo DateTime (dateToCalculateAge.Subtract (dateOfBirth) .Ticks) .Year - 1; } ... Dá 14 anos quando insiro 1990-06-01 e calculo a idade no dia ANTES de seu 14º aniversário (31/05/1990).
precisa saber é o seguinte
43
Esta é a versão que usamos aqui. Funciona e é bastante simples. É a mesma ideia que a de Jeff, mas acho que é um pouco mais clara, porque separa a lógica de subtrair uma, por isso é um pouco mais fácil de entender.
Você pode expandir o operador ternário para torná-lo ainda mais claro, se achar que esse tipo de coisa não é clara.
Obviamente, isso é feito como um método de extensão DateTime, mas claramente você pode pegar aquela linha de código que faz o trabalho e colocá-la em qualquer lugar. Aqui temos outra sobrecarga do método Extension que passa DateTime.Now, apenas para ser completo.
Eu acho que isso pode ser desativado em um dia quando exatamente um dos dateOfBirth ou dateAsAt cair em um ano bissexto. Considere a idade de uma pessoa nascida em 1º de março de 2003 em 29 de fevereiro de 2004. Para corrigir isso, é necessário fazer uma comparação lexicográfica de pares (Month, DayOfMonth) e usá-la como condicional.
Doug McClean
1
também não mostrará a idade certa a partir do seu aniversário.
dotjoe
43
A melhor maneira que eu conheço por causa dos anos bissextos e tudo é:
DateTime birthDate =newDateTime(2000,3,1);int age =(int)Math.Floor((DateTime.Now- birthDate).TotalDays/365.25D);
Isso dá "mais detalhes" a esta pergunta. Talvez seja isso que você está procurando
DateTime birth =newDateTime(1974,8,29);DateTime today =DateTime.Now;TimeSpan span = today - birth;DateTime age =DateTime.MinValue+ span;// Make adjustment due to MinValue equalling 1/1/1int years = age.Year-1;int months = age.Month-1;int days = age.Day-1;// Print out not only how many years old they are but give months and days as wellConsole.Write("{0} years, {1} months, {2} days", years, months, days);
Isso não funciona o tempo todo. Adicionar um Span ao DateTime.MinValue poderia funcionar, isso não leva em consideração os anos bissextos, etc. Data agora.
Athanasios Kataras
3
O próprio período de tempo leva automaticamente em consideração os anos bissextos entre duas datas, então não tenho certeza do que você está falando. Eu perguntei nos fóruns da Microsoft e a Microsoft confirmou que leva em consideração os anos bissextos entre duas datas.
Jacqueline Loriault 23/10
2
Considere os DOIS senarios a seguir. 1 DateTime.Now é 1/1/2001 e uma criança nasce em 1/1/2000. 2000 é um ano bissexto e o resultado será 1 ano, 0 mês e 1 dia. No segundo senarion, DateTime.Now é 1/1/2002 e a criança nasce em 1/1/2001. Nesse caso, o resultado será de 1 ano, 0 meses e 0 dias. Isso acontecerá porque você está adicionando o período em um ano sem salto. Se DateTime.MinValue fosse um ano bissexto, os resultados seriam 1 ano no primeiro e 0 anos 11 meses e 30 dias. (Experimente no seu código).
Athanasios Kataras
1
Voto a favor! Eu vim com uma solução praticamente idêntica (usei DateTime.MinValue.AddTicks (span.Ticks) em vez de +, mas o resultado é o mesmo e o seu possui alguns caracteres a menos de código).
Makotosan
4
Você está certo, não é. Mas se fosse esse seria o resultado. Por que isso Importa? Não faz. Em ambos os casos, pule ou não, há exemplos em que isso não funciona. Era isso que eu queria mostrar. O DIFF está correto. O período leva em consideração os anos bissextos. Mas ADICIONAR a uma data base não é. Experimente os exemplos no código e você verá que estou certo.
Athanasios Kataras /
28
Eu criei uma Função Definida pelo Usuário do SQL Server para calcular a idade de alguém, dada a data de nascimento. Isso é útil quando você precisa dele como parte de uma consulta:
using System;
using System.Data;
using System.Data.Sql;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;publicpartialclassUserDefinedFunctions{[SqlFunction(DataAccess=DataAccessKind.Read)]publicstaticSqlInt32CalculateAge(string strBirthDate){DateTime dtBirthDate =newDateTime();
dtBirthDate =Convert.ToDateTime(strBirthDate);DateTime dtToday =DateTime.Now;// get the difference in yearsint years = dtToday.Year- dtBirthDate.Year;// subtract another year if we're before the// birth day in the current yearif(dtToday.Month< dtBirthDate.Month||(dtToday.Month== dtBirthDate.Month&& dtToday.Day< dtBirthDate.Day))
years=years-1;int intCustomerAge = years;return intCustomerAge;}};
Isso foi extensivamente testado por unidade. Parece um pouco "mágico". O número 372 é o número de dias que haveria em um ano se todos os meses tivessem 31 dias.
Eu me deparei com essa discussão longa e irritante, e sua solução é uma abordagem muito boa e pequena. Obrigado por mantê-lo simples
nabuchodonossor
25
Passei algum tempo trabalhando nisso e criei isso para calcular a idade de alguém em anos, meses e dias. Eu testei contra o problema de 29 de fevereiro e os anos bissextos e parece funcionar, eu gostaria de receber comentários:
publicvoidLoopAge(DateTime myDOB,DateTimeFutureDate){int years =0;int months =0;int days =0;DateTime tmpMyDOB =newDateTime(myDOB.Year, myDOB.Month,1);DateTime tmpFutureDate =newDateTime(FutureDate.Year,FutureDate.Month,1);while(tmpMyDOB.AddYears(years).AddMonths(months)< tmpFutureDate){
months++;if(months >12){
years++;
months = months -12;}}if(FutureDate.Day>= myDOB.Day){
days = days +FutureDate.Day- myDOB.Day;}else{
months--;if(months <0){
years--;
months = months +12;}
days +=DateTime.DaysInMonth(FutureDate.AddMonths(-1).Year,FutureDate.AddMonths(-1).Month)+FutureDate.Day- myDOB.Day;}//add an extra day if the dob is a leap dayif(DateTime.IsLeapYear(myDOB.Year)&& myDOB.Month==2&& myDOB.Day==29){//but only if the future date is less than 1st Marchif(FutureDate>=newDateTime(FutureDate.Year,3,1))
days++;}}
Precisamos considerar pessoas com menos de 1 ano? como cultura chinesa, descrevemos a idade dos bebês pequenos como 2 meses ou 4 semanas.
Abaixo está minha implementação, não é tão simples quanto eu imaginava, especialmente para lidar com datas como 2/28.
publicstaticstringHowOld(DateTime birthday,DateTime now){if(now < birthday)thrownewArgumentOutOfRangeException("birthday must be less than now.");TimeSpan diff = now - birthday;int diffDays =(int)diff.TotalDays;if(diffDays >7)//year, month and week{int age = now.Year- birthday.Year;if(birthday > now.AddYears(-age))
age--;if(age >0){return age +(age >1?" years":" year");}else{// month and weekDateTime d = birthday;int diffMonth =1;while(d.AddMonths(diffMonth)<= now){
diffMonth++;}
age = diffMonth-1;if(age ==1&& d.Day> now.Day)
age--;if(age >0){return age +(age >1?" months":" month");}else{
age = diffDays /7;return age +(age >1?" weeks":" week");}}}elseif(diffDays >0){int age = diffDays;return age +(age >1?" days":" day");}else{int age = diffDays;return"just born";}}
Esta implementação passou abaixo dos casos de teste.
[TestMethod]publicvoidTestAge(){string age =HowOld(newDateTime(2011,1,1),newDateTime(2012,11,30));Assert.AreEqual("1 year", age);
age =HowOld(newDateTime(2011,11,30),newDateTime(2012,11,30));Assert.AreEqual("1 year", age);
age =HowOld(newDateTime(2001,1,1),newDateTime(2012,11,30));Assert.AreEqual("11 years", age);
age =HowOld(newDateTime(2012,1,1),newDateTime(2012,11,30));Assert.AreEqual("10 months", age);
age =HowOld(newDateTime(2011,12,1),newDateTime(2012,11,30));Assert.AreEqual("11 months", age);
age =HowOld(newDateTime(2012,10,1),newDateTime(2012,11,30));Assert.AreEqual("1 month", age);
age =HowOld(newDateTime(2008,2,28),newDateTime(2009,2,28));Assert.AreEqual("1 year", age);
age =HowOld(newDateTime(2008,3,28),newDateTime(2009,2,28));Assert.AreEqual("11 months", age);
age =HowOld(newDateTime(2008,3,28),newDateTime(2009,3,28));Assert.AreEqual("1 year", age);
age =HowOld(newDateTime(2009,1,28),newDateTime(2009,2,28));Assert.AreEqual("1 month", age);
age =HowOld(newDateTime(2009,2,1),newDateTime(2009,3,1));Assert.AreEqual("1 month", age);// NOTE.// new DateTime(2008, 1, 31).AddMonths(1) == new DateTime(2009, 2, 28);// new DateTime(2008, 1, 28).AddMonths(1) == new DateTime(2009, 2, 28);
age =HowOld(newDateTime(2009,1,31),newDateTime(2009,2,28));Assert.AreEqual("4 weeks", age);
age =HowOld(newDateTime(2009,2,1),newDateTime(2009,2,28));Assert.AreEqual("3 weeks", age);
age =HowOld(newDateTime(2009,2,1),newDateTime(2009,3,1));Assert.AreEqual("1 month", age);
age =HowOld(newDateTime(2012,11,5),newDateTime(2012,11,30));Assert.AreEqual("3 weeks", age);
age =HowOld(newDateTime(2012,11,1),newDateTime(2012,11,30));Assert.AreEqual("4 weeks", age);
age =HowOld(newDateTime(2012,11,20),newDateTime(2012,11,30));Assert.AreEqual("1 week", age);
age =HowOld(newDateTime(2012,11,25),newDateTime(2012,11,30));Assert.AreEqual("5 days", age);
age =HowOld(newDateTime(2012,11,29),newDateTime(2012,11,30));Assert.AreEqual("1 day", age);
age =HowOld(newDateTime(2012,11,30),newDateTime(2012,11,30));Assert.AreEqual("just born", age);
age =HowOld(newDateTime(2000,2,29),newDateTime(2009,2,28));Assert.AreEqual("8 years", age);
age =HowOld(newDateTime(2000,2,29),newDateTime(2009,3,1));Assert.AreEqual("9 years", age);Exception e =null;try{
age =HowOld(newDateTime(2012,12,1),newDateTime(2012,11,30));}catch(ArgumentOutOfRangeException ex){
e = ex;}Assert.IsTrue(e !=null);}
O TimeSpan foi minha primeira escolha, mas descobriu que ele não oferece uma propriedade TotalYears. Você pode tentar (ts.TotalDays / 365) - mas isso não explica anos bissextos etc.
Lazlow
19
A maneira mais simples que eu já encontrei é essa. Funciona corretamente para os locais dos EUA e da Europa Ocidental. Não posso falar com outros locais, especialmente lugares como a China. 4 compara mais, no máximo, após o cálculo inicial da idade.
publicintAgeInYears(DateTime birthDate,DateTime referenceDate){Debug.Assert(referenceDate >= birthDate,"birth date must be on or prior to the reference date");DateTime birth = birthDate.Date;DateTime reference = referenceDate.Date;int years =(reference.Year- birth.Year);//// an offset of -1 is applied if the birth date has // not yet occurred in the current year.//if(reference.Month> birth.Month);elseif(reference.Month< birth.Month)--years;else// in birth month{if(reference.Day< birth.Day)--years;}return years ;}
Eu estava analisando as respostas para isso e notei que ninguém fez referência às implicações regulatórias / legais dos nascimentos em dias bissextos. Por exemplo, por Wikipedia , se você nasceu em 29 de fevereiro em várias jurisdições, seu aniversário sem ano bissexto varia:
No Reino Unido e Hong Kong: é o dia ordinal do ano, então no dia seguinte, 1º de março é seu aniversário.
Na Nova Zelândia: é o dia anterior, 28 de fevereiro para fins de licença de motorista e 1º de março para outros fins.
Taiwan: é 28 de fevereiro.
E, tanto quanto eu posso dizer, nos EUA, os estatutos ficam em silêncio sobre o assunto, deixando o direito comum e a forma como vários órgãos reguladores definem as coisas em seus regulamentos.
Esta não é uma resposta direta, mas mais um raciocínio filosófico sobre o problema em questão, de um ponto de vista quase científico.
Eu argumentaria que a pergunta não especifica a unidade nem a cultura na qual medir a idade; a maioria das respostas parece assumir uma representação anual inteira. A unidade SI para o tempo é second, portanto, a resposta genérica correta deve ser (naturalmente assumindo normalizada DateTimee não levando em consideração os efeitos relativísticos):
var lifeInSeconds =(DateTime.Now.Ticks- then.Ticks)/TickFactor;
Na maneira cristã de calcular a idade em anos:
var then =...// Then, in this case the birthdayvar now =DateTime.UtcNow;int age = now.Year- then.Year;if(now.AddYears(-age)< then) age--;
Nas finanças, existe um problema semelhante ao calcular algo conhecido como Fração de contagem de dias , que é aproximadamente um número de anos para um determinado período. E a questão da idade é realmente uma questão de medir o tempo.
Exemplo para a convenção real / real (contando todos os dias "corretamente"):
DateTime start, end =....// Whatever, assume start is before enddouble startYearContribution =1-(double) start.DayOfYear/(double)(DateTime.IsLeapYear(start.Year)?366:365);double endYearContribution =(double)end.DayOfYear/(double)(DateTime.IsLeapYear(end.Year)?366:365);double middleContribution =(double)(end.Year- start.Year-1);double DCF = startYearContribution + endYearContribution + middleContribution;
Outra maneira bastante comum de medir o tempo geralmente é "serializando" (o cara que nomeou essa convenção de data deve estar seriamente enganando):
DateTime start, end =....// Whatever, assume start is before endint days =(end - start).Days;
Eu me pergunto quanto tempo temos para que a idade relativística em segundos se torne mais útil do que a aproximação aproximada dos ciclos da Terra ao redor do sol durante a vida até agora :) Ou, em outras palavras, quando um período deve ter um local ou uma função que representa o movimento para ser válido :)
Eu tenho um método personalizado para calcular a idade, além de uma mensagem de validação de bônus, caso isso ajude:
publicvoidGetAge(DateTime dob,DateTime now,outint years,outint months,outint days){
years =0;
months =0;
days =0;DateTime tmpdob =newDateTime(dob.Year, dob.Month,1);DateTime tmpnow =newDateTime(now.Year, now.Month,1);while(tmpdob.AddYears(years).AddMonths(months)< tmpnow){
months++;if(months >12){
years++;
months = months -12;}}if(now.Day>= dob.Day)
days = days + now.Day- dob.Day;else{
months--;if(months <0){
years--;
months = months +12;}
days +=DateTime.DaysInMonth(now.AddMonths(-1).Year, now.AddMonths(-1).Month)+ now.Day- dob.Day;}if(DateTime.IsLeapYear(dob.Year)&& dob.Month==2&& dob.Day==29&& now >=newDateTime(now.Year,3,1))
days++;}privatestringValidateDate(DateTime dob)//This method will validate the date{intYears=0;intMonths=0;intDays=0;GetAge(dob,DateTime.Now,outYears,outMonths,outDays);if(Years<18)
message =Years+" is too young. Please try again on your 18th birthday.";elseif(Years>=65)
message =Years+" is too old. Date of Birth must not be 65 or older.";elsereturnnull;//Denotes validation passed}
Chame o método aqui e passe o valor de data e hora (MM / dd / aaaa se o servidor estiver definido como localidade dos EUA). Substitua por qualquer caixa de mensagens ou recipiente para exibir:
DateTime dob =DateTime.Parse("03/10/1982");string message =ValidateDate(dob);
lbldatemessage.Visible=!StringIsNullOrWhitespace(message);
lbldatemessage.Text= message ??"";//Ternary if message is null then default to empty string
Lembre-se de que você pode formatar a mensagem da maneira que desejar.
staticstringCalcAge(DateTime birthDay){DateTime currentDate =DateTime.Now;int approximateAge = currentDate.Year- birthDay.Year;int daysToNextBirthDay =(birthDay.Month*30+ birthDay.Day)-(currentDate.Month*30+ currentDate.Day);if(approximateAge ==0|| approximateAge ==1){int month =Math.Abs(daysToNextBirthDay /30);int days =Math.Abs(daysToNextBirthDay %30);if(month ==0)return"Your age is: "+ daysToNextBirthDay +" days";return"Your age is: "+ month +" months and "+ days +" days";;}if(daysToNextBirthDay >0)return"Your age is: "+--approximateAge +" Years";return"Your age is: "+ approximateAge +" Years";;}
// ----------------------------------------------------------------------publicvoidCalculateAgeSamples(){PrintAge(newDateTime(2000,02,29),newDateTime(2009,02,28));// > Birthdate=29.02.2000, Age at 28.02.2009 is 8 yearsPrintAge(newDateTime(2000,02,29),newDateTime(2012,02,28));// > Birthdate=29.02.2000, Age at 28.02.2012 is 11 years}// CalculateAgeSamples// ----------------------------------------------------------------------publicvoidPrintAge(DateTime birthDate,DateTime moment ){Console.WriteLine("Birthdate={0:d}, Age at {1:d} is {2} years", birthDate, moment,YearDiff( birthDate, moment ));}// PrintAge
Essa pergunta clássica merece uma solução Noda Time .
staticintGetAge(LocalDate dateOfBirth){Instant now =SystemClock.Instance.Now;// The target time zone is important.// It should align with the *current physical location* of the person// you are talking about. When the whereabouts of that person are unknown,// then you use the time zone of the person who is *asking* for the age.// The time zone of birth is irrelevant!DateTimeZone zone =DateTimeZoneProviders.Tzdb["America/New_York"];LocalDate today = now.InZone(zone).Date;Period period =Period.Between(dateOfBirth, today,PeriodUnits.Years);return(int) period.Years;}
Uso:
LocalDate dateOfBirth =newLocalDate(1976,8,27);int age =GetAge(dateOfBirth);
Você também pode estar interessado nas seguintes melhorias:
Passar o relógio como IClock, em vez de usar SystemClock.Instance, melhoraria a testabilidade.
O fuso horário alvo provavelmente será alterado, então você também desejará um DateTimeZoneparâmetro.
Fiz contribuições para ele, mas é principalmente de Jon Skeet.
Matt Johnson-Pint
9
Usei a solução do ScArcher2 para um cálculo preciso do ano da idade de uma pessoa, mas eu precisava ir além e calcular os meses e dias junto com os anos.
publicstaticDictionary<string,int>CurrentAgeInYearsMonthsDays(DateTime? ndtBirthDate,DateTime? ndtReferralDate){//----------------------------------------------------------------------// Can't determine age if we don't have a dates.//----------------------------------------------------------------------if(ndtBirthDate ==null)returnnull;if(ndtReferralDate ==null)returnnull;DateTime dtBirthDate =Convert.ToDateTime(ndtBirthDate);DateTime dtReferralDate =Convert.ToDateTime(ndtReferralDate);//----------------------------------------------------------------------// Create our Variables//----------------------------------------------------------------------Dictionary<string,int> dYMD =newDictionary<string,int>();int iNowDate, iBirthDate, iYears, iMonths, iDays;string sDif ="";//----------------------------------------------------------------------// Store off current date/time and DOB into local variables//----------------------------------------------------------------------
iNowDate =int.Parse(dtReferralDate.ToString("yyyyMMdd"));
iBirthDate =int.Parse(dtBirthDate.ToString("yyyyMMdd"));//----------------------------------------------------------------------// Calculate Years//----------------------------------------------------------------------
sDif =(iNowDate - iBirthDate).ToString();
iYears =int.Parse(sDif.Substring(0, sDif.Length-4));//----------------------------------------------------------------------// Store Years in Return Value//----------------------------------------------------------------------
dYMD.Add("Years", iYears);//----------------------------------------------------------------------// Calculate Months//----------------------------------------------------------------------if(dtBirthDate.Month> dtReferralDate.Month)
iMonths =12- dtBirthDate.Month+ dtReferralDate.Month-1;else
iMonths = dtBirthDate.Month- dtReferralDate.Month;//----------------------------------------------------------------------// Store Months in Return Value//----------------------------------------------------------------------
dYMD.Add("Months", iMonths);//----------------------------------------------------------------------// Calculate Remaining Days//----------------------------------------------------------------------if(dtBirthDate.Day> dtReferralDate.Day)//Logic: Figure out the days in month previous to the current month, or the admitted month.// Subtract the birthday from the total days which will give us how many days the person has lived since their birthdate day the previous month.// then take the referral date and simply add the number of days the person has lived this month.//If referral date is january, we need to go back to the following year's December to get the days in that month.if(dtReferralDate.Month==1)
iDays =DateTime.DaysInMonth(dtReferralDate.Year-1,12)- dtBirthDate.Day+ dtReferralDate.Day;else
iDays =DateTime.DaysInMonth(dtReferralDate.Year, dtReferralDate.Month-1)- dtBirthDate.Day+ dtReferralDate.Day;else
iDays = dtReferralDate.Day- dtBirthDate.Day;//----------------------------------------------------------------------// Store Days in Return Value//----------------------------------------------------------------------
dYMD.Add("Days", iDays);return dYMD;}
Respostas:
Uma solução fácil de entender e simples.
No entanto, isso pressupõe que você esteja procurando a idéia ocidental de idade e não esteja usando o cálculo da Ásia Oriental .
fonte
Essa é uma maneira estranha de fazê-lo, mas se você formatar a data
yyyymmdd
e subtrair a data de nascimento da data atual, solte os últimos 4 dígitos da idade :)Não sei c #, mas acredito que isso funcione em qualquer idioma.
Solte os últimos 4 dígitos
28
.Código C #:
Ou, alternativamente, sem toda a conversão de tipo na forma de um método de extensão. Verificação de erro omitida:
fonte
20180101 - 20171231 = 8870
. Solte os últimos 4 dígitos e você terá (um implícito)0
para a idade. Como você conseguiu1
?Aqui está um trecho de teste:
Aqui você tem os métodos:
fonte
A resposta simples para isso é aplicar
AddYears
como mostrado abaixo, porque este é o único método nativo para adicionar anos ao dia 29 de fevereiro dos anos bissextos e obter o resultado correto do dia 28 de fevereiro para os anos comuns.Alguns acham que 1º de março é o aniversário dos pulos, mas nem o .Net nem nenhuma regra oficial apóiam isso, nem a lógica comum explica por que alguns nascidos em fevereiro devem ter 75% de seus aniversários em outro mês.
Além disso, um método Age se presta a ser adicionado como uma extensão para
DateTime
. Com isso, você pode obter a idade da maneira mais simples possível:int idade = birthDate.Age ();
Agora, execute este teste:
O exemplo da data crítica é este:
Data de nascimento: 2000-02-29 Data posterior: 2011-02-28 Idade: 11
Resultado:
E para a data posterior 28/02/2012:
fonte
date.Age(other)
?Minha sugestão
Parece que o ano está mudando na data certa. (Eu testei até 107 anos de idade.)
fonte
days in a year = 365.242199
Outra função, não por mim, mas encontrada na web e refinada um pouco:
Apenas duas coisas que me vêm à cabeça: E as pessoas de países que não usam o calendário gregoriano? DateTime.Now está na cultura específica do servidor, eu acho. Não tenho absolutamente nenhum conhecimento sobre como trabalhar com calendários asiáticos e não sei se há uma maneira fácil de converter datas entre calendários, mas, caso você esteja se perguntando sobre os chineses do ano 4660 :-)
fonte
2 Os principais problemas a serem resolvidos são:
1. Calcule a idade exata - em anos, meses, dias etc.
2. Calcular a idade geralmente percebida - as pessoas geralmente não se importam com a idade exata, apenas se importam com o aniversário do ano atual.
A solução para 1 é óbvia:
A solução para 2 é a que não é tão precisa na determinação da idade total, mas é percebida como precisa pelas pessoas. As pessoas também costumam usá-lo, quando calculam sua idade "manualmente":
Notas 2:
Apenas mais uma observação ... Eu criaria dois métodos estáticos sobrecarregados, um para uso universal e outro para facilidade de uso:
fonte
Aqui está uma frase:
fonte
Esta é a versão que usamos aqui. Funciona e é bastante simples. É a mesma ideia que a de Jeff, mas acho que é um pouco mais clara, porque separa a lógica de subtrair uma, por isso é um pouco mais fácil de entender.
Você pode expandir o operador ternário para torná-lo ainda mais claro, se achar que esse tipo de coisa não é clara.
Obviamente, isso é feito como um método de extensão
DateTime
, mas claramente você pode pegar aquela linha de código que faz o trabalho e colocá-la em qualquer lugar. Aqui temos outra sobrecarga do método Extension que passaDateTime.Now
, apenas para ser completo.fonte
A melhor maneira que eu conheço por causa dos anos bissextos e tudo é:
fonte
Eu uso isso:
fonte
Isso dá "mais detalhes" a esta pergunta. Talvez seja isso que você está procurando
fonte
Eu criei uma Função Definida pelo Usuário do SQL Server para calcular a idade de alguém, dada a data de nascimento. Isso é útil quando você precisa dele como parte de uma consulta:
fonte
Aqui está mais uma resposta:
Isso foi extensivamente testado por unidade. Parece um pouco "mágico". O número 372 é o número de dias que haveria em um ano se todos os meses tivessem 31 dias.
A explicação de por que funciona ( levantada daqui ) é:
fonte
Passei algum tempo trabalhando nisso e criei isso para calcular a idade de alguém em anos, meses e dias. Eu testei contra o problema de 29 de fevereiro e os anos bissextos e parece funcionar, eu gostaria de receber comentários:
fonte
Precisamos considerar pessoas com menos de 1 ano? como cultura chinesa, descrevemos a idade dos bebês pequenos como 2 meses ou 4 semanas.
Abaixo está minha implementação, não é tão simples quanto eu imaginava, especialmente para lidar com datas como 2/28.
Esta implementação passou abaixo dos casos de teste.
Espero que seja útil.
fonte
Mantendo-o simples (e possivelmente estúpido :)).
fonte
A maneira mais simples que eu já encontrei é essa. Funciona corretamente para os locais dos EUA e da Europa Ocidental. Não posso falar com outros locais, especialmente lugares como a China. 4 compara mais, no máximo, após o cálculo inicial da idade.
Eu estava analisando as respostas para isso e notei que ninguém fez referência às implicações regulatórias / legais dos nascimentos em dias bissextos. Por exemplo, por Wikipedia , se você nasceu em 29 de fevereiro em várias jurisdições, seu aniversário sem ano bissexto varia:
E, tanto quanto eu posso dizer, nos EUA, os estatutos ficam em silêncio sobre o assunto, deixando o direito comum e a forma como vários órgãos reguladores definem as coisas em seus regulamentos.
Para esse fim, uma melhoria:
Note-se que este código assume:
fonte
Não sei exatamente como você gostaria que ela retornasse para você, então acabei de criar uma sequência legível.
fonte
Esta não é uma resposta direta, mas mais um raciocínio filosófico sobre o problema em questão, de um ponto de vista quase científico.
Eu argumentaria que a pergunta não especifica a unidade nem a cultura na qual medir a idade; a maioria das respostas parece assumir uma representação anual inteira. A unidade SI para o tempo é
second
, portanto, a resposta genérica correta deve ser (naturalmente assumindo normalizadaDateTime
e não levando em consideração os efeitos relativísticos):Na maneira cristã de calcular a idade em anos:
Nas finanças, existe um problema semelhante ao calcular algo conhecido como Fração de contagem de dias , que é aproximadamente um número de anos para um determinado período. E a questão da idade é realmente uma questão de medir o tempo.
Exemplo para a convenção real / real (contando todos os dias "corretamente"):
Outra maneira bastante comum de medir o tempo geralmente é "serializando" (o cara que nomeou essa convenção de data deve estar seriamente enganando):
Eu me pergunto quanto tempo temos para que a idade relativística em segundos se torne mais útil do que a aproximação aproximada dos ciclos da Terra ao redor do sol durante a vida até agora :) Ou, em outras palavras, quando um período deve ter um local ou uma função que representa o movimento para ser válido :)
fonte
Aqui está uma solução.
fonte
Esta é uma das respostas mais precisas capazes de resolver o aniversário de 29 de fevereiro em comparação com qualquer ano de 28 de fevereiro.
fonte
Eu tenho um método personalizado para calcular a idade, além de uma mensagem de validação de bônus, caso isso ajude:
Chame o método aqui e passe o valor de data e hora (MM / dd / aaaa se o servidor estiver definido como localidade dos EUA). Substitua por qualquer caixa de mensagens ou recipiente para exibir:
Lembre-se de que você pode formatar a mensagem da maneira que desejar.
fonte
Que tal esta solução?
fonte
fonte
A abordagem a seguir (extraída da biblioteca de período de tempo para a classe .NET DateDiff ) considera o calendário das informações da cultura:
Uso:
fonte
Essa pergunta clássica merece uma solução Noda Time .
Uso:
Você também pode estar interessado nas seguintes melhorias:
Passar o relógio como
IClock
, em vez de usarSystemClock.Instance
, melhoraria a testabilidade.O fuso horário alvo provavelmente será alterado, então você também desejará um
DateTimeZone
parâmetro.Veja também meu post sobre este assunto: Manipulação de aniversários e outros aniversários
fonte
Usei a solução do ScArcher2 para um cálculo preciso do ano da idade de uma pessoa, mas eu precisava ir além e calcular os meses e dias junto com os anos.
fonte
Versão SQL:
fonte
Fiz uma pequena alteração na resposta de Mark Soen : reescrevi a terceira linha para que a expressão pudesse ser analisada um pouco mais facilmente.
Eu também fiz isso por uma questão de clareza.
fonte