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

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

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

Как в 1С проверить дату на пустое значение: ЗначениеЗаполнено, сравнение с пустой датой, проверка в запросе и СКД. Примеры кода и типичные ошибки.

Пустая дата в 1С — это не NULL и не ноль, а особое значение '00010101000000' (1 января 0001 года, 0 часов 0 минут 0 секунд). Если реквизит типа «Дата» не заполнен, платформа хранит именно его, и именно с ним нужно сравнивать переменную при проверке. Ошибка в такой проверке приводит к тому, что документы уходят в печать без даты отгрузки, отчёты показывают лишние строки, а обмены выгружают «01.01.0001» вместо пустого поля.

Способ проверки зависит от контекста: в коде встроенного языка используют функцию ЗначениеЗаполнено() или прямое сравнение с пустой датой, в запросах — оператор сравнения с параметром или конструкцию ЕСТЬ NULL для необязательных соединений, а в СКД — выражения языка запросов и настройку отборов. Ниже разобраны все рабочие варианты с примерами кода.

Важно понимать различие: пустая дата — это заполненное, но «нулевое» значение типа «Дата», а NULL — отсутствие значения вообще, которое появляется только в результатах запросов при левом соединении. Эти два случая проверяются по-разному, и смешивание их — самая частая причина ошибок.

Что такое пустая дата в 1С и чем она отличается от NULL

Когда реквизит типа «Дата» не заполнен, платформа присваивает ему значение по умолчанию — начало отсчёта календаря: 01.01.0001 0:00:00. Во встроенном языке это значение можно получить литералом '00010101000000' или его сокращённой формой '00010101'. Функция ТипЗнч() для такого значения вернёт тип «Дата», то есть формально поле не «пустое» в смысле отсутствия данных — оно заполнено нулевой датой.

NULL — принципиально другое состояние. Оно возникает только в запросах, когда при левом соединении для строки основной таблицы не нашлось пары в присоединяемой. Поле из присоединённой таблицы в этом случае равно NULL, а не пустой дате. Сравнение Поле = '00010101' для NULL вернёт не Истина и не Ложь, а NULL, и условие просто не сработает — строка «молча» выпадет из результата.

Проверка в коде через ЗначениеЗаполнено()

Самый универсальный и рекомендуемый способ — функция ЗначениеЗаполнено(). Она возвращает Ложь для пустой даты, неопределено, NULL, пустой строки, пустой ссылки и других «незаполненных» значений любого типа. Код получается коротким и одинаково работает для любых реквизитов:

Если НЕ ЗначениеЗаполнено(Документ.ДатаОтгрузки) Тогда

Сообщить("Не заполнена дата отгрузки!");

Возврат;

КонецЕсли;

Обратная проверка — «дата заполнена» — записывается без отрицания: Если ЗначениеЗаполнено(ДатаОплаты) Тогда ... КонецЕсли;. Такой стиль читается легче, чем сравнение с литералом, и его проще поддерживать.

У функции есть ограничение: она проверяет именно заполненность, а не корректность. Дата 01.01.1990, введённая пользователем по ошибке вместо реальной, считается заполненной. Если нужна бизнес-валидация (дата не раньше определённого периода, не в будущем), её пишут отдельным условием.

Прямое сравнение с пустой датой

Альтернатива — явное сравнение с литералом пустой даты. Оба варианта ниже эквивалентны:

Если ДатаОкончания = '00010101' Тогда

// дата не заполнена

КонецЕсли;

Если ДатаОкончания = '00010101000000' Тогда

// то же самое, полная форма

КонецЕсли;

Литерал даты в 1С записывается в одинарных кавычках в формате ГГГГММДДччммсс; время можно опустить. Платформа автоматически приводит правую часть сравнения к типу «Дата». Этот способ иногда предпочитают, когда нужно подчеркнуть, что проверяется конкретно дата, а не «любое пустое значение».

Типичная тонкость: если переменная может содержать не только дату, но и Неопределено (например, результат функции), сравнение с литералом вернёт Ложь, и проверка «пустоты» не сработает. ЗначениеЗаполнено() в такой ситуации надёжнее, потому что Неопределено она тоже считает незаполненным.

Сравнение способов проверки

ЗначениеЗаполнено()

Универсально: ловит пустую дату, Неопределено, пустую ссылку. Рекомендуемый вариант в коде.

Дата = '00010101'

Работает только если переменная точно типа «Дата». Для Неопределено даст неверный результат.

Дата = Дата(1,1,1)

Через конструктор Дата(год, месяц, день). Редкий вариант, встречается в старом коде.

Проверка пустой даты в запросе

