При интеграции с внешними системами через XML-файлы разработчики часто сталкиваются с ситуацией, когда дата в файле представлена в формате со смещением часового пояса (например, <date>2017-10-31T12:24:35.387+00:00</date>), однако после выполнения метода XMLЗначение(Тип("Дата"), ...) время в 1С автоматически увеличивается на несколько часов (например, становится 31.10.2017 15:24:35).
Разберем детально, почему платформа выполняет такое преобразование, какие ограничения накладывает примитивный тип Дата в 1С и как правильно получить исходное или всемирное координированное время (UTC).
Принцип работы десериализатора XML в платформе 1С
Поведение платформы при десериализации строковых данных в тип xs:dateTime строго соответствует стандарту XML Schema:
Z, +00:00, +03:00 и т. д.), 1С воспринимает это значение как абсолютный момент времени и автоматически конвертирует его в локальное время текущего сеанса пользователя — ЧасовойПоясСеанса(). Например, если время сеанса настроено на Московский часовой пояс (+3), то время 12:24:35+00:00 логично преобразуется в 15:24:35.2017-10-31T12:24:35), платформа считает дату локальной и загружает часы и минуты ровно так, как они записаны в файле.Ограничения типа Дата в 1С:
Дата в 1С не хранит в себе информацию о часовом поясе. После конвертации строки в дату знание об исходном смещении безвозвратно теряется..387) при преобразовании в тип Дата отбрасываются.Рассмотрим основные способы решения задачи в зависимости от требований бизнес-логики.
Если во входящем XML время гарантированно указано в нулевом часовом поясе (UTC / +00:00 / Z) и требуется получить именно значение 12:24:35, применим функцию УниверсальноеВремя к результату вызова XMLЗначение:
ЗначениеУзла = ЧтениеXML.Значение; // "2017-10-31T12:24:35.387+00:00"
ДатаСеанса = XMLЗначение(Тип("Дата"), ЗначениеУзла); // Получаем 31.10.2017 15:24:35 (для пояса +3)
ДатаUTC = УниверсальноеВремя(ДатаСеанса, ЧасовойПоясСеанса()); // Получаем 31.10.2017 12:24:35
Важное замечание: Этот способ возвращает исходное строковое время только в том случае, если в XML был передан именно пояс +00:00. Если файл будет содержать другое смещение (например, +05:00), функция УниверсальноеВремя пересчитает его в истинный UTC, а не вернет локальное время системы-отправителя.
При пакетной обработке больших файлов XML, содержащих данные в UTC, эффективным решением является программная установка часового пояса сеанса перед чтением:
ТекущийПояс = ЧасовойПоясСеанса();
УстановитьЧасовойПоясСеанса("UTC");
Попытка
// При чтении дат через XMLЗначение смещение происходить не будет
ДатаИзXML = XMLЗначение(Тип("Дата"), ЧтениеXML.Значение);
// 31.10.2017 12:24:35
Исключение
УстановитьЧасовойПоясСеанса(ТекущийПояс);
ВызватьИсключение;
КонецПопытки;
УстановитьЧасовойПоясСеанса(ТекущийПояс);
Если стоит задача получить время строго в том виде, в каком оно зафиксировано в файле отправителя, независимо от указанного в XML часового пояса и настроек текущего сеанса 1С, целесообразно выполнить строковый парсинг без использования стандартного сериализатора:
СтрокаДаты = ЧтениеXML.Значение; // "2017-10-31T12:24:35.387+00:00"
// Выделяем первые 19 символов вида "YYYY-MM-DDTHH:MM:SS"
ТолькоДатаВремя = Лев(СтрокаДаты, 19);
// Удаляем разделители для приведения к формату "YYYYMMDDHHMMSS"
ТолькоДатаВремя = СтрЗаменить(ТолькоДатаВремя, "-", "");
ТолькоДатаВремя = СтрЗаменить(ТолькоДатаВремя, "T", "");
ТолькоДатаВремя = СтрЗаменить(ТолькоДатаВремя, ":", "");
РезультатДата = Дата(ТолькоДатаВремя); // Получаем 31.10.2017 12:24:35
Проанализируем также обратную задачу: стандартный метод XMLСтрока(Дата) выгружает дату без информации о часовом поясе (например, 2017-10-31T12:24:35). Если принимающая внешняя система строго требует формат даты по стандарту ISO 8601 с признаком UTC (суффикс Z), формируем строку вручную через функцию Формат:
ТекущийМоментUTC = УниверсальноеВремя(ТекущаяДатаСеанса());
СтрокаДляXML = Формат(ТекущийМоментUTC, "ДФ=yyyy-MM-ddTHH:mm:ssZ");
// Результат: "2017-10-31T12:24:35Z"