Frage

Was ist eine gute Umsetzung einer IsLeapYear Funktion in VBA?

Bearbeiten: Ich lief das if-then und die DatSeriell Implementierung mit umwickelten Iterationen in einem Timer und die DatSeriell war schneller im Durchschnitt um 1-2 ms (5 Läufe von 300 Iterationen, mit mittlere Zell 1 Arbeitsblatt Formel auch arbeiten).

War es hilfreich?

Lösung

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  

Ich habe ursprünglich diese Funktion von Chip Pearson große Excel-Website.

Pearson-Website

Andere Tipps

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

Wikipedia für mehr ... http://en.wikipedia.org/wiki/Leap_year

Wenn Effizienz ist eine Überlegung und das erwartete Jahr ist zufällig, dann könnte es etwas besser, die häufigste Fall zuerst zu tun:

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

Als Variante des Chip Pearson Lösung, könnten Sie auch versuchen,

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

Ich fand diesen lustig man auf CodeToad :

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

Obwohl ich bin mir ziemlich sicher, dass die Verwendung von IsDate in einer Funktion ist wahrscheinlich langsamer als ein paar, wenn elseifs.

Public Function ISLeapYear(Y As Integer) AS Boolean
 ' Uses a 2 or 4 digit year
'To determine whether a year is a leap year, follow these steps:
'1    If the year is evenly divisible by 4, go to step 2. Otherwise, go to step 5.
'2    If the year is evenly divisible by 100, go to step 3. Otherwise, go to step 4.
'3    If the year is evenly divisible by 400, go to step 4. Otherwise, go to step 5.
'4    The year is a leap year (it has 366 days).
'5    The year is not a leap year (it has 365 days).

If Y Mod 4 = 0 Then ' This is Step 1 either goto step 2 else step 5
    If Y Mod 100 = 0 Then ' This is Step 2 either goto step 3 else step 4
        If Y Mod 400 = 0 Then ' This is Step 3 either goto step 4 else step 5
            ISLeapYear = True ' This is Step 4 from step 3
                Exit Function
        Else: ISLeapYear = False ' This is Step 5 from step 3
                Exit Function
        End If
    Else: ISLeapYear = True ' This is Step 4 from Step 2
            Exit Function
    End If
Else: ISLeapYear = False ' This is Step 5 from Step 1
End If


End Function
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

Ich sehe viele große Konzepte, die zusätzliche Verständnis zeigen und die Verwendung von Datumsfunktionen, die grandios sind zu lernen ... In Bezug auf die Code-Effizienz ..  Sehen Sie den Maschinencode für eine Funktion benötigt, um auszuführen

anstatt komplexe Datumsfunktionen verwenden nur ziemlich schnelle Integer-Funktionen BASIC wurde auf GOTO gebaut Ich vermute, dass so etwas wie unten schneller

  Function IsYLeapYear(Y%) As Boolean
     If Y Mod 4 <> 0 Then GoTo NoLY ' get rid of 75% of them
     If Y Mod 400 <> 0 And Y Mod 100 = 0 Then GoTo NoLY
     IsYLeapYear = True

Noly:

 End Function

Späte Antwort, die Leistung Frage zu beantworten.

TL / DR: die Math Versionen sind über 5x schneller


Ich sehe zwei Gruppen von Antworten hier

  1. Mathematische Interpretation der Schaltjahr-Definition
  2. Nutzen Sie die Excel-Datum / Zeit-Funktionen 29. Februar zu erfassen (diese fallen in zwei Lager: diejenigen, die ein Datum als String bauen und solche, die dies nicht tun)

Ich lief Zeittests auf allen geschrieben Antworten, eine entdeckte die Math Methoden sind über 5x schneller als die Datum / Zeit-Methoden.


Ich habe dann einige Optimierung der Methoden und kam mit (es glauben oder nicht Integer ist geringfügig schneller als Long in diesem Fall weiß nicht, warum.) Bis

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

Zum Vergleich kam ich (sehr wenig Unterschied zu der entsandten Version)

Public Function IsLeapYear2(yr As Integer) As Boolean
    IsLeapYear2 = Month(DateSerial(yr, 2, 29)) = 2
End Function

Das Datum / Zeit-Versionen, die ein Datum als String diskon bauen wurden sie wieder viel langsamer sind.

Der Test IsLeapYear jahrelang 100..9999, wiederholt 1000 mal

zu bekommen war

Ergebnisse

  • Math Version: 640ms
  • Datum / Uhrzeit Version: 3360ms

Der Testcode war

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

Hier ist eine weitere einfache Möglichkeit.

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

Wenn Leap_Day_Check 28 = dann ist es kein Schaltjahr, wenn es 29 ist es ist.

VBA weiß, was das Datum vor dem 1. März in einem Jahr ist und so setzt sie entweder 28 oder 29. Februar für uns sein.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top