Разработка и Конфигурация · 10 мин
Как получить начало дня в запросе 1С
Как получить начало дня в запросе 1С через НАЧАЛОПЕРИОДА, отбор документов за день, работа с границами периода, типовые ошибки и проверка результата.
Получить начало дня в запросе 1С чаще всего требуется при отборе документов за конкретную дату, построении отчётов по дням и сравнении дат без учёта времени. В языке запросов для этого существует встроенная функция НАЧАЛОПЕРИОДА, которая приводит любую дату со временем к полуночи указанного дня — 00:00:00.
Задача возникает потому, что тип «Дата» в 1С всегда содержит время с точностью до секунды. Документ, проведённый в 14:35:12, не равен дате «01.03.0001 00:00:00», и прямое сравнение Дата = &Дата без приведения к началу дня даст ложный результат. Поэтому безопасный подход — либо приводить значение к началу периода функцией, либо сравнивать через интервал «начало дня — конец дня».
Ниже разобраны синтаксис функции, практические сценарии отбора за день, альтернативы через параметры-границы, работа в СКД, а также типичные ошибки и способы проверить корректность результата.
Функция НАЧАЛОПЕРИОДА: синтаксис и принцип работы
Функция имеет два параметра: дата (или выражение даты) и тип периода. Для начала дня вторым параметром указывается ключевое слово ДЕНЬ:
ВЫБРАТЬ
НАЧАЛОПЕРИОДА(&ДатаСоВременем, ДЕНЬ) КАК НачалоДня
Если передать в параметр &ДатаСоВременем значение 15.06.2026 18:42:07, функция вернёт 15.06.2026 00:00:00. Аналогично работают другие типы периода: НЕДЕЛЯ, МЕСЯЦ, КВАРТАЛ, ГОД — функция универсальна и применяется для любых периодических отборов.
Важно понимать: функция выполняется на сервере СУБД при каждом вызове. Если она применяется к полю таблицы в условии ГДЕ, индекс по полю даты использоваться не будет, и на больших таблицах запрос может заметно замедлиться. Это ключевое ограничение, которое определяет выбор между двумя основными приёмами.
Отбор документов за один день
Самый частый сценарий — выбрать все документы, проведённые в течение конкретной даты, независимо от времени. Первый способ — приведение поля даты к началу дня и сравнение с параметром:
ВЫБРАТЬ
РеализацияТоваровУслуг.Ссылка,
РеализацияТоваровУслуг.Дата
ИЗ
Документ.РеализацияТоваровУслуг КАК РеализацияТоваровУслуг
ГДЕ
НАЧАЛОПЕРИОДА(РеализацияТоваровУслуг.Дата, ДЕНЬ) = &НужнаяДата
Параметр &НужнаяДата при этом можно передавать с любым временем — функция сравнивает уже приведённое значение, но сам параметр тоже стоит передавать как начало дня для однозначности: НачалоДня(ТекущаяДатаСеанса()) в коде модуля.
Этот вариант прост и читаем, но не использует индекс по полю «Дата». На таблицах с сотнями тысяч документов выборка может выполняться полным сканированием.
Производительный вариант через интервал
Более быстрый приём — сравнивать само поле даты с двумя параметрами-границами, вычисленными заранее в коде:
Запрос.УстановитьПараметр("НачалоДня", НачалоДня(ДатаОтбора));
Запрос.УстановитьПараметр("КонецДня", КонецДня(ДатаОтбора));
ГДЕ
РеализацияТоваровУслуг.Дата МЕЖДУ &НачалоДня И &КонецДня
Здесь функции НачалоДня() и КонецДня() — это методы встроенного языка (не языка запросов), они вычисляются один раз до выполнения запроса. СУБД использует индекс по полю «Дата», и выборка выполняется быстро даже на больших объёмах.
Два способа отбора за день
Короткая запись, параметр один. Минус: не используется индекс по дате, на больших таблицах медленнее.
Два параметра вычисляются в коде. Индекс работает, запрос быстрый. Рекомендуется для больших таблиц.
Начало дня для текущей даты и динамических отборов
Когда начало дня нужно не для параметра, а для «сегодня», в языке запросов доступна функция &ТекущаяДата через параметр либо конструкция с ТекущаяДатаСеанса() в коде. Прямой функции «текущая дата» в языке запросов нет — значение передаётся параметром:
Запрос.УстановитьПараметр("НачалоТекущегоДня", НачалоДня(ТекущаяДатаСеанса()));
Использовать ТекущаяДата() в серверном коде не рекомендуется: она возвращает время клиентского компьютера, которое может отличаться от серверного. ТекущаяДатаСеанса() гарантирует единое серверное время и корректную работу в распределённых системах с разными часовыми поясами.
Если отчёт строится за «последние N дней», начало периода вычисляют арифметикой дат: НачалоДня(ТекущаяДатаСеанса()) - (N - 1) * 86400, где 86400 — число секунд в сутках. В самом языке запросов для сдвига дат есть функция ДОБАВИТЬКДАТЕ(&Дата, ДЕНЬ, -7).
Начало дня в СКД и динамических списках
В системе компоновки данных функция НАЧАЛОПЕРИОДА используется так же, но параметры периода обычно оформляются как стандартный период. Типовой приём — выражение в параметрах виртуальной таблицы или в отборе:
ГДЕ
Продажи.Период МЕЖДУ &НачалоПериода И &КонецПериода
Для группировки данных по дням в отчёте поле периода приводят к началу дня, чтобы все записи внутри суток попали в одну группу:
ВЫБРАТЬ
НАЧАЛОПЕРИОДА(ПродажиОбороты.Период, ДЕНЬ) КАК День,
СУММА(ПродажиОбороты.СуммаОборот) КАК Сумма
ИЗ
РегистрНакопления.Продажи.Обороты(, , День, ) КАК ПродажиОбороты
СГРУППИРОВАТЬ ПО
НАЧАЛОПЕРИОДА(ПродажиОбороты.Период, ДЕНЬ)
Заметим, что у виртуальных таблиц оборотов периодичность «День» уже возвращает дату в начале дня, поэтому дополнительное приведение там избыточно — оно нужно при выборке из физических таблиц документов и регистров с произвольным временем.
Динамические списки
В динамическом списке произвольного запроса отбор «за сегодня» задаётся через параметр с выражением НачалоДня(ТекущаяДатаСеанса()) в обработчике ПриПолученииДанныхНаСервере или при создании формы. Задавать вычисляемое выражение прямо в тексте запроса списка нельзя — только через параметры.
- 1Определите, откуда берётся дата отбора: параметр, текущая дата сеанса или поле формы
- 2В коде вычислите границы: НачалоДня(Дата) и КонецДня(Дата)
- 3Передайте оба значения параметрами в запрос
- 4В тексте запроса используйте условие Дата МЕЖДУ &НачалоДня И &КонецДня
- 5Выполните запрос и проверьте, что попали документы с разным временем внутри дня
Частые ошибки и как их избежать
Первая ошибка — сравнение даты документа с параметром через равенство без приведения: Документ.Дата = &Дата. Поскольку у документа почти всегда есть время, а параметр передан как начало дня, условие не выполнится ни для одной записи. Запрос вернёт пустой результат без какой-либо ошибки, что затрудняет диагностику.
Вторая ошибка — использование КОНЕЦПЕРИОДА(&Дата, ДЕНЬ) там, где граница должна быть включительной. Функция возвращает 23:59:59, и документ с датой-временем, попадающей в последнюю секунду, обычно учитывается корректно, но при работе с границами моментов времени в регистрах поведение отличается. Для надёжности в отборах по документам используйте пару «начало дня — конец дня» через МЕЖДУ.
Третья ошибка — применение НАЧАЛОПЕРИОДА к полю в условии соединения таблиц или в ГДЕ на больших регистрах. Это отключает индексы и приводит к таймаутам. Выносите вычисление границ в параметры, а функцию применяйте только к параметрам и в секции ВЫБРАТЬ для группировок.
Проверка результата и отладка
Убедиться, что начало дня вычислено правильно, проще всего через консоль запросов: выполните запрос ВЫБРАТЬ НАЧАЛОПЕРИОДА(&Дата, ДЕНЬ) с тестовым параметром и проверьте, что результат — 00:00:00 нужной даты. Затем выполните основной запрос и сверьте, что в выборку попали документы с временем 00:05, 12:30 и 23:50 одного дня.
Дополнительная проверка — сравнить количество записей при отборе через НАЧАЛОПЕРИОДА и через интервал МЕЖДУ. Результаты должны совпадать. Если через интервал записей больше, где-то в данных встречаются даты за пределами ожидаемого диапазона или проблема в часовых поясах при загрузке данных из внешних систем.
При работе с сеансовыми датами в распределённых базах проверьте настройку часового пояса информационной базы: документ, введённый в другом поясе, может попасть «не в тот» день относительно серверного времени.
Как проверить результат
Возвращается 00:00:00 нужной даты
Время отлично от полуночи или дата смещена
Есть документы с любым временем внутри суток
Попадают только документы с 00:00:00 или выборка пуста
Запрос с МЕЖДУ выполняется быстро
Долгое выполнение — функция применена к полю в ГДЕ
FAQ
Чем НАЧАЛОПЕРИОДА отличается от функции НачалоДня() в коде?
НАЧАЛОПЕРИОДА — функция языка запросов, выполняется внутри запроса на СУБД. НачалоДня() — метод встроенного языка, вычисляется в коде до выполнения запроса, и результат передаётся параметром. Оба дают 00:00:00, но параметр позволяет использовать индексы.
Можно ли получить начало дня без функции, вычитанием времени?
Технически можно комбинацией ДОБАВИТЬКДАТЕ и извлечения частей даты, но это громоздко и нечитаемо. НАЧАЛОПЕРИОДА — штатный и самый понятный способ, альтернативы оправданы только в экзотических сценариях.
Почему запрос с НАЧАЛОПЕРИОДА(Дата, ДЕНЬ) = &Дата работает медленно?
Функция применена к полю таблицы, поэтому СУБД не может использовать индекс по дате и сканирует всю таблицу. Перепишите условие как Дата МЕЖДУ &НачалоДня И &КонецДня, вычислив параметры в коде.
Как получить начало дня для даты в произвольном часовом поясе?
Язык запросов работает с датами как с абсолютными значениями без учёта поясов. Если данные приходят из разных поясов, приводите их к единому поясу базы в коде перед передачей параметром, иначе границы дня будут смещены.
Что вернёт НАЧАЛОПЕРИОДА для пустой даты?
Для пустой даты (01.01.0001 00:00:00) функция вернёт ту же пустую дату. Если поле может быть пустым, добавьте проверку, иначе такие записи попадут в группу с минимальной датой при группировке.
Как сгруппировать обороты регистра по дням?
Используйте виртуальную таблицу оборотов с периодичностью «День» — поле Период уже будет в начале дня. Если данные берутся из физической таблицы, группируйте по НАЧАЛОПЕРИОДА(Период, ДЕНЬ).
Что важно запомнить
Начало дня в запросе 1С — это НАЧАЛОПЕРИОДА(&Дата, ДЕНЬ), результат 00:00:00. Для отборов на больших таблицах вычисляйте НачалоДня() и КонецДня() в коде и сравнивайте поле даты через МЕЖДУ — так работает индекс. Текущую дату передавайте параметром через ТекущаяДатаСеанса().