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).

Était-ce utile?

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.

Le site de 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

  1. Interprétation mathématique de la définition de l’année bissextile
  2. 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.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top