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

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

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

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

Метод 1: Использование вложенных функций (метод «копипаста»)

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

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

Разберем процесс по шагам:

  1. Переходим на закладку Вычисляемые поля в схеме компоновки данных.
  2. Добавляем новое поле (например, ДатаОкончания).
  3. В колонке Выражение прописываем вложенную конструкцию.

Проанализируем итоговое выражение:


ДобавитьКДате(ДобавитьКДате(ДатаПоверки, "Месяц", ПериодПоверки - 1), "День", -1)

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

Метод 2: Вынос логики в общий модуль

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

Для реализации выполним следующие действия:

  1. Создадим (или выберем существующий) общий модуль. В свойствах модуля обязательно должны быть установлены флаги Вызов сервера и Внешнее соединение.
  2. Напишем функцию, которая принимает необходимые параметры и возвращает итоговую дату.

Пример кода в общем модуле РаботаСДатамиВызовСервера:


Функция РассчитатьДатуОкончанияПоверки(ДатаНачала, КоличествоМесяцев) Экспорт
    
    ПромежуточнаяДата = ДобавитьМесяц(ДатаНачала, КоличествоМесяцев - 1);
    ИтоговаяДата = ПромежуточнаяДата - 86400; // Вычитаем сутки (в секундах)
    
    Возврат ИтоговаяДата;
    
КонецФункции

Теперь в СКД в поле Выражение достаточно вызвать эту функцию:


РаботаСДатамиВызовСервера.РассчитатьДатуОкончанияПоверки(ДатаПоверки, ПериодПоверки)

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

Метод 3: Расчет на уровне запроса

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

В языке запросов 1С функция ДОБАВИТЬКДАТЕ работает аналогично. Мы можем написать в тексте запроса:


ВЫБРАТЬ
    ДОБАВИТЬКДАТЕ(ДОБАВИТЬКДАТЕ(Таблица.ДатаПоверки, МЕСЯЦ, Таблица.ПериодПоверки - 1), ДЕНЬ, -1) КАК ДатаОкончания
ИЗ
    РегистрСведений.СведенияОПоверках КАК Таблица

Преимущества этого подхода:

Метод 4: Оптимизация через функцию КонецПериода

Часто задача «отнять один день» возникает из желания получить последний день предыдущего месяца. Если ваша цель именно в этом, то использование ДобавитьКДате с параметром «-1 день» может быть избыточным и менее надежным.

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

КонецПериода(ДобавитьКДате(ДатаПоверки, "Месяц", ПериодПоверки - 1), "День")

Функция КонецПериода(..., "День") устанавливает время на 23:59:59, что часто является более правильным для логики «по дату включительно».

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

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

1. Обработка пустых значений (NULL): Если в исходных данных поле ДатаПоверки не заполнено, вложенная функция вернет неопределенный результат или вызовет ошибку в некоторых версиях платформы. Правильнее всего использовать конструкцию ВЫБОР:


ВЫБОР 
    КОГДА ДатаПоверки = ДАТАВРЕМЯ(1, 1, 1) ТОГДА ДАТАВРЕМЯ(1, 1, 1) 
    ИНАЧЕ ДобавитьКДате(ДобавитьКДате(ДатаПоверки, "Месяц", ПериодПоверки - 1), "День", -1) 
КОНЕЦ

2. Порядок вычислений (Приоритет): Вычисляемые поля рассчитываются после набора данных запроса, но до расчета ресурсов. Это значит, что вы можете использовать вычисленную дату в качестве ресурса (например, взять МАКСИМУМ(ДатаОкончания)), но вы не можете в вычисляемом поле обратиться к результату агрегатной функции (сумме или среднему).

3. Оформление результата: Когда мы вычисляем сложную дату, она часто выводится со временем. Чтобы отчет выглядел профессионально, не нужно использовать функцию Формат() прямо в выражении поля. Выясним причину: это превратит дату в строку, и вы потеряете возможность сортировать колонку как дату. Вместо этого используйте колонку Оформление в СКД, установив параметр Формат в значение ДФ=dd.MM.yyyy.

Заключение

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

← На главную