2009-01-17 301 views
17

我想计算给定出生日期的人的年龄以及相对于当前日期的年,月和日的当前日期。如何计算年,月,日的人的年龄?

例如:

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

任何指针一种算法,这是否将受到赞赏。

+0

许多语言都可以在标准库中做到这一点。任何首选语言,或者你想要一个“纯”的算法? – 2009-01-17 12:10:40

+0

看看这篇文章:http://00f.net/2007/an-age-is-not-a-duration – MatthieuP 2009-01-17 12:17:47

+0

类似于http://stackoverflow.com/questions/9/how-doi-i-计算 - someones-age-in-c – some 2009-01-17 13:39:31

回答

15

首先,请注意一个假设,例如,如果您出生于2月1日,然后在随后的3月1日出生,即使您的年龄仅为28天,但您的年龄恰好为1个月大平均一个月。年份也有可变长度(由于闰年),这意味着您的生日年龄通常不是确切的整数年。如果您想要以年/月/日的形式表达您活着的确切时间,请参阅我的其他答案。但更有可能的是,你想把它恰到好处,以便在2月1日出生意味着每个2月1日你是X年,0个月和0天,并且在任何一个月的第一天你是X年,Y月,和0天。

在这种情况下,请继续阅读。 (注:以下内容仅适用于在过去的日期。)

生完孩子,(y,m,d),当前日期,(ynow,mnow,dnow)的日期和功能,让unix/epoch time for a given date,以下将输出一个3元素列表,给出年龄{年,月,日}:

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]; 

以下是等效的算法,如果你不喜欢所有的地板和器官功能障碍综合征。但我认为以上更好。一方面它可以避免在不需要时调用。

{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]; 
-3

由于您明显正在使用python:创建日期时间对象,其中一个使用“生日”,另一个使用“now”,将它们相减并从结果timedelta对象中读取年龄。

为什么会像闰年一样困扰?

4

这不是一个简单的问题,因为以上几天(如果我们不考虑leap-seconds)有不容易的公式。

几个月可以包含28,29,30或31天;年可以是365或366天。因此,当您尝试计算几个月和几年的完整时间单位时会出现问题。

这是一个interesting article考虑到所有复杂的方面来解决你在Java中的问题。

1

有一个关于python-list的讨论关于为什么计算年龄不是so straightforward a task

从讨论中我发现this implementation(我不会复制和粘贴在这里,因为它不是我的)。

虽然我还没有出现库中的任何下降。

0

如果你愿意违反“我的生日应该是整数岁”的原则,这里有一个办法。请注意,由于闰年,该原则并非严格正确,因此以下实际上更准确,但可能不太直观。如果你想知道某人的实际确切年数,这是我会这样做的方式。

首先将出生日期和当前时间都转换为纪元时间(从黎明以来的秒数,即1970年unix土地)并将其相减。例如,请看这个问题:How do I convert a date/time to epoch time (aka unix time -- seconds since 1970) in Perl?。您现在已经在几秒钟内确定了该人的确切年龄,需要将其转换为“36年,3个月,8天”之类的字符串。

这里是伪代码来做到这一点。它应该是简单的去除你不想要的数周或小时或任何部分...

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)); } 
1

年以来,几个月甚至几天可以有长度不均匀,则无法通过减去两个日期开始得到一个简单的持续时间。如果你想让结果与人类对待日期的方式相匹配,你就必须使用真正的日期,使用你的语言内置的函数来比以往更好地理解日期。

如何编写算法取决于您使用的语言,因为每种语言都有不同的函数集。我自己的实现在Java中,使用的尴尬,但技术上是正确的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); 
} 

这可能不是完美的,但它提供了人类可读的结果。术语是我自己的类,用于存储人类风格的时期,因为Java的日期库没有。

对于未来的项目,我打算转移到更好的Joda日期/时间库,它有一个Period类,并且可能必须重写此函数。

3

这里的其他人有正确的想法 - 你只需要能够扩展到其他语言。许多计算机系统从特定时间点(“时代”或“参考日期”)计算时间,并计算出日期,并提供从秒到日期的转换方法。你应该能够在数秒内获得当前时间,出生日期从时代转换到秒,减去两个值,然后在一天除以秒数:

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); 

在此的错误特别的代码是mktime()不能处理纪元之前的日期,这是1970年1月1日在基于Unix的系统中的日期。其他系统也会有类似的问题,这取决于他们如何计算时间。通用算法应该可行,你只需要知道你对特定系统的限制。

0

我认为你必须指定好一点。

比方说,出生日期是2008-02-01,这一天是2009-01-31

结果是什么?

  • 0年11个月和31天呢?
  • 0年,10个月和28 + 31 = 59天?
  • 0年,10个月和29 + 31 = 60天?
0

这是使用数学借贷规则。

 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

快速执行dreeves的答案。

ps。代替(y,m,d)(ynow,mnow,dnow)作为输入,我使用两个NSDate,这在现实世界中可能更方便。

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

我假设问题比只有一种编程语言更广泛。 如果您使用的是C#,则可以使用DateTimeOffset来计算此值。

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.Dayresult.Monthresult.Year将持有你所需要的信息。

0

我知道这有些过时,但这是一个简单的代码,我使用了Python库的功能(Python 3.5用于注释,但是没有工作)。

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)