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