Как правильно получить и обработать дату из API ОФД в 1С, если вместо нужной даты приходит 1970 год?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При интеграции 1С с внешними сервисами, такими как API Операторов фискальных данных (ОФД), разработчики часто сталкиваются с ситуацией, когда вместо ожидаемой даты (например, 09.10.2020) система отображает дату в районе января 1970 года. Это классическая проблема интерпретации времени в формате Unix Timestamp. В этой статье мы подробно разберем, почему это происходит, как устроена передача дат в JSON и как правильно настроить десериализацию в 1С, чтобы избежать «костылей» в коде.

Почему появляется дата 01.01.1970?

Для начала выясним причину. В большинстве современных веб-сервисов время передается как количество секунд (или миллисекунд), прошедших с начала «эпохи 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);

Рассмотрим, почему такой подход не рекомендуется:

  1. Магические числа: Константа 18526 — это попытка вручную вычислить разницу в днях между эпохой Unix и какой-то другой датой. Это не учитывает високосные годы и специфику часовых поясов.
  2. Сложность поддержки: Если API изменит формат (например, перейдет с миллисекунд на секунды или на стандарт ISO 8601), ваш код перестанет работать или будет выдавать неверные данные без ошибок.
  3. Производительность: Использование строковых манипуляций внутри цикла обработки массива данных замедляет работу системы.

Правильный метод №1: Использование функции ПрочитатьJSON с параметрами

Платформа 1С предоставляет мощный инструмент для работы с JSON. Рассмотрим метод ПрочитатьJSON. Вместо того чтобы сначала читать всё в соответствие, а потом перебирать свойства, мы можем сразу указать системе, какие поля являются датами.

Разберем параметры функции ПрочитатьJSON:

Пример правильного вызова:


ЧтениеJSON = Новый ЧтениеJSON;
ЧтениеJSON.УстановитьСтроку(ТелоОтвета);

// Указываем, какие поля нужно преобразовать в Дату автоматически
МассивИменДат = Новый Массив;
МассивИменДат.Добавить("dateTime");
МассивИменДат.Добавить("receivingDate");

// ФорматДатыJSON.Universal - подходит для Unix Timestamp (в секундах)
// Если приходят миллисекунды, потребуется функция восстановления
Данные = ПрочитатьJSON(ЧтениеJSON, Истина, МассивИменДат, ФорматДатыJSON.Universal);

Правильный метод №2: Функция восстановления (самый гибкий способ)

Если 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:

  1. Проверьте формат данных: Скорее всего, это Unix Timestamp. Выясните, передаются секунды (10 знаков) или миллисекунды (13 знаков).
  2. Откажитесь от ручных расчетов: Не используйте прибавление магических чисел к пустой дате в циклах.
  3. Используйте возможности платформы: Параметры ОжидаемыйФорматДаты и ФункцияВосстановления в методе ПрочитатьJSON — это наиболее профессиональный и эффективный путь решения задачи.
  4. Помните про UTC: Всегда проверяйте, нужно ли вам приводить полученное время к местному часовому поясу.

Используя эти рекомендации, вы напишете надежный код для интеграции с любым ОФД или внешним сервисом, обеспечив точность данных в вашей системе 1С.

← На главную