Как в 1С прибавить к дате определенное количество рабочих дней?

Программист 1С v8.3 (Управляемые формы)
← На главную

В процессе разработки в среде 1С:Предприятие часто возникает задача вычисления даты окончания какого-либо срока, исчисляемого в рабочих днях. Это может быть срок оплаты счета, дата поставки товара или крайний срок выполнения задачи. Простое прибавление секунд к дате здесь не поможет, так как необходимо игнорировать выходные и праздничные дни, опираясь на производственный календарь.

В этой статье мы подробно разберем, как реализовать этот алгоритм, рассмотрим использование инструментов Библиотеки стандартных подсистем (БСП) и напишем собственный запрос для получения результата, если использование БСП по каким-то причинам невозможно.

Способ 1: Использование стандартной функции БСП

Если ваша конфигурация построена на базе БСП (что справедливо для большинства современных типовых решений, таких как 1С:ERP, 1С:КА, 1С:УТ 11 или 1С:Бухгалтерия 3.0), то наиболее правильным и надежным способом будет использование программного интерфейса модуля КалендарныеГрафики.

Проанализируем функцию ДатаПоКалендарю. Этот метод универсален и позволяет работать как с общим производственным календарем РФ, так и с конкретными графиками работы (например, сменными).

Синтаксис функции:


Функция ДатаПоКалендарю(Знач ГрафикРаботы, Знач ДатаОт, Знач КоличествоДней, ВызыватьИсключение = Истина) Экспорт

Разберем параметры подробнее:

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

Рассмотрим пример кода для прибавления 10 рабочих дней к текущей дате:


// Получаем ссылку на основной производственный календарь (обычно с кодом "РФ")
КалендарьСсылка = Справочники.ПроизводственныеКалендари.НайтиПоНаименованию("Российская Федерация");

Если Не КалендарьСсылка.Пустая() Тогда
    НоваяДата = КалендарныеГрафики.ДатаПоКалендарю(КалендарьСсылка, ТекущаяДата(), 10);
    Сообщить("Дата через 10 рабочих дней: " + НоваяДата);
КонецЕсли;

Способ 2: Получение даты через запрос (универсальный метод)

Иногда требуется получить дату внутри запроса или в старых конфигурациях, где БСП отсутствует. В этом случае мы будем обращаться к регистру сведений РегламентированныйПроизводственныйКалендарь или его современному аналогу ДанныеПроизводственногоКалендаря.

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

Проанализируем пример запроса для получения 10-го рабочего дня:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ ПЕРВЫЕ 10
    |	Календарь.ДатаКалендаря КАК ДатаКалендаря
    |ИЗ
    |	РегистрСведений.ДанныеПроизводственногоКалендаря КАК Календарь
    |ГДЕ
    |	Календарь.ДатаКалендаря > &ДатаНачала
    |	И Календарь.ВидДня В (ЗНАЧЕНИЕ(Перечисление.ВидыДнейПроизводственногоКалендаря.Рабочий), 
    |                         ЗНАЧЕНИЕ(Перечисление.ВидыДнейПроизводственногоКалендаря.Предпраздничный))
    |	И Календарь.ПроизводственныйКалендарь = &Календарь
    |УПОРЯДОЧИТЬ ПО
    |	ДатаКалендаря ВОЗР";

Запрос.УстановитьПараметр("ДатаНачала", КонецДня(ТекущаяДата()));
Запрос.УстановитьПараметр("Календарь", КалендарьСсылка);

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

// Переходим к последней (десятой) записи
Пока Выборка.Следующий() Цикл
    ИскомаяДата = Выборка.ДатаКалендаря;
КонецЦикла;

Сообщить("Результат: " + ИскомаяДата);

В данном примере мы используем ВЫБРАТЬ ПЕРВЫЕ 10. Если нам нужно передать количество дней переменной, текст запроса придется формировать динамически или использовать временные таблицы для дальнейшей обработки.

Важные нюансы при работе с календарями

Рассмотрим несколько критических моментов, которые часто упускают разработчики при реализации подобных задач:

  1. Заполнение календаря: Любой программный метод вернет ошибку или пустую дату, если производственный календарь не заполнен в системе на текущий или следующий год. В БСП для проверки заполнения существует метод КалендарныеГрафики.ГрафикЗаполнен().
  2. Региональные праздники: Если ваша компания работает в регионах с национальными праздниками (например, Татарстан, Башкортостан), крайне важно использовать именно региональный календарь, а не общероссийский.
  3. Предпраздничные дни: При написании запросов вручную обязательно включайте ВидыДнейПроизводственногоКалендаря.Предпраздничный в фильтр, иначе вы пропустите сокращенные рабочие дни, и расчет будет неверным.
  4. Отрицательные значения: Если вам нужно узнать, какая дата была 5 рабочих дней назад, метод БСП ДатаПоКалендарю отработает корректно, если передать "-5". В случае с запросом — придется изменить знак сравнения на "меньше" и сменить сортировку на УБЫВ.

Разница между производственным календарем и графиком работы

Выясним причину, почему иногда результаты могут отличаться. Производственный календарь — это общегосударственный стандарт (пятидневка 40 часов). График работы — это конкретное расписание сотрудника или склада (например, "2 через 2" или шестидневка).

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

Таким образом, для большинства задач в современных конфигурациях 1С оптимальным выбором будет использование модуля КалендарныеГрафики, который берет на себя все сложности по работе с переносами праздников и типами дней.

← На главную