年齢を求める
60 GetAge 動作確認 Delphi2007 更新日 2008/01/31(木)
2010/07/06(火)

任意の日付間の年齢を調べる関数です。

ネット上には誤動作するコードが多すぎですので
チェックコードを書いておきました。
これで関数の信頼性が保たれます。

閏年の2月29日、つまり閏日に生まれた人の年齢計算については
テストコードを読むことで仕様がわかるようになっています。

閏年の誕生日は特殊な仕様が考えられるので、
閏日判定での特殊な年齢計算を行いたい場合は
GetAgeOld 関数を修正するほうがやりやすいと思います。

────────────────────
{-------------------------------
//年齢を調べる関数機能
    GetAgeOld/GetAge
機能:       指定した日付の時の年齢を求めます。
            今日を指定する場合CheckDateにDateを代入してください
戻り値:     年齢
備考:       CheckDateがBirthDateの前の日でも
            年齢が負の値になって正しい日付計算処理をします
            (必要ない処理かも…)
            計算するときに2通りの求め方をしてみました。
            GetAgeOldはEncodeDateしているので遅いかもしれない
            GetAgeを使ってください。
履歴:       2001/08/21
            2008/01/30
              関数名・変数名やコメントなどを修正
              テストコードをしっかり記述
//------------------------------}
function GetAgeOld(BirthDate, CheckDate: TDateTime): Integer;
var
  BirthYear, BirthMonth, BirthDay,
  CheckYear, CheckMonth, CheckDay: Word;
begin
  //誕生日,任意の日を年月日単位にバラす
  DecodeDate(BirthDate, BirthYear, BirthMonth, BirthDay);
  DecodeDate(CheckDate, CheckYear, CheckMonth, CheckDay);

  //現在(任意の年月日)の「年」から誕生日の「年」を引く
  Result := CheckYear - BirthYear;

  //チェックしたい年がうるう年ではない場合
  if not IsLeapYear(CheckYear) then
  begin
    //誕生日がうるう日なら
    if (BirthMonth=2) and (BirthDay=29) then
    begin
      BirthMonth := 3; BirthDay := 1;
    end; //誕生日を3/1にしておく
  end;

  //その年の誕生日を過ぎていなければさらに1歳引く
  if ( EncodeDate(CheckYear, CheckMonth, CheckDay)
       < EncodeDate(CheckYear, BirthMonth, BirthDay) ) then
    Result := Result - 1;
End;

function GetAge(BirthDate, CheckDate: TDateTime): Integer;
var
  BirthYear, BirthMonth, BirthDay,
  CheckYear, CheckMonth, CheckDay: Word;
begin
  DecodeDate(BirthDate, BirthYear, BirthMonth, BirthDay);
  DecodeDate(CheckDate, CheckYear, CheckMonth, CheckDay);

  Result := CheckYear - BirthYear;

  //誕生日を過ぎていなければさらに1歳引く
  if (CheckMonth < BirthMonth) then
  begin
    Dec(Result);
  end else
  if (CheckMonth = BirthMonth) then
  begin
    if (CheckDay < BirthDay) then
      Dec(Result);
  end;
End;

function Age(BirthDay, CheckDay:TDateTime):Integer;
begin
  Result := GetAge(BirthDay, CheckDay);
end;

type
  TAgeFunction = Function(A, B: TDateTime): Integer;

procedure testAge;

    function AgeText(BirthDateText, CheckDateText: String; Func: TAgeFunction): Integer;
    begin
      Result :=
        Func(StrToDate(BirthDateText), StrToDate(CheckDateText)) ;
    end;

    procedure CheckAgeFunction(BirthDateText, CheckDateText: String; CheckAge: Integer);
    begin
      Check(AgeText(BirthDateText, CheckDateText, GetAge), CheckAge);
      Check(AgeText(BirthDateText, CheckDateText, GetAgeOld), CheckAge);
    end;

begin
  //閏年が誕生日 と 閏年じゃない年 との年齢
  CheckAgeFunction('1992/02/28', '1993/02/27', 0);
  CheckAgeFunction('1992/02/28', '1993/02/28', 1);
  CheckAgeFunction('1992/02/28', '1993/03/01', 1);

  CheckAgeFunction('1992/02/29', '1993/02/27', 0);
  CheckAgeFunction('1992/02/29', '1993/02/28', 0);
  CheckAgeFunction('1992/02/29', '1993/03/01', 1);

  CheckAgeFunction('1992/03/01', '1993/02/27', 0);
  CheckAgeFunction('1992/03/01', '1993/02/28', 0);
  CheckAgeFunction('1992/03/01', '1993/03/01', 1);

  //閏年が誕生日 と 閏年 との年齢
  CheckAgeFunction('1992/02/28', '2008/02/27', 15);
  CheckAgeFunction('1992/02/28', '2008/02/28', 16);
  CheckAgeFunction('1992/02/28', '2008/02/29', 16);
  CheckAgeFunction('1992/02/28', '2008/03/01', 16);

  CheckAgeFunction('1992/02/29', '2008/02/27', 15);
  CheckAgeFunction('1992/02/29', '2008/02/28', 15);
  CheckAgeFunction('1992/02/29', '2008/02/29', 16);
  CheckAgeFunction('1992/02/29', '2008/03/01', 16);

  CheckAgeFunction('1992/03/01', '2008/02/27', 15);
  CheckAgeFunction('1992/03/01', '2008/02/28', 15);
  CheckAgeFunction('1992/03/01', '2008/02/29', 15);
  CheckAgeFunction('1992/03/01', '2008/03/01', 16);

  //閏年じゃない年が誕生日 と 閏年じゃない年 との年齢
  CheckAgeFunction('1993/02/28', '1994/02/27', 0);
  CheckAgeFunction('1993/02/28', '1994/02/28', 1);
  CheckAgeFunction('1993/02/28', '1994/03/01', 1);

  CheckAgeFunction('1993/03/01', '1994/02/27', 0);
  CheckAgeFunction('1993/03/01', '1994/02/28', 0);
  CheckAgeFunction('1993/03/01', '1994/03/01', 1);

  //閏年じゃない年が誕生日 と 閏年 との年齢
  CheckAgeFunction('2007/02/28', '2008/02/27', 0);
  CheckAgeFunction('2007/02/28', '2008/02/28', 1);
  CheckAgeFunction('2007/02/28', '2008/02/29', 1);
  CheckAgeFunction('2007/02/28', '2008/03/01', 1);

  CheckAgeFunction('2007/03/01', '2008/02/27', 0);
  CheckAgeFunction('2007/03/01', '2008/02/28', 0);
  CheckAgeFunction('2007/03/01', '2008/02/29', 0);
  CheckAgeFunction('2007/03/01', '2008/03/01', 1);
end;
//------------------------------
────────────────────


参考────────────────────
[Delphi-ML:33755] [Delphi-ML:33757] Re: 生年月日から年齢を取得
http://www2.big.or.jp/~osamu/Delphi/browse.cgi?index=33755
    CheckAgeFunction('1992/02/29', '1993/02/27', 0);
    このテストを通過しません。

http://www2.big.or.jp/~osamu/Delphi/browse.cgi?index=33757
    CheckAgeFunction('1992/03/01', '1993/02/27', 0);
    このテストを通過しません。

Delphi/年齢計算 - LANDHERE Wiki
http://wiki.landhere.info/pukiwiki.php?Delphi%2F%E5%B9%B4%E9%BD%A2%E8%A8%88%E7%AE%97
    ソースも間違っているし(2つめのDecodeDate)
    CheckAgeFunction('1992/02/28', '1993/03/01', 1);
    このテストを通過しません。

smdn: Delphiで遊んでみる その2.言語仕様中編
http://smdn.invisiblefulmoon.net/ikimasshoy/delphi/learningdelphi2.html
    CalcAge
    全テスト通過。上記のGetAgeと実装は同じです。

年齢を計算するには?
http://homepage1.nifty.com/MADIA/delphi/delphi_bbs/200702/200702_07020046.html

DelFusaBlog 年齢計算
http://delfusa.blog65.fc2.com/blog-entry-42.html
    関数名や変数名を変えただけで同一。

2/29生まれの人の誕生日について
きょうは何の日〜毎日が記念日〜
http://www.nnh.to/02/29.html
Yomiuri On-Line / なんでもクエスチョン
「早生まれ」4月1日含むのはなぜ?
http://www.yomiuri.co.jp/nandemo/list/20010129.htm
AddinBox期間計算まとめ
http://www.h3.dion.ne.jp/~sakatsu/period_topic2.htm