К статье
Практический материал

Разработка и Конфигурация · 10 мин

Как написать дату в запросе 1С

Как задать дату в запросе 1С: литерал ДАТАВРЕМЯ, параметры, границы периодов, функции НАЧАЛОПЕРИОДА и КОНЕЦПЕРИОДА. Примеры кода и типичные ошибки.

Дата — один из самых частых источников ошибок в запросах 1С. Запрос то возвращает пустой результат, то захватывает лишние документы, то выдаёт сообщение о неверном литерале. Причина почти всегда одна: дата задана не в том формате, который ожидает язык запросов, или граница периода выбрана неверно.

В языке запросов 1С есть три основных способа указать дату: литерал ДАТАВРЕМЯ, параметр запроса и вычисляемое значение через функции периодов. Каждый способ имеет свою область применения, и смешивать их без понимания различий не стоит.

Ниже разобраны синтаксис литералов, передача дат через параметры, работа с границами времени, типовые сценарии сравнения дат с учётом времени и ошибки, которые чаще всего встречаются на практике.

Литерал ДАТАВРЕМЯ: как записать дату прямо в тексте запроса

Язык запросов 1С не понимает строки вида "15.01.2026" и не принимает форматы вроде 2026-01-15. Единственный способ зашить дату в текст запроса — литерал ДАТАВРЕМЯ с числовыми аргументами: год, месяц, день и опционально часы, минуты, секунды.

ГДЕ

Продажи.Дата >= ДАТАВРЕМЯ(2026, 1, 15, 0, 0, 0)

Если время не указано, подразумевается начало дня — 00:00:00. Поэтому условие Дата = ДАТАВРЕМЯ(2026, 1, 15) найдёт только документы, проведённые ровно в полночь, а не все документы за 15 января. Это самая частая причина «пустого» запроса у начинающих разработчиков.

Для обозначения пустой даты (значение по умолчанию для реквизитов типа «Дата») используется литерал ДАТАВРЕМЯ(1, 1, 1) — первое января первого года. Сравнение с ним позволяет отобрать записи, где дата не заполнена.

Передача даты через параметр запроса

Литералы подходят только для отладки в консоли запросов. В реальном коде дату вычисляют на встроенном языке и передают параметром — так запрос не нужно пересобирать строкой, а тип данных контролируется платформой.

Запрос = Новый Запрос;

Запрос.Текст =

"ВЫБРАТЬ

| Реализация.Ссылка

|ИЗ

| Документ.РеализацияТоваровУслуг КАК Реализация

|ГДЕ

| Реализация.Дата МЕЖДУ &НачалоПериода И &КонецПериода";

Запрос.УстановитьПараметр("НачалоПериода", НачалоДня(ДатаНачала));

Запрос.УстановитьПараметр("КонецПериода", КонецДня(ДатаОкончания));

Ключевой момент — функции НачалоДня() и КонецДня(). Поле Дата документа хранит время с точностью до секунды, поэтому условие «МЕЖДУ» с полуночными границами отсечёт все документы последнего дня, кроме проведённых ровно в 00:00:00. КонецДня() возвращает 23:59:59, и диапазон становится полным.

Параметры проверяйте на заполненность до выполнения запроса. Если пользователь не указал дату, в параметр уйдёт пустое значение, и сравнение даст либо пустой результат, либо неочевидное поведение при сравнении с NULL в виртуальных таблицах.

Порядок действий
  1. 1
    Определите, нужна ли конкретная дата или диапазон
  2. 2
    Для диапазона вычислите границы: НачалоДня() и КонецДня()
  3. 3
    Передайте значения через УстановитьПараметр
  4. 4
    Выполните запрос и проверьте, что попали документы первого и последнего дня
  5. 5
    Для регистров накопления дополнительно проверьте границу через объект Граница

Дата и время в документах: почему сравнение «на равенство» не работает

