現在の年齢を出力する

ラボ

はじめに

 Excelで年齢を出力するには、数式マクロのDATEDIF関数が最も簡単です。
 DATEDIF関数は、2つの日付間の日数、月数、年数を計算する事が出来ます。
 
 =DATEDIF(開始日,終了日,“Y”)

 第二引数をNow()として現在の日付を指定すれば、開始日(生年月日)との差を年数(”Y”)で返してくれます。


 ちなみにDATEDIF関数は古いブックをサポートするために残している関数だそうです。

DATEDIF関数で年齢を出力する際の問題点

 DATEDIF関数は便利なのですが、今回の場合、参照するセルが空白の場合でも値を出力してしまう点が問題です。

 「123」と表示されるのは、日付型の1900年1月1日と現在(2023年12月12日時点)を計算してしまうからです。(123 = 2023 – 1900)

 空白を探知するだけでしたら数式マクロのIFを使えば回避できますが、数値などでも値を返してしまうため注意が必要です。

VBAで年齢を出力する

 VBAで数式マクロのDATEDIF関数と同じような関数にDateDiffというのがありますが、この関数で年齢を求める場合は、日付の差を年数(”yyyy”)で指定しても開始日と終了日の年を比べるだけなので、年齢を求めるのには向いていません。
 VBAで年齢を求める場合は、年の比較と、日付とその年の誕生日を比較して、誕生日に到達していなければ ‐1 とする必要があります。
 
 また、先の数式マクロのようにユーザー定義関数としてプログラムを書く場合、参照するセルに日付が入っているかどうかを考慮する必要があるでしょう。
 参照するセルが日付ではないばあい、エラーを出力するか、空白とするという選択肢があります。
 
 さらに、ユーザー定義関数としてでなくプログラムする場合は、エラーを発生させるか、-1などのありえない数値を返す方法が考えられます。
 
 今回は、ユーザー定義関数VBAで利用する場合の2つの方法を紹介します。

ユーザー定義関数

 今回は、引数に参照するセルを取り、現在の日付との差から年齢を出力するユーザー定義関数のプログラムを書いてみます。ユーザー定義関数とは、セルの数式マクロを自作したものです。

Function ageForBirthday(birthday As Variant) As Variant

    If IsDate(birthday) = False Then
        ageForBirthday = CVErr(xlErrValue) 'ユーザー定義関数の時
        'ageForBirthday = ""        '空白で出力したい時
      Exit Function
    End If
    
    Dim a As Long
    a = Year(Date) - Year(birthday)
    
    If Date < DateSerial(Year(Date), Month(birthday), Day(birthday)) Then
        a = a - 1
    End If
    
    ageForBirthday = a
End Function

 まず、引数返り値ですが、両方ともバリアント型にします。
 引数を日付型にしても良さそうですが、結局空白なども許してしまうため一旦バリアント型で受けてから日付型かを判断します。
 返り値に関してもエラー出力年齢(数値)の出力の2種類が想定されるのでバリアント型としています。
 
 IsDate関数で判断し、日付型でない場合は、CVErr(xlErrValue)としてエラー表示させます。
 場合によっては空白にした方が都合が良い場合は、下のコメントアウトしたコードを利用しても良いでしょう。
 
 引数が日付型だった場合は、現在の年と誕生日の年との差を計算します。
 
 次は、今の日付と、今年の誕生日を比較して、誕生日が到来していなければ‐1 とします
 
 これで、引数のセルが日付でない場合は、#VALUE! と表示され、日付の場合は今日の時点の年齢が表示されます。

VBAで利用する関数

 VBAプログラムの中で、年齢を出力するプログラムを組む場合はセルにエラーを表示させない場合もあるでしょう。
 そのままですと空白は1900年を基準に計算してしまうのでエラーに気付かない場合もあって問題があります。 日付以外の値が来た時はエラーを発生させるのが自然なやり方でしょう。
 
 自作関数でエラーを発生させるには、以下のようにします。
 
 Err.Raise Number:= エラー番号
 
 今回は「実行時エラー13 型が一致しません。」を表示させようにしてみました。

Function ageForBirthdayVBA(birthday) As Long
    If IsDate(birthday) = False Then
        Err.Raise Number:=13	'エラーを発生させる
    End If
    
    Dim a As Long
    
    a = Year(Date) - Year(birthday)
    
    If Date < DateSerial(Year(Date), Month(birthday), Day(birthday)) Then
        a = a - 1
    End If
    
    ageForBirthdayVBA = a
End Function

'////// 上のプロシージャを試すテストコード //////
Sub testAge()
    Debug.Print ageForBirthday(Range("B4"))
End Sub 

 テストコードでは、B4セルが空白の場合は、「実行時エラー13 型が一致しません。」が発生しエラーで止まるようになります。

まとめ

 年齢を求めるプログラムは、計算自体は簡単なのですが、日付型を扱う事からエラーに対する対処が面倒になります。

 日付型にはNULL(値が無い)という状態は存在せず、数値型のように何もなければ0と認識し、0は1900年1月0日(?)という解釈となり、計算式が成り立ってしまう事があるのです。

 このようなケースはエラーとなるより厄介で、ミスを受け入れたまま処理が進んでしまう事になるので注意が必要です。

コメント

タイトルとURLをコピーしました