Как получить количество секунд из даты в запросе 1С (Unix Timestamp)

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

В процессе разработки интеграций с внешними веб-сервисами, мобильными приложениями или при работе со сторонними базами данных перед разработчиком 1С часто возникает задача передать дату в универсальном числовом формате. Наиболее распространенным стандартом для этого является Unix Timestamp — количество секунд, прошедших с полуночи (00:00:00 UTC) 1 января 1970 года.

Если во встроенном языке 1С разность дат вычисляется простым арифметическим вычитанием, то внутри запросов действуют строгие правила СУБД. В этой статье мы подробно разберем, как правильно решить эту задачу непосредственно в запросе 1С, рассмотрим важные технические нюансы, связанные с переполнением типов данных, и научимся корректировать часовые пояса.

Базовое решение: Использование функции РАЗНОСТЬДАТ

Для вычисления разницы между двумя датами в языке запросов 1С предусмотрена специализированная функция РАЗНОСТЬДАТ. Она принимает три параметра: начальную дату, конечную дату и единицу измерения (секунда, минута, час, день и т.д.).

Давайте посмотрим на классический пример запроса, который преобразует дату из поля Период в количество секунд с начала Unix-эпохи (1 января 1970 года):


ВЫБРАТЬ
    РАЗНОСТЬДАТ(ДАТАВРЕМЯ(1970, 1, 1, 0, 0, 0), Таблица.Период, СЕКУНДА) КАК СекундыUnix
ИЗ
    РегистрСведений.КурсыВалют КАК Таблица

В данном примере функция ДАТАВРЕМЯ(1970, 1, 1, 0, 0, 0) задает статическую точку отсчета. Функция РАЗНОСТЬДАТ вычитает эту точку из значения поля Период и возвращает результат в секундах. Это простое и изящное решение, однако при его использовании на реальных базах данных вы гарантированно столкнетесь с серьезными проблемами, которые мы разберем далее.

Проблема №1: Критическая ошибка переполнения СУБД (DATEDIFF overflow)

Это самая распространенная ловушка, в которую попадают разработчики. Если в вашей таблице поле Период окажется незаполненным (то есть будет содержать пустую дату 1С — 01.01.0001 00:00:00), запрос аварийно завершит работу.

Вы увидите ошибку СУБД, которая в MS SQL Server выглядит следующим образом: «Функция datediff вызвала переполнение. Слишком большое количество частей даты...».

Выясним причину этой ошибки: СУБД пытается вычислить разницу в секундах между 1-м годом нашей эры и 1970-м годом. Полученное значение составляет примерно 62 миллиарда секунд. Однако для возврата результата функции разности дат СУБД использует стандартное 32-битное знаковое целое число (тип INT), максимальное значение которого ограничено числом 2 147 483 647 (около 68 лет в секундах). Число 62 миллиарда физически не помещается в этот лимит, что и вызывает аппаратный сбой.

Решение проблемы: Чтобы предотвратить падение запроса, нам необходимо обязательно защитить вычисление с помощью условной конструкции ВЫБОР КОГДА. Мы будем производить расчет только в том случае, если целевая дата больше нашей базовой даты (1970 год):


ВЫБРАТЬ
    ВЫБОР 
        КОГДА Таблица.Период > ДАТАВРЕМЯ(1970, 1, 1, 0, 0, 0) 
            ТОГДА РАЗНОСТЬДАТ(ДАТАВРЕМЯ(1970, 1, 1, 0, 0, 0), Таблица.Период, СЕКУНДА) 
        ИНАЧЕ 0 
    КОНЕЦ КАК СекундыUnixЗащищенные
ИЗ
    РегистрСведений.КурсыВалют КАК Таблица

Этот подход гарантирует стабильность работы информационной системы, исключая любые аномалии с пустыми или некорректными датами в базе данных.

Проблема №2: Корректировка часовых поясов (UTC против Локального времени)

Классический Unix Timestamp по стандарту должен рассчитываться относительно всемирного координированного времени (UTC). В то же время в базах данных 1С даты документов, транзакций и записей регистров чаще всего хранятся по местному времени (времени сервера или пользователя).

