В процессе разработки в среде 1С:Предприятие часто возникает задача вычисления даты окончания какого-либо срока, исчисляемого в рабочих днях. Это может быть срок оплаты счета, дата поставки товара или крайний срок выполнения задачи. Простое прибавление секунд к дате здесь не поможет, так как необходимо игнорировать выходные и праздничные дни, опираясь на производственный календарь.
В этой статье мы подробно разберем, как реализовать этот алгоритм, рассмотрим использование инструментов Библиотеки стандартных подсистем (БСП) и напишем собственный запрос для получения результата, если использование БСП по каким-то причинам невозможно.
Если ваша конфигурация построена на базе БСП (что справедливо для большинства современных типовых решений, таких как 1С:ERP, 1С:КА, 1С:УТ 11 или 1С:Бухгалтерия 3.0), то наиболее правильным и надежным способом будет использование программного интерфейса модуля КалендарныеГрафики.
Проанализируем функцию ДатаПоКалендарю. Этот метод универсален и позволяет работать как с общим производственным календарем РФ, так и с конкретными графиками работы (например, сменными).
Синтаксис функции:
Функция ДатаПоКалендарю(Знач ГрафикРаботы, Знач ДатаОт, Знач КоличествоДней, ВызыватьИсключение = Истина) Экспорт
Разберем параметры подробнее:
Календари или ПроизводственныеКалендари. Это ключевой параметр, который определяет, какие дни считать рабочими.Рассмотрим пример кода для прибавления 10 рабочих дней к текущей дате:
// Получаем ссылку на основной производственный календарь (обычно с кодом "РФ")
КалендарьСсылка = Справочники.ПроизводственныеКалендари.НайтиПоНаименованию("Российская Федерация");
Если Не КалендарьСсылка.Пустая() Тогда
НоваяДата = КалендарныеГрафики.ДатаПоКалендарю(КалендарьСсылка, ТекущаяДата(), 10);
Сообщить("Дата через 10 рабочих дней: " + НоваяДата);
КонецЕсли;
Иногда требуется получить дату внутри запроса или в старых конфигурациях, где БСП отсутствует. В этом случае мы будем обращаться к регистру сведений РегламентированныйПроизводственныйКалендарь или его современному аналогу ДанныеПроизводственногоКалендаря.
Логика запроса заключается в следующем: мы выбираем все рабочие дни, которые строго больше нашей начальной даты, сортируем их по возрастанию и берем запись под номером, равным количеству добавляемых дней.
Проанализируем пример запроса для получения 10-го рабочего дня:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 10
| Календарь.ДатаКалендаря КАК ДатаКалендаря
|ИЗ
| РегистрСведений.ДанныеПроизводственногоКалендаря КАК Календарь
|ГДЕ
| Календарь.ДатаКалендаря > &ДатаНачала
| И Календарь.ВидДня В (ЗНАЧЕНИЕ(Перечисление.ВидыДнейПроизводственногоКалендаря.Рабочий),
| ЗНАЧЕНИЕ(Перечисление.ВидыДнейПроизводственногоКалендаря.Предпраздничный))
| И Календарь.ПроизводственныйКалендарь = &Календарь
|УПОРЯДОЧИТЬ ПО
| ДатаКалендаря ВОЗР";
Запрос.УстановитьПараметр("ДатаНачала", КонецДня(ТекущаяДата()));
Запрос.УстановитьПараметр("Календарь", КалендарьСсылка);
РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();
// Переходим к последней (десятой) записи
Пока Выборка.Следующий() Цикл
ИскомаяДата = Выборка.ДатаКалендаря;
КонецЦикла;
Сообщить("Результат: " + ИскомаяДата);
В данном примере мы используем ВЫБРАТЬ ПЕРВЫЕ 10. Если нам нужно передать количество дней переменной, текст запроса придется формировать динамически или использовать временные таблицы для дальнейшей обработки.
Рассмотрим несколько критических моментов, которые часто упускают разработчики при реализации подобных задач:
КалендарныеГрафики.ГрафикЗаполнен().ВидыДнейПроизводственногоКалендаря.Предпраздничный в фильтр, иначе вы пропустите сокращенные рабочие дни, и расчет будет неверным.ДатаПоКалендарю отработает корректно, если передать "-5". В случае с запросом — придется изменить знак сравнения на "меньше" и сменить сортировку на УБЫВ.Выясним причину, почему иногда результаты могут отличаться. Производственный календарь — это общегосударственный стандарт (пятидневка 40 часов). График работы — это конкретное расписание сотрудника или склада (например, "2 через 2" или шестидневка).
Если ваша задача — рассчитать дату отгрузки со склада, который работает без выходных, использование производственного календаря будет ошибкой. В функциях БСП в параметр ГрафикРаботы в таком случае нужно передавать ссылку из справочника Календари, настроенного соответствующим образом. Механика вызова функции при этом не изменится, что делает код универсальным.
Таким образом, для большинства задач в современных конфигурациях 1С оптимальным выбором будет использование модуля КалендарныеГрафики, который берет на себя все сложности по работе с переносами праздников и типами дней.