Пустая дата и периоды в запросе 1С 8.3: ДАТАВРЕМЯ, МЕЖДУ, КОНЕЦПЕРИОДА и РАЗНОСТЬДАТ
Пустая дата в запросе 1С 8.3 хранится как '00010101' (01.01.0001 00:00:00), а не как NULL. Проверить реквизит на пустую дату в секции ГДЕ можно прямо в тексте запроса через литерал ПолеДаты = ДАТАВРЕМЯ(1, 1, 1) либо через параметр &ПустаяДата со значением Дата(1, 1, 1). Если поле получено из таблицы после ЛЕВОЕ СОЕДИНЕНИЕ, оборачивайте его в ЕСТЬNULL(Таб.ДатаОплаты, ДАТАВРЕМЯ(1, 1, 1)) = ДАТАВРЕМЯ(1, 1, 1).
Оператор МЕЖДУ &Начало И &Конец включает обе границы (>= и <=), но при передаче даты без времени (00:00:00) теряет все документы последнего дня. Чтобы захватить день целиком до 23:59:59, закрывайте верхнюю границу функцией КОНЕЦПЕРИОДА(&Конец, ДЕНЬ) в запросе или КонецДня() в коде 1С.
Пустая дата в запросе 1С 8.3: ДАТАВРЕМЯ(1, 1, 1) и параметр &ПустаяДата
В платформе 1С:Предприятие 8.3 реквизит с примитивным типом Дата в основной таблице никогда не бывает равен NULL. Незаполненная дата хранится в базе данных как начальная точка календаря — 1 января 0001 года 00 часов 00 минут 00 секунд (в литералах встроенного языка '00010101' или Дата(1, 1, 1)). Поэтому условие ПолеДаты ЕСТЬ NULL для обычного реквизита документа или справочника не вернёт ни одной строки.
В 1С проверка на пустую дату в запросе выполняется двумя способами: через встроенный литерал ДАТАВРЕМЯ(1, 1, 1) или через параметр запроса &ПустаяДата:
// Способ 1. Литерал ДАТАВРЕМЯ прямо в тексте запроса (удобно для СКД и динамических списков)
ВЫБРАТЬ
Счета.Ссылка КАК Счет,
Счета.Контрагент КАК Контрагент,
Счета.СуммаДокумента КАК Сумма
ИЗ
Документ.СчетНаОплатуПокупателю КАК Счета
ГДЕ
Счета.ДатаОплаты = ДАТАВРЕМЯ(1, 1, 1)
И Счета.СрокОплаты > ДАТАВРЕМЯ(1, 1, 1, 0, 0, 0)
// Способ 2. Передача параметра из встроенного языка 1С
// Запрос.УстановитьПараметр("ПустаяДата", Дата(1, 1, 1));
Записи ДАТАВРЕМЯ(1, 1, 1) и ДАТАВРЕМЯ(1, 1, 1, 0, 0, 0) полностью эквивалентны: если часы, минуты и секунды опущены, платформа автоматически подставляет нули. Литерал ДАТАВРЕМЯ(1, 1, 1) особенно удобен в схемах компоновки данных (СКД), произвольных запросах динамических списков и отборе Консоли запросов, где не хочется заводить лишний технический параметр.
Если запрос вызывается программно из модуля, можно использовать и параметр:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Договоры.Ссылка КАК Договор,
| Договоры.Наименование КАК Наименование
|ИЗ
| Справочник.ДоговорыКонтрагентов КАК Договоры
|ГДЕ
| Договоры.СрокДействия = &ПустаяДата";
Запрос.УстановитьПараметр("ПустаяДата", Дата(1, 1, 1));
Выборка = Запрос.Выполнить().Выбрать();
Обратная проверка «дата заполнена» записывается как ПолеДаты <> ДАТАВРЕМЯ(1, 1, 1) или ПолеДаты > ДАТАВРЕМЯ(1, 1, 1), поскольку любая реальная дата в учёте больше 01.01.0001.
Проверка пустой даты после ЛЕВОЕ СОЕДИНЕНИЕ через ЕСТЬNULL
Ситуация меняется, когда поле даты выбирается из правой таблицы после ЛЕВОЕ СОЕДИНЕНИЕ или из реквизита составного типа. В таком поле одновременно встречаются два разных «пустых» состояния:
- в присоединённой таблице нашлась запись, но реквизит даты в ней не заполнен — значение равно
ДАТАВРЕМЯ(1, 1, 1); - в присоединённой таблице нет подходящей строки — платформа возвращает
NULL.
Если написать просто Таб.ДатаОплаты = ДАТАВРЕМЯ(1, 1, 1), строки с NULL отсеются, так как сравнение NULL с любой датой даёт ложь. Чтобы одним условием отобрать и незаполненную дату, и отсутствие присоединённой строки, оберните поле в функцию ЕСТЬNULL:
ВЫБРАТЬ
Заказы.Ссылка КАК Заказ,
Заказы.СуммаДокумента КАК Сумма,
ЕСТЬNULL(Оплаты.ДатаОплаты, ДАТАВРЕМЯ(1, 1, 1)) КАК ДатаОплаты
ИЗ
Документ.ЗаказКлиента КАК Заказы
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ГрафикОплатыЗаказов КАК Оплаты
ПО Заказы.Ссылка = Оплаты.Заказ
ГДЕ
ЕСТЬNULL(Оплаты.ДатаОплаты, ДАТАВРЕМЯ(1, 1, 1)) = ДАТАВРЕМЯ(1, 1, 1)
Здесь ЕСТЬNULL(Оплаты.ДатаОплаты, ДАТАВРЕМЯ(1, 1, 1)) подменяет NULL на 01.01.0001 00:00:00, после чего оба случая проверяются единым сравнением с ДАТАВРЕМЯ(1, 1, 1). И наоборот, условие ЕСТЬNULL(Оплаты.ДатаОплаты, ДАТАВРЕМЯ(1, 1, 1)) <> ДАТАВРЕМЯ(1, 1, 1) оставит только те строки, где запись в правой таблице существует и дата в ней реально заполнена.
МЕЖДУ в запросе 1С: включает границы или нет и почему теряется последний день
Логический оператор Выражение МЕЖДУ Начало И Конец проверяет вхождение значения в диапазон и включает обе границы. В языке запросов 1С конструкция Документы.Дата МЕЖДУ &Начало И &Конец строго равнозначна паре нестрогих неравенств:
Документы.Дата >= &Начало И Документы.Дата <= &Конец
Несмотря на то что правая граница включена, именно на ней разработчики чаще всего теряют документы за последний день периода. Причина в том, что реквизит Дата у документов в 1С всегда хранит дату со временем (например, 31.10.2026 14:30:00), а реквизит формы отчёта с составом даты «Дата» или литерал Дата(2026, 10, 31) передаёт в параметр полночь начала этого дня — 31.10.2026 00:00:00.
В результате при проверке 31.10.2026 14:30:00 <= 31.10.2026 00:00:00 условие возвращает Ложь, и в выборку попадают только те редкие документы, которые записаны ровно в 00:00:00. Чтобы закрыть период концом дня (23:59:59) непосредственно в запросе, оберните верхнюю границу в функцию КОНЕЦПЕРИОДА(&Конец, ДЕНЬ):
ВЫБРАТЬ
Реализация.Ссылка КАК Документ,
Реализация.Дата КАК ДатаДокумента,
Реализация.СуммаДокумента КАК Сумма
ИЗ
Документ.РеализацияТоваровУслуг КАК Реализация
ГДЕ
Реализация.Проведен = ИСТИНА
И Реализация.Дата МЕЖДУ НАЧАЛОПЕРИОДА(&Начало, ДЕНЬ)
И КОНЕЦПЕРИОДА(&Конец, ДЕНЬ)
Если передавать готовые границы из кода на встроенном языке, то же самое делают функциями глобального контекста НачалоДня(ВыбраннаяДатаНачала) и КонецДня(ВыбраннаяДатаКонца) либо через объект СтандартныйПериод, у которого свойство ДатаОкончания уже приведено к 23:59:59.
23:59:59, сверит количество документов за последний день и покажет результат без запуска Конфигуратора.
Функции НАЧАЛОПЕРИОДА и КОНЕЦПЕРИОДА в запросе 1С 8.3
Функции языка запросов НАЧАЛОПЕРИОДА(Дата, ТипПериода) и КОНЕЦПЕРИОДА(Дата, ТипПериода) приводят переданную дату к первой (00:00:00) или последней (23:59:59) секунде выбранного календарного интервала. Они работают как с параметрами (&ДатаОтчета), так и с полями таблиц при группировке оборотов по месяцам, неделям или кварталам:
ВЫБРАТЬ
НАЧАЛОПЕРИОДА(Продажи.Период, МЕСЯЦ) КАК МесяцПродажи,
КОНЕЦПЕРИОДА(Продажи.Период, КВАРТАЛ) КАК КонецКвартала,
СУММА(Продажи.СуммаОборот) КАК Выручка
ИЗ
РегистрНакопления.Продажи.Обороты(&Начало, КОНЕЦПЕРИОДА(&Конец, ДЕНЬ), Регистратор) КАК Продажи
СГРУППИРОВАТЬ ПО
НАЧАЛОПЕРИОДА(Продажи.Период, МЕСЯЦ),
КОНЕЦПЕРИОДА(Продажи.Период, КВАРТАЛ)
Второй параметр — ключевое слово языка запросов (пишется без кавычек). В платформе 1С 8.3 поддерживаются следующие виды периодов:
СЕКУНДА,МИНУТА,ЧАС,ДЕНЬ— усечение или дополнение времени внутри суток;НЕДЕЛЯ,ДЕКАДА,МЕСЯЦ— группировка оперативных отчётов по неделям, десятидневкам и месяцам;КВАРТАЛ,ПОЛУГОДИЕ,ГОД— укрупнённые интервалы для управленческой и регламентированной отчётности.
Обратите внимание на производительность: применять НАЧАЛОПЕРИОДА(ПолеТаблицы, ДЕНЬ) = &День к полю индексированной таблицы в секции ГДЕ не рекомендуется, так как вызов функции поверх колонки мешает СУБД эффективно использовать индекс по дате. Гораздо быстрее оставить слева само поле таблицы, а функции применить к параметрам: ПолеТаблицы МЕЖДУ НАЧАЛОПЕРИОДА(&День, ДЕНЬ) И КОНЕЦПЕРИОДА(&День, ДЕНЬ).
РАЗНОСТЬДАТ и ДОБАВИТЬКДАТЕ: расчёт просрочки и сдвиг дат в запросе
Для вычисления интервала между двумя датами и сдвига даты на нужное число дней, месяцев или лет в языке запросов 1С предусмотрены функции РАЗНОСТЬДАТ(Дата1, Дата2, Тип) и ДОБАВИТЬКДАТЕ(Дата, Тип, Количество).
Порядок аргументов в РАЗНОСТЬДАТ критичен: функция вычитает первую дату из второй (Дата2 - Дата1). Если Дата1 меньше Дата2, результат положительный; если больше — отрицательный. Кроме того, РАЗНОСТЬДАТ считает количество пересечённых границ выбранного периода, а не делит секунды на 86400 с дробным остатком. Например, разница в ДЕНЬ между 10.10.2026 23:50:00 и 11.10.2026 00:05:00 равна 1, хотя прошло всего 15 минут.
ВЫБРАТЬ
Этапы.Ссылка КАК Заказ,
Этапы.ДатаОплатыПлан КАК ПлановаяДата,
ДОБАВИТЬКДАТЕ(Этапы.ДатаОплатыПлан, ДЕНЬ, 5) КАК КрайнийСрокСОтсрочкой,
РАЗНОСТЬДАТ(Этапы.ДатаОплатыПлан, &ТекущаяДата, ДЕНЬ) КАК ДнейПросрочки
ИЗ
Документ.ЗаказКлиента КАК Этапы
ГДЕ
Этапы.ДатаОплатыПлан <> ДАТАВРЕМЯ(1, 1, 1)
И Этапы.ДатаОплатыПлан < НАЧАЛОПЕРИОДА(&ТекущаяДата, ДЕНЬ)
В функции ДОБАВИТЬКДАТЕ(Дата, Тип, Количество) третий аргумент может быть как положительным (сдвиг в будущее), так и отрицательным (сдвиг в прошлое). Например, ДОБАВИТЬКДАТЕ(&ДатаОтчета, МЕСЯЦ, -1) вернёт ту же дату месяц назад; если исходная дата приходилась на 31-е число, а в целевом месяце 30 дней, платформа корректно вернёт последний день целевого месяца.
Важная деталь при расчёте просрочки: перед вызовом РАЗНОСТЬДАТ(ПлановаяДата, &ТекущаяДата, ДЕНЬ) всегда отсекайте незаполненные даты условием ПлановаяДата <> ДАТАВРЕМЯ(1, 1, 1). Иначе для документов с пустой датой 01.01.0001 запрос насчитает более 739 тысяч дней просрочки.
РАЗНОСТЬДАТ и выведет готовую таблицу.
Сводная таблица функций работы с датами и периодами в запросе 1С
Ниже собраны все конструкции языка запросов 1С 8.3 для проверки пустых дат, границ периодов и арифметики дат с их аналогами во встроенном языке:
| Задача | Конструкция в языке запросов 1С | Аналог во встроенном языке (BSL) | Особенность работы |
|---|---|---|---|
| Литерал пустой даты | ДАТАВРЕМЯ(1, 1, 1) |
Дата(1, 1, 1) или '00010101' |
Равно 01.01.0001 00:00:00; это не NULL |
Пустая дата после ЛЕВОЕ СОЕДИНЕНИЕ |
ЕСТЬNULL(Поле, ДАТАВРЕМЯ(1, 1, 1)) = ДАТАВРЕМЯ(1, 1, 1) |
НЕ ЗначениеЗаполнено(Выборка.Поле) |
Ловит и незаполненную дату, и NULL при отсутствии строки справа |
| Отбор за период включительно | Поле МЕЖДУ &Начало И КОНЕЦПЕРИОДА(&Конец, ДЕНЬ) |
НачалоДня(Д1) и КонецДня(Д2) |
Обе границы включены (>= и <=); конец дня — 23:59:59 |
| Приведение к началу / концу интервала | НАЧАЛОПЕРИОДА(Дата, Тип) / КОНЕЦПЕРИОДА(Дата, Тип) |
НачалоМесяца(), КонецКвартала(), КонецГода() |
Поддерживает от СЕКУНДА до ГОД, включая НЕДЕЛЯ и ДЕКАДА |
| Разница между датами | РАЗНОСТЬДАТ(Дата1, Дата2, Тип) |
(Дата2 - Дата1) (только в секундах) |
Вычитает Дата1 из Дата2; считает пересечённые границы Тип |
| Сдвиг даты вперёд или назад | ДОБАВИТЬКДАТЕ(Дата, Тип, Число) |
ДобавитьМесяц(Дата, Число) или Дата + Секунды |
Отрицательное Число сдвигает дату назад в прошлое |
| Извлечение части даты | ГОД(Д), МЕСЯЦ(Д), ДЕНЬ(Д), ДЕНЬНЕДЕЛИ(Д) |
Год(Д), Месяц(Д), День(Д), ДеньНедели(Д) |
Возвращают целое число; ДЕНЬНЕДЕЛИ считает от понедельника (1..7) |
Частые ошибки при работе с датами и периодами в запросе 1С
-
Проверка обычного поля даты через
ЕСТЬ NULL. Незаполненный реквизит типаДатав таблице документа или справочника хранит01.01.0001 00:00:00, а неNULL. УсловиеДатаОплаты ЕСТЬ NULLмолча вернёт пустую выборку — используйте= ДАТАВРЕМЯ(1, 1, 1). -
Потеря документов за последний день в
МЕЖДУ. Передача в верхнюю границуДата(2026, 10, 31)задаёт полночь00:00:00, поэтому все документы от 31 числа со временем в течение дня отсекаются. Закрывайте правую границу черезКОНЕЦПЕРИОДА(&Конец, ДЕНЬ)илиКонецДня(). -
Сравнение поля после
ЛЕВОЕ СОЕДИНЕНИЕбезЕСТЬNULL. Если в присоединённой таблице нет записи, поле равноNULL, и условиеТаб.Дата = ДАТАВРЕМЯ(1, 1, 1)его не отберёт. Оборачивайте поле вЕСТЬNULL(Таб.Дата, ДАТАВРЕМЯ(1, 1, 1)). -
Перепутаны местами аргументы
РАЗНОСТЬДАТ. Функция считаетДата2 - Дата1. Если поставить текущую дату первым параметром, а более раннюю плановую дату вторым, количество дней просрочки получится со знаком минус. -
Расчёт
РАЗНОСТЬДАТпо незаполненным датам. Если не отфильтровать строки сДАТАВРЕМЯ(1, 1, 1), разница между первым годом нашей эры и сегодняшним днём даст сотни тысяч дней и исказит итоги по отчёту. -
Вызов
НАЧАЛОПЕРИОДАот поля таблицы в секцииГДЕ. ЗаписьГДЕ НАЧАЛОПЕРИОДА(Док.Дата, МЕСЯЦ) = &НачалоМесяцазаставляет СУБД вычислять функцию для каждой строки вместо поиска по индексу. Переносите вычисление на параметры:ГДЕ Док.Дата МЕЖДУ НАЧАЛОПЕРИОДА(&Дата, МЕСЯЦ) И КОНЕЦПЕРИОДА(&Дата, МЕСЯЦ).
Частые вопросы о пустой дате и периодах в запросе 1С
Как проверить поле на пустую дату в запросе 1С 8.3 без передачи параметра?
Используйте встроенный литерал языка запросов ДАТАВРЕМЯ(1, 1, 1) в условии ГДЕ ПолеДаты = ДАТАВРЕМЯ(1, 1, 1). Если поле получено из присоединённой таблицы после ЛЕВОЕ СОЕДИНЕНИЕ, оберните его в ЕСТЬNULL(ПолеДаты, ДАТАВРЕМЯ(1, 1, 1)) = ДАТАВРЕМЯ(1, 1, 1), чтобы одновременно обработать и пустую дату, и NULL.
Включает ли оператор МЕЖДУ границы периода в запросе 1С?
Да, оператор МЕЖДУ Начало И Конец включает обе границы и работает как >= Начало И <= Конец. Однако если передать верхнюю границу датой без времени (00:00:00), документы за последний день с временем 14:30:00 не попадут в отбор, поэтому правую границу нужно приводить к концу дня через КОНЕЦПЕРИОДА(&Конец, ДЕНЬ) или КонецДня().
В каком порядке передавать даты в функцию РАЗНОСТЬДАТ в запросе 1С?
Первым параметром передаётся начальная (меньшая) дата, вторым — конечная (большая), третьим — тип периода без кавычек: РАЗНОСТЬДАТ(ДатаНачала, ДатаОкончания, ДЕНЬ). Функция вычитает первую дату из второй и возвращает целое число пересечённых границ указанного периода.