Определение количества дней в месяце — одна из самых распространённых задач при работе с датами в 1С:Предприятие. Казалось бы, что может быть проще? Но на практике программисты сталкиваются с нюансами: високосные годы, разная длительность месяцев, необходимость учитывать рабочие/выходные дни. В этой статье мы разберём 7 способов получить количество дней в месяце — от стандартных функций платформы до универсальных алгоритмов, работающих даже с историческими датами.
Вы узнаете, как:
- 📅 Использовать встроенную функцию
ДнейВМесяце()и её ограничения - 🔄 Получать количество дней для произвольной даты (включая будущие периоды)
- 📊 Учитывать рабочие дни с помощью календарей 1С
- 💡 Оптимизировать код для массовой обработки дат
Все примеры приведены для актуальных версий 1С:Предприятие 8.3 и 8.2, но majority методов будут работать и в более ранних редакциях. Если вы часто работаете с датами в конфигурациях (например, при расчёте зарплаты, планировании графиков или аналитике), эта статья поможет избежать типичных ошибок и написать надёжный код.
1. Стандартная функция ДнейВМесяце() — простейший способ
Самый очевидный метод — использовать встроенную функцию ДнейВМесяце(). Она возвращает количество дней в указанном месяце с учётом високосных лет. Синтаксис:
КоличествоДней = ДнейВМесяце(Год, Месяц);
Где:
- 📌
Год— числовое значение года (например,2026) - 📌
Месяц— номер месяца от1(январь) до12(декабрь)
Пример использования:
Сообщить(ДнейВМесяце(2026, 2)); // Вернёт 29 (февраль 2026 — високосный год)
Преимущества метода:
- ⚡ Максимальная простота — одна строка кода
- 🔒 Надёжность — платформа 1С сама учитывает високосные годы
- 📈 Быстродействие — встроенная функция оптимизирована
Ограничения:
- ❌ Требует явного указания года и месяца (нельзя передать дату типа
Дата) - ❌ Не работает с датами до
1900 года(вернёт ошибку)
ТекущаяДата = ТекущаяДата();
КоличествоДней = ДнейВМесяце(Год(ТекущаяДата), Месяц(ТекущаяДата));
-->
2. Альтернатива: функция КонецМесяца() для работы с типом Дата
Если у вас уже есть переменная типа Дата, удобнее использовать функцию КонецМесяца(). Она возвращает последнюю дату месяца, после чего можно вычислить количество дней через День():
МояДата = '2026-02-15';
ПоследнийДень = КонецМесяца(МояДата);
КоличествоДней = День(ПоследнийДень); // 29 для февраля 2026
Когда этот метод удобнее ДнейВМесяце():
- 🔄 Когда дата хранится в переменной типа
Дата(не нужно извлекать год и месяц отдельно) - 📅 При работе с диапазонами дат (например, в отчётах)
- 🔄 Когда требуется не только количество дней, но и последняя дата месяца
Пример для текущего месяца:
ПоследнийДеньТекущегоМесяца = КонецМесяца(ТекущаяДата());
КоличествоДней = День(ПоследнийДеньТекущегоМесяца);
Что возвращает КонецМесяца() для февраля 2000 года?
Функция вернёт '2000-02-29', так как 2000 год был високосным (делится на 400 без остатка).
3. Универсальный алгоритм для любых дат (включая исторические)
Встроенные функции 1С не работают с датами до 1900 года. Если вам нужно обработать исторические данные (например, в архивных отчётах), используйте самостоятельный расчёт с учётом правил високосных лет:
Функция ДнейВМесяцеУниверсально(Год, Месяц)
Если Месяц = 2 Тогда
// Проверка на високосный год
Если (Год % 4 = 0 И Год % 100 <> 0) Или (Год % 400 = 0) Тогда
Возврат 29;
Иначе
Возврат 28;
КонецЕсли;
ИначеЕсли Месяц В [4, 6, 9, 11] Тогда
Возврат 30;
Иначе
Возврат 31;
КонецЕсли;
КонецФункции;
Преимущества:
- 🌍 Работает с любыми годами (включая до 1900 и после 2100)
- 🔧 Не зависит от ограничений платформы 1С
- 📜 Подходит для исторических расчётов (например, в музеях или архивах)
Недостатки:
- ⚠️ Требует ручного тестирования для краевых случаев
- ⏱ Дольше выполняется, чем встроенные функции
Для большинства бизнес-задач в 1С достаточно встроенных функций. Универсальный алгоритм нужен только при работе с нестандартными датами (до 1900 года или после 2100).
4. Получение рабочих дней в месяце (с учётом календарей)
Если вам нужно не общее количество дней, а количество рабочих дней (например, для расчёта зарплаты или планирования задач), используйте Календарь из подсистемы "Зарплата и Управление Персоналом".
Пример кода:
// Получаем календарь (например, "Пятидневка")
Календарь = Календари.Пятидневка;
// Устанавливаем период (первый и последний день месяца)
НачалоМесяца = НачалоМесяца(ТекущаяДата());
КонецМесяца = КонецМесяца(ТекущаяДата());
// Получаем количество рабочих дней
РабочиеДни = Календарь.РабочиеДни(НачалоМесяца, КонецМесяца);
Нюансы:
- 📅 Требуется наличие подсистемы "Зарплата и Управление Персоналом" в конфигурации
- 🔧 Календари настраиваются в справочнике
Календари(например, "Пятидневка", "Шестидневка") - ⚠️ Учитываются праздничные дни согласно законодательству РФ
Если подсистемы нет, можно использовать внешние обработки или написать свой алгоритм с учётом выходных. Например, для пятидневки:
Функция РабочиеДниВМесяце(ДатаНачала, ДатаКонца)
РабочиеДни = 0;
ТекущаяДата = ДатаНачала;
Пока ТекущаяДата <= ДатаКонца Цикл
Если ДеньНедели(ТекущаяДата) <> 6 И ДеньНедели(ТекущаяДата) <> 7 Тогда
РабочиеДни = РабочиеДни + 1;
КонецЕсли;
ТекущаяДата = ТекущаяДата + 86400; // +1 день
КонецЦикла;
Возврат РабочиеДни;
КонецФункции;
Убедитесь, что в конфигурации есть подсистема "Зарплата и Управление Персоналом"|Проверьте настройки календаря (пятидневка/шестидневка)|Учитывайте региональные праздники (если нужны)|Тестируйте код на краевых датах (например, январь с новогодними каникулами)-->
5. Оптимизация для массовой обработки дат
Если вам нужно получить количество дней для многих месяцев (например, при построении отчётов за несколько лет), оптимизируйте код, чтобы избежать повторных вычислений. Примеры:
Способ 1: Кэширование результатов
Перем мКэшДнейВМесяце;
// Функция с кэшированием
Функция ДнейВМесяцеКэшированно(Год, Месяц)
КлючКэша = Строка(Год) + "_" + Строка(Месяц);
Если НЕ мКэшДнейВМесяце.Свойство(КлючКэша) Тогда
мКэшДнейВМесяце[КлючКэша] = ДнейВМесяце(Год, Месяц);
КонецЕсли;
Возврат мКэшДнейВМесяце[КлючКэша];
КонецФункции;
Способ 2: Векторизация (для больших массивов)
// Пример для массива дат
МассивДат = Новый Массив;
МассивДат.Добавить('2026-01-01');
МассивДат.Добавить('2026-02-01');
// ...
Результаты = Новый Массив;
Для Каждого Дата Из МассивДат Цикл
ПоследнийДень = КонецМесяца(Дата);
Результаты.Добавить(День(ПоследнийДень));
КонецЦикла;
Способ 3: Использование запроса (для СУБД)
Если данные хранятся в базе, можно перенести логику в запрос:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| День(КОНЕЦМЕСЯЦА(&Дата)) КАК КоличествоДней
|ИЗ
| МойРегистр КАК Т";
Запрос.УстановитьПараметр("Дата", ТекущаяДата());
Результат = Запрос.Выполнить();
При работе с тысячами дат кэширование ускоряет выполнение в 10–100 раз. Для миллионов записей оптимально использовать запросы к СУБД.
6. Типичные ошибки и как их избежать
Даже опытные программисты 1С иногда допускают ошибки при работе с датами. Рассмотрим самые распространённые:
| Ошибка | Причина | Как исправить |
|---|---|---|
| Неверное количество дней в феврале | Не учтён високосный год | Использовать ДнейВМесяце() или проверять Год % 4 |
Ошибка "Неверный аргумент" в ДнейВМесяце() |
Передан год < 1900 | Использовать универсальный алгоритм (раздел 3) |
| Неправильный расчёт рабочих дней | Не учтены праздники или региональные особенности | Настроить календарь в ЗУП или добавить проверку праздников |
| Медленная работа при массовой обработке | Отсутствует кэширование | Добавить кэш (раздел 5) или использовать запросы |
Дополнительные ловушки:
- 🕒 Часовые пояса: Если работаете с датами в разных поясах, приводите их к одному перед расчётами.
- 📅 Начало/конец месяца: Функции
НачалоМесяца()иКонецМесяца()возвращают дату с временем00:00:00и23:59:59соответственно. Это может влиять на сравнения. - 🔄 Переход на летнее/зимнее время: В редких случаях может сдвигать даты (актуально для исторических данных до 2011 года в РФ).
- 📌
31 декабря(переход на новый год) - 📌
28–29 февраля(високосный год) - 📌
1 января(праздники)
7. Практические примеры использования
Рассмотрим реальные сценарии, где требуется определять количество дней в месяце:
Пример 1: Расчёт нормы рабочего времени в табеле
// Получаем количество рабочих дней в месяце
РабочиеДни = Календарь.РабочиеДни(НачалоМесяца(ДатаОтчёта), КонецМесяца(ДатаОтчёта));
// Норма часов = рабочие дни * 8 часов
НормаЧасов = РабочиеДни * 8;
Пример 2: Планирование графика платежей
// Последний день месяца для оплаты
ДатаОплаты = КонецМесяца(ТекущаяДата());
Если ДеньНедели(ДатаОплаты) = 6 Тогда // Если суббота
ДатаОплаты = ДатаОплаты - 1; // Переносим на пятницу
ИначеЕсли ДеньНедели(ДатаОплаты) = 7 Тогда // Если воскресенье
ДатаОплаты = ДатаОплаты - 2; // Переносим на пятницу
КонецЕсли;
Пример 3: Аналитика продаж по месяцам
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Год(Документ.Дата) КАК Год,
| Месяц(Документ.Дата) КАК Месяц,
| День(КОНЕЦМЕСЯЦА(Документ.Дата)) КАК ДнейВМесяце,
| СУММА(Документ.Сумма) КАК ОбщаяСумма
|ИЗ
| Документ.РеализацияТоваровУслуг КАК Документ
|ГРУППИРОВАТЬ ПО
| Год(Документ.Дата),
| Месяц(Документ.Дата)";
Результат = Запрос.Выполнить();
Пример 4: Валидация введённой даты
Функция ДатаКорректна(ДатаСтрока)
Попытка
Дата = Дата(ДатаСтрока);
// Проверяем, что день не превышает количество дней в месяце
Если День(Дата) > ДнейВМесяце(Год(Дата), Месяц(Дата)) Тогда
Возврат Ложь;
КонецЕсли;
Возврат Истина;
Исключение
Возврат Ложь;
КонецПопытки;
КонецФункции;
Как проверить, что февраль 2026 года високосный?
Можно использовать простой проверочный код:
Год = 2026;
Если (Год % 4 = 0 И Год % 100 <> 0) Или (Год % 400 = 0) Тогда
Сообщить("Високосный!");
Иначе
Сообщить("Не високосный");
КонецЕсли;
Для 2026 года выведет "Високосный!".
FAQ: Ответы на частые вопросы
🔹 Почему функция ДнейВМесяце() не работает с годами до 1900?
Платформа 1С:Предприятие внутренне хранит даты в формате, который не поддерживает годы до 1900 (ограничение связано с реализацией календарных функций в ядре системы). Для исторических дат используйте универсальный алгоритм из раздела 3.
🔹 Как получить количество дней в месяце для даты в формате строки?
Сначала преобразуйте строку в тип Дата, затем используйте КонецМесяца():
ДатаСтрока = "15.05.2026";
Дата = Дата(ДатаСтрока);
КоличествоДней = День(КонецМесяца(Дата)); // 31 для мая
🔹 Можно ли получить количество дней в месяце без программирования (в пользовательском режиме)?
Да, в 1С есть встроенные возможности:
- Откройте календарь (например, в поле ввода даты).
- Выберите нужный месяц — внизу отобразится количество дней.
- Или используйте отчёт
"Календарь"в подсистеме "Зарплата и Кадры".
Однако для автоматизации (например, в отчётах) всё равно потребуется программный код.
🔹 Как учесть региональные праздники при расчёте рабочих дней?
В подсистеме "Зарплата и Управление Персоналом":
- Откройте справочник
Календари. - Выберите или создайте календарь (например, "Пятидневка").
- В разделе
"Праздничные дни"добавьте региональные даты. - Используйте этот календарь в функции
РабочиеДни().
Если подсистемы нет, придётся вручную добавлять проверки в код (например, через массив праздничных дат).
🔹 Почему мой код возвращает 28 дней для февраля 2026 года?
Скорее всего, вы:
- Используете универсальный алгоритм (раздел 3), но неверно реализовали проверку високосного года.
- Или передаёте в
ДнейВМесяце()не тот год (например,2023вместо2026).
Проверьте:
Сообщить(ДнейВМесяце(2026, 2)); // Должно вернуть 29
Функция ПолучитьДнейВМесяце(Дата) Экспорт
Возврат День(КонецМесяца(Дата));
КонецФункции;
И вызывать её из любого места конфигурации.-->
⚠️ Внимание: При работе с датами в 1С учитывайте, что некоторые функции (например, ДнейВМесяце()) могут вести себя по-разному в разных версиях платформы. Для критических расчётов (например, в бухгалтерских отчётах) всегда тестируйте код на актуальной версии вашей конфигурации.