Конструкция ДАТАВРЕМЯ(1970, 1, 1) в запросе создает «локальную» дату. Если мы просто вычислим разность, полученный результат будет отличаться от истинного Unix-времени на величину вашего часового пояса. Например, для Московского времени (UTC+3) погрешность составит ровно 3 часа (или 10 800 секунд).

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

Рассмотрим пример реализации такого запроса:


ВЫБРАТЬ
    ВЫБОР 
        КОГДА Таблица.Период > ДАТАВРЕМЯ(1970, 1, 1, 0, 0, 0) 
            ТОГДА РАЗНОСТЬДАТ(ДАТАВРЕМЯ(1970, 1, 1, 0, 0, 0), Таблица.Период, СЕКУНДА) - &СмещениеВСекундах
        ИНАЧЕ 0 
    КОНЕЦ КАК ИстинныйUnixTimestamp
ИЗ
    РегистрСведений.КурсыВалют КАК Таблица

В коде встроенного языка перед выполнением этого запроса мы должны передать разницу между локальным временем и UTC:


// Определяем смещение локального времени относительно UTC в секундах
ТекущаяДатаЛокал = ТекущаяДата();
ТекущаяДатаUTC = УниверсальноеВремя(ТекущаяДатаЛокал);
СмещениеВСекундах = ТекущаяДатаЛокал - ТекущаяДатаUTC;

Запрос = Новый Запрос;
Запрос.Текст = "..."; // Текст запроса, приведенный выше
Запрос.УстановитьПараметр("СмещениеВСекундах", СмещениеВСекундах);
Результат = Запрос.Выполнить();

Такой подход обеспечивает математическую точность интеграции с любыми внешними веб-сервисами независимо от того, в каком часовом поясе физически запущен сервер 1С.

Альтернатива: Вычисления во встроенном языке (вне запроса)

Если перед вами не стоит жесткая задача агрегации или группировки данных по секундам непосредственно внутри базы данных, производить расчеты в запросе не обязательно. Встроенный язык 1С предлагает гораздо более простой синтаксис для работы с временными интервалами.

При обычном вычитании одной даты из другой платформа автоматически возвращает результат в секундах. Давайте посмотрим на примеры:

  1. Простой перевод локальной даты в секунды:
    
    Дата1С = ТекущаяДата();
    КоличествоСекунд = Дата1С - '19700101000000';
    
  2. Получение точного Unix-времени с учетом UTC:
    
    Дата1С = ТекущаяДата();
    КоличествоСекундUTC = УниверсальноеВремя(Дата1С) - '19700101000000';
    

Использование встроенного языка значительно упрощает чтение кода и полностью защищает от ошибок переполнения СУБД, так как платформа 1С автоматически масштабирует разрядность чисел при вычислениях на клиенте или сервере.

Дополнительно: Получение временных меток в миллисекундах

Многие современные веб-API (в частности, написанные на Node.js, Java, а также интеграции с криптобиржами) требуют передачи Timestamp не в секундах, а в миллисекундах. Это выражается в виде 13-значного числа.

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


ВЫБРАТЬ
    ВЫБОР 
        КОГДА Таблица.Период > ДАТАВРЕМЯ(1970, 1, 1, 0, 0, 0) 
            ТОГДА РАЗНОСТЬДАТ(ДАТАВРЕМЯ(1970, 1, 1, 0, 0, 0), Таблица.Период, СEКУНДА) * 1000
        ИНАЧЕ 0 
    КОНЕЦ КАК TimestampВМиллисекундах
ИЗ
    РегистрСведений.КурсыВалют КАК Таблица

При этом стоит учитывать, что три последних знака полученного числа всегда будут нулевыми (например, 1609459200000), но такой формат будет полностью валиден и успешно принят любой принимающей JSON-системой.

Подведем итоги: Конвертация даты в секунды в запросе 1С — это простая задача, требующая, однако, внимания к деталям. Всегда используйте конструкцию ВЫБОР КОГДА для предотвращения падения СУБД при обработке пустых дат и не забывайте корректировать часовой пояс, если ваша система обменивается данными с внешним миром.

← На главную