Pergunta

O que é uma boa implementação de uma função IsLeapYear em VBA?

Editar: corri o se-em seguida, e a implementação SérieData com iterações embrulhadas em um temporizador, e o SérieData foi mais rápido na média por 1-2 ms (5 corridas de 300 iterações, com 1 fórmula média planilha célula também de trabalho).

Foi útil?

Solução

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  

Inicialmente eu tenho essa função a partir do site grande de Chip Pearson Excel.

site da Pearson

Outras dicas

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

Wikipédia para mais ... http://en.wikipedia.org/wiki/Leap_year

Se a eficiência é uma consideração e no ano esperado é aleatória, então ele pode ser um pouco melhor para fazer o caso mais frequentes em primeiro lugar:

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

Como uma variação sobre a solução Chip Pearson, você também pode tentar

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

Eu encontrei este engraçado em CodeToad :

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

Embora eu tenho certeza que o uso de IsDate em uma função é provavelmente mais lento do que um par de se, 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

Eu vejo muitos grandes conceitos que indicam a compreensão adicional e uso de funções de data que são ótimos para aprender a partir de ... Em termos de eficiência do código .. Considere o código de máquina necessário para uma função para executar

em vez de funções de data complexos utilizar funções inteiros única bastante rápido BASIC foi construída sobre GOTO Eu suspeito que algo como abaixo é mais rápido

  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

resposta tardia de abordar a questão do desempenho.

TL / DR: Math versões são cerca de 5x mais rápido


Eu vejo dois grupos de respostas aqui

  1. interpretação matemática da definição Leap Year
  2. utilizar o Data Excel / funções tempo para detectar 29 fev (estes caem em dois campos: os que construir uma data como uma string, e aqueles que não o fazem)

Eu corri testes de tempo em todas as respostas postadas, uma descobriu os Matemática métodos são cerca de 5x mais rápido que o Data / métodos de tempo.


Então eu fiz alguma otimização dos métodos e veio com (acredite ou não Integer é marginalmente mais rápido do que Long neste caso, não sei por quê.)

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

Para efeito de comparação, eu vim (muito pouca diferença para a versão publicada)

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

A Data / versões Tempo que constroem uma data como uma cadeia foram descontados como eles são muito mais lento novamente.

O teste era para obter IsLeapYear durante anos 100..9999, repetido 1000 vezes

Resultados

  • Math Versão: 640ms
  • Data / Hora Versão: 3360ms

O código de teste 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

Aqui está outra opção simples.

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

Se Leap_Day_Check = 28, então não é um ano bissexto, se é 29 que é.

VBA sabe o que a data antes de 1 de Março é em um ano e assim vai configurá-lo para ser 28 ou 29 de Fevereiro, para nós.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top