Вопрос

Какова хорошая реализация функции IsLeapYear в VBA?

Редактировать: Я запустил if-then и реализацию DateSerial с итерациями, заключенными в таймер, и DateSerial был быстрее в среднем на 1-2 мс (5 прогонов по 300 итераций, при этом также работала 1 средняя формула таблицы ячеек).

Это было полезно?

Решение

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  

Первоначально я получил эту функцию с замечательного сайта Excel Чипа Пирсона.

сайт Пирсона

Другие советы

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

Если учитывается эффективность, а ожидаемый год является случайным, то, возможно, лучше сначала рассмотреть наиболее частый случай:

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

В качестве варианта решения Чипа Пирсона вы также можете попробовать

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

Я нашел эту забавную штуку на КодЖаба :

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

Хотя я почти уверен, что использование IsDate в функции, вероятно, медленнее, чем пара if и elseif.

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

Я вижу много замечательных концепций, которые указывают на дополнительное понимание и использование функций даты, которые потрясающе учиться у ...С точки зрения эффективности кода..рассмотрите машинный код, необходимый для выполнения функции

Вместо сложных функций даты используются только довольно быстрые целочисленные функции.

  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

Поздний ответ на вопрос о производительности.

TL/DR:тот Математика версии касаются в 5 раз быстрее


Я вижу здесь две группы ответов

  1. Математическая интерпретация определения високосного года
  2. Используйте функции даты и времени Excel для определения 29 февраля (они делятся на два лагеря:те, которые создают дату в виде строки, и те, которые этого не делают)

Я провел тесты времени для всех опубликованных ответов и обнаружил Математика методы о в 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

Версии Date/Time, которые создают дату в виде строки, были исключены, поскольку они снова намного медленнее.

Испытание заключалось в том, чтобы получить IsLeapYear за годы 100..9999, повторено 1000 раз

Полученные результаты

  • Математическая версия:640 мс
  • Версия даты/времени:3360 мс

Тестовый код был

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

Вот еще один простой вариант.

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

Если Leap_Day_Check = 28, то год не високосный, если 29, то високосный.

VBA знает, какая дата в году будет перед 1 марта, поэтому установит для нас это 28 или 29 февраля.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top