Разработка и Конфигурация · 11 мин
Как посчитать количество рабочих дней между датами в 1С
Как в 1С посчитать количество рабочих дней между датами: функция КалендарныеГрафики, запрос к регламентированному календарю, разница в днях и типичные ошибки.
Задача подсчёта рабочих дней между двумя датами возникает в 1С постоянно: расчёт сроков оплаты по договору, контроль доставки, определение даты отпуска, планирование производства. Главная сложность в том, что простая разность дат даёт календарные дни, а рабочие дни зависят от производственного календаря — выходных, праздников и переносов.
В типовых конфигурациях (1С:Бухгалтерия, 1С:ERP, 1С:ЗУП, 1С:Управление торговлей) есть готовый механизм — регламентированный производственный календарь и программный интерфейс библиотеки стандартных подсистем (БСП). В самописных решениях придётся либо подключить календарь, либо считать дни вручную через цикл или запрос.
Ниже разобраны все рабочие способы: от одной строки кода через функцию БСП до запроса к регистру сведений «ДанныеПроизводственногоКалендаря», а также ограничения каждого подхода и способы проверить результат.
Почему простая разность дат не подходит
В языке 1С даты можно вычитать напрямую: (Дата2 - Дата1) / 86400 даст количество календарных дней, поскольку разность дат возвращает секунды. Это работает быстро, но не учитывает ни субботы, ни воскресенья, ни праздники, ни переносы рабочих дней, которые ежегодно утверждаются постановлениями правительства.
Например, между 1 и 10 мая может оказаться всего 3–4 рабочих дня из-за праздников, хотя календарная разница — 9 дней. Для расчёта пени или сроков договора такая ошибка критична: дата платежа сместится, и компания получит претензию контрагента или неверно начислит неустойку.
Поэтому правильный подход — опираться на производственный календарь, который хранится в информационной базе и обновляется. Все способы ниже так или иначе используют этот календарь, кроме упрощённого варианта «только суббота и воскресенье», который подходит лишь для грубых прикидок.
Способ 1: функция КалендарныеГрафики из БСП
В конфигурациях на базе Библиотеки стандартных подсистем есть общий модуль КалендарныеГрафики. Он содержит готовые функции для работы с рабочими днями. Основная — РазностьДатПоКалендарю.
График = КалендарныеГрафики.ОсновнойПроизводственныйКалендарь();
КоличествоДней = КалендарныеГрафики.РазностьДатПоКалендарю(
График, ДатаНачала, ДатаОкончания);
Функция вернёт число рабочих дней между датами по указанному графику. Обратите внимание: в разных версиях БСП состав параметров и точное имя функции могут отличаться, поэтому перед использованием откройте модуль КалендарныеГрафики в конфигураторе и посмотрите область «ПрограммныйИнтерфейс» — там перечислены актуальные функции с описанием параметров.
Для обратной задачи — получить дату через N рабочих дней — используйте функцию ДатаПоКалендарю того же модуля. Это удобно для расчёта плановой даты отгрузки или оплаты.
Где взять ссылку на график
Основной календарь обычно доступен через функцию КалендарныеГрафики.ОсновнойПроизводственныйКалендарь(). Если в базе несколько графиков работы (например, для разных регионов или подразделений), получайте нужный элемент справочника «ПроизводственныеКалендари» по коду или наименованию.
Способ 2: запрос к регистру ДанныеПроизводственногоКалендаря
Когда нужно посчитать рабочие дни сразу для множества строк — например, в отчёте по договорам — вызывать функцию в цикле медленно. Эффективнее одним запросом обратиться к регистру сведений ДанныеПроизводственногоКалендаря, где каждая дата помечена видом дня (рабочий, выходной, праздничный и т.д.).
ВЫБРАТЬ
КОЛИЧЕСТВО(Календарь.Дата) КАК РабочихДней
ИЗ
РегистрСведений.ДанныеПроизводственногоКалендаря КАК Календарь
ГДЕ
Календарь.ПроизводственныйКалендарь = &График
И Календарь.Дата МЕЖДУ &ДатаНачала И &ДатаОкончания
И Календарь.ВидДня = ЗНАЧЕНИЕ(Перечисление.ВидыДнейПроизводственногоКалендаря.Рабочий)
Запрос вернёт количество рабочих дней в интервале включительно. Если нужно учитывать и предпраздничные (сокращённые) дни как рабочие, добавьте в условие соответствующий вид дня через ИЛИ или конструкцию В (&ВидыДней) со списком значений.
Имя регистра и перечисления приведены для типовых конфигураций на БСП. В старых или отраслевых решениях структура может отличаться — проверьте состав метаданных в конфигураторе через поиск по слову «Календарь».
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ КОЛИЧЕСТВО(Дата) КАК РабочихДней ИЗ РегистрСведений.ДанныеПроизводственногоКалендаря ГДЕ ПроизводственныйКалендарь = &График И Дата МЕЖДУ &Начало И &Конец И ВидДня = ЗНАЧЕНИЕ(Перечисление.ВидыДнейПроизводственногоКалендаря.Рабочий)";
Запрос.УстановитьПараметр("График", График);
Запрос.УстановитьПараметр("Начало", ДатаНачала);
Запрос.УстановитьПараметр("Конец", ДатаОкончания);
Выборка = Запрос.Выполнить().Выбрать();Способ 3: цикл с проверкой дня недели
Если конфигурация самописная, календаря нет, а точность до праздников не требуется, можно обойтись циклом. Функция ДеньНедели(Дата) возвращает число от 1 (понедельник) до 7 (воскресенье), поэтому достаточно исключить значения 6 и 7.
РабочихДней = 0;
ТекущаяДата = НачалоДня(ДатаНачала);
Пока ТекущаяДата <= ДатаОкончания Цикл
Если ДеньНедели(ТекущаяДата) < 6 Тогда
РабочихДней = РабочихДней + 1;
КонецЕсли;
ТекущаяДата = ТекущаяДата + 86400;
КонецЦикла;
Этот метод не требует никаких данных в базе и работает в любой конфигурации, включая пустую. Но у него принципиальное ограничение: праздничные дни (1 января, 9 мая и т.д.) будут посчитаны как рабочие, если попадают на будни, а перенесённые рабочие субботы — как выходные.
Способ 4: отчёт «Календарь» и ручная проверка
Иногда нужно не программировать, а просто быстро узнать число рабочих дней. В типовых конфигурациях откройте справочник «Производственные календари» (обычно в разделе «Администрирование» или «НСИ») и посмотрите календарь на нужный год: рабочие, выходные и праздничные дни выделены цветом, а в подвале часто выводится итоговое количество рабочих дней по месяцам.
В 1С:ЗУП и 1С:ERP есть также отчёты по графикам работы сотрудников, где видно количество рабочих дней в произвольном периоде. Это удобно для разовой проверки результата, полученного кодом.
Как проверить и обновить производственный календарь
Любой из точных способов опирается на данные календаря. Если он не заполнен на нужный период, результат будет неверным или функция выдаст ошибку. Проверка занимает минуту.
- 1Откройте «Администрирование — Производственные календари» (или «НСИ — Производственные календари»).
- 2Откройте нужный календарь и убедитесь, что данные заполнены на весь требуемый период, включая следующий год.
- 3Если данные отсутствуют — нажмите «Заполнить по умолчанию» или обновите календарь через интернет-сервис 1С, если он подключён.
- 4Повторите расчёт и сверьте результат с видимым календарём за короткий период, например за одну неделю.
Особое внимание уделите границам года: расчёты, захватывающие январь, ломаются чаще всего, потому что календарь на новый год ещё не заполнен. В клиент-серверных базах с автоматическим обновлением через сервис 1С такая проблема возникает реже, но при отключённом интернете календарь обновлять нужно вручную.
Как проверить результат расчёта
Функция возвращает 5 рабочих дней
Возвращает 7 или 0 — календарь не заполнен или неверный график
Количество дней меньше 5 на число праздничных будней
Результат не отличается от обычной недели — праздники не учтены
Расчёт выполняется без ошибок
Ошибка или пустой результат — не заполнен календарь на следующий год
Граничные случаи: включать ли крайние даты
Один из самых частых источников расхождений — включение начальной и конечной дат в расчёт. Запрос с условием МЕЖДУ &Начало И &Конец включает обе границы, а функция РазностьДатПоКалендарю в зависимости от версии БСП может трактовать границы иначе. Прежде чем использовать расчёт в учётных целях, проверьте его на интервале из одного рабочего дня: результат должен быть предсказуемым (0 или 1 — по вашей методике).
Второй нюанс — время в датах. Если в дате окончания хранится время (например, 15.05 17:30), сравнение может работать неожиданно. Перед расчётом приводите даты к началу дня функцией НачалоДня() или, наоборот, используйте КонецДня() для верхней границы.
Третий случай — дата начала позже даты окончания. Добавьте явную проверку и либо меняйте даты местами, либо возвращайте 0 с сообщением пользователю. Молчаливая ошибка здесь опаснее явной.
Сравнение способов и выбор под задачу
Какой способ выбрать
Оптимален для разовых расчётов в коде типовых конфигураций. Требует БСП и заполненный календарь.
Лучший выбор для отчётов и пакетной обработки множества периодов. Требует знания структуры метаданных конкретной конфигурации.
Подходит для самописных конфигураций без календаря и грубых прикидок. Не учитывает праздники и переносы.
Для разовой ручной проверки без программирования. Не масштабируется.
Для большинства прикладных задач в типовых конфигурациях достаточно функции РазностьДатПоКалендарю. К запросу переходите, когда расчёт нужен в отчёте или обработке по многим строкам. Цикл без календаря оставьте для вспомогательных инструментов, где точность до праздников не важна.
Что важно запомнить
Рабочие дни в 1С корректно считаются только по производственному календарю: функцией КалендарныеГрафики.РазностьДатПоКалендарю для одиночных расчётов или запросом к регистру ДанныеПроизводственногоКалендаря для пакетных. Перед расчётом проверьте заполнение календаря на весь период и определитесь с включением граничных дат.
Частые вопросы
Функция возвращает ошибку «Производственный календарь не заполнен». Что делать?
Откройте справочник «Производственные календари», выберите используемый календарь и заполните его на нужный год кнопкой «Заполнить по умолчанию» или через обновление из сервиса 1С. После заполнения повторите расчёт.
Как посчитать не рабочие, а календарные дни между датами?
Вычтите даты напрямую: (ДатаОкончания - ДатаНачала) / 86400. Разность дат в 1С даёт секунды, поэтому деление на 86400 (число секунд в сутках) возвращает количество дней. Календарь при этом не нужен.
Как получить дату через N рабочих дней от заданной?
Используйте функцию КалендарныеГрафики.ДатаПоКалендарю(График, ДатаНачала, КоличествоДней) из БСП. Она вернёт дату, отстоящую на указанное число рабочих дней. Без БСП задачу решают циклом с проверкой вида дня по регистру календаря.
Почему результат расходится на один день с расчётом бухгалтера?
Чаще всего дело во включении граничных дат: один метод считает обе крайние даты, другой — только одну. Проверьте расчёт на интервале из одного рабочего дня и согласуйте методику. Также убедитесь, что оба расчёта используют один и тот же производственный календарь.
Работает ли расчёт, если у сотрудника шестидневная неделя?
Да, но нужен соответствующий график. Создайте отдельный производственный календарь или график работы с шестидневной неделей и передавайте именно его в функцию расчёта. Стандартный календарь «РФ» рассчитан на пятидневку.
Можно ли посчитать рабочие дни в запросе СКД без кода?
Да. Добавьте в набор данных запрос к регистру «ДанныеПроизводственногоКалендаря» с отбором по виду дня и периоду, сгруппируйте с функцией КОЛИЧЕСТВО по датам и свяжите с основными данными отчёта. Вычисляемые поля и код в модуле объекта для этого не обязательны.