Как найти Leapyear в VBA?

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

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

1-2 мс из скольких мс? то есть каков выигрыш в эффективности относительный? Просто любопытно!

Jean-François Corbett 11.08.2011 10:43

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

Lance Roberts 11.08.2011 10:45
Что такое компоненты React? Введение в компоненты | Типы компонентов
Что такое компоненты React? Введение в компоненты | Типы компонентов
Компонент - это независимый, многократно используемый фрагмент кода, который делит пользовательский интерфейс на более мелкие части. Например, если мы...
13
2
20 719
10
Перейти к ответу Данный вопрос помечен как решенный

Ответы 10

Ответ принят как подходящий

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 Чипа Пирсона.

Сайт Пирсона

креативное решение! Интересно, как он работает по сравнению с другими опубликованными.

Erik van Brakel 25.09.2008 02:52

При этом не учитываются все правила високосного года.

StingyJack 16.10.2008 20:28

На самом деле, если вы изучите то, что они делают, это всегда сработает. Они проверяют, есть ли в феврале 29 дней, и это делает его високосным. По сути, он закладывает правила високосного года для Microsoft. У чипа много хороших решений.

Lance Roberts 17.10.2008 04:46

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

этот может быть даже более эффективным. Мне нравится, что он специально берет определение високосного года и превращает его в ответ.

nathaniel 24.09.2008 20:17

переменная isLeap не используется

Lance Roberts 24.09.2008 20:23

Если делиться на 4 без остатка, это еще не значит, что год високосный! 2100 год - не високосный. Разделение теста на 400 должно предшествовать делению на 4.

rp. 24.09.2008 20:47

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

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 = false, поскольку логические значения по умолчанию равны false :)

Oorang 02.06.2009 22:41

Я нашел этот забавный на CodeToad:

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

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

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

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

вы хотите использовать функцию ДЕНЬ вместо функции МЕСЯЦ?

Lance Roberts 08.08.2011 10:20

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)

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

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

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

а не сложные функции даты используйте только довольно быстрые целочисленные функции 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

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

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

Версии даты и времени, которые строят дату в виде строки, были сброшены со счетов, поскольку они снова намного медленнее.

Тест должен был получить 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

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