私は、現在の日付を基準にして、生年月日と現在の日付を年、月、日で指定した人の年齢を計算します。
例えば:
>>> calculate_age(2008, 01, 01)
1 years, 0 months, 16 days
それを行うアルゴリズムへのポインタは高く評価されます。
最初に、たとえば、2月1日に生まれ、次の3月1日に生まれた場合、日齢が28歳で平均月の長さよりも短いにもかかわらず、あなたはちょうど1か月であると仮定します。 。また、年には(うるう年のために)可変長があります。これは、誕生日の年齢が正確な年数ではないことを意味します。あなたが生きてきた正確な時間を年/月/日で表現したい場合は、私の他の答えを見てください。しかし、2月1日に生まれることは、毎年2月1日がX歳、0ヶ月、0日であり、任意の月の1日にX歳、Yヶ月であることを意味するように、それを適切に修正したい場合があります。と0日。
その場合は、読み続けてください。 (注:以下は過去の日付に対してのみ機能します。)
生年月日、_(y,m,d)
_、現在の日付、_(ynow,mnow,dnow)
_、および与えられた unix /エポック時間を与える関数tm()
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];
_
以下は、すべてのフロアとモッドが気に入らない場合の同等のアルゴリズムです。しかし、私は上記の方が良いと思います。 1つには、必要のないときにtm()
を呼び出さないようにします。
_{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];
_
他の人たちは正しい考えを持っています-あなたは単にそれを他の言語に拡張することができる必要があるだけです。多くのコンピューターシステムは、特定のポイント(「エポック」または「参照日」)から秒単位で時間をカウントし、そこから日付を計算し、秒から日付に変換するメソッドを提供します。現在の時間を秒で取得し、誕生日をエポックから秒に変換し、2つの値を減算して、それを1日の秒数で割ります。
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()がエポック(Unixベースのシステムでは1970年1月1日)より前の日付を処理できないことです。時間のカウント方法に応じて、他のシステムでも同様の問題が発生します。一般的なアルゴリズムが機能するはずです。特定のシステムに対する制限を知っていれば十分です。
「誕生日には整数である必要があります」という原則に違反することをいとわないなら、これを行う方法があります。うるう年のため、この原則は厳密には真実ではないことに注意してください。そのため、以下は実際にはより正確ですが、おそらく直感的ではありません。あなたが誰かの実際の正確な年齢を知りたいなら、これは私がそれをする方法です。
最初に、誕生日と現在時刻の両方をエポック時刻(時間の夜明けからの秒数、つまりUNIXランドでは1970)に変換し、それらを減算します。その方法については、たとえば、この質問を参照してください: Perlで日付/時刻をエポック時間(別名UNIX時間-1970年からの秒数)に変換するにはどうすればよいですか? 。これで、人物の正確な年齢が秒単位でわかり、「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)); }
年、月、日で長さが不均一になる可能性があるため、2つの日付を減算して単純な期間を取得することから始めることはできません。結果を人間が日付を処理する方法と一致させる場合は、代わりに、日付をよりよく理解する言語の組み込み関数を使用して、実際の日付を処理する必要があります。
各言語には異なる関数セットがあるため、そのアルゴリズムの記述方法は、使用する言語によって異なります。ぎこちないが技術的には正しいGregorianCalendarを使用した、Javaでの独自の実装:
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の日付ライブラリには期間がないため、Termは人間スタイルの期間を格納するための私の独自のクラスです。
今後のプロジェクトでは、Periodクラスが含まれる、より優れたJoda日付/時刻ライブラリに移動する予定です。おそらく、この関数を書き直す必要があります。
Python-listで、年齢の計算が それほど単純なタスク ではない理由についての議論があります。
その議論から私は this implementation を見つけました(それは私のものではないので、ここにコピーして貼り付けません)。
しかし、私はライブラリーの低下をまったく見ていません。
私はそれが少し時代遅れであることを知っていますが、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)
Swift dreevesの回答の実装。
ps。入力として(y、m、d)(ynow、mnow、dnow)の代わりに、2つの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))
要件をもう少し詳しく指定する必要があると思います。
生年月日が2008-02-01、日が2009-01-31であるとします。
結果はどうですか?
質問は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.Day
、result.Month
、result.Year
は、必要な情報を保持します。
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))
これは、数学の借用規則を使用したものです。
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);