How can I calculate the age of a person in year, month, days?
我想以相对于当前日期的年、月和日计算给定出生日期和当前日期的人的年龄。
例如:
1 2 | >>> calculate_age(2008, 01, 01) 1 years, 0 months, 16 days |
任何指向某个算法的指针都将被赞赏。
首先,注意假设,比如说,你生于二月一号,准确地说是一月一号,即使你的年龄只有28岁,但比平均月长。年复一年也有变长度(由于年复一年),这意味着你的生日年龄通常不是一个准确的年复一年数。如果你想在几年/一个月/几天内准确地表达出来,请看我的其他答案。但你越想逃避这一切,就越想在二月出生,这意味着你在二月的第一天是十年,零个月,零个月,而在任何一个月的第一天,你是十年,一个月,一个月,零天。
在这种情况下,阅读。(NB:The following only works for dates in the past.)
给出出生日期,
1 2 3 4 5 6 7 | 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]; |
跟踪是一个等效算法,如果你不喜欢所有的流量和模式。但我认为上面的东西更好。有一件事,当它不需要时,它会呼唤
ZZU1
这不是一个简单的问题,因为上面的日子(如果我们不考虑闰秒)有不容易的公式。
月可以是28天、29天、30天或31天;年可以是365天或366天。因此,当您试图计算月份和年份的完整时间单位时,就会出现问题。
这里有一篇有趣的文章,它考虑到用Java来解决您的问题的所有复杂方面。
这里的其他人有正确的想法-您只需要能够将其扩展到其他语言。许多计算机系统从一个特定的点("epoch"或"reference date")开始以秒为单位计算时间,并从那里计算出日期,并提供从秒转换为日期的方法。您应该能够以秒为单位获取当前时间,将出生日期从历元转换为秒,减去这两个值,然后将其除以一天中的秒数:
1 2 3 4 5 6 7 | 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 ", timenow, timebirth, diff_sec, days); |
这个特定代码中的bug是mktime()无法处理epoch之前的日期,在基于Unix的系统中是1970年1月1日。其他系统也会存在类似的问题,这取决于它们如何计算时间。一般的算法应该有效,你只需要知道你对特定系统的限制。
如果你愿意违背"生日那天我应该是一个整数岁"的原则,这里有一个方法可以做到这一点。请注意,由于闰年的原因,这一原则并不完全正确,因此下面的内容实际上更准确,尽管可能不太直观。如果你想知道某人实际的确切年龄,我会这样做的。
首先将出生日期和当前时间都转换为纪元时间(从时间开始的秒数,即在Unix Land中为1970秒),然后减去它们。请参阅,例如,这个问题以了解如何做到这一点:如何在Perl中将日期/时间转换为epoch时间(即unix时间——1970年以来的秒数)?你现在有了这个人的准确年龄(以秒为单位),需要把它转换成一个字符串,比如"36岁,3个月,8天"。
这是伪代码。它应该是直接删除周或小时或任何你不想要的部分…
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | 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)); } |
我接受的问题比一种编程语言宽泛。如果您使用的是C 35,您可以使用日期偏移来计算这个。
1 2 3 4 5 6 7 8 | 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); |
你会得到你需要的信息。
由于年、月甚至天的长度可能不均匀,因此不能从减去这两个日期开始计算一个简单的持续时间。如果你想让结果与人类对待日期的方式相匹配,你就必须使用真实的日期,使用你的语言内置的功能,比你以前更了解日期。
该算法的编写方式取决于您使用的语言,因为每种语言都有一组不同的函数。我自己在Java中实现的,使用了笨拙但技术上正确的GregorianCalendar:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | 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日期/时间库,其中确实有一个句点类,可能需要重写这个函数。
这个算法打印下一个格式->24年,8个月,2天
1 2 3 4 5 6 7 8 9 10 | from dateutil.relativedelta import * from datetime import date def calc_age(dob): today = date.today() age = relativedelta(today, dob) print str(age.years)+" Years,"+str(age.months)+" Months,"+str(age.days)+" Days" #test it calc_age(date(1993,10,10)) |
我知道这是一个比特,但这里是一个简单的代码,我使用的是Python图书馆的力量(Python 3.5 for annotations,but this i s a simple code I used,with the power of the python library(Python 3.5 for annotations,but works wit
1 2 3 4 5 6 7 8 9 | 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) |
The swift implementation of dreeves's answer.
Ps.Instead of(y,m,d)(ynow,mnow,dnow)as the inputs,I use two nsdate's,which may be more handy in real world usages.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | 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 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | 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); |
显然,您使用的是python:create-to-datetime对象,其中一个具有"birthday"和一个具有"now",因此请减去它们,并从生成的timedelta对象中读取年龄。
为什么要为闰年之类的事情烦恼?