Реквизит Дата у документа — это момент времени, а не календарный день. Два документа «за сегодня» имеют разные значения даты, если проведены в 09:15 и 18:40. Поэтому условие Документ.Дата = &Дата почти никогда не даёт ожидаемого результата, если в параметр передана дата без точного времени.

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

ГДЕ

Документ.Дата >= &НачалоДня

И Документ.Дата <= &КонецДня

Альтернатива — функция языка запросов НАЧАЛОПЕРИОДА: условие НАЧАЛОПЕРИОДА(Документ.Дата, ДЕНЬ) = &Дата приведёт дату каждой строки к началу дня и сравнит с параметром. Это работает, но заставляет запрос вычислять функцию для каждой записи и мешает использованию индексов, поэтому на больших таблицах диапазон предпочтительнее.

Типичные ошибки
01
Сравнение Дата = &Дата без учёта времени — запрос находит только документы в 00:00:00 или не находит ничего
02
КонецПериода = НачалоДня(ДатаОкончания) — теряются все документы последнего дня диапазона, кроме полуночных
03
Дата строкой в тексте запроса — ошибка синтаксиса или неявное приведение типов
04
Передача незаполненной даты в параметр без проверки — пустой результат, который принимают за отсутствие данных

Функции НАЧАЛОПЕРИОДА и КОНЕЦПЕРИОДА в тексте запроса

Когда границу нужно вычислить внутри самого запроса, используются встроенные функции НАЧАЛОПЕРИОДА(Дата, Период) и КОНЕЦПЕРИОДА(Дата, Период). Второй аргумент — ключевое слово: СЕКУНДА, МИНУТА, ЧАС, ДЕНЬ, НЕДЕЛЯ, МЕСЯЦ, КВАРТАЛ, ГОД.

ГДЕ

Продажи.Период МЕЖДУ НАЧАЛОПЕРИОДА(&Дата, МЕСЯЦ)

И КОНЕЦПЕРИОДА(&Дата, МЕСЯЦ)

Такой приём удобен, когда пользователь указывает произвольную дату, а отчёт должен показать весь месяц или квартал, в который она попадает. Обратите внимание: КОНЕЦПЕРИОДА возвращает последнюю секунду периода (23:59:59), что корректно для сравнений, но для виртуальных таблиц регистров накопления границу лучше задавать через объект Граница — об этом ниже.

Для сдвига даты внутри запроса есть функция ДОБАВИТЬКДАТЕ(Дата, ТипПериода, Количество). Например, ДОБАВИТЬКДАТЕ(&Дата, ДЕНЬ, -7) вернёт дату неделей ранее. Это позволяет строить скользящие периоды без вычислений на встроенном языке.

Границы и моменты времени в регистрах

Виртуальные таблицы регистров накопления и сведений (Остатки, Обороты) принимают параметры периода, и здесь есть тонкость: параметр «конец периода» воспринимается как момент времени, и документ, проведённый в ту же секунду, может попасть или не попасть в выборку в зависимости от позиции внутри секунды.

Для точного управления границей на встроенном языке создают объект Граница:

ГраницаКонца = Новый Граница(КонецДня(ДатаОкончания), ВидГраницы.Включая);

Запрос.УстановитьПараметр("КонецПериода", ГраницаКонца);

Вид границы «Включая» гарантирует, что движения, сделанные ровно на граничном моменте, войдут в результат. Если передать просто дату, платформа трактует её как границу «исключая» для итогов на момент времени в некоторых сценариях, что даёт расхождения в копейках и остатках, которые трудно отладить.

Проверка на пустую дату и сравнение с NULL

Незаполненный реквизит типа «Дата» хранит значение ДАТАВРЕМЯ(1, 1, 1), а не NULL. Поэтому проверка на пустоту выглядит так:

ГДЕ

Заказ.ДатаОтгрузки = ДАТАВРЕМЯ(1, 1, 1)

