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

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

При разработке отчетов в Системе компоновки данных (СКД) или при написании обычных запросов программисты часто сталкиваются с задачей фильтрации данных по времени суток. Например, пользователю требуется получить документы или движения регистров за определенный месяц (например, август), но только те, которые были проведены в определенном интервале времени — скажем, с 11:00 до 17:00 или с 18:30 до 22:15.

Если применить стандартное условие МЕЖДУ к обычным параметрам даты и времени, система выберет непрерывный период от первой даты до второй, включая все ночные и утренние часы между днями. Нам же требуется применить «циклический» фильтр, который будет работать внутри каждых суток выбранного месяца. В этой статье мы подробно разберем, как решить эту задачу эффективно, красиво и с учетом производительности базы данных.

Проблема непрерывного интервала дат

Рассмотрим типичную ошибку начинающих разработчиков. Если передать в параметры запроса даты 01.08.2020 11:00:00 и 31.08.2020 17:00:00 и написать условие:


ГДЕ
    Продажи.Дата МЕЖДУ &ДатаНачала И &ДатаОкончания

В выборку попадут абсолютно все документы, начиная с 11:00 первого августа и заканчивая 17:00 тридцать первого августа. Документы, созданные в полночь, в 3 часа ночи или в 9 утра любого промежуточного дня, также окажутся в отчете. Это происходит потому, что СУБД рассматривает дату и время как единую линейную шкалу времени.

Чтобы решить задачу правильно, нам необходимо разделить условие на две независимые части:

  1. Ограничение по календарному периоду (например, весь месяц август).
  2. Ограничение по времени суток (например, только часы с 11:00 до 17:00 внутри каждых суток).

Решение 1. Фильтрация по часам с помощью функции ЧАС()

Проанализируем самый простой способ решения, который упоминался на форуме. Если пользователю достаточно задавать интервалы с точностью до «круглых» часов (без минут и секунд), мы можем использовать встроенную функцию языка запросов 1С ЧАС().

Посмотрим на пример реализации такого запроса:


ВЫБРАТЬ
    Продажи.Ссылка КАК Документ,
    Продажи.Дата КАК Дата
ИЗ
    Документ.РеализацияТоваровУслуг КАК Продажи
ГДЕ
    Продажи.Дата МЕЖДУ &ДатаНачала И &ДатаОкончания
    И ЧАС(Продажи.Дата) МЕЖДУ &ЧасНачала И &ЧасОкончания

В данном случае в параметры &ЧасНачала и &ЧасОкончания передаются обычные целые числа (например, 11 и 17).

В чем минус этого подхода: данный вариант абсолютно не подходит, если пользователю потребуется указать интервал с минутами (например, с 11:30 до 17:45). Функция ЧАС() просто отсекает минуты. Документ со временем 11:15 вернет значение часа 11 и попадет в интервал 11-17, хотя фактически он был проведен раньше нижней границы 11:30.

Решение 2. Точное сравнение времени суток (универсальный метод)

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

Идея заключается в следующем:

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

На выходе мы получим значение даты вида 01.01.0001 ЧЧ:ММ:СС. Точно такое же значение времени на пустую дату возвращают параметры СКД, если у них установлен тип «Дата» с составом данных «Время».

Посмотрим на пример запроса с использованием этой механики:


ВЫБРАТЬ
    Продажи.Ссылка КАК Документ,
    Продажи.Дата КАК Дата
ИЗ
    Документ.РеализацияТоваровУслуг КАК Продажи
ГДЕ
    Продажи.Дата МЕЖДУ &ДатаНачала И &ДатаОкончания
    И ДОБАВИТЬКДАТЕ(ДАТАВРЕМЯ(1, 1, 1), СЕКУНДА, РАЗНОСТЬДАТ(НАЧАЛОПЕРИОДА(Продажи.Дата, ДЕНЬ), Продажи.Дата, СЕКУНДА)) МЕЖДУ &ВремяНачала И &ВремяОкончания

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

