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

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

Работа с датами в системе 1С:Предприятие часто вызывает трудности у начинающих разработчиков. Основная причина заключается в том, что тип данных Дата в 1С всегда содержит и календарный день, и время с точностью до секунды. Если мы видим в интерфейсе «01.01.2023», для платформы это на самом деле «01.01.2023 00:00:00». В этой статье мы подробно разберем, как правильно обрабатывать такие данные в запросах, как отсекать временную составляющую и как корректно сравнивать периоды.

Почему возникают ошибки при сравнении дат?

Рассмотрим стандартную ситуацию: у нас есть документ, созданный 23.05.2018 в 15:42:35, и запись в регистре сведений, которая действует до 23.05.2018. Если мы попытаемся сравнить их напрямую через оператор равенства или даже через некоторые условия диапазона, мы можем получить пустой результат. Выясним причину: документ со временем 15:42:35 уже «больше», чем дата в регистре, если там сохранено значение 00:00:00. Именно поэтому, когда время документа становится хотя бы на одну секунду больше полночи (00:00:01), стандартные условия сравнения могут перестать работать.

Использование функций НАЧАЛОПЕРИОДА и КОНЕЦПЕРИОДА

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

  1. НАЧАЛОПЕРИОДА(Дата, ДЕНЬ) — эта функция сбрасывает время в 00:00:00. Это идеальный способ «отсечь» время, оставив только дату.
  2. КОНЕЦПЕРИОДА(Дата, ДЕНЬ) — эта функция устанавливает время в 23:59:59. Она незаменима, когда нужно включить весь день целиком в условие поиска.

Посмотрим на пример из практики, когда нам нужно найти записи в регистре, в диапазон которых попадает дата документа:


ГДЕ
    &ДатаДокумента МЕЖДУ Регистр.НачалоПериода И КОНЕЦПЕРИОДА(Регистр.КонецПериода, ДЕНЬ)

В данном случае, даже если в поле КонецПериода регистра записана дата с нулевым временем, функция КОНЕЦПЕРИОДА расширит границу до последней секунды дня, и документ, созданный в середине дня, попадет в выборку.

Разбор проблемы дублирования строк

Часто при выполнении запроса в консоли или программно разработчик видит в два раза больше результатов, чем ожидал. Проанализируем ситуацию: если мы делаем ВНУТРЕННЕЕ СОЕДИНЕНИЕ документа с регистром только по сотруднику, 1С выберет все документы этого сотрудника, существующие в базе. Чтобы ограничить выборку текущим документом, необходимо обязательно добавить условие по ссылке.

Рассмотрим правильный вариант запроса, который решает проблему лишних строк и некорректного сравнения времени:


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

Здесь важно обратить внимание на два момента. Во-первых, фильтр Ведомость.Ссылка = &Ссылка гарантирует, что мы работаем только с данными одного конкретного документа. Во-вторых, использование КОНЕЦПЕРИОДА для правой границы диапазона регистра позволяет корректно сопоставить время.

Профессиональные рекомендации по оптимизации

Хотя функции приведения периода работают быстро, хорошим тоном в разработке на 1С считается подготовка параметров до передачи их в запрос. Разберем по шагам, как это сделать в программном коде:


Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ ... ГДЕ &ДатаПараметр МЕЖДУ Т.Начало И Т.Конец";

// Вместо того чтобы вычислять НАЧАЛОПЕРИОДА в запросе, 
// передадим уже подготовленное значение начала дня.
Запрос.УстановитьПараметр("ДатаПараметр", НачалоДня(Объект.Дата));

Это не только упрощает чтение кода запроса, но и в некоторых случаях позволяет SQL-серверу более эффективно использовать индексы, так как над полем-параметром не производятся вычисления.

Сравнение дат через классические неравенства

Опытные разработчики часто советуют использовать классические знаки сравнения (>=, <=) вместо оператора МЕЖДУ. Это связано с тем, что МЕЖДУ включает обе границы (и начало, и конец). Если вам нужно строго исключить следующую дату, можно использовать конструкцию:


ГДЕ
    ДатаПроверки >= НачалоПериода
    И ДатаПроверки < &ДатаСледующегоДня

Где &ДатаСледующегоДня — это НачалоДня(НужнаяДата) + 86400 (количество секунд в сутках). Такой подход считается наиболее «чистым» с точки зрения математической логики исключения пересечений.

Работа с пустыми датами

Выясним еще одну важную деталь: как быть, если дата конца периода в регистре не заполнена (пустая дата), что часто означает «бессрочно»? В 1С пустая дата — это 01.01.0001 00:00:00. Если вы примените к ней КОНЕЦПЕРИОДА, она все равно останется пустой датой, и условие МЕЖДУ не сработает. В таких случаях структуру ГДЕ следует дополнить:


ГДЕ
    &Дата >= ПроцентУдержаний.НачалоПериода
    И (ПроцентУдержаний.КонецПериода = ДАТАВРЕМЯ(1, 1, 1) 
        ИЛИ &Дата <= КОНЕЦПЕРИОДА(ПроцентУдержаний.КонецПериода, ДЕНЬ))

Подведем итог: для корректного отсечения времени и сравнения дат всегда используйте НАЧАЛОПЕРИОДА или КОНЕЦПЕРИОДА, не забывайте фильтровать запросы по ссылке на объект, чтобы избежать дублей, и по возможности подготавливайте параметры в коде 1С с помощью функций НачалоДня() или КонецДня().

← На главную