2009-01-17 8 views
17

Ich möchte das Alter einer Person mit dem Geburtsdatum und dem aktuellen Datum in Jahren, Monaten und Tagen im Verhältnis zum aktuellen Datum berechnen.Wie kann ich das Alter einer Person in Jahr, Monat, Tagen berechnen?

Zum Beispiel:

>>> calculate_age(2008, 01, 01) 
1 years, 0 months, 16 days 

Alle Zeiger auf einen Algorithmus, der das tut, wird geschätzt.

+0

Viele Sprachen können dies in ihren Standardbibliotheken tun. Irgendeine bevorzugte Sprache oder willst du einen "reinen" Algorithmus? –

+0

Werfen Sie einen Blick auf diesen Artikel: http://00f.net/2007/an-age-is-not-a-duration – MatthieuP

+0

Ähnlich wie http://stackoverflow.com/questions/9/how-do-i- calculate-someones-age-in-c – some

Antwort

15

Beachten Sie zuerst die Annahme, dass, wenn Sie zum Beispiel am 1. Februar, dann am folgenden 1. März geboren wurden, Sie genau 1 Monat alt sind, obwohl Ihr Alter in Tagen nur 28 - weniger als die Länge ist eines durchschnittlichen Monats. Die Jahre haben auch eine variable Länge (aufgrund von Schaltjahren), was bedeutet, dass Ihr Alter an Ihrem Geburtstag in der Regel keine exakte ganze Zahl von Jahren ist. Wenn Sie die genaue Zeit, in der Sie in Jahren/Monaten/Tagen gelebt haben, ausdrücken möchten, sehen Sie sich meine andere Antwort an. Aber wahrscheinlicher ist es, dass Sie es richtig korrigieren, so dass die Geburt am 1. Februar bedeutet, dass Sie am 1. Februar X Jahre, 0 Monate und 0 Tage alt sind und am 1. eines Monats X Jahre, Y Monate, und 0 Tage.

In diesem Fall lesen Sie weiter. (NB: die folgenden funktioniert nur für Termine in der Vergangenheit.)

ein Geburtsdatum gegeben, (y,m,d), das aktuelle Datum, (ynow,mnow,dnow) und eine Funktion die unix/epoch time for a given date, die folgende ausgeben wird ein 3-Element geben Liste gibt Alter als {Jahre, Monate, Tage}:

t0 = y*12 + m - 1;  # total months for birthdate. 
t = ynow*12 + mnow - 1; # total months for Now. 
dm = t - t0;    # delta months.  
if(dnow >= d) return [floor(dm/12), mod(dm,12), dnow-d]; 
dm--; t--; 
return [floor(dm/12), mod(dm,12), 
     (tm({ynow,mnow,dnow}) - tm({floor(t/12), mod(t,12)+1, d}))/60/60/24]; 

Es folgt ein Äquivalent Algorithmus, wenn Sie nicht alle mögen die Böden und Mods. Aber ich denke, das obige ist besser. Zum einen vermeidet es den Aufruf von , wenn es nicht nötig ist.

{yl, ml} = {ynow, mnow}; 
if(mnow < m || mnow == m && dnow < d) yl--; 
if(dnow < d) ml--; 
years = yl - y; 
months = ml + 12*(ynow - yl) - m; 
yl = ynow; 
if(ml == 0) { ml = 12; yl--; } 
days = (tm({ynow, mnow, dnow}) - tm({yl, ml, d}))/60/60/24; 
return [years, months, days]; 
+0

Btw, ich glaube, das ist das Richtige für Leute, die am 29. Februar geboren sind. Sie sind nämlich einen Tag kürzer als eine ganze Zahl von Jahren am 28. Februar und eines Tages mehr als eine ganze Zahl von Jahren am 1. März, unabhängig davon ob es einen Feb 29 gab. – dreeves

+1

