При интеграции 1С с внешними сервисами, такими как API Операторов фискальных данных (ОФД), разработчики часто сталкиваются с ситуацией, когда вместо ожидаемой даты (например, 09.10.2020) система отображает дату в районе января 1970 года. Это классическая проблема интерпретации времени в формате Unix Timestamp. В этой статье мы подробно разберем, почему это происходит, как устроена передача дат в JSON и как правильно настроить десериализацию в 1С, чтобы избежать «костылей» в коде.
Для начала выясним причину. В большинстве современных веб-сервисов время передается как количество секунд (или миллисекунд), прошедших с начала «эпохи Unix» — 1 января 1970 года (UTC). Если 1С получает число, но не знает, что это дата, она либо оставляет его числом, либо при попытке принудительного преобразования к дате отсчитывает это количество секунд от начала времен (0001-01-01), либо, если используется формат JSON, некорректно обрабатывает смещение.
Если вы видите дату 19.01.1970, это означает, что число, пришедшее из API, было интерпретировано как небольшое количество секунд. Чаще всего проблема кроется в миллисекундах. API ОФД часто возвращают 13-значное число (миллисекунды), в то время как стандартные функции могут ожидать 10-значное число (секунды).
Проанализируем фрагмент кода, который часто используют новички, пытаясь «подогнать» результат под правильный ответ:
Данные.dateTime = ПрочитатьДатуJSON("new Date("+Формат(Данные.dateTime, "ЧГ=")+")", ФорматДатыJSON.JavaScript)
+ (18526 * 60 * 60 * 24) - (6 * 60 * 60) - (14 * 60);
Рассмотрим, почему такой подход не рекомендуется:
18526 — это попытка вручную вычислить разницу в днях между эпохой Unix и какой-то другой датой. Это не учитывает високосные годы и специфику часовых поясов.Платформа 1С предоставляет мощный инструмент для работы с JSON. Рассмотрим метод ПрочитатьJSON. Вместо того чтобы сначала читать всё в соответствие, а потом перебирать свойства, мы можем сразу указать системе, какие поля являются датами.
Разберем параметры функции ПрочитатьJSON:
ЧтениеJSON — объект чтения.ПрочитатьВСоответствие — Истина (если нам нужна структура).ИменаСвойствСоЗначениямиДата — массив имен полей (например, "dateTime", "receivingDate").ОжидаемыйФорматДаты — здесь указывается, в каком виде API присылает дату.Пример правильного вызова:
ЧтениеJSON = Новый ЧтениеJSON;
ЧтениеJSON.УстановитьСтроку(ТелоОтвета);
// Указываем, какие поля нужно преобразовать в Дату автоматически
МассивИменДат = Новый Массив;
МассивИменДат.Добавить("dateTime");
МассивИменДат.Добавить("receivingDate");
// ФорматДатыJSON.Universal - подходит для Unix Timestamp (в секундах)
// Если приходят миллисекунды, потребуется функция восстановления
Данные = ПрочитатьJSON(ЧтениеJSON, Истина, МассивИменДат, ФорматДатыJSON.Universal);
Если API присылает дату в нестандартном виде (например, число в миллисекундах или специфическая строка), лучше всего использовать функцию восстановления. Она позволяет перехватить обработку каждого свойства JSON в момент чтения.
Рассмотрим, как это реализовать. Сначала создадим саму функцию (она должна находиться в общем модуле или модуле формы с признаком &НаКлиенте / &НаСервере):
Функция ПреобразоватьДатуОФД(ИмяСвойства, Значение, ДополнительныеПараметры) Экспорт
Если ИмяСвойства = "dateTime" Или ИмяСвойства = "receivingDate" Тогда
// Если значение - число (миллисекунды Unix)
Если ТипЗнч(Значение) = Тип("Число") Тогда
// Конвертируем миллисекунды в секунды и добавляем к дате начала эпохи
ДатаНачала = Дата(1970, 1, 1, 0, 0, 0);
Возврат ДатаНачала + (Значение / 1000);
КонецЕсли;
КонецЕсли;
Возврат Значение;
КонецФункции
Теперь применим эту функцию при чтении:
ЧтениеJSON = Новый ЧтениеJSON;
ЧтениеJSON.УстановитьСтроку(ТелоОтвета);
// Передаем имя функции восстановления
Результат = ПрочитатьJSON(ЧтениеJSON, Истина, , , "ПреобразоватьДатуОФД", ЭтотОбъект);
Проанализируем ситуацию: этот метод хорош тем, что 1С сама проходит по дереву JSON, и как только встречает поле с указанным именем, вызывает ваш алгоритм. Это чисто, надежно и легко отлаживается.
Важно помнить, что Unix Timestamp — это всегда время в формате UTC (по Гринвичу). Кассовые чеки в ОФД фиксируются по местному времени кассы. Если вы просто преобразуете число, вы получите время UTC. Чтобы получить локальное время, необходимо добавить смещение часового пояса организации.
Посмотрим на пример учета смещения:
// Предположим, смещение +3 часа (Москва)
СмещениеСекунд = 3 * 60 * 60;
ДатаUTC = Дата(1970, 1, 1) + (ЗначениеИзAPI / 1000);
ЛокальнаяДата = ДатаUTC + СмещениеСекунд;
Подведем итоги нашего разбора. Если вы столкнулись с датой 1970 года при работе с API:
ОжидаемыйФорматДаты и ФункцияВосстановления в методе ПрочитатьJSON — это наиболее профессиональный и эффективный путь решения задачи.Используя эти рекомендации, вы напишете надежный код для интеграции с любым ОФД или внешним сервисом, обеспечив точность данных в вашей системе 1С.