При работе с обменом данными через XML программисты 1С часто сталкиваются с ситуацией, когда функция XMLЗначение возвращает дату и время, отличные от тех, что указаны в строке-источнике. Например, при попытке прочитать строку "2021-09-30T00:00:00+03:00" система может вернуть результат 29.09.2021 23:00:00. На первый взгляд это кажется ошибкой платформы, но на самом деле за этим стоит строгая логика работы с часовыми поясами. Разберем детально, почему так происходит и как правильно обрабатывать подобные ситуации.
Для начала проанализируем ситуацию: когда мы используем функцию XMLЗначение для типа Дата, платформа 1С выполняет не просто парсинг строки, а полноценную десериализацию по стандартам XML Schema (XSD). В формате XML строка даты и времени (тип dateTime) может содержать информацию о смещении относительно UTC (например, +03:00).
Важно понимать ключевую особенность платформы: тип Дата в 1С не хранит информацию о часовом поясе. Это всегда "голая" дата и время. Однако, когда платформа встречает в XML-файле абсолютный момент времени (указанный со смещением или символом Z — UTC), она автоматически конвертирует это время в локальное время текущего сеанса.
Рассмотрим пример. Если в строке указано 00:00 со смещением +03:00, а сеанс 1С запущен в часовом поясе со смещением +02:00, платформа честно пересчитывает абсолютный момент времени. Разница в один час приводит к тому, что время "откатывается" на 23:00 предыдущего дня. Это и есть ответ на вопрос о логике работы функции: 1С приводит "мировое" время к вашему "местному" времени.
Часто возникает путаница, когда программист проверяет часы на своем компьютере и видит там +03:00 (например, московское время), но 1С все равно выдает результат со смещением. Давайте выясним причину такого поведения. В платформе 1С существует два различных понятия:
ЧасовойПоясСеанса().Если в настройках пользователя 1С или в параметрах запуска информационной базы явно не указан часовой пояс, система пытается определить его по настройкам ОС. Однако в клиент-серверном варианте код может выполняться на сервере, где настройки времени могут отличаться от клиентских. Проанализируем ситуацию с помощью простого кода, который стоит запустить в той же процедуре, где вызывается XMLЗначение:
Сообщить("Часовой пояс сеанса: " + ЧасовойПоясСеанса());
Сообщить("Текущее время сеанса: " + ТекущаяДата());
Сообщить("Локальное системное время: " + ТекущаяДатаВРабочемЧасовомПоясе());
Если ЧасовойПоясСеанса() вернет значение, отличное от ожидаемого (например, Europe/Kaliningrad вместо Europe/Moscow), это и будет причиной разницы в один час при чтении XML.
Еще один важный аспект — актуальность таблиц часовых поясов (tz database). Правила перехода на летнее и зимнее время в России менялись несколько раз (в 2011 и 2014 годах). Если ваша операционная система или платформа 1С используют устаревшие данные о зонах, возможны ошибки преобразования. Рассмотрим ситуацию: для даты в сентябре (летнее время) смещение может быть +3, а для даты в январе — +2. Платформа учитывает эти правила автоматически на основе даты, которую она парсит.
Если код выполняется на сервере под управлением Linux, убедитесь, что пакет tzdata обновлен. В Windows должны быть установлены последние накопительные обновления часовых поясов. Если платформа 1С считает, что в указанную дату действовал другой часовой пояс, она применит его правила, что и приведет к неожиданному результату в функции XMLЗначение.
В зависимости от ваших задач, мы можем предложить несколько вариантов решения проблемы смещения времени.
Если вы точно знаете, в каком поясе должны работать данные, вы можете принудительно установить его в начале работы. Это гарантирует, что XMLЗначение будет выполнять конвертацию по понятным вам правилам. Используйте метод УстановитьЧасовойПоясСеанса().
// Установим московское время для текущего сеанса
УстановитьЧасовойПоясСеанса("Europe/Moscow");
ЗначениеДаты = XMLЗначение(Тип("Дата"), "2021-09-30T00:00:00+03:00");
// Теперь результат будет соответствовать ожиданиям, если смещение совпадает
Если ваша задача — получить дату "как она написана" в XML, игнорируя часовые пояса (так называемое "неопределенное время"), самым простым способом будет удаление части строки со смещением перед вызовом функции. Разберем по шагам, как это сделать:
+ или Z в строке.XMLЗначение.
ИсходнаяСтрока = "2021-09-30T00:00:00+03:00";
// Отрезаем всё после T00:00:00
ПозицияПлюса = СтрНайти(ИсходнаяСтрока, "+");
Если ПозицияПлюса > 0 Тогда
ЧистаяСтрока = Лев(ИсходнаяСтрока, ПозицияПлюса - 1);
Иначе
ЧистаяСтрока = СтрЗаменить(ИсходнаяСтрока, "Z", "");
КонецЕсли;
ДатаРезультат = XMLЗначение(Тип("Дата"), ЧистаяСтрока);
// Результат будет: 30.09.2021 00:00:00
Функция XMLЗначение фактически является упрощенной оберткой над механизмами XDTO. Если вам нужен более тонкий контроль, вы можете использовать СериализаторXDTO или напрямую работать с фабрикой XDTO. Рассмотрим пример чтения через тип dateTime из пространства имен XML Schema:
ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.УстановитьСтроку("<d>" + ИсходнаяСтрока + "</d>");
ЧтениеXML.Прочитать(); // встаем на элемент d
// Тип dateTime всегда учитывает смещение, но вы можете прочитать значение как строку
ЗначениеСтрокой = ЧтениеXML.ПрочитатьВычисляемоеЗначение();
Однако помните, что стандартный тип dateTime в 1С всегда будет пытаться привести время к локальному. Если вам принципиально важно сохранять время без изменений, лучше использовать Способ 2.
Мы выяснили, что логика функции XMLЗначение заключается в строгом следовании стандартам XML, где время с указанным смещением является абсолютным моментом времени. Платформа 1С автоматически пересчитывает этот момент в локальное время вашего сеанса. Чтобы избежать путаницы, всегда проверяйте ЧасовойПоясСеанса() и, при необходимости, предварительно обрабатывайте входящие строки данных.