我想计算给定出生日期的人的年龄以及相对于当前日期的年,月和日的当前日期。如何计算年,月,日的人的年龄?
例如:
>>> calculate_age(2008, 01, 01)
1 years, 0 months, 16 days
任何指针一种算法,这是否将受到赞赏。
我想计算给定出生日期的人的年龄以及相对于当前日期的年,月和日的当前日期。如何计算年,月,日的人的年龄?
例如:
>>> calculate_age(2008, 01, 01)
1 years, 0 months, 16 days
任何指针一种算法,这是否将受到赞赏。
首先,请注意一个假设,例如,如果您出生于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];
由于您明显正在使用python:创建日期时间对象,其中一个使用“生日”,另一个使用“now”,将它们相减并从结果timedelta对象中读取年龄。
为什么会像闰年一样困扰?
这不是一个简单的问题,因为以上几天(如果我们不考虑leap-seconds)有不容易的公式。
几个月可以包含28,29,30或31天;年可以是365或366天。因此,当您尝试计算几个月和几年的完整时间单位时会出现问题。
这是一个interesting article考虑到所有复杂的方面来解决你在Java中的问题。
有一个关于python-list的讨论关于为什么计算年龄不是so straightforward a task。
从讨论中我发现this implementation(我不会复制和粘贴在这里,因为它不是我的)。
虽然我还没有出现库中的任何下降。
如果你愿意违反“我的生日应该是整数岁”的原则,这里有一个办法。请注意,由于闰年,该原则并非严格正确,因此以下实际上更准确,但可能不太直观。如果你想知道某人的实际确切年数,这是我会这样做的方式。
首先将出生日期和当前时间都转换为纪元时间(从黎明以来的秒数,即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)); }
年以来,几个月甚至几天可以有长度不均匀,则无法通过减去两个日期开始得到一个简单的持续时间。如果你想让结果与人类对待日期的方式相匹配,你就必须使用真正的日期,使用你的语言内置的函数来比以往更好地理解日期。
如何编写算法取决于您使用的语言,因为每种语言都有不同的函数集。我自己的实现在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类,并且可能必须重写此函数。
这里的其他人有正确的想法 - 你只需要能够扩展到其他语言。许多计算机系统从特定时间点(“时代”或“参考日期”)计算时间,并计算出日期,并提供从秒到日期的转换方法。你应该能够在数秒内获得当前时间,出生日期从时代转换到秒,减去两个值,然后在一天除以秒数:
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的系统中的日期。其他系统也会有类似的问题,这取决于他们如何计算时间。通用算法应该可行,你只需要知道你对特定系统的限制。
我认为你必须指定好一点。
比方说,出生日期是2008-02-01,这一天是2009-01-31
结果是什么?
这是使用数学借贷规则。
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);
快速执行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))
我假设问题比只有一种编程语言更广泛。 如果您使用的是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.Day
,result.Month
,result.Year
将持有你所需要的信息。
我知道这有些过时,但这是一个简单的代码,我使用了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)
许多语言都可以在标准库中做到这一点。任何首选语言,或者你想要一个“纯”的算法? – 2009-01-17 12:10:40
看看这篇文章:http://00f.net/2007/an-age-is-not-a-duration – MatthieuP 2009-01-17 12:17:47
类似于http://stackoverflow.com/questions/9/how-doi-i-计算 - someones-age-in-c – some 2009-01-17 13:39:31