NULL появляется только при соединениях таблиц, когда в присоединяемой таблице нет подходящей строки. Там проверка делается через ЕСТЬ NULL или функцию ЕСТЬNULL(Поле, ДАТАВРЕМЯ(1,1,1)). Смешивание этих двух случаев — частая причина логических ошибок: разработчик проверяет поле левого соединения на пустую дату, а оно на самом деле NULL, и условие молча не срабатывает.

Контрольные точки

Как проверить результат

Документы первого и последнего дня периода
Норма

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

Тревожный признак

Документы последнего дня отсутствуют — конец периода задан без КонецДня()

Пустые даты в реквизитах
Норма

Отбираются сравнением с ДАТАВРЕМЯ(1, 1, 1)

Тревожный признак

Условие ЕСТЬ NULL не находит записи — значение пустое, а не NULL

Остатки на конец периода
Норма

Совпадают со стандартным отчётом

Тревожный признак

Расхождение — граница передана без вида «Включая»

Частые ошибки и как их избежать

Первая группа ошибок — формат. Дата строкой, дата в формате с дефисами, ведущие нули с кавычками — всё это либо синтаксическая ошибка, либо неявное приведение типов, которое портит сравнение. Правило простое: в тексте запроса — только литерал ДАТАВРЕМЯ, из кода — только параметр типа «Дата».

Вторая группа — время. Любое сравнение дат документов должно учитывать, что дата содержит время. Диапазоны строятся через НачалоДня/КонецДня или функции периодов, сравнение на равенство с календарной датой не используется.

Третья группа — производительность. Функции НАЧАЛОПЕРИОДА и КОНЕЦПЕРИОДА вокруг поля таблицы отключают использование индекса по этому полю. На больших таблицах вычисляйте границы один раз в параметрах и сравнивайте поле напрямую.

Итог

Что важно запомнить

В тексте запроса дата — это литерал ДАТАВРЕМЯ(год, месяц, день, часы, минуты, секунды). В коде даты передают параметрами с границами НачалоДня и КонецДня. Пустая дата — ДАТАВРЕМЯ(1, 1, 1), а для регистров конец периода задают объектом Граница с видом «Включая».

Частые вопросы

Как указать текущую дату в запросе 1С?

В языке запросов нет аналога функции «сейчас». Текущую дату получают на встроенном языке через ТекущаяДатаСеанса() и передают в запрос параметром. Использовать ТекущаяДата() на сервере не рекомендуется — она возвращает время клиентского компьютера и может расходиться с серверным.

Как отобрать документы за один конкретный день?

Передайте два параметра: НачалоДня(Дата) и КонецДня(Дата), и используйте условие «Дата МЕЖДУ &Начало И &Конец». Сравнение на равенство не подойдёт, потому что дата документа содержит время проведения.

Чем ДАТАВРЕМЯ(1, 1, 1) отличается от NULL?

ДАТАВРЕМЯ(1, 1, 1) — это пустое значение типа «Дата», которое хранится в незаполненном реквизите. NULL появляется только при соединениях таблиц, когда запись не найдена. Проверки для них разные: сравнение с литералом в первом случае и ЕСТЬ NULL во втором.

Можно ли написать дату в запросе строкой вида "2026-01-15"?

Нет. Язык запросов не преобразует строку в дату автоматически в условиях сравнения. Используйте литерал ДАТАВРЕМЯ(2026, 1, 15) или передайте дату параметром. Если строка приходит извне, сначала преобразуйте её в тип «Дата» на встроенном языке.

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

Функцией НАЧАЛОПЕРИОДА(&Дата, МЕСЯЦ). Аналогично работают КОНЕЦПЕРИОДА для конца периода и ДОБАВИТЬКДАТЕ для сдвига на заданное число дней, месяцев или лет. Учитывайте, что применение этих функций к полю таблицы в условии ГДЕ замедляет запрос на больших объёмах.

Почему итоги по регистру на дату не совпадают со стандартным отчётом?

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