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