wszystkie dotychczasowe odpowiedzi nie zostały przeoczone, to zależy od tego, gdzie dana osoba się urodziła i gdzie jest teraz.
Yaur
40
@Yaur: Wystarczy przeliczyć czas teraz + narodziny na GMT / UTC, wiek jest tylko wartością względną, dlatego strefy czasowe są nieistotne. Aby określić bieżącą strefę czasową użytkownika, możesz użyć GeoLocating.
Jeśli bierzemy pod uwagę sugestię @Yaur dotyczącą obliczeń w różnych strefach czasowych, to czy dzienny czas oszczędzania światła może wpłynąć w jakiś sposób na obliczenia?
DDM,
6
Przegłosowano, ponieważ jest to wyraźnie zadanie domowe i nie podjęto żadnej istniejącej próby.
Marie,
Odpowiedzi:
2122
Łatwe do zrozumienia i proste rozwiązanie.
// 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--;
Chciałem tylko skomentować wydajność DateTime.Now. Jeśli nie potrzebujesz dokładnej wartości strefy czasowej, użyj DateTime.UtcNow jest to znacznie szybsze.
JAG
104
Biorąc pod uwagę, że rozmawiamy o urodzinach, możesz po prostu użyć DateTime. Dzisiaj, biorąc pod uwagę, że część czasu nie ma znaczenia.
Tristan Warner-Smith
78
Ta odpowiedź nie działa we wszystkich lokalizacjach i dla wszystkich grup wiekowych. Kilka krajów pominęło daty po narodzinach obecnych żyjących ludzi, w tym Rosja (1918), Grecja (1924) i Turcja (1926).
Lars D,
30
W rzeczywistości nadal nie jest to całkowicie poprawne. Ten kod zakłada, że „bday” to część daty DateTime. To przypadek na marginesie (wydaje mi się, że większość ludzi będzie po prostu przekazywać daty, a nie daty), ale jeśli podasz urodziny jako datę i godzinę, w której czas jest większy niż 00:00:00, wtedy „ Wpadnę na błąd, na który zwrócił uwagę Danvil. Ustawienie bday = bday.Date naprawia to.
Øyvind
119
Ostatnia linia zmusiła mnie do zbytniego myślenia. Zamiast tego, co powiesz na: if (bday.AddYears (wiek)> teraz) age--; To wydaje się być bardziej intuicyjne wyrażenie.
cdiggins,
1015
Jest to dziwny sposób, aby to zrobić, ale jeśli sformatujesz datę yyyymmddi odejmiesz datę urodzenia od bieżącej daty, upuść ostatnie 4 cyfry, które masz w wieku :)
Nie znam C #, ale wierzę, że to zadziała w dowolnym języku.
20080814-19800703=280111
Upuść ostatnie 4 cyfry = 28.
Kod C #:
int now =int.Parse(DateTime.Now.ToString("yyyyMMdd"));int dob =int.Parse(dateOfBirth.ToString("yyyyMMdd"));int age =(now - dob)/10000;
Lub alternatywnie bez konwersji wszystkich typów w postaci metody rozszerzenia. Pominięto sprawdzanie błędów:
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;}
W rzeczywistości jest to świetne do użycia w MS-SQL z polami datetime (łączna liczba dni od 01-011900)
Patrik
w alternatywnej odpowiedzi można uniknąć przepełnienia liczb całkowitych, odejmując lata, a następnie odejmując miesiąc * 30,5 + dzień i dzieląc przez 366
numerek
5
@numerek Prześlij sugerowane modyfikacje jako własną odpowiedź. Co warte jest tego, bieżący rok 10000 razy nie jest bliski przepełnieniu liczb całkowitych o dwa rzędy wielkości. 20 150 000 vs 2 147 483 648
GalacticCowboy
7
@LongChalk 20180101 - 20171231 = 8870. Upuść ostatnie 4 cyfry i masz (domyślnie) 0wiek. Jak się dostałeś 1?
Rufus L
4
Wiem, że to stara odpowiedź, ale nie zrobiłbym z niej metody rozszerzenia, nie jest to właściwe miejsce do definiowania takiej logiki.
Chociaż ten kod działa, zapewnia on, że osoba urodzona w dniu przestępnym osiąga następny rok w dniu 1 marca w latach bez przestępstwa, a nie w dniu 28 lutego. W rzeczywistości każda z opcji może być poprawna . Wikipedia ma coś do powiedzenia na ten temat . Więc chociaż twój kod nie jest „zły”, nie jest to również przyjęte rozwiązanie.
Matt Johnson-Pint,
18
@MattJohnson Myślę, że to właściwie prawda. Jeśli mój dzień był 29 lutego, to 28 lutego mój dzień nie minął, a ja powinienem być w tym samym wieku co 27 lutego. Jednak 1 marca minęło moje urodziny i powinienem być w następnym wieku. W Stanach Zjednoczonych firma sprzedająca alkohol będzie miała napis: „Jeśli urodziłeś się po tym dniu w RRRR, nie możesz kupić alkoholu” (gdzie RRRR zmienia się co roku). Oznacza to, że ktoś urodzony 29 lutego nie może kupić alkoholu 28 lutego w roku, w którym skończy 21 lat (większość miejsc), i popiera pomysł, że nie są o rok starsi do 1 marca.
jfren484
4
@ jfren484 - przeczytaj artykuł w Wikipedii. Różni się znacznie w zależności od jurysdykcji.
Matt Johnson-Pint
9
@ jfren484 Twoje roszczenie nie ma absolutnie nic wspólnego z filozofią; ale wszystko, co dotyczy twojego osobistego odczucia . Gdy osoba urodzona 29 lutego „wiek” jest w dużej mierze nieistotny, chyba że wiek stanowi „prawną granicę wieku” (np. Może kupić alkohol, głosować, uzyskać emeryturę, dołączyć do wojska, uzyskać prawo jazdy). Rozważmy wiek picia w USA (21 lat): dla większości osób to 7670 dni. Ma 7671 dni, jeśli urodził się przed 29 lutego w roku przestępnym lub od 1 marca przed rokiem przestępnym. Jeśli urodził się 29 lutego: 28 lutego to 7670 dni, a 1 marca to 7671 dni. Wybór jest dowolny , może iść w jedną stronę.
Rozczarowany
4
@CraigYoung Nie rozumiesz, co miałem na myśli przez filozofię. Użyłem tego terminu w przeciwieństwie do prawa. Jeśli ktoś pisze aplikację, która musi znać wiek prawny danej osoby, wystarczy wiedzieć, w jaki sposób sądy prawne, w których jej aplikacja jest wykorzystywana w / w leczeniu osób urodzonych 29 lutego. Jeśli jednak jesteśmy mówiąc o tym, jak należy to traktować, to z definicji jest to filozofia. I tak, opinia, którą wydałem, jest moją własną opinią, ale jak powiedziałem, myślę, że łatwiej byłoby się kłócić o 1 marca niż o 28 lutego.
jfren484
109
Prostą odpowiedzią na to jest zastosowanie, AddYearsjak pokazano poniżej, ponieważ jest to jedyna natywna metoda dodania lat do 29 lutego lat przestępnych i uzyskania prawidłowego wyniku z 28 lutego dla wspólnych lat.
Niektórzy uważają, że 1 marca to urodziny skaczących zwierząt, ale ani .Net, ani żadna oficjalna reguła tego nie potwierdzają, ani też wspólna logika nie wyjaśnia, dlaczego niektórzy urodzeni w lutym powinni mieć 75% swoich urodzin w innym miesiącu.
Ponadto metoda Age może zostać dodana jako rozszerzenie DateTime. Dzięki temu możesz uzyskać wiek w najprostszy możliwy sposób:
Element listy
int wiek = 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;}}
Teraz uruchom ten test:
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();}}
Przykład daty krytycznej jest następujący:
Data urodzenia: 2000-02-29 Późniejsza data: 2011-02-28 Wiek: 11
Komentarz na temat urodzin 29 lutego 1 marca, technicznie rzecz biorąc, mając je 28, jest zbyt wcześnie (w rzeczywistości 1 dzień wcześniej). Pierwszego dnia jest o jeden dzień za późno. Ale ponieważ urodziny są pomiędzy, użycie pierwszego do obliczenia wieku w latach bez przestępowania ma dla mnie większy sens, ponieważ ta osoba jest rzeczywiście taka stara 1 marca (i 2 i 3) każdego roku, ale nie 28 lutego.
CyberClaw
1
Z punktu widzenia projektowania oprogramowania pisanie tego jako metody rozszerzenia nie ma dla mnie większego sensu. date.Age(other)?
marsze
90
Moja sugestia
int age =(int)((DateTime.Now- bday).TotalDays/365.242199);
Wydaje się, że rok zmienia się we właściwą datę. (Testowałem na miejscu do 107. roku życia)
Średnia długość roku w kalendarzu gregoriańskim wynosi 365,2425 dni.
dan04,
4
Powiedziałbym, że jest to jedno z najprostszych rozwiązań i jest wystarczająco dobre . Kogo to obchodzi, jeśli mam pół dnia przed swoimi X urodzinami, a program mówi, że mam X lat. Program ma mniej więcej rację, choć nie matematycznie. Naprawdę podoba mi się to rozwiązanie.
Peter Perháč,
13
^^ Ponieważ czasami jest to ważne. W moich testach nie udaje się to w dniu urodzin osób, co oznacza, że są młodsi niż oni.
Czad
76
Kolejna funkcja, nie przeze mnie, ale znaleziona w Internecie i nieco ją udoskonaliła:
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;}
Dwie rzeczy, które przychodzą mi do głowy: co z ludźmi z krajów, które nie używają kalendarza gregoriańskiego? Myślę, że DateTime.Now należy do kultury specyficznej dla serwera. Mam absolutnie zerową wiedzę na temat pracy z kalendarzami azjatyckimi i nie wiem, czy istnieje prosty sposób na konwersję dat między kalendarzami, ale na wszelki wypadek zastanawiasz się nad tymi Chińczykami z roku 4660 :-)
Wydaje się, że najlepiej obsługuje różne regiony (formaty daty).
webdad3,
53
2 Główne problemy do rozwiązania to:
1. Oblicz dokładny wiek - w latach, miesiącach, dniach itp.
2. Oblicz ogólnie postrzegany wiek - ludzie zwykle nie dbają o to, ile dokładnie mają lat, po prostu obchodzą urodziny w bieżącym roku.
Rozwiązanie dla 1 jest oczywiste:
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
Rozwiązanie na 2 to takie, które nie jest tak precyzyjne w określaniu całkowitego wieku, ale jest postrzegane przez ludzi jako precyzyjne. Ludzie też zwykle go używają, gdy obliczają swój wiek „ręcznie”:
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}
Uwagi do 2 .:
To jest moje preferowane rozwiązanie
Nie możemy używać funkcji DateTime.DayOfYear ani TimeSpans, ponieważ zmieniają liczbę dni w latach przestępnych
Umieściłem tam trochę więcej wierszy dla czytelności
Jeszcze jedna uwaga ... Stworzyłbym dla niego 2 statyczne metody przeciążenia, jedną do uniwersalnego zastosowania, drugą do łatwości użycia:
To jest zepsute. Udostępniono do testowania: public static int CalculateAge (DateTime dateOfBirth, DateTime dateToCalculateAge) {zwróć nowy DateTime (dateToCalculateAge.Subtract (dateOfBirth) .Ticks) .Rok - 1; } ... Podaje wiek 14, kiedy wprowadzam 1990-06-01 i obliczam wiek w dniu PRZED jego 14. urodzinami (1990-05-31).
Kjensen
43
To jest wersja, której używamy tutaj. Działa i jest dość prosty. Jest to ten sam pomysł, co Jeff, ale myślę, że jest trochę jaśniejszy, ponieważ oddziela logikę odejmowania jednego, więc jest to trochę łatwiejsze do zrozumienia.
Możesz rozwinąć operator trójskładnikowy, aby uczynić go jeszcze jaśniejszym, jeśli uważasz, że tego rodzaju rzeczy są niejasne.
Oczywiście jest to wykonywane jako metoda rozszerzenia DateTime, ale najwyraźniej możesz pobrać jeden wiersz kodu, który działa i umieścić go w dowolnym miejscu. Tutaj mamy kolejne przeciążenie metody Extension, która przechodzi DateTime.Now, tylko dla kompletności.
Myślę, że może to być wyłączone o jeden dzień, kiedy dokładnie data dateOfBirth lub dateAsAt przypada w roku przestępnym. Rozważ wiek osoby urodzonej 1 marca 2003 r. W dniu 29 lutego 2004 r. Aby to naprawić, musisz wykonać porównanie leksykograficzne par (Month, DayOfMonth) i użyć tego dla warunkowego.
Doug McClean,
1
nie będzie też pokazywał odpowiedniego wieku w dniu twoich urodzin.
dotjoe
43
Najlepszy sposób, jaki znam ze względu na lata przestępne i wszystko to:
DateTime birthDate =newDateTime(2000,3,1);int age =(int)Math.Floor((DateTime.Now- birthDate).TotalDays/365.25D);
To daje „więcej szczegółów” na to pytanie. Może właśnie tego szukasz
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);
To nie działa cały czas. Dodanie zakresu do DateTime.MinValue może działać, bo to nie uwzględnia lat przestępnych itp. Jeśli dodasz lata, miesiące i dni do wieku za pomocą funkcji AddYears (), AddMonths i AddDays (), nie zawsze zwróci Datetime . Teraz data.
Athanasios Kataras
3
sam okres czasu automatycznie uwzględnia lata przestępne między dwiema datami, więc nie jestem pewien, o co ci chodzi. Zapytałem na forach Microsoft i Microsoft potwierdziło, że bierze pod uwagę lata przestępne między dwiema datami.
Jacqueline Loriault
2
Rozważ następujące dwa senarios. 1st DateTime.Teraz jest 1/1/2001, a dziecko urodziło się 1/1/2000. Rok 2000 to rok przestępny, a wynik wyniesie 1 rok, 0 miesięcy i 1 dzień. W drugim searionie DateTime.Now jest 1/1/2002, a dziecko urodziło się 1/1/2001. W takim przypadku wynik wyniesie 1 rok, 0 miesięcy i 0 dni. Stanie się tak, ponieważ dodajesz przedział czasowy w roku bez przestępowania. Gdyby DateTime.MinValue był rokiem przestępnym, wyniki byłyby 1 rok na początku i 0 lat 11 miesięcy i 30 dni. (Wypróbuj w swoim kodzie).
Athanasios Kataras
1
Głosuj! Wymyśliłem rozwiązanie, które jest prawie identyczne (użyłem DateTime.MinValue.AddTicks (span.Ticks) zamiast +, ale wynik jest taki sam, a twój ma kilka znaków mniej kodu).
Makotosan,
4
Masz całkowitą rację, że nie. Ale JEŚLI to byłby wynik. Dlaczego to ma znaczenie? Tak nie jest. W obu przypadkach skok lub nie, istnieją przykłady, w których to nie działa. Właśnie to chciałem pokazać. DIFF jest poprawny. Rozpiętość uwzględnia lata przestępne. Ale DODAWANIE do daty bazowej nie jest. Wypróbuj przykłady w kodzie, a zobaczysz, że mam rację.
Athanasios Kataras
28
Utworzyłem funkcję SQL Server zdefiniowaną przez użytkownika, aby obliczyć czyjś wiek, biorąc pod uwagę jego datę urodzenia. Jest to przydatne, gdy potrzebujesz go w ramach zapytania:
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;}};
Natknąłem się na tę długą i irytującą dyskusję, a twoje rozwiązanie jest naprawdę miłym i małym podejściem. Dzięki za uproszczenie
nabuchodonossor
25
Spędziłem trochę czasu nad tym pracując i wymyśliłem to, aby obliczyć czyjś wiek w latach, miesiącach i dniach. Testowałem pod kątem problemu z 29 lutego i lat przestępnych i wydaje się, że działa, będę wdzięczny za wszelkie opinie:
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++;}}
Czy musimy brać pod uwagę osoby w wieku poniżej 1 roku? jako kultura chińska określamy wiek małych dzieci jako 2 miesiące lub 4 tygodnie.
Poniżej moja realizacja, nie jest tak prosta, jak sobie wyobrażałem, szczególnie w przypadku daty takiej jak 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";}}
Ta implementacja przeszła poniżej przypadków testowych.
[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);}
TimeSpan był moim pierwszym wyborem, ale stwierdził, że nie oferuje właściwości TotalYears. Możesz spróbować (ts.TotalDays / 365) - ale nie uwzględnia to lat przestępnych itp.
Lazlow
19
Najprostszym sposobem, jaki kiedykolwiek znalazłem, jest to. Działa poprawnie w lokalizacjach w USA i Europie Zachodniej. Nie mogę rozmawiać z innymi lokalizacjami, zwłaszcza z miejscami takimi jak Chiny. 4 dodatkowe porównuje najwyżej po początkowym obliczeniu wieku.
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 ;}
Patrzyłem na odpowiedzi na to i zauważyłem, że nikt nie wspomniał o implikacjach regulacyjnych / prawnych narodzin przestępnych. Na przykład, według Wikipedii , jeśli urodziłeś się 29 lutego w różnych jurysdykcjach, Twoje urodziny w roku innym niż przestępny są różne:
W Wielkiej Brytanii i Hongkongu: jest to zwykły dzień roku, więc następnego dnia, 1 marca, są twoje urodziny.
W Nowej Zelandii: jest dzień poprzedni, 28 lutego w celu uzyskania prawa jazdy i 1 marca w innych celach.
Tajwan: jest 28 lutego.
I tak blisko, jak mogę powiedzieć, w USA statuty milczą w tej sprawie, pozostawiając to prawu powszechnemu i temu, jak różne organy regulacyjne definiują rzeczy w swoich przepisach.
To nie jest bezpośrednia odpowiedź, ale bardziej filozoficzne rozumowanie na temat problemu z quasi-naukowego punktu widzenia.
Twierdziłbym, że pytanie nie określa jednostki ani kultury, w której należy mierzyć wiek, większość odpowiedzi wydaje się zakładać całkowitą roczną reprezentację. Jednostką czasu dla SI jest second, ergo, prawidłowa odpowiedź ogólna powinna być (oczywiście zakładając, że znormalizowana DateTimei nie biorąc pod uwagę efektów relatywistycznych):
var lifeInSeconds =(DateTime.Now.Ticks- then.Ticks)/TickFactor;
W chrześcijański sposób obliczania wieku w latach:
var then =...// Then, in this case the birthdayvar now =DateTime.UtcNow;int age = now.Year- then.Year;if(now.AddYears(-age)< then) age--;
W finansach występuje podobny problem przy obliczaniu czegoś często określanego jako ułamek liczby dni , który z grubsza jest liczbą lat w danym okresie. Problem wieku jest tak naprawdę kwestią pomiaru czasu.
Przykład faktycznej / faktycznej (liczącej wszystkie dni „poprawnie”) konwencji:
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;
Innym dość powszechnym sposobem mierzenia czasu jest „serializacja” (koleś, który nazwał tę konwencję dat, musiał poważnie się potknąć):
DateTime start, end =....// Whatever, assume start is before endint days =(end - start).Days;
Zastanawiam się, jak długo musimy przebyć, zanim relatywistyczny wiek w sekundach stanie się bardziej użyteczny niż przybliżone przybliżenie cykli Ziemi wokół Słońca w dotychczasowym życiu :) Lub innymi słowy, kiedy należy podać okres lub lokalizację funkcja reprezentująca ruch, aby była poprawna :)
Mam spersonalizowaną metodę obliczania wieku oraz komunikat potwierdzający premię na wypadek, gdyby pomógł:
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}
Wywołaj metodę tutaj i przekaż wartość daty / godziny (MM / dd / rrrr, jeśli serwer ustawiony jest na ustawienia regionalne USA). Zamień to na dowolne okno komunikatu lub dowolny pojemnik do wyświetlenia:
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
Pamiętaj, że możesz sformatować wiadomość w dowolny sposób.
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
To klasyczne pytanie zasługuje na rozwiązanie 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;}
Stosowanie:
LocalDate dateOfBirth =newLocalDate(1976,8,27);int age =GetAge(dateOfBirth);
Mogą Cię również zainteresować następujące ulepszenia:
Przekazywanie zegara jako IClockzamiast SystemClock.Instancepoprawiałoby testowalność.
Docelowa strefa czasowa prawdopodobnie ulegnie zmianie, więc chcesz również DateTimeZoneparametr.
Przyczyniłem się do tego, ale przede wszystkim należy do Jona Skeeta.
Matt Johnson-Pint
9
Użyłem rozwiązania ScArcher2 do dokładnego obliczenia wieku osób, ale musiałem pójść dalej i obliczyć ich Miesiące i Dni wraz z Latami.
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;}
Odpowiedzi:
Łatwe do zrozumienia i proste rozwiązanie.
Zakłada się jednak, że szukasz zachodniej idei wieku i nie używasz liczenia wschodnioazjatyckiego .
źródło
Jest to dziwny sposób, aby to zrobić, ale jeśli sformatujesz datę
yyyymmdd
i odejmiesz datę urodzenia od bieżącej daty, upuść ostatnie 4 cyfry, które masz w wieku :)Nie znam C #, ale wierzę, że to zadziała w dowolnym języku.
Upuść ostatnie 4 cyfry =
28
.Kod C #:
Lub alternatywnie bez konwersji wszystkich typów w postaci metody rozszerzenia. Pominięto sprawdzanie błędów:
źródło
20180101 - 20171231 = 8870
. Upuść ostatnie 4 cyfry i masz (domyślnie)0
wiek. Jak się dostałeś1
?Oto fragment testowy:
Oto metody:
źródło
Prostą odpowiedzią na to jest zastosowanie,
AddYears
jak pokazano poniżej, ponieważ jest to jedyna natywna metoda dodania lat do 29 lutego lat przestępnych i uzyskania prawidłowego wyniku z 28 lutego dla wspólnych lat.Niektórzy uważają, że 1 marca to urodziny skaczących zwierząt, ale ani .Net, ani żadna oficjalna reguła tego nie potwierdzają, ani też wspólna logika nie wyjaśnia, dlaczego niektórzy urodzeni w lutym powinni mieć 75% swoich urodzin w innym miesiącu.
Ponadto metoda Age może zostać dodana jako rozszerzenie
DateTime
. Dzięki temu możesz uzyskać wiek w najprostszy możliwy sposób:int wiek = birthDate.Age ();
Teraz uruchom ten test:
Przykład daty krytycznej jest następujący:
Data urodzenia: 2000-02-29 Późniejsza data: 2011-02-28 Wiek: 11
Wynik:
A w późniejszym terminie 28.02.2012:
źródło
date.Age(other)
?Moja sugestia
Wydaje się, że rok zmienia się we właściwą datę. (Testowałem na miejscu do 107. roku życia)
źródło
days in a year = 365.242199
Kolejna funkcja, nie przeze mnie, ale znaleziona w Internecie i nieco ją udoskonaliła:
Dwie rzeczy, które przychodzą mi do głowy: co z ludźmi z krajów, które nie używają kalendarza gregoriańskiego? Myślę, że DateTime.Now należy do kultury specyficznej dla serwera. Mam absolutnie zerową wiedzę na temat pracy z kalendarzami azjatyckimi i nie wiem, czy istnieje prosty sposób na konwersję dat między kalendarzami, ale na wszelki wypadek zastanawiasz się nad tymi Chińczykami z roku 4660 :-)
źródło
2 Główne problemy do rozwiązania to:
1. Oblicz dokładny wiek - w latach, miesiącach, dniach itp.
2. Oblicz ogólnie postrzegany wiek - ludzie zwykle nie dbają o to, ile dokładnie mają lat, po prostu obchodzą urodziny w bieżącym roku.
Rozwiązanie dla 1 jest oczywiste:
Rozwiązanie na 2 to takie, które nie jest tak precyzyjne w określaniu całkowitego wieku, ale jest postrzegane przez ludzi jako precyzyjne. Ludzie też zwykle go używają, gdy obliczają swój wiek „ręcznie”:
Uwagi do 2 .:
Jeszcze jedna uwaga ... Stworzyłbym dla niego 2 statyczne metody przeciążenia, jedną do uniwersalnego zastosowania, drugą do łatwości użycia:
źródło
Oto jedna linijka:
źródło
To jest wersja, której używamy tutaj. Działa i jest dość prosty. Jest to ten sam pomysł, co Jeff, ale myślę, że jest trochę jaśniejszy, ponieważ oddziela logikę odejmowania jednego, więc jest to trochę łatwiejsze do zrozumienia.
Możesz rozwinąć operator trójskładnikowy, aby uczynić go jeszcze jaśniejszym, jeśli uważasz, że tego rodzaju rzeczy są niejasne.
Oczywiście jest to wykonywane jako metoda rozszerzenia
DateTime
, ale najwyraźniej możesz pobrać jeden wiersz kodu, który działa i umieścić go w dowolnym miejscu. Tutaj mamy kolejne przeciążenie metody Extension, która przechodziDateTime.Now
, tylko dla kompletności.źródło
Najlepszy sposób, jaki znam ze względu na lata przestępne i wszystko to:
źródło
Używam tego:
źródło
To daje „więcej szczegółów” na to pytanie. Może właśnie tego szukasz
źródło
Utworzyłem funkcję SQL Server zdefiniowaną przez użytkownika, aby obliczyć czyjś wiek, biorąc pod uwagę jego datę urodzenia. Jest to przydatne, gdy potrzebujesz go w ramach zapytania:
źródło
Oto kolejna odpowiedź:
Zostało to szeroko przetestowane jednostkowo. Wygląda trochę „magicznie”. Liczba 372 to liczba dni w roku, gdyby każdy miesiąc miał 31 dni.
Wyjaśnienie, dlaczego to działa ( zdjęto stąd ) to:
źródło
Spędziłem trochę czasu nad tym pracując i wymyśliłem to, aby obliczyć czyjś wiek w latach, miesiącach i dniach. Testowałem pod kątem problemu z 29 lutego i lat przestępnych i wydaje się, że działa, będę wdzięczny za wszelkie opinie:
źródło
Czy musimy brać pod uwagę osoby w wieku poniżej 1 roku? jako kultura chińska określamy wiek małych dzieci jako 2 miesiące lub 4 tygodnie.
Poniżej moja realizacja, nie jest tak prosta, jak sobie wyobrażałem, szczególnie w przypadku daty takiej jak 2/28.
Ta implementacja przeszła poniżej przypadków testowych.
Mam nadzieję, że to jest pomocne.
źródło
Prostota (i być może głupota :)).
źródło
Najprostszym sposobem, jaki kiedykolwiek znalazłem, jest to. Działa poprawnie w lokalizacjach w USA i Europie Zachodniej. Nie mogę rozmawiać z innymi lokalizacjami, zwłaszcza z miejscami takimi jak Chiny. 4 dodatkowe porównuje najwyżej po początkowym obliczeniu wieku.
Patrzyłem na odpowiedzi na to i zauważyłem, że nikt nie wspomniał o implikacjach regulacyjnych / prawnych narodzin przestępnych. Na przykład, według Wikipedii , jeśli urodziłeś się 29 lutego w różnych jurysdykcjach, Twoje urodziny w roku innym niż przestępny są różne:
I tak blisko, jak mogę powiedzieć, w USA statuty milczą w tej sprawie, pozostawiając to prawu powszechnemu i temu, jak różne organy regulacyjne definiują rzeczy w swoich przepisach.
W tym celu poprawa:
Należy zauważyć, że ten kod zakłada:
źródło
Nie jestem pewien, jak dokładnie chciałbyś, żeby ci to zwróciło, więc właśnie utworzyłem czytelny ciąg.
źródło
To nie jest bezpośrednia odpowiedź, ale bardziej filozoficzne rozumowanie na temat problemu z quasi-naukowego punktu widzenia.
Twierdziłbym, że pytanie nie określa jednostki ani kultury, w której należy mierzyć wiek, większość odpowiedzi wydaje się zakładać całkowitą roczną reprezentację. Jednostką czasu dla SI jest
second
, ergo, prawidłowa odpowiedź ogólna powinna być (oczywiście zakładając, że znormalizowanaDateTime
i nie biorąc pod uwagę efektów relatywistycznych):W chrześcijański sposób obliczania wieku w latach:
W finansach występuje podobny problem przy obliczaniu czegoś często określanego jako ułamek liczby dni , który z grubsza jest liczbą lat w danym okresie. Problem wieku jest tak naprawdę kwestią pomiaru czasu.
Przykład faktycznej / faktycznej (liczącej wszystkie dni „poprawnie”) konwencji:
Innym dość powszechnym sposobem mierzenia czasu jest „serializacja” (koleś, który nazwał tę konwencję dat, musiał poważnie się potknąć):
Zastanawiam się, jak długo musimy przebyć, zanim relatywistyczny wiek w sekundach stanie się bardziej użyteczny niż przybliżone przybliżenie cykli Ziemi wokół Słońca w dotychczasowym życiu :) Lub innymi słowy, kiedy należy podać okres lub lokalizację funkcja reprezentująca ruch, aby była poprawna :)
źródło
Oto rozwiązanie.
źródło
Jest to jedna z najdokładniejszych odpowiedzi, która jest w stanie rozwiązać urodziny 29 lutego w porównaniu z dowolnym rokiem 28 lutego.
źródło
Mam spersonalizowaną metodę obliczania wieku oraz komunikat potwierdzający premię na wypadek, gdyby pomógł:
Wywołaj metodę tutaj i przekaż wartość daty / godziny (MM / dd / rrrr, jeśli serwer ustawiony jest na ustawienia regionalne USA). Zamień to na dowolne okno komunikatu lub dowolny pojemnik do wyświetlenia:
Pamiętaj, że możesz sformatować wiadomość w dowolny sposób.
źródło
Co powiesz na to rozwiązanie?
źródło
źródło
Następujące podejście (wyciąg z biblioteki okresów dla klasy .NET DateDiff ) uwzględnia kalendarz informacji o kulturze:
Stosowanie:
źródło
To klasyczne pytanie zasługuje na rozwiązanie Noda Time .
Stosowanie:
Mogą Cię również zainteresować następujące ulepszenia:
Przekazywanie zegara jako
IClock
zamiastSystemClock.Instance
poprawiałoby testowalność.Docelowa strefa czasowa prawdopodobnie ulegnie zmianie, więc chcesz również
DateTimeZone
parametr.Zobacz także mój post na blogu na ten temat: Obsługa urodzin i innych rocznic
źródło
Użyłem rozwiązania ScArcher2 do dokładnego obliczenia wieku osób, ale musiałem pójść dalej i obliczyć ich Miesiące i Dni wraz z Latami.
źródło
Wersja SQL:
źródło
Wprowadziłem jedną małą zmianę w odpowiedzi Marka Soena: przepisałem trzecią linię, aby wyrażenie było łatwiejsze do przeanalizowania.
Zrobiłem to również w celu zachowania przejrzystości.
źródło