Ich benutze tatsächlich diesen Code (geändert für C#) in einer WP7-Anwendung, die ich schrieb. Heute war mein Glückstag zum Testen, denn als ich den 31.01.2012 mit dem 10/20/2011 verglichen habe, den allerletzten Teil, wo du tm() mit d als letzten Parameter nennst, erstickt es, weil es so ist versuchen, ein Datum von 9/31/2011 zu konstruieren, das offensichtlich nicht existent ist. Ich löste es, indem ich d auf die Anzahl der Tage im Monat für das Jahr und den Monat an diesem Punkt setzte (yl, ml), wenn der Tag größer war als die Anzahl der Tage im Monat. Nicht zu schwer zu kodieren, wenn die Sprache es nicht unterstützt. DateTime.DaysInMonth (Jahr, Monat) in C#. –

+0

Danke für den Fehlerbericht! Ich denke, ich habe dies mit einer intelligenteren Version von tm() getestet, wobei tm (2011, 9, 31) dasselbe ist wie tm (2011, 10, 1).In deiner Version ist ein Monat nach dem 31. August der 30. September; In meiner Version ist es der 1. Oktober. Es hängt wahrscheinlich von der Anwendung ab, die mehr Sinn macht (und wahrscheinlich meistens nicht wirklich wichtig ist). – dreeves

-3

Da Sie offensichtlich Python verwenden: Erstellen Sie zu Datetime-Objekten, eins mit "Geburtstag" und eins mit "jetzt", subtrahieren Sie sie und lesen Sie das Alter aus dem resultierenden Timedelta-Objekt.

Warum sich mit Dingen wie Schaltjahren beschäftigen?

+0

Ich benutze Python, aber ich suche wirklich ein generischer Algorithmus, der in der von mir verwendeten Sprache implementiert werden kann. –

4

Das ist keine einfache Frage, da über Tage (wenn wir leap-seconds nicht berücksichtigen) gibt es keine einfachen Formeln.

Monate können aus 28, 29, 30 oder 31 Tagen bestehen; Jahre können 365 oder 366 Tage sein. Daher treten Probleme auf, wenn Sie versuchen, ganze Zeiteinheiten für Monate und Jahre zu berechnen.

Hier ist eine interesting article, die alle komplexen Aspekte berücksichtigt, um Ihre Frage in Java zu lösen.

+0

Es ist nicht nur "über Stunden". Tage und Wochen sind immer noch eindeutig. Der wahre Trick ist die Definition der Länge eines Jahres (und ein Monat, der ein Zwölftel eines Jahres ist, hängt auch von dieser Definition ab). Aber alles andere ist eindeutig in Sekunden definiert. Siehe meine Antwort unten. – dreeves

+0

Ich habe es von "Stunden" auf "Tage" aktualisiert, Sie haben Recht. Ich erwähne Wochen nicht, weil es normalerweise keine wünschenswerte Art ist, Perioden zu messen (und im Beispiel ghoseb bezieht sich auch nicht auf Wochen) –

1

Es gibt eine Diskussion über Python-Liste darüber, warum die Berechnung eines Alters nicht so straightforward a task ist.

Von dieser Diskussion fand ich this implementation (die ich hier nicht kopieren und einfügen werde, weil es nicht meiner ist).

Ich habe jedoch keinen Tropfen in Bibliotheken gefunden.

0

Hier ist ein Weg, es zu tun, wenn Sie bereit sind, das Prinzip zu verletzen "Ich sollte eine ganze Zahl von Jahren alt an meinem Geburtstag sein". Beachten Sie, dass dieses Prinzip aufgrund von Schaltjahren nicht streng zutrifft. Das Folgende ist also genauer, wenn auch vielleicht weniger intuitiv. Wenn Sie wissen wollen, wie alt jemand tatsächlich ist, so würde ich es tun.

Zuerst konvertieren Sie sowohl das Geburtsdatum als auch die aktuelle Zeit in die Epoche (Anzahl der Sekunden seit Beginn der Zeit, dh 1970 in Unix-Land) und subtrahieren Sie sie. Siehe zum Beispiel diese Frage, wie man das macht: How do I convert a date/time to epoch time (aka unix time -- seconds since 1970) in Perl?. Sie haben jetzt das genaue Alter der Person in Sekunden und müssen das in eine Zeichenfolge wie "36 Jahre, 3 Monate, 8 Tage" konvertieren.

Hier ist Pseudocode, es zu tun. Es sollte einfach sein, die Wochen oder Stunden zu entfernen, oder was auch immer Teile, die Sie nicht wollen, ...

daysInYear = 365.2425; # Average lengh of a year in the gregorian calendar. 
         # Another candidate for len of a year is a sidereal year, 
         # 365.2564 days. cf. http://en.wikipedia.org/wiki/Year 
weeksInYear = daysInYear/7; 
daysInMonth = daysInYear/12; 
weeksInMonth = daysInMonth/7; 
sS = 1; 
mS = 60*sS; 
hS = 60*mS; 
dS = 24*hS; 
wS = 7*dS; 
oS = daysInMonth*dS; 
yS = daysInYear*dS; 

# Convert a number of seconds to years,months,weeks,days,hrs,mins,secs. 
seconds2str[secs] 
{ 
    local variables: 
    y, yQ= False, o, oQ= False, w, wQ= False, 
    d, dQ= False, h, hQ= False, m, mQ= False, s= secs; 

    if(secs<0) return "-" + seconds2str(-secs); # "+" is string concatenation. 

    y = floor(s/yS); 
    if(y>0) yQ = oQ = wQ = dQ = hQ = mQ = True; 
    s -= y * yS; 

    o = floor(s/oS); 
    if(o>0) oQ = wQ = dQ = hQ = mQ = True; 
    s -= o * oS; 

    w = floor(s/wS); 
    if(w>0) wQ = dQ = hQ = mQ = True; 
    s -= w * wS; 

    d = floor(s/dS); 
    if(d>0) dQ = hQ = mQ = True; 
    s -= d * dS; 

    h = floor(s/hS); 
    if(h>0) hQ = mQ = True; 
    s -= h * hS; 

    m = floor(s/mS); 
    if(m>0) mQ = True; 
    s -= m * mS; 

    return 
    (yQ ? y + " year" + maybeS(y) + " " : "") + 
    (oQ ? o + " month" + maybeS(o) + " " : "") + 
    (wQ ? w + " week" + maybeS(w) + " " : "") + 
    (dQ ? d + " day" + maybeS(d) + " " : "") + 
    (hQ ? dd(h) + ":" : "") + 
    (mQ ? dd(m) + ":" + dd(round(s)) + "s" : s + "s"); 
} 


# Returns an "s" if n!=1 and "" otherwise. 
maybeS(n) { return (n==1 ? "" : "s"); } 

# Double-digit: takes a number from 0-99 and returns it as a 2-character string. 
dd(n) { return (n<10 ? "0" + tostring(n) : tostring(n)); } 
+0

Leider, ohne wirklich Schaltjahre und Sommerzeit zu berücksichtigen, werden die Ergebnisse oft ein freier Tag sein. –

+0

Danke Michael! Ich habe der Antwort einen Vorbehalt gemacht. Sie könnten argumentieren, dass die Antwort, die eine ganze Anzahl von Jahren am Geburtstag der Person gibt, ist, was oft ein freier Tag sein wird! Also denke ich, dass diese Antwort auch einen Wert hat, abhängig von der genauen Anwendung. – dreeves

1

Seit Jahren, Monaten und Tagen sogar uneben Längen haben, können Sie nicht durch Subtraktion der beiden Daten beginnen um eine einfache Dauer zu bekommen. Wenn Sie möchten, dass das Ergebnis mit der Art und Weise übereinstimmt, wie Menschen Daten behandeln, müssen Sie stattdessen mit echten Daten arbeiten und dabei die Funktionen Ihrer Sprache verwenden, die Daten besser verstehen als je zuvor.

Wie dieser Algorithmus geschrieben wird, hängt von der Sprache ab, die Sie verwenden, da jede Sprache unterschiedliche Funktionen hat. Meine eigene Implementierung in Java, mit dem ungeschickten aber technisch korrekt GregorianCalendar:

Term difference (Date from, Date to) { 
    GregorianCalendar cal1 = new GregorianCalendar(); 
    cal1.setTimeInMillis(from.getTime()); 

    GregorianCalendar cal2 = new GregorianCalendar(); 
    cal2.setTimeInMillis(to.getTime()); 

    int years = cal2.get(Calendar.YEAR) - cal1.get(Calendar.YEAR); 
    int months = cal2.get(Calendar.MONTH) - cal1.get(Calendar.MONTH); 
    int days = cal2.get(Calendar.DAY_OF_MONTH) - cal1.get(Calendar.DAY_OF_MONTH); 
    if (days < 0) { 
     months--; 
     days += cal1.getActualMaximum(Calendar.DAY_OF_MONTH); 
    } 
    if (months < 0) { 
     years--; 
     months += 12; 
    } 
    return new Term(years, months, days); 
} 

Dies kann nicht perfekt sein, aber es liefert den Menschen lesbare Ergebnisse.Term ist eine eigene Klasse zum Speichern von Perioden im menschlichen Stil, da die Date-Bibliotheken von Java keine haben.

Für zukünftige Projekte plane ich, zu der viel besseren Joda Datum/Zeit-Bibliothek zu wechseln, die eine Periode Klasse darin hat, und wahrscheinlich diese Funktion neu schreiben muss.

3

Andere hier haben die richtige Idee - Sie müssen es einfach auf andere Sprachen erweitern können. Viele Computersysteme zählen die Zeit in Sekunden ab einem bestimmten Punkt (die "Epoche" oder das "Referenzdatum") und ermitteln das Datum von dort aus und bieten Methoden an, um von Sekunden zu Daten zu konvertieren. Sie sollten die aktuelle Zeit in Sekunden erhalten können, das Geburtsdatum Sekunden aus der Epoche wandeln, subtrahieren die beiden Werte, dann ist das dividieren durch die Anzahl der Sekunden in einem Tag:

int timenow = time(0); 
struct tm birthday = { tm_mday = 16 , .tm_mon = 1 , .tm_year = 1963 }; 
int timebirth = mktime(&birthday_tm); 
int diff_sec = timenow - timebirth; 
int days = diff_sec/(24 * 60 * 60); 
printf("%d - %d = %d seconds, or %d days\n", timenow, timebirth, diff_sec, days); 

Der Fehler in dieser Besonderer Code ist, dass mktime() nicht mit Daten vor der Epoche umgehen kann, die am 1. Januar 1970 in Unix-basierten Systemen ist. Ähnliche Probleme treten auf anderen Systemen auf, abhängig davon, wie sie die Zeit zählen. Der allgemeine Algorithmus sollte funktionieren, Sie müssen nur Ihre Grenzen für bestimmte Systeme kennen.

+0

BTW, ich habe dafür gestimmt, aber Sie sollten wahrscheinlich time_t anstelle von int verwendet haben. mktime() ist eine großartige Funktion. – dicroce

+0

Ja, time_t wäre vielleicht besser. Also ein Beispiel für den Spaß von C, Sie können alle Arten von lustigen Tricks mit Typnamen machen. Zumindest habe ich den Code kompiliert und ausgeführt bevor ich gepostet habe :-). –

