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

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

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

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

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

Основной приём — привести значение к началу дня, то есть к полуночи соответствующей даты. После такого приведения все записи внутри одного дня получают одинаковое значение, и их можно сравнивать, группировать и объединять без учёта часов, минут и секунд. Это стандартный и самый быстрый способ, поддерживаемый всеми СУБД, с которыми работает платформа 1С.

Важно понимать: отсечение времени в запросе меняет только значение для сравнения или группировки, но не тип данных. Результат по-прежнему имеет тип «Дата», просто с нулевым временем. Если же нужно вывести дату пользователю в привычном виде «дд.мм.гггг», дополнительно применяют форматирование — уже на уровне компоновки или встроенного языка.

Функция НАЧАЛОПЕРИОДА — основной способ отсечь время

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

ВЫБРАТЬ

НАЧАЛОПЕРИОДА(РеализацияТоваров.Дата, ДЕНЬ) КАК ДатаБезВремени,

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

ИЗ

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

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

Обратная функция — КОНЕЦПЕРИОДА(Дата, ДЕНЬ) — возвращает 23:59:59 того же дня. Пара НАЧАЛОПЕРИОДА/КОНЕЦПЕРИОДА часто используется для построения диапазона «весь день целиком», когда нельзя полагаться на точное равенство.

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

Типичная задача — выбрать документы за конкретный день, когда параметр приходит как дата без времени, а в базе у документов дата содержит часы и минуты. Прямое сравнение «Дата = &Дата» не сработает: полночь параметра не равна, например, 14:32:10 у документа.

Первый корректный вариант — привести поле к началу дня и сравнить с параметром:

ВЫБРАТЬ

Заказ.Ссылка КАК Заказ

ИЗ

Документ.ЗаказКлиента КАК Заказ

ГДЕ

НАЧАЛОПЕРИОДА(Заказ.Дата, ДЕНЬ) = &Дата

Второй вариант — задать диапазон от начала до конца дня. Он предпочтительнее с точки зрения производительности, потому что позволяет СУБД использовать индекс по полю даты, тогда как вызов функции над полем в условии часто отключает индексный поиск:

ГДЕ

Заказ.Дата МЕЖДУ НАЧАЛОПЕРИОДА(&Дата, ДЕНЬ) И КОНЕЦПЕРИОДА(&Дата, ДЕНЬ)

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

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

ВЫБРАТЬ

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

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

ИЗ

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

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

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

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

День

В регистрах накопления и сведений для периодичности по дням есть альтернатива — виртуальные таблицы оборотов с параметром периодичности «День». Там платформа сама агрегирует данные по датам, и писать НАЧАЛОПЕРИОДА вручную не требуется. Но при работе с таблицами документов или при соединении нескольких источников ручное приведение остаётся основным инструментом.

Порядок действий
  1. 1
    Определите, какое поле содержит дату со временем и какая операция нужна: фильтрация, группировка или вывод
  2. 2
    Оберните поле в НАЧАЛОПЕРИОДА(Поле, ДЕНЬ) и дайте выражению понятный псевдоним
  3. 3
    Для фильтрации по одному дню используйте либо сравнение приведённого значения с параметром, либо диапазон от начала до конца дня
  4. 4
    Выполните запрос в консоли запросов и проверьте, что время в результате равно 0:00:00 и строки за день сгруппированы вместе

Получение текущей даты без времени и работа с параметрами

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

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

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

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

bsl
Запрос = Новый Запрос("ВЫБРАТЬ НАЧАЛОПЕРИОДА(Т.Дата, ДЕНЬ) КАК День ИЗ Документ.ПриходнаяНакладная КАК Т"); Запрос.УстановитьПараметр("Сегодня", НачалоДня(ТекущаяДатаСеанса()));

Вывод даты без времени пользователю: форматирование

НАЧАЛОПЕРИОДА убирает время из значения, но при выводе в табличный документ или поле формы дата всё равно может отображаться с «0:00:00», если формат поля не задан. За отображение отвечает не запрос, а форматная строка.

В схеме компоновки данных для поля задают формат в настройках: например, «ДФ=dd.MM.yyyy». Во встроенном языке используют Формат(Значение, "ДЛФ=D") — короткий формат даты без времени. В запросе с конструкцией ВЫРАЗИТЬ можно привести значение к типу «Дата» с указанием состава даты, но на практике чаще достаточно форматирования на этапе вывода.

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

Сравнение вариантов

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

Универсально для группировки и сравнения; при фильтрации по полю может отключать индекс на больших таблицах

Диапазон МЕЖДУ НАЧАЛОПЕРИОДА и КОНЕЦПЕРИОДА

Лучший выбор для отбора документов за день: сохраняет использование индекса по дате

Виртуальные таблицы оборотов с периодичностью День

Подходит для регистров накопления: платформа агрегирует по дням сама, но неприменимо к таблицам документов

Форматирование при выводе

Решает только задачу отображения без времени; значение в данных остаётся с временем

Типичные ошибки и ограничения

Самая частая ошибка — сравнение поля даты напрямую с параметром, в котором лежит начало дня. Запрос отрабатывает без ошибки, но возвращает пустой результат, потому что ни один документ не проведён ровно в полночь. Признак проблемы: запрос «не видит» заведомо существующие документы.

Вторая ошибка — использование КОНЕЦПЕРИОДА с границей вида «меньше или равно» при работе с моментами времени документов. У документа есть не только дата, но и ссылка в составе момента времени, поэтому для строгих границ в выборках по позиции документа применяют объект Граница во встроенном языке, а не просто конец дня.

Третья группа ошибок связана с часовыми поясами. ТекущаяДатаСеанса() возвращает время сеанса сервера, которое может отличаться от локального времени пользователя в другом поясе. Если «сегодня» для пользователя и для сервера различаются, отбор по дню даст неожиданные результаты — это нужно учитывать в распределённых системах.

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

Проверка результата

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

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

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

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

Время в приведённом поле
Норма

У всех строк одного дня время 0:00:00

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

Время отличается — НАЧАЛОПЕРИОДА применена не к тому полю

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

Возвращаются все документы дня независимо от времени

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

Пустой результат или часть документов пропущена

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

Одна строка итогов на каждый день

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

Множество строк внутри дня — группировка идёт по дате со временем

Отображение в отчёте
Норма

Дата выводится в заданном формате

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

Отображается '0:00:00' — не настроен формат поля

Итог

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

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

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

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

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

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

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

Что быстрее: функция над полем или диапазон дат?

На больших таблицах диапазон МЕЖДУ обычно быстрее, потому что СУБД может использовать индекс по полю даты. Функция НАЧАЛОПЕРИОДА над полем в условии часто приводит к полному сканированию. На небольших таблицах разница незаметна, и можно выбирать более читаемый вариант.

Как в запросе получить текущую дату без времени?

Напрямую вызвать ТекущаяДата() в тексте запроса нельзя. Передайте значение параметром: во встроенном языке выполните УстановитьПараметр("Сегодня", НачалоДня(ТекущаяДатаСеанса())), а в запросе используйте параметр &Сегодня.

Как убрать «0:00:00» в отчёте на СКД?

Откройте настройки отчёта, найдите нужное поле и задайте для него формат, например ДФ=dd.MM.yyyy, на закладке с пользовательскими полями или в настройках оформления. Менять текст запроса для этого не требуется — отображение времени решается форматом, а не данными.

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

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