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

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

Как добавить рабочие дни к дате в 1С

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

Задача прибавить к дате несколько рабочих дней встречается в 1С постоянно: расчёт сроков оплаты по договору, даты отгрузки, дедлайнов задач, сроков исполнения заявок. Главная сложность в том, что встроенная функция ДобавитьКДате() умеет работать только с календарными единицами — секундами, днями, месяцами — и ничего не знает о выходных и праздниках.

Поэтому «прибавить 5 рабочих дней» нельзя заменить на «прибавить 5 дней»: результат почти всегда попадёт на выходной или не учтёт праздничные дни. Правильное решение строится на данных производственного календаря, который хранится в базе.

Ниже разобраны все рабочие подходы: от простого сдвига календарных дней до полноценного расчёта по графику с учётом праздников, а также типичные ошибки и способы проверить результат.

Что умеет ДобавитьКДате и почему этого недостаточно

Встроенная функция ДобавитьКДате(Дата, Тип, Количество) сдвигает дату на заданное число календарных единиц. Тип может принимать значения «Секунда», «Минута», «Час», «День», «Неделя», «Месяц», «Квартал», «Год».

НоваяДата = ДобавитьКДате(ТекущаяДатаСеанса(), "День", 10);

Функция корректно обрабатывает переходы через месяцы и годы, високосные годы, но понятия «рабочий день» в ней нет. Суббота, воскресенье и праздники считаются обычными днями.

Если договор требует оплаты «в течение 5 рабочих дней», а вы прибавите просто 5 дней, срок может оказаться смещён на 2–3 дня, а в периоды длинных праздников — ещё сильнее. Для юридически значимых сроков такая ошибка критична.

Как устроен учёт рабочих дней через производственный календарь

В типовых конфигурациях на базе Библиотеки стандартных подсистем (БСП) данные о рабочих и нерабочих днях хранятся в регистре сведений «Данные производственного календаря» (измерение — дата, ресурс — вид дня). Сам календарь — элемент справочника «Производственные календари».

Вид дня принимает значения: рабочий, суббота, воскресенье, праздник, предпраздничный, дополнительный выходной. Логика расчёта опирается именно на эти записи, поэтому календарь должен быть заполнен на весь период, в котором выполняются вычисления.

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

Расчёт через КалендарныеГрафики в типовых конфигурациях

В конфигурациях с БСП (УТ, ERP, Бухгалтерия, ЗУП) есть готовый программный интерфейс — общий модуль КалендарныеГрафики. Он умеет получать даты с учётом графика работы и не требует писать собственные циклы.

Ключевая функция — ДатыПоГрафику или ДатаПоКалендарю (состав методов зависит от версии БСП). Типовой вызов для получения даты через N рабочих дней:

График = Справочники.ПроизводственныеКалендари.НайтиПоКоду("РФ");

НоваяДата = КалендарныеГрафики.ДатаПоКалендарю(График, ДатаНачала, 5);

Функция вернёт дату, которая наступит через 5 рабочих дней после начальной, с учётом выходных и праздников из указанного календаря. Если календарь не задан, ряд методов использует календарь по умолчанию из настроек.

Обратите внимание: в разных версиях БСП имена и сигнатуры процедур отличаются. Перед использованием откройте общий модуль «КалендарныеГрафики» в конфигураторе и посмотрите область «ПрограммныйИнтерфейс» — там перечислены доступные методы с описанием параметров.

Порядок действий в типовой конфигурации
  1. 1
    Убедитесь, что производственный календарь заполнен на нужный период
  2. 2
    Откройте общий модуль КалендарныеГрафики и найдите подходящую функцию в программном интерфейсе
  3. 3
    Передайте начальную дату, количество рабочих дней и ссылку на календарь
  4. 4
    Проверьте результат на дате, после которой идут выходные или праздники

Собственная функция через запрос к регистру календаря

В самописных конфигурациях или когда типовой механизм недоступен, расчёт пишется вручную. Идея: запросом выбрать из регистра календаря ближайшие рабочие дни после начальной даты и взять N-й по счёту.

Запрос = Новый Запрос;

Запрос.Текст =

"ВЫБРАТЬ ПЕРВЫЕ 5

| Данные.Дата КАК Дата

|ИЗ

| РегистрСведений.ДанныеПроизводственногоКалендаря КАК Данные

|ГДЕ

| Данные.Дата > &ДатаНачала

| И Данные.ВидДня = ЗНАЧЕНИЕ(Перечисление.ВидыДнейПроизводственногоКалендаря.Рабочий)

|УПОРЯДОЧИТЬ ПО

| Дата";

Запрос.УстановитьПараметр("ДатаНачала", ДатаНачала);

Результат = Запрос.Выполнить().Выгрузить();

Если Результат.Количество() >= 5 Тогда

НоваяДата = Результат[4].Дата;

КонецЕсли;

Моменты, которые нужно учесть в собственной реализации. Во-первых, «ПЕРВЫЕ N» в запросе должно соответствовать числу прибавляемых дней — параметризуйте его или выбирайте с запасом. Во-вторых, предпраздничные дни обычно считаются рабочими (сокращёнными), поэтому в фильтр вида дня их тоже включают, если это требуется логикой.

