При интеграции систем 1С с внешними программными продуктами (особенно на базе старых версий MySQL или специфических легаси-решений) разработчики часто сталкиваются с требованием передать "пустую" дату именно в формате 0000-00-00T00:00:00. Однако стандарт XML Schema (W3C), которому строго следует платформа 1С, считает такую запись недопустимой. Согласно спецификации ISO 8601, летоисчисление начинается с 0001 года, и "нулевого" года не существует.
В этой статье мы подробно разберем, почему возникает эта проблема и какими способами ее можно обойти, сохранив работоспособность обмена данными.
Когда мы пытаемся передать в функцию XMLСтрока() пустую дату 1С — Дата(1, 1, 1) — платформа преобразует ее в канонический вид 0001-01-01T00:00:00. Если же мы пытаемся вручную записать строку 0000-00-00T00:00:00 в узел, типизированный как dateTime, сериализатор 1С выдает ошибку соответствия простому типу. Это происходит потому, что валидатор проверяет значение на соответствие правилам XSD перед записью.
Этот метод является самым популярным и быстрым в реализации. Суть его заключается в том, что мы сначала формируем правильный с точки зрения 1С XML-документ, а затем правим его как обычный текст. Рассмотрим этот процесс по шагам.
ЗаписьXML.Дата(1, 1, 1).0001-01-01T00:00:00 на требуемую 0000-00-00T00:00:00.Посмотрим на пример реализации данного метода:
// Сначала формируем XML в строку
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.УстановитьСтроку();
// ... логика записи узлов ...
// Предположим, мы записали пустую дату:
ЗаписьXML.ЗаписатьСоответствующееЗначение(Дата(1,1,1), "PartsOrderReceivedDateTime");
ТекстXML = ЗаписьXML.Закрыть();
// Выполняем подмену "неправильного" года
ТекстXML = СтрЗаменить(ТекстXML, "0001-01-01T00:00:00", "0000-00-00T00:00:00");
// Теперь ТекстXML содержит требуемый формат для внешней системы
Важный нюанс: если в ваших данных могут встречаться реальные даты, соответствующие первому января первого года (что маловероятно для бизнес-данных), этот метод может затронуть их. Однако для большинства управленческих и бухгалтерских задач этот риск равен нулю.
Если вы используете XDTO для генерации XML, система будет жестко контролировать типы. Чтобы обойти ограничение типа dateTime, мы можем изменить определение элемента в схеме. Рассмотрим ситуацию, когда мы меняем тип данных элемента на string (строку).
Выясним преимущества этого подхода: вы сможете передавать абсолютно любую строку в поле даты, и 1С не будет пытаться ее валидировать как дату. Проанализируем действия:
XDTO-пакет найдите нужное свойство.{http://www.w3.org/2001/XMLSchema}dateTime на {http://www.w3.org/2001/XMLSchema}string."0000-00-00T00:00:00", если заполнена — преобразуйте ее в XML-строку самостоятельно.Пример кода при использовании измененного XDTO-пакета:
Если ЗначениеЗаполнено(Объект.ДатаПриема) Тогда
ОбъектXDTO.PartsOrderReceivedDateTime = XMLСтрока(Объект.ДатаПриема);
Иначе
ОбъектXDTO.PartsOrderReceivedDateTime = "0000-00-00T00:00:00";
КонецЕсли;
Использование ЗаписьDOM позволяет более гибко управлять содержимым узлов. В отличие от прямой записи через ЗаписьXML с типизацией, DOM-модель позволяет создать текстовый узел с любым содержимым. Разберем, как это реализовать.
Проанализируем пример кода:
ДокументDOM = Новый ДокументDOM;
КорневойУзел = ДокументDOM.СоздатьЭлемент("Data");
ДокументDOM.ДобавитьПодчиненный(КорневойУзел);
ЭлементДата = ДокументDOM.СоздатьЭлемент("PartsOrderReceivedDateTime");
// Мы просто записываем текст, 1С не проверяет формат даты в DOM-узле
ТекстДаты = ДокументDOM.СоздатьТекстовыйУзел("0000-00-00T00:00:00");
ЭлементДата.ДобавитьПодчиненный(ТекстДаты);
КорневойУзел.ДобавитьПодчиненный(ЭлементДата);
// Записываем DOM в файл
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.ОткрытьФайл("C:\temp\export.xml");
ЗаписьDOM = Новый ЗаписьDOM;
ЗаписьDOM.Записать(ДокументDOM, ЗаписьXML);
ЗаписьXML.Закрыть();
Прежде чем прибегать к "хакам" с нулевыми годами, стоит выяснить у администраторов принимающей системы: не поддерживают ли они стандартный для XML способ передачи отсутствующих значений через атрибут nil. С точки зрения профессиональной разработки, это самый правильный путь.
В XML это выглядит так: <DateNode xsi:nil="true" />. В 1С при работе с XDTO это реализуется установкой свойства в значение Неопределено (при условии, что в схеме установлен флаг Возможно пустое / nillable).
// Если в XDTO свойство помечено как nillable
ОбъектXDTO.DateNode = Неопределено;
// При сериализации 1С сама добавит атрибут xsi:nil="true"
Выбор метода зависит от гибкости принимающей стороны. Если они категорически требуют 0000-00-00, наиболее надежным и простым методом остается Способ 1 (СтрЗаменить). Если же вы проектируете систему с нуля, старайтесь придерживаться типа string для таких полей или использовать стандартный xsi:nil, чтобы избежать конфликтов со спецификацией XML.