13

什么是 VBA 中 IsLeapYear 函数的良好实现?

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

4

10 回答 10

27
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 网站获得这个功能的。

皮尔逊的网站

于 2008-09-24T16:10:43.857 回答
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

于 2008-09-24T16:16:09.943 回答
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
于 2008-09-24T21:28:55.183 回答
2

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

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

虽然我很确定在函数中使用 IsDate 可能比几个 if、elseif 慢。

于 2008-09-25T00:50:08.927 回答
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
于 2011-08-08T05:15:28.440 回答
2

解决性能问题的迟到答案。

TL/DR:数学版本快 5 倍左右


我在这里看到两组答案

  1. 闰年定义的数学解释
  2. 利用 Excel 日期/时间函数来检测 2 月 29 日(这些分为两个阵营:将日期构建为字符串的阵营,以及不将日期构建为字符串的阵营)

我对所有发布的答案进行了时间测试,发现数学方法比日期/时间方法快约5 倍。


然后我对方法进行了一些优化并想出了(信不信由你 IntegerLong在这种情况下要快一点,不知道为什么。)

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

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

测试是获得IsLeapYear100..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
于 2018-06-05T04:28:51.683 回答
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
于 2013-09-28T15:30:34.270 回答
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
于 2014-08-19T06:13:21.010 回答
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

没有:

 End Function
于 2017-04-13T02:54:25.453 回答
0

这是另一个简单的选择。

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

如果 Leap_Day_Check = 28 则不是闰年,如果是 29 则是闰年。

VBA 知道 3 月 1 日之前的日期是一年中的日期,因此我们会将其设置为 2 月 28 日或 29 日。

于 2015-11-19T16:10:50.513 回答