В-третьих, всегда проверяйте, что запрос вернул достаточно строк. Если календарь заканчивается раньше, чем найден N-й рабочий день, функция должна явно сообщить об этом, а не молча вернуть пустую дату.

Вариант без календаря: сдвиг с учётом только выходных

Если в базе нет производственного календаря, а требуется лишь пропускать субботу и воскресенье, можно обойтись циклом с проверкой дня недели. Функция ДеньНедели() возвращает 1 для понедельника и 7 для воскресенья.

Функция ДобавитьРабочиеДни(ДатаНачала, ЧислоДней)

Результат = ДатаНачала;

Добавлено = 0;

Пока Добавлено < ЧислоДней Цикл

Результат = Результат + 86400; // один день в секундах

Если ДеньНедели(Результат) < 6 Тогда

Добавлено = Добавлено + 1;

КонецЕсли;

КонецЦикла;

Возврат Результат;

КонецФункции

Этот способ прост и не зависит от данных, но праздничные будни он считает рабочими. Для внутренних несрочных расчётов это допустимо, для сроков по договорам — нет.

Сравнение подходов

ДобавитьКДате

Только календарные дни. Подходит, когда выходные не важны, например для срока хранения

КалендарныеГрафики (БСП)

Точный учёт выходных и праздников. Требует типовую конфигурацию и заполненный календарь

Свой запрос к регистру

Полный контроль и работа в любой конфигурации, но нужно самостоятельно обрабатывать пустые периоды

Цикл с ДеньНедели

Без зависимостей и данных, но игнорирует праздники

Граничные случаи: что считать начальной датой

Самая частая разногласия вызывает вопрос: входит ли сама начальная дата в отсчёт. Формулировки «в течение 5 рабочих дней с даты отгрузки» и «не позднее 5-го рабочего дня, следующего за датой отгрузки» дают разные результаты. Зафиксируйте нужное поведение в коде явно: начинать отсчёт со следующего дня или включать текущий, если он рабочий.

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

Третий момент — время в дате. Если начальная дата содержит время (например, 15:30), результат расчёта унаследует его. Для документов часто нужно начало дня: примените НачалоДня() к результату.

Типичные ошибки
01
Прибавлять календарные дни вместо рабочих — срок попадает на выходные и праздники
02
Не проверять заполненность календаря — функция возвращает пустую дату без явной ошибки
03
Забыть про предпраздничные дни — они исключаются из расчёта, хотя являются рабочими
04
Игнорировать время в дате — результат содержит неожиданное время суток
05
Не определить, входит ли начальная дата в отсчёт — срок смещается на один день

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

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

Для расчёта через календарь сверьте результат визуально: откройте производственный календарь в пользовательском режиме и посчитайте рабочие дни вручную. Совпадение ручного и программного результата на 3–4 тестовых датах обычно достаточно, чтобы считать функцию рабочей.

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

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

Сдвиг на 1 рабочий день от пятницы
Норма

Результат — ближайший понедельник или первый рабочий день после праздников

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

Результат — суббота или воскресенье

Период с праздниками
Норма

Праздничные дни пропущены, количество рабочих дней совпадает с ручным подсчётом

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

Праздничный будень засчитан как рабочий

Конец заполненного календаря
Норма

Функция явно сообщает о нехватке данных

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

Возвращается пустая дата без объяснения

Итог

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

Для календарных дней используйте ДобавитьКДате, для рабочих — производственный календарь: в типовых конфигурациях через модуль КалендарныеГрафики, в остальных — запрос к регистру календаря. Перед расчётом убедитесь, что календарь заполнен, и явно определите, входит ли начальная дата в отсчёт.

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

Можно ли прибавить рабочие дни без производственного календаря?

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

Что делать, если КалендарныеГрафики возвращает пустую дату?

Чаще всего причина в незаполненном производственном календаре на нужный период. Откройте календарь в пользовательском режиме и проверьте, что год расчётной даты заполнен. Также проверьте, что передана корректная ссылка на календарь, а не пустое значение.

Как прибавить рабочие дни с учётом графика конкретного сотрудника?

Используйте график работы сотрудника вместо общероссийского календаря. В ЗУП графики хранятся в справочнике графиков работы сотрудников, и функции КалендарныеГрафики принимают ссылку на такой график. Это важно для сменных графиков, где выходные не совпадают с субботой и воскресеньем.

Считается ли предпраздничный день рабочим?

В производственном календаре предпраздничный день — отдельный вид дня: он рабочий, но сокращённый. При подсчёте количества рабочих дней его обычно включают. Если важна продолжительность в часах, а не количество дней, предпраздничные дни нужно обрабатывать отдельно.

Как прибавить рабочие дни в запросе, без кода?

Напрямую в языке запросов такой функции нет. Практический приём — соединить таблицу с регистром календаря, отобрать рабочие дни после начальной даты и пронумеровать их, выбрав N-й. Для сложной логики надёжнее выполнить расчёт в коде и передать результат в запрос параметром.

Чем отличается ДобавитьКДате от простого сложения даты с числом?

Сложение даты с числом прибавляет секунды: выражение Дата + 86400 сдвигает дату на одни сутки. ДобавитьКДате с типом «Месяц» или «Год» корректно обрабатывает разную длину месяцев и високосные годы, чего арифметика в секундах не делает. Для дней оба способа равнозначны.