Решение 3. Универсальный алгоритм с переходом через полночь

Выясним причину, почему предыдущие решения могут не сработать в специфических сценариях. На форуме справедливо заметили: что делать, если пользователю нужно выбрать ночную смену, например, с 20:00 вечера до 03:00 утра следующего дня?

Если мы просто напишем условие Время МЕЖДУ &ВремяНачала И &ВремяОкончания, запрос не вернет ни одной строки, так как время 20:00 математически больше, чем 03:00. Для решения этой проблемы мы должны применить гибкую логику ветвления условий в секции ГДЕ.

Если время начала меньше или равно времени окончания, мы используем стандартное условие «И» (диапазон находится внутри одних суток). Если же время начала больше времени окончания (происходит переход через полночь), мы используем условие «ИЛИ» (нам подходят все записи, которые позже вечерней границы ИЛИ раньше утренней).

Проанализируем итоговую конструкцию запроса:


ВЫБРАТЬ
    Продажи.Ссылка КАК Документ,
    Продажи.Дата КАК Дата,
    ДОБАВИТЬКДАТЕ(ДАТАВРЕМЯ(1, 1, 1), СЕКУНДА, РАЗНОСТЬДАТ(НАЧАЛОПЕРИОДА(Продажи.Дата, ДЕНЬ), Продажи.Дата, СЕКУНДА)) КАК ЧистоеВремя
ПОМЕСТИТЬ ВТ_Данные
ИЗ
    Документ.РеализацияТоваровУслуг КАК Продажи
ГДЕ
    Продажи.Дата МЕЖДУ &ДатаНачала И &ДатаОкончания
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    ВТ_Данные.Документ,
    ВТ_Данные.Дата
ИЗ
    ВТ_Данные КАК ВТ_Данные
ГДЕ
    (&ВремяНачала <= &ВремяОкончания И ВТ_Данные.ЧистоеВремя МЕЖДУ &ВремяНачала И &ВремяОкончания)
    ИЛИ (&ВремяНачала > &ВремяОкончания И (ВТ_Данные.ЧистоеВремя >= &ВремяНачала ИЛИ ВТ_Данные.ЧистоеВремя <= &ВремяОкончания))

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

Оптимизация производительности запроса (Sargability)

Рассмотрим критически важный аспект работы с СУБД — оптимизацию скорости выполнения запроса. Использование математических функций, таких как РАЗНОСТЬДАТ, ДОБАВИТЬКДАТЕ или НАЧАЛОПЕРИОДА, непосредственно в секции ГДЕ применительно к индексируемому полю (в нашем случае это поле Дата) лишает систему управления базами данных возможности использовать индексы. СУБД будет вынуждена произвести полное сканирование всей таблицы (Full Table Scan) для вычисления секунд для каждого документа в базе данных, что приведет к колоссальным задержкам на крупных информационных базах.

Чтобы избежать этой проблемы, мы применили разделение запроса на два этапа через временную таблицу:

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

Настройка параметров в Системе компоновки данных (СКД)

Для того чтобы пользователю было максимально удобно работать с отчетом, настроим параметры СКД на вкладке «Параметры»:

  1. Выбор месяца: Создайте параметр ПериодОтчета с типом СтандартныйПериод. Пользователь сможет в интерактивном режиме в один клик выбирать любой месяц. Также создайте два скрытых параметра ДатаНачала и ДатаОкончания (снимите для них флаг «Доступные поля»), указав в колонке «Выражение» формулы &ПериодОтчета.ДатаНачала и &ПериодОтчета.ДатаОкончания соответственно.
  2. Выбор времени суток: Создайте параметры ВремяНачала и ВремяОкончания с типом Дата. В свойствах этих параметров (колонка «Параметры редактирования») укажите Состав даты: Время. При открытии отчета у пользователя будет отображаться удобная маска ввода времени (например, 11:30:00), а календарные дни заполняться не будут.

Такой подход делает работу с отчетом интуитивно понятной, быстрой и исключает ошибки ручного ввода дат.

← На главную