VBA での IsLeapYear 関数の適切な実装は何ですか?
編集: if-then と DateSerial の実装を繰り返しをタイマーでラップして実行したところ、DateSerial は平均で 1 ~ 2 ミリ秒高速でした (300 回の繰り返しを 5 回実行し、1 つの平均セル ワークシート式も機能しています)。
VBA での IsLeapYear 関数の適切な実装は何ですか?
編集: if-then と DateSerial の実装を繰り返しをタイマーでラップして実行したところ、DateSerial は平均で 1 ~ 2 ミリ秒高速でした (300 回の繰り返しを 5 回実行し、1 つの平均セル ワークシート式も機能しています)。
Public Function isLeapYear(Yr As Integer) As Boolean
' returns FALSE if not Leap Year, TRUE if Leap Year
isLeapYear = (Month(DateSerial(Yr, 2, 29)) = 2)
End Function
この関数は、Chip Pearson の優れた Excel サイトから入手したものです。
public function isLeapYear (yr as integer) as boolean
isLeapYear = false
if (mod(yr,400)) = 0 then isLeapYear = true
elseif (mod(yr,100)) = 0 then isLeapYear = false
elseif (mod(yr,4)) = 0 then isLeapYear = true
end function
詳細はウィキペディア... http://en.wikipedia.org/wiki/Leap_year
効率が考慮され、予想される年がランダムである場合は、最も頻繁なケースを最初に実行する方がわずかに良い場合があります。
public function isLeapYear (yr as integer) as boolean
if (mod(yr,4)) <> 0 then isLeapYear = false
elseif (mod(yr,400)) = 0 then isLeapYear = true
elseif (mod(yr,100)) = 0 then isLeapYear = false
else isLeapYear = true
end function
Chip Pearson ソリューションのバリエーションとして、試すこともできます
Public Function isLeapYear(Yr As Integer) As Boolean
' returns FALSE if not Leap Year, TRUE if Leap Year
isLeapYear = (DAY(DateSerial(Yr, 3, 0)) = 29)
End Function
CodeToadでこの面白いものを見つけました:
Public Function IsLeapYear(Year As Varient) As Boolean
IsLeapYear = IsDate("29-Feb-" & Year)
End Function
関数内での IsDate の使用は、おそらくいくつかの if や elseif よりも遅いと確信していますが。
パフォーマンスの問題に対処するための遅い回答。
TL/DR: Mathバージョンは約5 倍高速です
ここに 2 つのグループの回答が表示されます
投稿されたすべての回答に対して時間テストを実行したところ、MathメソッドがDate/Time メソッドよりも約5 倍高速であることがわかりました。
次に、メソッドの最適化を行い、思いつきました(信じられない かもしれませんが、この場合Integer
よりもわずかに高速ですLong
。理由はわかりません。)
Function IsLeapYear1(Y As Integer) As Boolean
If Y Mod 4 Then Exit Function
If Y Mod 100 Then
ElseIf Y Mod 400 Then Exit Function
End If
IsLeapYear1 = True
End Function
比較のために、私が思いついた(投稿されたバージョンとの違いはほとんどありません)
Public Function IsLeapYear2(yr As Integer) As Boolean
IsLeapYear2 = Month(DateSerial(yr, 2, 29)) = 2
End Function
日付を文字列として構築する日付/時刻バージョンは、再び大幅に低速になるため割引されました。
テストはIsLeapYear
100..9999 年を取得することで、1000 回繰り返されました。
結果
テストコードは
Sub Test()
Dim n As Long, i As Integer, j As Long
Dim d As Long
Dim t1 As Single, t2 As Single
Dim b As Boolean
n = 1000
Debug.Print "============================="
t1 = Timer()
For j = 1 To n
For i = 100 To 9999
b = IsYLeapYear1(i)
Next i, j
t2 = Timer()
Debug.Print 1, (t2 - t1) * 1000
t1 = Timer()
For j = 1 To n
For i = 100 To 9999
b = IsLeapYear2(i)
Next i, j
t2 = Timer()
Debug.Print 2, (t2 - t1) * 1000
End Sub
Public Function isLeapYear(Optional intYear As Variant) As Boolean
If IsMissing(intYear) Then
intYear = Year(Date)
End If
If intYear Mod 400 = 0 Then
isLeapYear = True
ElseIf intYear Mod 4 = 0 And intYear Mod 100 <> 0 Then
isLeapYear = True
End If
End Function
別の簡単なオプションを次に示します。
Leap_Day_Check = Day(DateValue("01/03/" & Required_Year) - 1)
Leap_Day_Check = 28 の場合はうるう年ではなく、29 の場合はうるう年です。
VBA は 3 月 1 日より前の日付を認識しているため、2 月 28 日または 29 日と設定されます。