Comment trouvez-vous l'année bissextile chez VBA?
-
02-07-2019 - |
Question
Qu'est-ce qu'une bonne implémentation d'une fonction IsLeapYear dans VBA?
Éditer: J'ai exécuté l'implémentation de if-then et de DateSerial avec des itérations encapsulées dans un minuteur. DateSerial était en moyenne plus rapide de 1 à 2 ms (5 exécutions de 300 itérations, avec Une formule de feuille de calcul de cellule moyenne fonctionne également).
La solution
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
J'ai initialement obtenu cette fonction du grand site Excel de Chip Pearson.
Autres conseils
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 pour plus ... http://fr.wikipedia.org/wiki/Leap_year
Si l'efficacité est prise en compte et que l'année attendue est aléatoire, il serait peut-être légèrement préférable de commencer par le cas le plus fréquent:
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
Comme variante de la solution Chip Pearson, vous pouvez également essayer
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
J'ai trouvé ce drôle sur CodeToad :
Public Function IsLeapYear(Year As Varient) As Boolean
IsLeapYear = IsDate("29-Feb-" & Year)
End Function
Bien que je sois à peu près sûr que l'utilisation d'IsDate dans une fonction est probablement plus lente que si, sinon, il faut.
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
Je vois beaucoup de grands concepts qui indiquent une compréhension supplémentaire et l'utilisation de fonctions de date qui sont formidables à apprendre de ... En termes d'efficacité du code .. considérons le code machine nécessaire à l'exécution d'une fonction
plutôt que des fonctions de date complexes n'utilise que des fonctions entières assez rapides BASIC a été construit sur GOTO Je soupçonne que quelque chose comme ci-dessous est plus rapide
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
Réponse tardive à la question des performances.
TL / DR: les versions Math sont environ 5 fois plus rapides
Je vois deux groupes de réponses ici
- Interprétation mathématique de la définition de l’année bissextile
- Utilisez les fonctions Date / Heure Excel pour détecter le 29 février (celles-ci se répartissent en deux camps: celles qui construisent une date sous forme de chaîne et celles qui ne le font pas)
J'ai effectué des tests de temps sur toutes les réponses publiées et découvert que les méthodes Math étaient environ 5 fois plus rapides que les méthodes Date / Heure.
J'ai ensuite optimisé les méthodes et suis arrivé (croyez-le ou non), Integer
est légèrement plus rapide que Long
dans ce cas, je ne sais pas pourquoi. )
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
À titre de comparaison, je suis arrivé (très peu de différence par rapport à la version publiée)
Public Function IsLeapYear2(yr As Integer) As Boolean
IsLeapYear2 = Month(DateSerial(yr, 2, 29)) = 2
End Function
Les versions Date / Heure qui construisent une date sous forme de chaîne ont été actualisées car elles sont à nouveau beaucoup plus lentes.
Le test consistait à obtenir IsLeapYear
pour les années 100..9999, répétée 1 000 fois
Résultats
- Version mathématique: 640ms
- Version date / heure: 3360ms
Le code de test était
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
Voici une autre option simple.
Leap_Day_Check = Day(DateValue("01/03/" & Required_Year) - 1)
Si Leap_Day_Check = 28, il ne s'agit pas d'une année bissextile, mais du 29.
VBA connaît la date du 1er mars de chaque année et le fixera donc au 28 ou au 29 février.