Function 你如何看待VBA的Leapyear?

Function 你如何看待VBA的Leapyear?,function,vba,excel,code-snippets,Function,Vba,Excel,Code Snippets,什么是VBA中IsLeapYear函数的良好实现 编辑:我运行了if-then和DateSerial实现,迭代被包装在一个计时器中,DateSerial平均快了1-2毫秒(5次300次迭代,1个平均单元格工作表公式也起作用) 我最初是从Chip Pearson伟大的Excel网站获得此功能的 维基百科了解更多。。。 如果效率是一个考虑因素,并且预期年份是随机的,那么最好先处理最常见的情况: public function isLeapYear (yr as integer) as boolea

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

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

我最初是从Chip Pearson伟大的Excel网站获得此功能的

维基百科了解更多。。。

如果效率是一个考虑因素,并且预期年份是随机的,那么最好先处理最常见的情况:

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
公共函数isLeapYear(yr为整数)为布尔值
如果(mod(yr,4))为0,则isLeapYear=false
elseif(mod(yr,400))=0,则isLeapYear=true
elseif(mod(yr,100))=0,则isLeapYear=false
else isLeapYear=true
端函数
我在以下网站上找到了这张有趣的照片:


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

作为芯片上的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
公共函数isLeapYear(可选intYear作为变量)为布尔值
如果是失踪(年),那么
intYear=年(日期)
如果结束
如果intYear Mod 400=0,则
isLeapYear=True
否则,intYear Mod 4=0,intYear Mod 100=0
isLeapYear=True
如果结束
端函数

这里是另一个简单的选项

Leap_Day_Check = Day(DateValue("01/03/" & Required_Year) - 1)
如果闰年=28,则不是闰年,如果是29,则是闰年


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

我看到许多伟大的概念,表明我们需要额外的理解 以及日期函数的使用,非常值得学习。。。 在代码效率方面。。 考虑函数执行< /P>所需的机器代码。 而不是复杂的日期函数 仅使用相当快的整数函数 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

延迟回答性能问题

TL/DR:Math版本大约快了5倍


我在这里看到两组答案

  • 闰年定义的数学解释
  • 利用Excel日期/时间函数检测2月29日(分为两大阵营:将日期构建为字符串的阵营和不构建日期的阵营)
  • 我对所有发布的答案进行了时间测试,发现数学方法比日期/时间方法快了大约5倍


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

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

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

    这项测试是为了获得100到9999年的
    IsLeapYear
    ,重复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
    

    这个可能更有效。我喜欢它特别采用闰年的定义,并将其应用到答案中。变量isLeap没有被使用。被4平均整除不是闰年!2100年不是闰年。测试的400除法部分应在4除法之前。创造性解决方案!我想知道它对其他帖子的表现如何。这并没有考虑到所有的闰年规则。事实上,如果你研究他们在做什么,它总是有效的。他们检查二月是否有29天,这使它成为一年。它基本上把leapyear规则押给了微软。芯片有很多很好的解决方案。如果效率是你的目标,你可以去掉isLeapYear=false,因为布尔值默认为false:)你的意思是使用DAY函数而不是MONTH函数吗?多少毫秒中有1-2毫秒?i、 e.相对效率增益是多少?只是好奇@珍,问得好,那是几年前的事了。当我下周回到工作岗位做更多的测试时,我会尽力记住,这会特别好,因为从那时起,有更多的答案。
    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
    
    Leap_Day_Check = Day(DateValue("01/03/" & Required_Year) - 1)
    
      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
    
    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
    
    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