К статье
Практический материал

Разработка и Конфигурация · 9 мин

Как определить количество дней в месяце в 1С

Способы узнать количество дней в месяце в 1С: функция День() с КонецМесяца(), встроенный язык, запросы, СКД. Примеры кода, типичные ошибки и проверка результата.

Во встроенном языке 1С нет отдельной функции «КоличествоДнейВМесяце», поэтому задача решается комбинацией стандартных функций работы с датами. Самый распространённый приём — взять конец месяца от нужной даты и извлечь из него номер дня: он и будет равен количеству дней в этом месяце. Приём работает одинаково в тонком и толстом клиенте, на сервере и в веб-клиенте, поскольку использует базовые функции платформы.

Задача встречается постоянно: расчёт оклада по фактически отработанным дням, нормы времени, проверка корректности введённой даты, формирование отчётов по дням, построение календарных графиков. Важно понимать, что количество дней зависит не только от месяца, но и от года — февраль високосного года содержит 29 дней. Платформа учитывает високосность автоматически, поэтому ручные таблицы «31-28-31» в коде писать не нужно и не следует.

Ниже разобраны способы получения количества дней во встроенном языке, в запросах и в СКД, а также вариант через разность дат, типичные ошибки и способы проверить результат.

Основной способ: День(КонецМесяца(Дата))

Функция КонецМесяца(Дата) возвращает дату-время, соответствующее последнему моменту месяца, — например, для 15.03 возвращается 31.03 23:59:59. Функция День(Дата) извлекает из даты число месяца. Вместе они дают искомое значение одной строкой:

ДнейВМесяце = День(КонецМесяца(ТекущаяДата));

Если нужно получить количество дней для произвольного месяца и года, сначала сформируйте любую дату внутри этого месяца через функцию Дата(Год, Месяц, День), а затем примените тот же приём:

НужнаяДата = Дата(Год, Месяц, 1);

ДнейВМесяце = День(КонецМесяца(НужнаяДата));

Приём корректно обрабатывает все частные случаи: февраль обычного года вернёт 28, февраль високосного — 29, апрель — 30, январь — 31. Високосность определяется платформой по григорианскому календарю, вмешательство разработчика не требуется.

bsl
Функция КоличествоДнейВМесяце(Год, Месяц)
	Возврат День(КонецМесяца(Дата(Год, Месяц, 1)));
КонецФункции

Альтернатива через разность дат

Второй рабочий вариант — вычислить разность между началом следующего месяца и началом текущего. Разность дат в 1С выражается в секундах, поэтому результат делится на количество секунд в сутках — 86400:

ДнейВМесяце = (НачалоМесяца(ДобавитьМесяц(НужнаяДата, 1)) - НачалоМесяца(НужнаяДата)) / 86400;

Этот способ полезен, когда в алгоритме уже вычисляются границы периода и дополнительный вызов КонецМесяца избыточен. Математически оба варианта дают одинаковый результат, но первый короче и читается легче, поэтому в новом коде предпочтителен именно он.

Обратите внимание: вычитание дат даёт число секунд, а не дней. Частая ошибка новичков — забыть деление на 86400 и получить значение вроде 2678400 вместо 31. Если результат выглядит аномально большим, проверьте единицы измерения.

Количество дней в запросе

В языке запросов 1С доступны те же функции с другим синтаксисом. Конец месяца получается через КОНЕЦПЕРИОДА(&Дата, МЕСЯЦ), номер дня — через ДЕНЬ(). Типовой фрагмент запроса:

ВЫБРАТЬ

ДЕНЬ(КОНЕЦПЕРИОДА(&Дата, МЕСЯЦ)) КАК ДнейВМесяце

Если количество дней нужно для каждой строки таблицы — например, для списка документов с разными датами, — функции применяются к полю выборки, а не к параметру:

ВЫБРАТЬ

Документы.Дата КАК Дата,

ДЕНЬ(КОНЕЦПЕРИОДА(Документы.Дата, МЕСЯЦ)) КАК ДнейВМесяце

ИЗ

Документ.НачислениеЗарплаты КАК Документы

Такой подход позволяет рассчитать, например, дневную ставку начисления прямо в запросе: Сумма / ДЕНЬ(КОНЕЦПЕРИОДА(Документы.Дата, МЕСЯЦ)). Это удобнее, чем выгружать данные и считать в цикле, особенно на больших объёмах.

Использование в СКД и выражениях компоновки

В системе компоновки данных количество дней обычно вычисляется на уровне запроса набора данных — тем же выражением ДЕНЬ(КОНЕЦПЕРИОДА(...)). Это предпочтительный путь: расчёт выполняется на сервере СУБД, результат доступен как обычное поле для группировок, ресурсов и отборов.

Если поле нужно вычислить уже на уровне компоновки (например, источник данных — внешний набор), используйте вычисляемое поле с функциями языка выражений СКД. Там доступен вызов функций общих модулей с признаком доступности из компоновки, поэтому можно вынести расчёт в общий модуль и ссылаться на него из выражения. Учтите, что общий модуль должен быть серверным и с включённым флагом «Вызов сервера», иначе выражение не выполнится.

