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

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

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

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

В языке запросов 1С значение типа «Дата» всегда содержит и дату, и время с точностью до секунды. Когда документ проведён в 14:35:27, в поле даты хранится именно это значение, а не просто календарный день. Из-за этого сравнение Дата = &Дата часто не находит ни одной записи: переданный параметр содержит время 00:00:00, а реальные даты документов — нет.

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

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

Функция НАЧАЛОПЕРИОДА: синтаксис и поведение

Функция имеет два аргумента: выражение типа «Дата» и тип периода. Вызов НАЧАЛОПЕРИОДА(Документ.Дата, ДЕНЬ) возвращает ту же календарную дату, но с временем 00:00:00. Именно это и понимается под «датой без времени» в запросе: отдельного типа «дата без времени» в языке запросов нет, время всегда присутствует, но обнуляется.

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

Пример простого запроса, выводящего дату документа без времени:

ВЫБРАТЬ

НАЧАЛОПЕРИОДА(РеализацияТоваровУслуг.Дата, ДЕНЬ) КАК ДатаДень,

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

ИЗ

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

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

Сравнение даты без времени с параметром

Самая частая задача — отобрать документы за конкретный день, когда в параметр передана дата без времени. Прямое сравнение Дата = &Дата не сработает, если у документов время отлично от 00:00:00. Правильный вариант — привести к началу дня обе стороны сравнения:

ВЫБРАТЬ

Реализация.Ссылка КАК Документ

ИЗ

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

ГДЕ

НАЧАЛОПЕРИОДА(Реализация.Дата, ДЕНЬ) = НАЧАЛОПЕРИОДА(&Дата, ДЕНЬ)

Приведение параметра к началу дня делает условие устойчивым независимо от того, передали в параметр дату с временем или без. Если вы точно контролируете, что параметр всегда приходит с нулевым временем, правую часть можно упростить до = &Дата, но приведение обеих сторон — более безопасная практика.

У этого подхода есть ограничение по производительности: функция, применённая к полю таблицы в условии ГДЕ, как правило, не позволяет использовать индекс по полю даты. На больших таблицах предпочтительнее отбор по диапазону, описанный в следующем разделе.

Отбор за день через диапазон: НАЧАЛОПЕРИОДА и КОНЕЦПЕРИОДА

Альтернатива сравнению приведённых дат — условие «поле между началом и концом дня». Здесь функция применяется только к параметрам, а поле таблицы остаётся «чистым», что сохраняет возможность индексного поиска:

ВЫБРАТЬ

Реализация.Ссылка КАК Документ

ИЗ

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

ГДЕ

Реализация.Дата МЕЖДУ НАЧАЛОПЕРИОДА(&Дата, ДЕНЬ) И КОНЕЦПЕРИОДА(&Дата, ДЕНЬ)

Функция КОНЕЦПЕРИОДА(&Дата, ДЕНЬ) возвращает последнюю секунду дня — 23:59:59. Конструкция МЕЖДУ включает обе границы, поэтому попадают все документы от 00:00:00 до 23:59:59 включительно.

Тот же приём работает для произвольных периодов: передайте два параметра и используйте МЕЖДУ НАЧАЛОПЕРИОДА(&ДатаНачала, ДЕНЬ) И КОНЕЦПЕРИОДА(&ДатаОкончания, ДЕНЬ). Так вы гарантированно захватите первый и последний дни диапазона целиком, даже если пользователь указал границы с ненулевым временем.

Два способа отбора за день

НАЧАЛОПЕРИОДА(Поле, ДЕНЬ) = &Дата

Проще читается, удобно в небольших таблицах и виртуальных соединениях, но обычно блокирует использование индекса по дате.

Поле МЕЖДУ НАЧАЛОПЕРИОДА и КОНЕЦПЕРИОДА

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

Группировка и итоги по дням

Когда нужно свернуть данные по календарным дням — например, суммы продаж по дням месяца — поле с приведённой датой помещается в группировку:

ВЫБРАТЬ

НАЧАЛОПЕРИОДА(Продажи.Период, ДЕНЬ) КАК День,

СУММА(Продажи.СуммаОборот) КАК Сумма

ИЗ

РегистрНакопления.Продажи.Обороты КАК Продажи

СГРУППИРОВАТЬ ПО

НАЧАЛОПЕРИОДА(Продажи.Период, ДЕНЬ)

УПОРЯДОЧИТЬ ПО

День

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

Если результат запроса выводится в отчёт на СКД, группировку по дням можно задать и настройками отчёта, но явная группировка в тексте запроса делает поведение предсказуемым независимо от пользовательских настроек.

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

Проверка результата и типичные ошибки

