Как правильно рассчитать разность дат в вычисляемых полях СКД?

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

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

Почему возникает ошибка «Неверные параметры "-"»

Проанализируем поведение системы при попытке вычесть одну дату из другой. В программном коде 1С оператор «минус» для дат перегружен: операция Дата1 - Дата2 возвращает количество секунд между моментами времени. Однако язык выражений СКД — это отдельный диалект платформы, правила которого отличаются как от встроенного языка 1С:Предприятия, так и от языка запросов СУБД.

В языке выражений компоновки данных бинарные операторы сложения и вычитания (+ и -) строго типизированы и работают исключительно с числами. Попытка вычесть дату из даты или отнять от даты числовое значение (например, ЗаказПокупателя.Дата - 2) вызывает синтаксическую ошибку, так как система не поддерживает арифметику дат через стандартные операторы.

Использование функции РАЗНОСТЬДАТ в выражении СКД

Для вычисления временного интервала между датами в СКД предназначена встроенная функция РАЗНОСТЬДАТ(). При переходе с языка запросов разработчики часто допускают ошибку, указывая третий параметр (период) как ключевое слово без кавычек, например: РАЗНОСТЬДАТ(ЗаказПокупателя.Дата, &ТекДата, ДЕНЬ). Это приводит к ошибке синтаксического анализа.

Главное отличие: в языке выражений СКД третий параметр функции РАЗНОСТЬДАТ обязательно должен быть строковым литералом (в двойных кавычках).

Посмотрим на корректный синтаксис выражения вычисляемого поля:

РАЗНОСТЬДАТ(ЗаказПокупателя.Дата, &ТекДата, "ДЕНЬ")

В качестве единицы измерения периода допускается указывать следующие строковые значения (регистр символов значения не имеет):

  1. "СЕКУНДА"
  2. "МИНУТА"
  3. "ЧАС"
  4. "ДЕНЬ"
  5. "НЕДЕЛЯ"
  6. "ДЕКАДА"
  7. "МЕСЯЦ"
  8. "КВАРТАЛ"
  9. "ПОЛУГОДИЕ"
  10. "ГОД"

Особенности расчета границ периодов

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

Если начальная дата равна 31.12.2023 23:59:59, а конечная — 01.01.2024 00:00:01, вызов РАЗНОСТЬДАТ(Дата1, Дата2, "ГОД") вернет 1, хотя фактически прошло всего две секунды. Аналогично для дней: пересечение полуночи добавляет единицу к результату.

Если требуется получить точное математическое количество суток или часов с дробной частью, разность следует рассчитать в секундах, а затем разделить на константу времени:

РАЗНОСТЬДАТ(ЗаказПокупателя.Дата, &ТекДата, "СЕКУНДА") / 86400

Обработка пустых значений и значений NULL

При вычислении разности дат важно учитывать наличие незаполненных реквизитов. Если одно из полей не заполнено (содержит пустую дату 0001-01-01 или значение NULL), функция вернет либо NULL, либо огромное число (разницу между началом нашей эры и текущей датой).

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


ВЫБОР
    КОГДА ЗаказПокупателя.Дата ЕСТЬ NULL ИЛИ ЗаказПокупателя.Дата = ДАТАВРЕМЯ(1, 1, 1)
        ТОГДА 0
    ИНАЧЕ РАЗНОСТЬДАТ(ЗаказПокупателя.Дата, &ТекДата, "ДЕНЬ")
КОНЕЦ

Альтернативные способы расчета разности дат

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

  1. Расчет в тексте запроса: Если поле доступно на этапе формирования набора данных, вычисление разности лучше перенести в текст запроса. В запросе СУБД период пишется без кавычек: РАЗНОСТЬДАТ(ЗаказПокупателя.Дата, &ТекДата, ДЕНЬ). Это снижает нагрузку на процессор компоновки данных.
  2. Вызов функции общего модуля: В выражении вычисляемого поля СКД можно вызывать экспортные функции доступных общих модулей: МойОбщийМодуль.РассчитатьРазницуДат(ЗаказПокупателя.Дата, &ТекДата). Для успешного выполнения общий модуль должен иметь признак «Сервер» (или «Клиент», если отчет формируется на клиенте), а функция должна быть объявлена с ключевым словом Экспорт.
← На главную