При интеграции платформы 1С:Предприятие с внешними платежными шлюзами, в частности с REST API эквайринга Сбербанка, разработчики часто сталкиваются с тем, что даты транзакций, регистрации заказов и проведения платежей возвращаются в непривычном формате. Вместо стандартной строки даты шлюз присылает длинное числовое значение, например 1554091557065. Это значение представляет собой временную метку Unix Timestamp, выраженную в миллисекундах.
В рамках этой статьи мы подробно разберем, как правильно работать с такими данными в 1С. Мы проанализируем популярные ошибки разработчиков при ручной конвертации, рассмотрим правильный математический алгоритм преобразования, а также внедрим передовые практики автоматического восстановления дат в процессе десериализации JSON-пакетов средствами платформы 1С:Предприятие 8.3.
Стандартное время Unix (POSIX time) — это система описания моментов времени, определяемая как количество секунд, прошедших с полуночи (00:00:00 UTC) 1 января 1970 года (эпоха Unix). Однако современные веб-сервисы, ориентированные на высокую точность и построенные на технологиях JavaScript/Java (включая API Сбербанка), используют более точную метрику — миллисекунды с начала эпохи Unix.
Число 1554091557065 состоит из 13 цифр:
1554091557) — это стандартное Unix-время в секундах, соответствующее дате 01.04.2019 04:05:57 UTC.065) — это миллисекунды.Если попытаться обработать это значение стандартными методами 1С напрямую, мы неизбежно столкнемся с ошибками позиционирования во времени. Разберем типичное ошибочное решение, которое часто встречается на форумах.
Начинающие разработчики часто пытаются применить простую арифметику дат в 1С. В платформе прибавление числа к переменной типа Дата трактуется как добавление указанного количества секунд. Из-за этого возникает соблазн написать следующий код:
Функция СконвертироватьВремяUnixTS(UnixTime)
// ОШИБОЧНЫЙ КОД!
Возврат МестноеВремя('19700101' + UnixTime);
КонецФункции
Выясним причину, почему этот код вернет некорректный результат. Если мы передадим в эту функцию число 1554091557065, платформа попытается прибавить к базовой дате 1 января 1970 года более полутора триллионов секунд. В результате нехитрых математических расчетов мы получим дату в районе 49279 года. Очевидно, что такое поведение программы является грубой логической ошибкой.
Для того чтобы получить корректную дату, нам необходимо предварительно перевести миллисекунды в секунды.
Рассмотрим по шагам правильный алгоритм ручной конвертации. Нам необходимо выполнить следующие действия:
Цел(), так как стандартный тип данных Дата в 1С не поддерживает хранение миллисекунд.'19700101000000'.Посмотрим на практический пример реализации такой функции на языке программирования 1С:
// Функция преобразует Unix Timestamp (миллисекунды) в стандартную дату 1С
// Параметры:
// UnixTimeMillisecond - Число или Строка - временная метка от Сбербанка
// Возвращаемое значение:
// Дата (UTC)
Функция ПреобразоватьUnixMillisВДату1С(Знач UnixTimeMillisecond) Экспорт
Если Не ЗначениеЗаполнено(UnixTimeMillisecond) Тогда
Возврат '00010101000000';
КонецЕсли;
Попытка
Число Milliseconds = Число(UnixTimeMillisecond);
Исключение
ЗаписьЖурналаРегистрации("ИнтеграцияСбербанк.ОшибкаКонвертацииДаты",
УровеньЖурналаРегистрации.Ошибка, , ,
"Не удалось привести значение к числу: " + UnixTimeMillisecond);
Возврат '00010101000000';
КонецПопытки;
// Переводим миллисекунды в секунды
ЧислоСекунд = Цел(ЧислоMilliseconds / 1000);
// Прибавляем секунды к начальной точке отсчета (в формате UTC)
ДатаUTC = '19700101000000' + ЧислоСекунд;
Возврат ДатаUTC;
КонецФункции
Данный метод стабильно работает на любых версиях платформы 1С:Предприятие 8, включая старые релизы. Однако, если мы работаем в современных конфигурациях, платформенные механизмы предоставляют более элегантный способ решения задачи.
Начиная с версии платформы 1С:Предприятие 8.3.6, разработчикам доступен объект ЧтениеJSON, который позволяет гибко управлять процессом десериализации данных. Вместо того чтобы обходить полученное дерево соответствий и вручную конвертировать каждое числовое поле с датой, мы можем задействовать специальный механизм — функцию восстановления дат.
Для этого мы преобразуем числовое представление Unix Timestamp в строку формата даты JavaScript прямо «на лету» в процессе чтения JSON-пакета, а затем вызовем встроенную функцию платформы ПрочитатьДатуJSON.
Разберем по шагам, как настроить этот процесс в коде:
// Основной метод, выполняющий чтение ответа от Сбербанка
Процедура РазобратьОтветЭквайринга(СтрокаОтветаСбера)
Чтение = Новый ЧтениеJSON;
Чтение.УстановитьСтроку(СтрокаОтветаСбера);
// В параметрах ПрочитатьJSON указываем имя функции восстановления,
// которая будет вызываться для каждого свойства десериализуемого объекта
ДанныеОтвета = ПрочитатьJSON(Чтение, Ложь, , , "ВосстановитьДатыСбербанка", ЭтотОбъект);
Чтение.Закрыть();
// На выходе в структуре ДанныеОтвета поля дат будут содержать полноценный тип Дата 1С
Если ДанныеОтвета.Свойство("createdDate") Тогда
ЗаписатьДатуВБазу(ДанныеОтвета.createdDate);
КонецЕсли;
КонецПроцедуры
// Функция восстановления, вызываемая платформой автоматически.
// Должна быть объявлена с ключевым словом Экспорт.
Функция ВосстановитьДатыСбербанка(Свойство, Значение, ДополнительныеПараметры) Экспорт
// Определяем перечень полей Сбербанка, содержащих временные метки.
// Обычно это поля "date", "createdDate", "registerDate", "paymentDate" и т.д.
Если Свойство = "date"
Или Свойство = "createdDate"
Или Свойство = "registerDate"
Или Свойство = "paymentDate" Тогда
Если ТипЗнч(Значение) = Тип("Число") И Значение > 0 Тогда
// Формируем строковое представление инициализации даты в JavaScript.
// Пример: "new Date(1554091557065)"
СтрокаJS = "new Date(" + Формат(Значение, "ЧГ=") + ")";
// Читаем дату с использованием платформенного формата JavaScript
Возврат ПрочитатьДатуJSON(СтрокаJS, ФорматДатыJSON.JavaScript);
КонецЕсли;
КонецЕсли;
// Все остальные поля возвращаем без изменений
Возврат Значение;
КонецФункции
Использование функции восстановления дат — это наиболее правильный подход с точки зрения стандартов разработки фирмы «1С». Это упрощает код, избавляет от необходимости пост-обработки структуры данных и снижает вероятность пропуска полей, требующих конвертации.
Проанализируем важный аспект интеграции, связанный с географическим распределением серверов и часовыми поясами. Все временные метки, передаваемые через REST API Сбербанка, зафиксированы в часовом поясе UTC (Всемирное координированное время).
Когда мы получаем дату из Unix Timestamp с помощью сложения с базовой датой или через ПрочитатьДатуJSON, платформа 1С возвращает нам время по стандарту UTC. Если вы запишете эту дату в информационную базу «как есть», пользователи в интерфейсе могут увидеть смещенное время (например, на 3 часа меньше для Московского времени).
Для корректного отображения времени пользователям необходимо учитывать следующие правила:
МестноеВремя(ДатаUTC) преобразует дату из формата UTC в часовой пояс того компьютера, на котором выполняется код. Обратите внимание: если код выполняется на сервере 1С, будет использован часовой пояс сервера, а не клиентского компьютера.+ 3 * 3600).Пример преобразования полученной UTC-даты в локальное время сервера 1С:
ДатаUTC = ПреобразоватьUnixMillisВДату1С(1554091557065);
ЛокальнаяДатаСервера = МестноеВремя(ДатаUTC); // Смещение произойдет автоматически на основе настроек ОС сервера
Используя предложенные методики, мы обеспечим точную и надежную интеграцию с платежными сервисами Сбербанка, исключив любые расхождения во времени транзакций и упростив дальнейшую техническую поддержку программного решения.