В тексте запроса литералы дат пишутся через функцию ДАТАВРЕМЯ(год, месяц, день, часы, минуты, секунды). Пустая дата — это ДАТАВРЕМЯ(1,1,1). Условие отбора документов без даты отгрузки выглядит так:

ВЫБРАТЬ

Реализация.Ссылка

ИЗ

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

ГДЕ

Реализация.ДатаОтгрузки = ДАТАВРЕМЯ(1, 1, 1)

Второй вариант — передать пустую дату параметром. Это удобно, когда значение формируется в коде или условие переиспользуется:

Запрос.УстановитьПараметр("ПустаяДата", '00010101');

// в тексте запроса: ГДЕ Реализация.ДатаОтгрузки = &ПустаяДата

Для отбора наоборот — только заполненных дат — используют неравенство: ГДЕ Реализация.ДатаОтгрузки <> ДАТАВРЕМЯ(1, 1, 1). Учтите, что такое условие отсекает и строки с NULL, если поле приходит из левого соединения.

bsl
Если НЕ ЗначениеЗаполнено(Объект.ДатаОплаты) Тогда
    ВызватьИсключение "Не заполнена дата оплаты";
КонецЕсли;

// В запросе:
// ГДЕ Док.ДатаОплаты = ДАТАВРЕМЯ(1, 1, 1)
// или через параметр: ГДЕ Док.ДатаОплаты = &ПустаяДата

NULL в левом соединении: почему обычная проверка не срабатывает

Классическая ловушка: запрос соединяет документы с регистром оплат левым соединением, и для неоплаченных документов поле Оплата.Дата равно NULL. Условие ГДЕ Оплата.Дата = ДАТАВРЕМЯ(1,1,1) такие строки не найдёт — сравнение с NULL даёт NULL, а не Истину.

Правильные варианты проверки:

ГДЕ Оплата.Дата ЕСТЬ NULL

// или с учётом обоих случаев:

ГДЕ (Оплата.Дата ЕСТЬ NULL

ИЛИ Оплата.Дата = ДАТАВРЕМЯ(1, 1, 1))

Если в выборке нужно вместо NULL показать осмысленное значение, используют ЕСТЬNULL(): ЕСТЬNULL(Оплата.Дата, ДАТАВРЕМЯ(1,1,1)) КАК ДатаОплаты. После такой обёртки поле в результате уже никогда не будет NULL, и дальше с ним можно работать как с обычной датой, включая стандартную проверку на пустоту.

Проверка даты в СКД и динамических списках

В схеме компоновки данных проверка выполняется на уровне запроса набора данных — действуют те же правила с ДАТАВРЕМЯ(1,1,1) и ЕСТЬ NULL. Если нужно дать пользователю отбор «только с пустой датой» или «только с заполненной», удобно добавить вычисляемое поле:

ВЫБОР

КОГДА Док.ДатаОтгрузки = ДАТАВРЕМЯ(1, 1, 1)

ТОГДА ИСТИНА

ИНАЧЕ ЛОЖЬ

КОНЕЦ КАК ДатаОтгрузкиПустая

Дальше в настройках отчёта пользователь ставит отбор «ДатаОтгрузкиПустая = Истина» без знания внутреннего представления пустой даты. В динамических списках с произвольным запросом подход тот же: условие либо зашивается в текст запроса, либо выносится в параметр, доступный в настройке списка.

В отборах динамического списка через интерфейс (без изменения запроса) пустую дату можно выбрать прямо в поле сравнения — поле даты по умолчанию содержит именно пустое значение, и вид сравнения «Равно» отберёт записи с незаполненной датой.

Как добавить проверку пустой даты в отчёт СКД
  1. 1
    Откройте схему компоновки данных и перейдите на закладку «Наборы данных»
  2. 2
    В запросе добавьте вычисляемое поле с конструкцией ВЫБОР ... ДАТАВРЕМЯ(1,1,1)
  3. 3
    Если поле из левого соединения — оберните его в ЕСТЬNULL()
  4. 4
    На закладке «Настройки» добавьте отбор по новому полю
  5. 5
    Сформируйте отчёт и проверьте, что строки с пустой датой отбираются корректно

Проверка на форме и в макете печати

В модуле формы проверка ничем не отличается от обычного кода: ЗначениеЗаполнено(Объект.ДатаОтгрузки). Типовой сценарий — валидация перед записью в обработчике ПередЗаписью или ОбработкаПроверкиЗаполнения. Второй вариант предпочтительнее: он штатно подсвечивает незаполненное поле и блокирует запись с понятным сообщением.

Процедура ОбработкаПроверкиЗаполнения(Отказ, ПроверяемыеРеквизиты)

Если НЕ ЗначениеЗаполнено(ДатаОтгрузки) Тогда