+0

... mit der Ausnahme, dass es an einem Tag keine feste Anzahl von Sekunden gibt. An der Sommerzeitgrenze sind die Tage eine Stunde länger oder kürzer. Und das ist überall auf der Welt anders. –

0

Ich denke, Sie müssen die Anforderungen ein wenig besser angeben.

Sagen wir, das Geburtsdatum ist 2008-02-01 und der Tag ist 2009-01-31

Was ist das Ergebnis?

  • 0 Jahre, 11 Monate und 31 Tage?
  • 0 Jahre, 10 Monate und 28 + 31 = 59 Tage?
  • 0 Jahre, 10 Monate und 29 + 31 = 60 Tage?
0

Hier ist dies mit der Leihregel der Mathematik.

 DateTime dateOfBirth = new DateTime(2000, 4, 18); 
     DateTime currentDate = DateTime.Now; 

     int ageInYears = 0; 
     int ageInMonths = 0; 
     int ageInDays = 0; 

     ageInDays = currentDate.Day - dateOfBirth.Day; 
     ageInMonths = currentDate.Month - dateOfBirth.Month; 
     ageInYears = currentDate.Year - dateOfBirth.Year; 

     if (ageInDays < 0) 
     { 
      ageInDays += DateTime.DaysInMonth(currentDate.Year, currentDate.Month); 
      ageInMonths = ageInMonths--; 

      if (ageInMonths < 0) 
      { 
       ageInMonths += 12; 
       ageInYears--; 
      } 
     } 
     if (ageInMonths < 0) 
     { 
      ageInMonths += 12; 
      ageInYears--; 
     } 

     Console.WriteLine("{0}, {1}, {2}", ageInYears, ageInMonths, ageInDays); 
