Как посчитать разницу дат в выводимых строках (между текущей и предыдущей) в СКД 1С?

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

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

В этой статье мы подробно разберем, почему стандартные математические операторы вычитания вызывают ошибку при работе с датами в СКД, как правильно использовать специализированную функцию РАЗНОСТЬДАТ, как извлечь значение из предыдущей строки с помощью ВычислитьВыражение и как настроить расчет итогов по группировкам, чтобы отчет работал корректно на всех уровнях.

Выясняем причину: почему возникает ошибка вычитания дат в СКД?

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


isNULL(ВЫЧИСЛИТЬВЫРАЖЕНИЕ("Дата", , , "Предыдущая", "Предыдущая") - ДобавитьКДате(Дата,"День",-1), 0)

При попытке выполнить такой отчет система выдает ошибку: «Неверные параметры "-"». Давайте разберем, почему так происходит.

Дело в том, что в языке выражений СКД (в отличие от стандартного SQL-подобного языка запросов 1С или встроенного языка программирования) прямое вычитание дат с помощью математического оператора «-» не поддерживается. Компоновщик данных не умеет самостоятельно преобразовывать разность двух объектов типа Дата в число секунд или дней при обычном вычитании. Также в вычисляемых полях СКД нельзя вычесть число из даты напрямую. Любые операции, связанные с нахождением интервалов времени, должны выполняться строго через специализированные функции компоновщика.

Важные особенности синтаксиса функции РАЗНОСТЬДАТ в СКД

Для определения интервала времени между двумя датами в 1С существует стандартная функция РАЗНОСТЬДАТ. Однако ее синтаксис имеет принципиальное отличие в зависимости от того, где именно вы ее используете:

  1. Использование в запросе (на уровне СУБД): Третий параметр (тип периода) указывается как ключевое слово без кавычек.
    Пример: РАЗНОСТЬДАТ(ДатаНачала, ДатаКонца, ДЕНЬ)
  2. Использование в вычисляемых полях или ресурсах СКД: Третий параметр обязательно должен передаваться в виде строкового литерала в двойных кавычках.
    Пример: РАЗНОСТЬДАТ(ДатаНачала, ДатаКонца, "ДЕНЬ")

Если в окне вычисляемых полей СКД вы напишете параметр без кавычек (например, ДЕНЬ, ЧАС или МИНУТА), система выдаст синтаксическую ошибку: «Поле "ДЕНЬ" не обнаружено», так как СКД попытается найти поле набора данных с таким именем.

Пошаговое решение: расчет разницы с предыдущей строкой

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

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

ВычислитьВыражение(Выражение, Группировка, ТипРасчета, Начало, Конец, Сортировка, ИерархическаяСортировка, ОбработкаОдинаковыхЗначенийПорядка)

Для нашей задачи ключевыми являются параметры Начало и Конец, в которых мы укажем значение "Предыдущая".

Шаг 1. Создание вычисляемого поля

Перейдите на вкладку «Вычисляемые поля» вашей схемы компоновки данных. Добавьте новую строку:

Проанализируем детально структуру этого выражения:

  1. ВычислитьВыражение("Дата", , , "Предыдущая") — эта конструкция обращается к значению поля Дата в предыдущей строке текущей группировки. Обратите внимание, что имя поля передается в виде строкового литерала в кавычках.
  2. РАЗНОСТЬДАТ(..., Дата, "ДЕНЬ") — вычисляет разницу в днях между полученной датой из предыдущей строки и текущей датой текущей строки. Обратите внимание, что в качестве типа периода используется строковое значение "ДЕНЬ" (в кавычках).
  3. ЕстьNull(..., 0) — критически важная обертка. Для самой первой строки отчета предыдущей записи просто не существует. В этом случае функция ВычислитьВыражение вернет значение NULL. Следовательно, функция РАЗНОСТЬДАТ, получив один из параметров со значением NULL, также вернет пустое значение. Конструкция ЕстьNull заменяет пустоту на 0 для первой строки.

Если вы хотите сделать отчет более лаконичным и наглядным, можно использовать условную конструкцию ВЫБОР, чтобы вместо нуля в первой строке выводилась пустая ячейка или прочерк:


Выбор 
    Когда ВычислитьВыражение("Дата", , , "Предыдущая") Есть Null 
        Тогда "" 
    Иначе РАЗНОСТЬДАТ(ВычислитьВыражение("Дата", , , "Предыдущая"), Дата, "ДЕНЬ") 
Конец

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

Описанный выше метод идеально работает для детальных записей отчета. Однако если вы просто выведите это вычисляемое поле в отчет, то на уровне группировок (например, по Контрагенту, Складу или Договору) или в строке «Общий итог» вы увидите пустые значения или некорректно рассчитанные данные. Это происходит потому, что СКД пытается рассчитать выражение ВычислитьВыражение в контексте всей группировки в целом, а не детальных записей.

Чтобы СКД правильно суммировала полученные разницы дат по группировкам, мы должны превратить наше вычисляемое поле в Ресурс и задать для него правильное агрегатное выражение.

Шаг 2. Настройка ресурсов

  1. Перейдите на вкладку «Ресурсы» схемы компоновки данных.
  2. Перетащите поле РазницаДней в список ресурсов.
  3. В поле Выражение укажите специальную конструкцию: Сумма(ВычислитьВыражениеСГруппировкойМассив("РазницаДней", "ДетальныеЗаписи"))
  4. В колонке Рассчитывать по... укажите те группировки, в которых вы хотите видеть сумму разностей дат (например, по иерархии выше детальных записей), либо оставьте поле пустым, чтобы расчет шел по всем уровням, кроме детальных.

Разберем работу этой конструкции:

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

Практический пример: расчет разницы времени в минутах

Рассмотрим более точный пример, когда нам нужно посчитать разницу между событиями в минутах. Это актуально для анализа работы службы поддержки (тикетов) или обработки заказов покупателей, для которых автоматическое формирование документов по заказам ускорит работу с входящими заявками без ручного ввода.

Выражение в Вычисляемых полях для расчета интервала в минутах:


Выбор 
    Когда ВычислитьВыражение("ДатаСтатуса", , , "Предыдущая") Есть Null 
        Тогда 0 
    Иначе РАЗНОСТЬДАТ(ВычислитьВыражение("ДатаСтатуса", , , "Предыдущая"), ДатаСтатуса, "МИНУТА") 
Конец

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

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

← На главную