Разработка и Конфигурация · 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Добавьте в выборку поле НАЧАЛОПЕРИОДА(Период, ДЕНЬ) с понятным псевдонимом, например День
- 2Перечислите это же выражение в секции СГРУППИРОВАТЬ ПО
- 3Добавьте агрегатные функции для числовых показателей (СУММА, КОЛИЧЕСТВО)
- 4Отсортируйте результат по полю День для хронологического порядка
- 5Выполните запрос в консоли запросов и убедитесь, что записи одного дня объединены в одну строку
Проверка результата и типичные ошибки
Быстрый способ проверить, что время действительно обнулено, — выполнить запрос в консоли запросов и посмотреть значение вычисляемого поля. Для даты без времени оно должно отображаться как «дд.мм.гггг 0:00:00». Если время осталось — функция не применена к тому полю или применена к копии значения, а в сравнении используется исходное.
Ещё один контроль — сравнить количество строк до и после группировки: если после группировки по НАЧАЛОПЕРИОДА(..., ДЕНЬ) число строк не уменьшилось на данных, где точно есть несколько документов в день, значит группируется не то выражение.
Отдельная ловушка — границы периода в отчётах. Если пользователь задаёт окончание периода датой без времени (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, а в параметр чаще всего передаётся дата с нулевым временем. Равенство дат-времени точное, поэтому записи не совпадают. Приведите обе стороны к началу дня или используйте диапазон.
Что быстрее: НАЧАЛОПЕРИОДА в условии или диапазон МЕЖДУ?
На больших таблицах быстрее диапазон: поле остаётся без функции, и СУБД может использовать индекс по дате. Функция над полем в условии обычно приводит к полному сканированию. На малых выборках разница незаметна.
Как отобрать записи за текущий день?
Передайте в параметр текущую дату сеанса из кода (ТекущаяДатаСеанса()) и используйте условие НАЧАЛОПЕРИОДА(Поле, ДЕНЬ) = НАЧАЛОПЕРИОДА(&ТекущаяДата, ДЕНЬ) либо диапазон от начала до конца этого дня. Само значение текущей даты в тексте запроса не вычисляется — его нужно передать параметром.
Работает ли НАЧАЛОПЕРИОДА с периодами крупнее дня?
Да. Поддерживаются МИНУТА, ЧАС, ДЕНЬ, НЕДЕЛЯ, МЕСЯЦ, КВАРТАЛ, ГОД, ДЕКАДА, ПОЛУГОДИЕ. Например, НАЧАЛОПЕРИОДА(Дата, МЕСЯЦ) возвращает первое число месяца с нулевым временем — это удобно для помесячных итогов.