0

Die schnelle Implementierung von Dreeves 'Antwort.

ps.anstelle von (y, m, d) (jetzt, mnow, dnow) als Eingaben benutze ich zwei NSDates, die in der realen Welt nützlicher sein können.

extension NSDate { 

    convenience init(ageDateString:String) { 
     let dateStringFormatter = NSDateFormatter() 
     dateStringFormatter.dateFormat = "yyyy-MM-dd" 
     dateStringFormatter.locale = NSLocale(localeIdentifier: "en_US_POSIX") 
     let d = dateStringFormatter.dateFromString(ageDateString)! 
     self.init(timeInterval:0, sinceDate:d) 
    } 

    func ageFrom(date: NSDate) -> (Int, Int, Int) { 
     let cal = NSCalendar.currentCalendar() 

     let y = cal.component(NSCalendarUnit.Year, fromDate: date) 
     let m = cal.component(NSCalendarUnit.Month, fromDate: date) 
     let d = cal.component(NSCalendarUnit.Day, fromDate: date) 
     let ynow = cal.component(NSCalendarUnit.Year, fromDate: self) 
     let mnow = cal.component(NSCalendarUnit.Month, fromDate: self) 
     let dnow = cal.component(NSCalendarUnit.Day, fromDate: self) 

     let t0 = y * 12 + m - 1  // total months for birthdate. 
     var t = ynow * 12 + mnow - 1; // total months for Now. 
     var dm = t - t0;    // delta months. 
     if(dnow >= d) { 
      return (Int(floor(Double(dm)/12)), dm % 12, dnow - d) 
     } 
     dm-- 
     t-- 
     return (Int(floor(Double(dm)/12)), dm % 12, Int((self.timeIntervalSince1970 - NSDate(ageDateString: "\(Int(floor(Double(t)/12)))-\(t%12 + 1)-\(d)").timeIntervalSince1970)/60/60/24)) 
    } 

} 

