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