Быстрый способ проверить, что время действительно обнулено, — выполнить запрос в консоли запросов и посмотреть значение вычисляемого поля. Для даты без времени оно должно отображаться как «дд.мм.гггг 0:00:00». Если время осталось — функция не применена к тому полю или применена к копии значения, а в сравнении используется исходное.

Ещё один контроль — сравнить количество строк до и после группировки: если после группировки по НАЧАЛОПЕРИОДА(..., ДЕНЬ) число строк не уменьшилось на данных, где точно есть несколько документов в день, значит группируется не то выражение.

Типичные ошибки
01
Сравнение Дата = &Дата без приведения: документы с ненулевым временем не попадают в выборку, результат пустой или неполный
02
Использование КОНЕЦПЕРИОДА вместо НАЧАЛОПЕРИОДА при группировке: записи одного дня разваливаются, итоги дробятся
03
Приведение только поля таблицы, но не параметра: если в параметр передали дату с временем, равенство снова не выполняется
04
Ожидание, что НАЧАЛОПЕРИОДА меняет тип значения: тип остаётся «Дата», меняется только время — на 00:00:00
05
Применение функции к полю в условии на большой таблице без необходимости: запрос замедляется из-за отказа от индекса

Отдельная ловушка — границы периода в отчётах. Если пользователь задаёт окончание периода датой без времени (00:00:00), весь последний день кроме полуночи выпадает из выборки. Решение — оборачивать параметр окончания в КОНЕЦПЕРИОДА(&ДатаОкончания, ДЕНЬ) или приводить границы программно перед передачей в запрос.

Альтернативы вне языка запросов

Если дата обрабатывается в коде встроенного языка до передачи в запрос, там есть свои средства: функция НачалоДня(Дата) и КонецДня(Дата) возвращают те же границы. Часто проще подготовить параметры в коде и передать в запрос уже готовые значения, чем применять функции внутри текста запроса.

В СКД для отображения даты без времени также доступны периоды-выражения и форматная строка поля: например, задать полю формат «ДФ=dd.MM.yyyy», чтобы время не выводилось. Но это влияет только на представление, а не на сравнение и группировку — логику отбора всё равно нужно строить через НАЧАЛОПЕРИОДА или диапазон.

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

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

Значение поля после НАЧАЛОПЕРИОДА(..., ДЕНЬ)
Норма

Отображается как дата с временем 0:00:00

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

Время отлично от нуля — функция применена не к тому полю

Отбор документов за конкретный день
Норма

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

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

Видны только документы с временем 00:00:00 или выборка пуста

Группировка по дням
Норма

Один календарный день — одна строка результата

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

Несколько строк на один день

Последний день периода в отчёте
Норма

Данные последнего дня включены целиком

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

Последний день пустой или усечён

Итог

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

Дата без времени в запросе 1С — это НАЧАЛОПЕРИОДА(Дата, ДЕНЬ), то есть дата с временем 00:00:00. Для сравнения приводите обе стороны условия, для отбора на больших таблицах используйте диапазон МЕЖДУ НАЧАЛОПЕРИОДА и КОНЕЦПЕРИОДА, а границы периодов в отчётах всегда расширяйте до конца дня.

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

Можно ли получить в запросе значение типа «дата» совсем без компонента времени?

Нет. Тип «Дата» в 1С всегда включает время с точностью до секунды. «Дата без времени» на практике означает дату с временем 00:00:00, которую даёт НАЧАЛОПЕРИОДА(Дата, ДЕНЬ). Отображение без времени — задача форматной строки, а не типа данных.

Чем НАЧАЛОПЕРИОДА отличается от КОНЕЦПЕРИОДА?

НАЧАЛОПЕРИОДА возвращает первый момент периода (для дня — 00:00:00), КОНЕЦПЕРИОДА — последний (для дня — 23:59:59). Для отбрасывания времени нужна первая, вторая используется для правильной верхней границы диапазона.

Почему условие Дата = &Дата не находит документы?

Потому что у документов время обычно отлично от 00:00:00, а в параметр чаще всего передаётся дата с нулевым временем. Равенство дат-времени точное, поэтому записи не совпадают. Приведите обе стороны к началу дня или используйте диапазон.

Что быстрее: НАЧАЛОПЕРИОДА в условии или диапазон МЕЖДУ?

На больших таблицах быстрее диапазон: поле остаётся без функции, и СУБД может использовать индекс по дате. Функция над полем в условии обычно приводит к полному сканированию. На малых выборках разница незаметна.

Как отобрать записи за текущий день?

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

Работает ли НАЧАЛОПЕРИОДА с периодами крупнее дня?

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