はじめに
個人的な話です。
VBAで指定した年の各月の日数を取得する機能が必要になり、
閏年(うるう年)のことを考慮した実装をしました。
2024年の閏年が終わり、今更ではあるのですが、
備忘録として書かせていただきます。
よくみかける判定方法
Function IsLeapYear(iYear As Integer) As Boolean
If (iYear Mod 400 = 0) Then
IsLeapYear = True
ElseIf (iYear Mod 100 = 0) Then
IsLeapYear = False
ElseIf (iYear Mod 4 = 0) Then
IsLeapYear = True
Else
IsLeapYear = False
End If
End Function
・西暦が4で割り切れる、かつ、100で割り切れない
・西暦が400で割り切れる
のどちらかに当てはまれば閏年、当てはまらない場合は通常年と判定するやり方です。
これを使っても良かったのですが、
再度判定結果からTrueの場合は29日、Falseの場合は28日を返すのは
気が引けるな~ということで他の方法を模索しました。
その1.DateSerial関数を使う方法
20XX/3/1から1を引いた値を求め、3/1の前日つまり2月の最終日を取得するようにしました。
これを使えば閏年かどうかの判定はこちら側で行わなくても済むようになります。
※他の言語では対応していないものもあります
Function GetFebDays(iYear As Integer) As Integer
GetFebDays = Day(DateSerial(iYear, 3, 1) - 1)
End Function
ちなみに指定した日付から1年の間に閏年が含まれているか判定し、
2月の日数を返したい場合は以下のように書きます。
Function GetFebDays(HopeDay As Date) As Integer
Dim monthPart As Integer
Dim yearPart As Integer
monthPart = Month(HopeDay)
yearPart = year(HopeDay)
'2月を過ぎていたら翌年で計算する
If monthPart > 2 Then
yearPart = yearPart + 1
End If
GetFebDays = Day(DateSerial(yearPart, 3, 1) - 1)
End Function
その2.DateAdd関数を使う方法
その1と同様のやり方ではございますが、こちらでも可能だと思います。
Function GetFebDays(iYear As Integer) As Integer
GetFebDays = Day(DateAdd("d", -1, DateSerial(iYear, 3, 1))
End Function
おまけ
他の言語(JavaScriptやC#)ではどうなのかも調べてみました
その1.JavaScriptの場合
2月の29番目もしくは3月の0番目を指定し、
存在する場合は29を返すというやり方もあります。
function isLeapYear(year) {
return new Date(year, 1, 29).getDate() === 29;
}
function isLeapYear(year) {
return new Date(year, 2, 0).getDate() === 29;
}
その2.C#の場合
そもそもDateTimeクラスにIsLeapYearメソッドが用意されているみたいです。
引数に4桁の数字を指定して使います
bool resule = DateTime.IsLeapYear(2020);
さいごに
浅い感想ですが、いろいろなやり方があるんだな~と思いました。
正直、DateSerial関数を使ったやり方は少しひねっていて初心者ぽくない感じが僕は好きです。笑
ただ先述の通り、言語によっては出来たり出来なかったりするみたいなので、
オーソドックスなModを使ったやり方が書く側もコードを見る側も理解しやすいのかなと思いました。