13

VBA での IsLeapYear 関数の適切な実装は何ですか?

編集: if-then と DateSerial の実装を繰り返しをタイマーでラップして実行したところ、DateSerial は平均で 1 ~ 2 ミリ秒高速でした (300 回の繰り返しを 5 回実行し、1 つの平均セル ワークシート式も機能しています)。

4

10 に答える 10

27
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 サイトから入手したものです。

ピアソンのサイト

于 2008-09-24T16:10:43.857 に答える
14
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

于 2008-09-24T16:16:09.943 に答える
5

効率が考慮され、予想される年がランダムである場合は、最も頻繁なケースを最初に実行する方がわずかに良い場合があります。

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
于 2008-09-24T21:28:55.183 に答える
2

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
于 2011-08-08T05:15:28.440 に答える
2

CodeToadでこの面白いものを見つけました:

Public Function IsLeapYear(Year As Varient) As Boolean
  IsLeapYear = IsDate("29-Feb-" & Year)
End Function 

関数内での IsDate の使用は、おそらくいくつかの if や elseif よりも遅いと確信していますが。

于 2008-09-25T00:50:08.927 に答える
2

パフォーマンスの問題に対処するための遅い回答。

TL/DR: Mathバージョンは約5 倍高速です


ここに 2 つのグループの回答が表示されます

  1. うるう年の定義の数学的解釈
  2. Excel の日付/時刻関数を使用して 2 月 29 日を検出します (これらは、日付を文字列として作成するグループと作成しないグループの 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

日付を文字列として構築する日付/時刻バージョンは、再び大幅に低速になるため割引されました。

テストはIsLeapYear100..9999 年を取得することで、1000 回繰り返されました。

結果

  • 演算バージョン: 640ms
  • 日付/時刻バージョン: 3360ms

テストコードは

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
于 2018-06-05T04:28:51.683 に答える
1
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
于 2014-08-19T06:13:21.010 に答える
0

別の簡単なオプションを次に示します。

Leap_Day_Check = Day(DateValue("01/03/" & Required_Year) - 1)

Leap_Day_Check = 28 の場合はうるう年ではなく、29 の場合はうるう年です。

VBA は 3 月 1 日より前の日付を認識しているため、2 月 28 日または 29 日と設定されます。

于 2015-11-19T16:10:50.513 に答える