ОбщегоНазначения.СообщитьПользователю(

"Укажите дату отгрузки", , "ДатаОтгрузки", , Отказ);

КонецЕсли;

КонецПроцедуры;

В макетах печати пустая дата, выведенная напрямую, отобразится как «01.01.0001» — это выглядит как дефект печатной формы. Чтобы вместо неё выводить пустую строку или прочерк, в коде формирования печати используют Формат() с форматной строкой: Формат(ДатаОтгрузки, "ДЛФ=D; ДП='—'"). Параметр ДП задаёт представление именно пустой даты.

Типичные ошибки при проверке дат
01
Сравнение с пустой строкой: Дата = "" никогда не истинно, проверка бесполезна
02
Игнорирование NULL в левом соединении — строки теряются из запроса
03
Вывод пустой даты в печать без Формат() — на бланке появляется 01.01.0001
04
Проверка Неопределено сравнением с '00010101' — результат Ложь, ветка не выполнится
05
Проверка заполненности вместо бизнес-валидации: дата 01.01.1990 считается заполненной

Как убедиться, что проверка работает правильно

После внедрения проверки протестируйте три состояния: реквизит не заполнен вообще, заполнен реальной датой и (для запросов с соединениями) отсутствует связанная запись. Для каждого состояния поведение должно быть предсказуемым: сообщение об ошибке, штатное продолжение, корректная строка в отчёте.

Быстрый способ проверить значение в отладчике — вычислить выражение ЗначениеЗаполнено(Реквизит) и посмотреть само значение переменной. Если там 01.01.0001 0:00:00 — это пустая дата; если «NULL» — значение пришло из соединения и требует другой обработки.

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

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

Значение реквизита в отладчике
Норма

01.01.0001 0:00:00 — пустая дата, ЗначениеЗаполнено() = Ложь

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

NULL — поле из левого соединения, нужна проверка ЕСТЬ NULL

Результат запроса с условием на пустую дату
Норма

В выборку попали все документы без даты, включая строки с NULL

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

Часть документов без даты отсутствует — вероятно, не обработан NULL

Печатная форма
Норма

Вместо пустой даты прочерк или пусто

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

На бланке выводится 01.01.0001

Итог

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

В коде используйте ЗначениеЗаполнено() — это универсально и безопасно. В запросах сравнивайте с ДАТАВРЕМЯ(1,1,1) или параметром, а для полей из левых соединений добавляйте ЕСТЬ NULL. В печатных формах скрывайте пустую дату через Формат() с параметром ДП.

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

Чем отличается проверка Дата = '00010101' от ЗначениеЗаполнено(Дата)?

Результат одинаков, если переменная гарантированно имеет тип «Дата». Разница проявляется, когда в переменной может оказаться Неопределено или значение другого типа: ЗначениеЗаполнено() корректно вернёт Ложь, а сравнение с литералом — нет. Поэтому в универсальном коде предпочтительна функция.

Почему запрос с условием Дата = ДАТАВРЕМЯ(1,1,1) не находит часть документов?

Почти всегда причина в левом соединении: для документов без связанной записи поле равно NULL, а сравнение NULL с любым значением не даёт Истину. Добавьте условие ИЛИ Поле ЕСТЬ NULL либо оберните поле в ЕСТЬNULL(Поле, ДАТАВРЕМЯ(1,1,1)) в списке выборки.

Как вывести в отчёте «Не указана» вместо пустой даты?

В запросе набора данных используйте конструкцию ВЫБОР КОГДА Дата = ДАТАВРЕМЯ(1,1,1) ТОГДА "Не указана" ИНАЧЕ ... КОНЕЦ, однако тогда поле станет строковым. Альтернатива без потери типа — оставить дату как есть и применить форматную строку с параметром ДП в настройках оформления поля.

Работает ли проверка пустой даты в управляемых и обычных формах одинаково?

Да, ЗначениеЗаполнено() и сравнение с '00010101' работают одинаково в обоих режимах и в тонком, и в толстом клиенте, включая серверный контекст. Различий в поведении пустой даты между платформенными режимами нет.

Можно ли проверить пустую дату в отборе динамического списка без изменения запроса?

Да. В настройке отбора добавьте условие по полю даты с видом сравнения «Равно» и оставьте значение пустым — поле даты по умолчанию содержит пустую дату, и отбор сработает корректно. Для вида «Не равно» получите записи только с заполненными датами.

Что вернёт функция Дата() с аргументами (1,1,1)?

Конструктор Дата(1, 1, 1) вернёт 1 января 0001 года — то есть ту самую пустую дату. Это третий способ получить значение для сравнения наряду с литералом '00010101' и ДАТАВРЕМЯ(1,1,1) в запросах; в новом коде обычно используют литерал или ЗначениеЗаполнено().