你如何在VBA找到闰年?

时间:2008-09-24 16:10:31

标签: excel function vba excel-vba code-snippets

VBA中IsLeapYear函数的一个很好的实现是什么?

编辑:我运行了if-then和DateSerial实现,迭代包含在一个计时器中,而DateSerial的平均速度提高了1-2毫秒(5次运行300次迭代, 1平均单元格工作表公式也有效。)

10 个答案:

答案 0 :(得分:21)

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  

我最初从Chip Pearson的Excel网站上获得了这个功能。

Pearson's site

答案 1 :(得分:14)

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

维基百科了解更多...... http://en.wikipedia.org/wiki/Leap_year

答案 2 :(得分:5)

如果考虑效率并且预期年份是随机的,那么首先做最常见的案例可能稍好一些:

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

答案 3 :(得分:2)

我在CodeToad上发现了这个有趣的一个:

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

虽然我很确定在一个函数中使用IsDate可能比一些if,elseifs慢。

答案 4 :(得分:2)

作为Chip Pearson解决方案的变体,您也可以尝试

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

答案 5 :(得分:1)

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

答案 6 :(得分:1)

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

答案 7 :(得分:1)

我看到许多伟大的概念表明了更多的理解 以及可以学习的日期函数的使用...... 在代码效率方面..  考虑执行函数所需的机器代码

而不是复杂的日期函数 只使用相当快的整数函数 BASIC建立在GOTO之上 我怀疑下面的东西更快

  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

答案 8 :(得分:1)

解决性能问题的最后答案。

TL / DR:数学版本约快5倍

我在这里看到两组答案

  1. 闰年定义的数学解释
  2. 利用Excel日期/时间函数来检测2月29日(这些属于两个阵营:那些将日期构建为字符串,而那些不构成字符串的那些阵营)
  3. 我对所有发布的答案进行了时间测试,发现数学方法比日期/时间方法快5倍

    然后我对这些方法进行了一些优化并提出(相信与否Integer在这种情况下比Long略快,不知道为什么。)

    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
    

    为了比较,我提出了(与发布的版本差别很小)

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

    将日期构建为字符串的日期/时间版本打折,因为它们再次慢得多。

    测试是获得IsLeapYear年100 ... 9999,重复1000次

    <强>结果

    • 数学版:640ms
    • 日期/时间版本:3360ms

    测试代码是

    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
    

答案 9 :(得分:0)

这是另一个简单的选择。

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

如果Leap_Day_Check = 28那么它不是闰年,如果它是29,那么。

VBA知道3月1日之前的日期是一年,所以我们会将其定为2月28日或29日。