В процессе разработки на платформе 1С:Предприятие 8 часто возникает необходимость вычислить количество календарных дней в конкретном месяце. Это может потребоваться для расчета заработной платы, распределения суммы расходов по дням месяца, формирования графиков или аналитических отчетов. В данной статье мы разберем как самые простые и изящные способы, предложенные сообществом, так и более сложные профессиональные методы, учитывающие специфику бизнес-логики.
Самый быстрый и лаконичный способ получить число дней в месяце — это комбинация функций День и КонецМесяца. Давайте проанализируем, как это работает. Функция КонецМесяца возвращает дату и время последнего мгновения указанного месяца (23:59:59). Поскольку дата последнего дня месяца совпадает с порядковым номером этого дня, функция День вернет нам именно общее количество дней.
Рассмотрим конкретный пример кода:
// Определим произвольную дату
НашаДата = Дата(2023, 02, 15); // Февраль 2023 года
// Получаем количество дней
КоличествоДней = День(КонецМесяца(НашаДата));
// Для февраля 2023 года результат будет 28
Сообщить("В текущем месяце " + КоличествоДней + " дн.");
Этот способ является универсальным, так как платформа 1С автоматически учитывает високосные годы (что удобно при начислении зарплаты). Вам не нужно писать дополнительные проверки для февраля — функция КонецМесяца сделает это за вас.
Иногда в алгоритмах удобнее использовать математический подход, основанный на разности между началом текущего месяца и началом следующего. Разберем этот алгоритм по шагам. Мы знаем, что при вычитании одной даты из другой в 1С результат возвращается в секундах. Чтобы перевести секунды в дни, их нужно разделить на количество секунд в сутках (86400).
Посмотрим на пример реализации:
НашаДата = ТекущаяДата();
НачалоЭтогоМесяца = НачалоМесяца(НашаДата);
НачалоСледующегоМесяца = ДобавитьМесяц(НачалоЭтогоМесяца, 1);
КоличествоДней = (НачалоСледующегоМесяца - НачалоЭтогоМесяца) / 86400;
Этот метод полезен тем, что он исключает работу с временем внутри суток, оперируя «чистыми» датами начал периодов. Важно помнить: при использовании такого подхода всегда приводите даты к началу дня с помощью функции НачалоДня или НачалоМесяца, чтобы избежать ошибок из-за разницы в часах и минутах.
Часто задачу нужно решить не в коде модуля, а непосредственно при выборке данных из базы. В языке запросов 1С логика аналогична встроенному языку, но синтаксис функций немного отличается (для отладки пригодится консоль запросов). Рассмотрим два варианта написания запроса.
Вариант А (наиболее оптимальный):
Используем встроенную функцию запроса ДЕНЬ к результату функции КОНЕЦПЕРИОДА.
ВЫБРАТЬ
ДЕНЬ(КОНЕЦПЕРИОДА(&Дата, МЕСЯЦ)) КАК КолДнейВМесяце
Вариант Б (через разность дат):
Если вам требуется вычислить разницу более сложным способом, можно использовать функцию РАЗНОСТЬДАТ. Однако здесь есть нюанс: разность между 1-м числом текущего месяца и 1-м числом следующего даст точное количество дней, а разность между началом и концом одного месяца потребует прибавления единицы.
ВЫБРАТЬ
РАЗНОСТЬДАТ(НАЧАЛОПЕРИОДА(&Дата, МЕСЯЦ), КОНЕЦПЕРИОДА(&Дата, МЕСЯЦ), ДЕНЬ) + 1 КАК КолДнейВМесяце
Проанализируем важный аспект: обработка NULL. Если в запросе вы используете левое соединение и поле с датой может быть пустым, функция ДЕНЬ вернет NULL. Чтобы избежать падения отчета или ошибки в расчетах, всегда используйте конструкцию ЕСТЬNULL.
ВЫБРАТЬ
ЕСТЬNULL(ДЕНЬ(КОНЕЦПЕРИОДА(Таблица.ДатаПродажи, МЕСЯЦ)), 0) КАК КоличествоДней
ИЗ
РегистрНакопления.Продажи КАК Таблица
В типовых конфигурациях, таких как 1С:ЗУП или 1С:ERP, простого количества календарных дней часто недостаточно. Бухгалтеру или расчетчику важно знать количество именно рабочих или выходных дней. Для этого в системе предусмотрен РегистрСведений.ДанныеПроизводственногоКалендаря.
Рассмотрим, как получить данные из этого регистра. Выясним причину, почему это лучше ручного расчета: календарь учитывает официальные переносы праздников, утвержденные правительством, что невозможно вычислить простыми математическими функциями.
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| СУММА(1) КАК КоличествоРабочихДней
|ИЗ
| РегистрСведений.ДанныеПроизводственногоКалендаря КАК Календарь
|ГДЕ
| Календарь.Дата МЕЖДУ &НачалоПериода И &КонецПериода
| И Календарь.ВидДня В (ЗНАЧЕНИЕ(Перечисление.ВидыДнейПроизводственногоКалендаря.Рабочий),
| ЗНАЧЕНИЕ(Перечисление.ВидыДнейПроизводственногоКалендаря.Предпраздничный))";
Запрос.УстановитьПараметр("НачалоПериода", НачалоМесяца(ТекущаяДата()));
Запрос.УстановитьПараметр("КонецПериода", КонецМесяца(ТекущаяДата()));
Если ваша конфигурация построена на базе БСП (что является стандартом для современных решений 1С), мы рекомендуем использовать готовые программные интерфейсы. Это делает код более читаемым и надежным. Обратите внимание на модуль КалендарныеГрафики.
Например, для получения количества дней в периоде по определенному календарю можно вызвать функцию:
КалендарныеГрафики.КоличествоДнейВПериоде(ДатаНачала, ДатаОкончания, Календарь)
Разберем ситуацию, когда вам нужно определить количество дней в году. Часто программисты пытаются проверять остаток от деления года на 4, но в 1С есть более изящный способ, аналогичный методу разности дат:
// Вычисляем разницу между 1 января текущего и следующего года
КоличествоДнейВГоду = (Дата(Год(НашаДата) + 1, 1, 1) - Дата(Год(НашаДата), 1, 1)) / 86400;
Если результат равен 366 — год високосный. Аналогично можно быстро проверить количество дней в феврале:
ДнейВФеврале = День(КонецМесяца(Дата(Год(НашаДата), 2, 1)));
Мы рассмотрели различные подходы к определению количества дней в месяце в среде 1С. Подведем итог:
День(КонецМесяца(Дата)).ДЕНЬ(КОНЕЦПЕРИОДА(Дата, МЕСЯЦ)) с обязательной проверкой на NULL.Выбор метода зависит от контекста вашей задачи. Для простых расчетов достаточно одной строки кода, а для сложных систем планирования ресурсов стоит задействовать возможности регистров сведений и библиотечных функций.