При работе с языком запросов 1С часто возникает задача привести произвольное значение даты и времени к началу текущего дня (то есть установить время в 00:00:00). Рассмотрим подробнее, как правильно решить эту задачу, а также разберем важные нюансы, связанные с производительностью и обработкой сложных типов данных.
Для получения даты на начало дня в языке запросов 1С предназначена встроенная функция НАЧАЛОПЕРИОДА. В качестве аргументов функция принимает исходное поле с датой и тип периода, к началу которого требуется привести значение.
Синтаксис функции выглядит следующим образом:
НАЧАЛОПЕРИОДА(ИсходнаяДата, ДЕНЬ)
Посмотрим на пример использования функции в реальном запросе:
ВЫБРАТЬ
Продажи.Ссылка КАК Документ,
Продажи.Дата КАК ДатаДокумента,
НАЧАЛОПЕРИОДА(Продажи.Дата, ДЕНЬ) КАК ДатаНаНачалоДня
ИЗ
Документ.Продажи КАК Продажи
В результате выполнения такого запроса поле ДатаНаНачалоДня будет содержать дату документа со временем 00:00:00.
Проанализируем ситуацию, когда исходное поле имеет составной тип данных (например, может содержать не только дату, но и строку или ссылку) либо возвращает NULL в результате левого или правого соединения таблиц. В таких случаях вызов функции НАЧАЛОПЕРИОДА может привести к ошибке «Неверные параметры "НАЧАЛОПЕРИОДА"».
Чтобы избежать ошибок, разберем по шагам правильную обработку таких полей:
NULL, обернем его в функцию ЕСТЬNULL.ДАТА с помощью конструкции ВЫРАЗИТЬ.Пример безопасного вызова функции:
НАЧАЛОПЕРИОДА(ЕСТЬNULL(ВЫРАЗИТЬ(Таблица.ПолеСоставногоТипа КАК ДАТА), ДАТАВРЕМЯ(1, 1, 1)), ДЕНЬ)
Если исходная дата является пустой (0001-01-01 / ДАТАВРЕМЯ(1, 1, 1)), функция НАЧАЛОПЕРИОДА вернет исходную пустую дату. Если в аргумент передается значение NULL, результатом работы функции также станет NULL.
Выясним причину возможного замедления запросов при использовании функции в условиях отбора. Использование конструкции НАЧАЛОПЕРИОДА(Таблица.Дата, ДЕНЬ) в секции ГДЕ блокирует использование индексов СУБД по полю даты. В результате вместо точечного поиска выполняется полное сканирование таблицы, что существенно снижает скорость работы системы на больших объемах данных.
Важная рекомендация: не оборачивайте поле таблицы в функцию в секции ГДЕ. Вместо этого заранее подготавливайте граничные даты на стороне встроенного языка 1С и передавайте их в запрос в качестве параметров через оператор МЕЖДУ:
// В коде на встроенном языке:
Запрос.УстановитьПараметр("ДатаНачала", НачалоДня(ИсходнаяДата));
Запрос.УстановитьПараметр("ДатаКонца", КонецДня(ИсходнаяДата));
// В тексте запроса:
ГДЕ
Таблица.Дата МЕЖДУ &ДатаНачала И &ДатаКонца
В качестве второго параметра функции НАЧАЛОПЕРИОДА можно указывать не только ДЕНЬ, но и другие типы периодов: СЕКУНДА, МИНУТА, ЧАС, НЕДЕЛЯ, ДЕКАДА, МЕСЯЦ, КВАРТАЛ, ПОЛУГОДИЕ, ГОД.
Если необходимо получить начало дня со сдвигом на определенное количество суток (например, начало следующего дня), сочетаем НАЧАЛОПЕРИОДА с функцией ДОБАВИТЬКДАТЕ:
ДОБАВИТЬКДАТЕ(НАЧАЛОПЕРИОДА(ИсходнаяДата, ДЕНЬ), ДЕНЬ, 1)