Come trovi l'anno bisestile in VBA?
-
02-07-2019 - |
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).
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.
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
- Interpretazione matematica della definizione dell'Anno bisestile
- 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.