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