Проверка на наличие действительной даты — VBA

#excel #vba #validation #days

#excel #vba #проверка #дни

Вопрос:

Ребята, моя основная цель — избежать недопустимых дней.

На листе 1 у меня есть:

  • Проверка данных A1 с указанием лет (с 1900-2019)
  • Проверка данных B1 со всеми месяцами
  • C1 я использую событие изменения (если оба поля A1 и A2 не пусты), вычисляю, сколько дней в выбранном месяце на основе выбранного года, и создаю проверку данных, включающую все доступные дни.

Для вычисления дней я использую:

 Option Explicit

Sub test()

    Dim ndays As Long

    With ThisWorkbook.Worksheets("Sheet1")

        ndays = Day(DateSerial(.Range("A1").Value, .Range("B1").Value   1, 1) - 1)

    End With

End Sub   
  

Структура листа:

введите описание изображения здесь

Есть ли более простой способ подсчета дней?

Комментарии:

1. Я бы не подумал, что вам для этого требуется VBA, вы думали о создании динамического списка проверки данных с использованием именованных диапазонов?

2. Почему в вашем коде используется B1 , когда данные находятся в A2 ??

3. @Gary’s Student я редактирую вопрос, потому что предыдущий содержит ошибки. я также загружаю фотографию и свой код. Буду признателен за любую помощь.

Ответ №1:

вы могли бы использовать:

  • DateValue() функция для построения даты из строки, которую вы составляете с вашими значениями года и месяца, и добавлением любого действительного номера дня (я выбрал «1», чтобы быть уверенным …)

  • EOMONTH() функция рабочего листа для получения последнего дня результирующей даты месяца:

как показано ниже:

 With someSheet
    ...
    nb_days = Day(WorksheetFunction.EoMonth(DateValue(.Range("A1").Value amp; " " amp; .Range("B1").Value amp; " 1"), 0))
    ...
End With
  

Комментарии:

1. ПРИМЕЧАНИЕ, во втором примере диапазоны не указаны на листе (без точек)

2. @DisplayName не могли бы вы, пожалуйста, просмотреть обновленный вопрос? я пытаюсь прояснить вопрос, потому что получаю ошибку типа 13..

3. @Error1004, смотрите отредактированный ответ в соответствии с вашим отредактированным вопросом

Ответ №2:

Я предлагаю использовать UDF (определяемую пользователем функцию) ниже.

 Function MonthDays(Rng As Range) As Integer

    Const Y As Integer = 1
    Const M As Integer = 2

    Dim Arr As Variant

    Application.Volatile                    ' recalculates on every change
    If Application.WorksheetFunction.Count(Rng) = 2 Then
        Arr = Rng.Value
        MonthDays = DateDiff("d", DateSerial(Arr(Y, 1), Arr(M, 1), 1), _
                                  DateSerial(Arr(Y, 1), Arr(M, 1)   1, 1))
    End If
End Function
  

Вы можете вызвать его непосредственно с рабочего листа с помощью вызова функции, подобной =MonthDays(A1:A2) где A1 содержит год, а A2 — месяц. Если какая-либо из них отсутствует, функция возвращает 0. Функция принимает невозможные числа как для года, так и для месяца и вернет логический результат, например, 14-м месяцем года является февраль следующего года. Однако вы можете ограничить количество записей проверкой данных.

Все UDF-файлы могут вызываться как обычные функции из вашего кода. Cells(3, 1).Value = MonthDays(Range("A1:A2")) будет иметь тот же эффект, что и ввод вызова функции, как описано в предыдущем абзаце в формате A3. Однако, если функция вызывается из VBA, строка Application.Volatile не потребуется (неэффективно).

Комментарии:

1. FWIW, я думаю, Application.Volatile здесь избыточен; если я правильно помню, UDF-файлы пересчитываются в соответствии с теми же правилами, что и обычные функции рабочего листа, т. е. всякий раз, когда изменяется прецедент ( Rng changes). По моему опыту Application.Volatile , как правило, полезно только для UDF, не принимающих аргументов, или которые работают со временем / случайными числами. В случае OP вы хотите, чтобы функция пересчитывала только при выборе другого месяца, что должно произойти автоматически