Domanda

Qual è una buona implementazione di una funzione IsLeapYear in VBA?

Modifica: Ho eseguito l'implementazione if-then e DateSerial con iterazioni racchiuse in un timer e DateSerial era più veloce in media di 1-2 ms (5 esecuzioni di 300 iterazioni, con Funziona anche con una formula del foglio di lavoro di una cella media).

È stato utile?

Soluzione

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  

Originariamente ho ottenuto questa funzione dal fantastico sito Excel di Chip Pearson.

Sito di Pearson

Altri suggerimenti

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 per altro ... http://en.wikipedia.org/wiki/Leap_year

Se l'efficienza è una considerazione e l'anno previsto è casuale, allora potrebbe essere leggermente meglio fare prima il caso più frequente:

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

Come variante della soluzione Chip Pearson, puoi anche provare

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

Ho trovato questo divertente su CodeToad :

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

Anche se sono abbastanza sicuro che l'uso di IsDate in una funzione sia probabilmente più lento di un paio di if, 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

Vedo molti grandi concetti che indicano una comprensione extra e l'uso di funzioni di data che sono eccezionali per imparare da ... In termini di efficienza del codice.  considerare il codice macchina necessario per eseguire una funzione

piuttosto che funzioni di data complesse usa solo funzioni intere abbastanza veloci BASIC è stato creato su GOTO Sospetto che qualcosa come sotto sia più veloce

  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

Risposta tardiva per rispondere alla domanda di rendimento.

TL / DR: le versioni Math sono circa 5 volte più veloci


Vedo due gruppi di risposte qui

  1. Interpretazione matematica della definizione dell'Anno bisestile
  2. Utilizza le funzioni Data / Ora di Excel per rilevare il 29 febbraio (rientrano in due campi: quelli che costruiscono una data come stringa e quelli che non lo fanno)

Ho eseguito i test del tempo su tutte le risposte pubblicate, e ho scoperto che i metodi Matematica sono 5 volte più veloci rispetto ai metodi Data / Ora.


Ho quindi ottimizzato i metodi e mi è venuto in mente (credeteci o meno Integer in questo caso è leggermente più veloce di Long , non so perché. )

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

Per confronto, sono arrivato (poca differenza rispetto alla versione pubblicata)

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

Le versioni di data / ora che costruiscono una data come stringa sono state scontate perché sono di nuovo molto più lente.

Il test è stato ottenere IsLeapYear per anni 100..9999, ripetuto 1000 volte

Risultati

  • Versione matematica: 640ms
  • Versione data / ora: 3360 ms

Il codice di test era

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

Ecco un'altra semplice opzione.

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

Se Leap_Day_Check = 28 allora non è un anno bisestile, se è 29 lo è.

VBA sa quale sarà la data prima del 1 ° marzo tra un anno e quindi la fisseremo per il 28 o il 29 febbraio per noi.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top