// sample usage 
let birthday = NSDate(ageDateString: "2012-7-8") 
print(NSDate().ageFrom(birthday)) 
1

Ich nehme an, die Fragen sind breiter als nur eine Programmiersprache. Wenn Sie C# verwenden, können Sie DateTimeOffset verwenden, um dies zu berechnen.

var offset = DateTimeOffset.MinValue; 
var lastDate = DateTime.Today; 
var firstDate = new DateTime(2006,11,19); 


var diff = (lastDate- firstDate); 
var resultWithOffset = DateTimeOffset.MinValue.AddDays(diff.TotalDays); 
var result = resultWithOffset.AddDays(-offset.Day).AddMonths(-offset.Month).AddYears(-offset.Year); 

result.Day, result.Month, result.Year die Informationen, die Sie benötigen halten.

0

Ich weiß, dass es ein wenig veraltet ist, aber hier ist ein einfacher Code, den ich verwendet habe, mit der Macht der Python-Bibliothek (Python 3.5 für Anmerkungen, aber funktioniert ohne).

from datetime import date, timedelta 

def age(birth: date) -> (int, int, int): 
     """ 
      Get a 3-int tuple telling the exact age based on birth date. 
     """ 
     today_age = date(1, 1, 1) + (date.today() - birth) 
     # -1 because we start from year 1 and not 0. 
     return (today_age.year - 1, today_age.month - 1, today_age.day - 1) 
Verwandte Themen