Для отчётов по норме времени и производственным календарям учтите: количество календарных дней месяца — не то же самое, что количество рабочих дней. Рабочие дни определяются по регистру сведений с данными календаря (в типовых конфигурациях — «Данные производственного календаря» или аналог), а не арифметикой дат.

Типичные ошибки и как их избежать

Первая ошибка — жёстко зашитая таблица дней по месяцам без учёта високосного года. Такой код ломается раз в четыре года, причём сбой проявляется только в феврале и легко ускользает от тестирования. Всегда полагайтесь на функции платформы.

Вторая ошибка — путаница между КонецМесяца и КонецДня или ручным конструированием даты вида Дата(Год, Месяц, 31). Последний вариант для месяцев с 30 днями либо даст неверную дату, либо приведёт к неочевидному поведению при переносе даты. Доверяйте вычисление границы месяца платформе.

Третья группа ошибок связана с типами: если на вход функции подаётся строка или дата с пустым значением (01.01.0001), результат будет некорректным или вызовет ошибку. Перед расчётом проверяйте заполненность даты через ЗначениеЗаполнено().

Типичные ошибки
01
Зашитая таблица 31-28-31 без учёта високосного года — сбой в феврале
02
Забытое деление на 86400 при расчёте через разность дат — результат в секундах
03
Конструирование даты Дата(Год, Месяц, 31) для месяцев с 30 днями
04
Отсутствие проверки пустой даты перед вызовом КонецМесяца
05
Подмена понятия «рабочие дни» количеством календарных дней месяца

Как проверить результат

Проверка проста и выполняется на контрольных значениях. Для января любого года функция должна вернуть 31, для апреля — 30, для февраля невисокосного года — 28, для февраля високосного — 29. Високосными считаются годы, делящиеся на 4, кроме делящихся на 100, но с сохранением високосности для делящихся на 400.

Быстрый способ проверить код — выполнить выражение в консоли кода или через «Вычислить выражение» в отладчике, подставив даты из разных месяцев. Если все четыре контрольных значения совпали, реализация корректна.

Контрольные точки

Как проверить результат

Январь любого года
Норма

Возвращается 31

Тревожный признак

30 или другое число — ошибка в логике

Февраль невисокосного года
Норма

Возвращается 28

Тревожный признак

29 — не учтена високосность

Февраль високосного года
Норма

Возвращается 29

Тревожный признак

28 — жёсткая таблица без високосности

Пустая дата на входе
Норма

Обработана проверкой ЗначениеЗаполнено

Тревожный признак

Ошибка выполнения или 31 от 01.01.0001

Где это применяется на практике

Наиболее частый сценарий — расчёт дневной ставки: оклад, делённый на количество дней в месяце начисления. Аналогично считаются среднедневные показатели выручки, нормы выработки, пени за дни просрочки в пределах месяца.

Второй сценарий — валидация пользовательского ввода: если форма принимает год, месяц и день раздельными полями, проверка День <= День(КонецМесяца(Дата(Год, Месяц, 1))) отсекает несуществующие даты вроде 30 февраля ещё до записи данных.

Третий сценарий — построение таблиц периодов: при обходе дней месяца в цикле верхняя граница цикла задаётся именно этим значением, что исключает выход за пределы месяца.

Итог

Что важно запомнить

Количество дней в месяце получают выражением День(КонецМесяца(Дата)) во встроенном языке и ДЕНЬ(КОНЕЦПЕРИОДА(Дата, МЕСЯЦ)) в запросах. Платформа сама учитывает високосные годы; ручные таблицы дней не нужны и опасны. Для рабочих дней используйте производственный календарь, а не календарные дни.

Частые вопросы

Есть ли в 1С готовая функция «КоличествоДнейВМесяце»?

В стандартном встроенном языке такой функции нет. В некоторых типовых конфигурациях и библиотеках (например, в составе БСП) встречаются обёртки с похожими названиями, но внутри они используют ту же пару День(КонецМесяца(Дата)).

Как учесть високосный год при расчёте?

Никаких дополнительных действий не требуется: функция КонецМесяца сама возвращает 28 или 29 февраля в зависимости от года переданной даты. Главное — не заменять расчёт жёстко зашитой таблицей дней по месяцам.

Чем количество календарных дней отличается от рабочих?

Календарные дни — это просто длина месяца (28–31). Рабочие дни определяются производственным календарём с учётом выходных и праздников и хранятся в регистрах сведений конфигурации. Для расчёта зарплаты и норм времени используется именно календарь, а не арифметика дат.

Как получить количество дней в произвольном периоде, а не в месяце?

Вычислите разность дат в секундах и разделите на 86400: (КонецПериода - НачалоПериода) / 86400. Если нужно включить обе граничные даты, добавьте к результату единицу.

Почему КонецМесяца возвращает время 23:59:59 и не мешает ли это?

Это штатное поведение: функция возвращает последнюю секунду последнего дня месяца. Для функции День это не имеет значения — номер дня извлекается корректно. Время важно учитывать только при сравнении дат в условиях и запросах.

Работает ли этот приём в мобильной платформе и веб-клиенте?

Да, функции День, КонецМесяца, НачалоМесяца и ДобавитьМесяц доступны во всех режимах исполнения: тонкий, толстый, веб-клиент, мобильная платформа и сервер. Код переносим без изменений.