Como você encontrar Leap Year em VBA?
-
02-07-2019 - |
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).
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.
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
- interpretação matemática da definição Leap Year
- 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.