При разработке отчетов в системе компоновки данных (СКД) часто возникает задача посчитать разность между двумя датами не в календарных, а именно в рабочих днях. Стандартная функция РАЗНОСТЬДАТ вычисляет общий календарный интервал в днях, месяцах или годах, но не умеет отсекать субботы, воскресенья и праздничные дни. Разберем, как обойти это ограничение и реализовать точный расчет рабочих дней разными способами.
Рассмотрим, почему не удается обойтись простой формулой в вычисляемых полях. Функция РАЗНОСТЬДАТ в языке запросов и языке выражений СКД предназначена только для подсчета календарного времени между двумя отметками. В ней не предусмотрены встроенные параметры для учета графиков работы или праздников.
Кроме того, в самом языке выражений СКД отсутствуют специализированные функции для прямого обращения к календарным графикам, поэтому получить интервал в рабочих днях набором стандартных выражений компоновки данных без обращения к базе или коду не получится.
Проанализируем базовый способ решения задачи на уровне запроса СКД. Для учета праздников и выходных дней используется регистр сведений РегламентированныйПроизводственныйКалендарь (или ДанныеПроизводственногоКалендаря в более новых конфигурациях).
Посмотрим на пример запроса, который суммирует только необходимые дни из диапазона между строгими границами периода:
ВЫБРАТЬ
СУММА(ВЫБОР
КОГДА Календарь.ВидДня = ЗНАЧЕНИЕ(Перечисление.ВидыДнейПроизводственногоКалендаря.Рабочий)
ИЛИ Календарь.ВидДня = ЗНАЧЕНИЕ(Перечисление.ВидыДнейПроизводственногоКалендаря.Предпраздничный)
ТОГДА 1
ИНАЧЕ 0
КОНЕЦ) КАК КоличествоРабочихДней
ИЗ
РегистрСведений.РегламентированныйПроизводственныйКалендарь КАК Календарь
ГДЕ
Календарь.ДатаКалендаря МЕЖДУ &НачалоПериода И &КонецПериода
Обратите внимание: в регистрах сведений производственных календарей дни делятся на несколько категорий. Помимо обычного рабочего дня существует вид Предпраздничный. Предпраздничные дни также являются рабочими, поэтому их обязательно нужно включать в условие выбора, иначе итоговый результат будет занижен.
Разберем вариант, когда запрос менять нежелательно, а расчёт необходимо вынести в вычисляемые поля СКД. Платформа 1С позволяет из поля «Выражение» вычисляемого поля вызывать экспортные функции серверных общих модулей.
КалендарныеГрафики.Пример формулы для вычисляемого поля СКД:
ИмяСерверногоМодуля.ПосчитатьРабочиеДни(ДатаНачала, ДатаОкончания)
Внутри функции общего модуля вы можете описать алгоритм считывания данных из производственного календаря или вызова программного интерфейса БСП.
Рассмотрим ситуацию, когда требуется быстро исключить только субботы и воскресенья, а точный учет государственных праздников и переносов не требуется. В этом случае можно обойтись математическим расчетом на языке запросов с использованием функции ДЕНЬНЕДЕЛИ:
ДЕНЬНЕДЕЛИ(Дата) определяем дни недели для начала и конца периода и корректируем остаток неполной недели.Выясним возможные проблемы со скоростью выполнения отчета. Если связывать основную таблицу отчета с регистром календаря напрямую по условию ДатаКалендаря МЕЖДУ ДатаНачала И ДатаОкончания для каждой детальной записи, возникает неточное соединение (Non-Equi Join). На больших массивах данных (десятки тысяч строк) такой подход существенно снижает скорость работы отчета.
Чтобы избежать задержек, придерживаемся следующего алгоритма оптимизации:
(ДатаНачала, ДатаОкончания) с использованием группировки СГРУППИРОВАТЬ ПО.