我想計算給定出生日期的人的年齡以及相對於當前日期的年,月和日的當前日期。如何計算年,月,日的人的年齡?
例如:
>>> 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