При ведении технологических логов, разработке систем регистрации высокочастотных событий или анализе производительности систем в платформе «1С:Предприятие 8» крайне важно фиксировать точный момент времени. Стандартный тип Дата поддерживает точность только до секунды. Чтобы обойти это ограничение, разработчики часто используют системную функцию ТекущаяУниверсальнаяДатаВМиллисекундах(). Она возвращает числовое значение — количество миллисекунд, прошедших с начала нашей эры (01.01.0001 00:00:00).
Однако работать с огромными числами вида 63723256363572 человеку крайне неудобно. Возникает естественная задача: как вернуть эти системные миллисекунды к привычному для глаза представлению (например, "23.04.2020 19:32:43"). В этой статье мы подробно разберем, как выполнить это преобразование правильно, избежав типичных ошибок с часовыми поясами, и рассмотрим современные стандарты разработки в среде 1С.
Для начала разберем базовый алгоритм преобразования. Поскольку точка отсчета для функции ТекущаяУниверсальнаяДатаВМиллисекундах() — это начало нашей эры (01.01.0001 00:00:00), а платформа 1С позволяет складывать объекты типа Дата с числами (интерпретируя числа как секунды), наша задача сводится к простому арифметическому действию:
Цел() для отсечения дробной части.Дата(1, 1, 1).Давайте посмотрим на простейший пример кода, реализующий эту математику:
ВсегоМиллисекунд = 63723256363572; // Значение из лога
Секунды = Цел(ВсегоМиллисекунд / 1000);
УниверсальнаяДата = Дата(1, 1, 1) + Секунды;
// В результате мы получим универсальное (GMT/UTC) время в формате Дата
Однако здесь мы сталкиваемся с первой серьезной проблемой: полученное время будет универсальным (по Гринвичу). Оно будет отличаться от локального времени пользователя на величину смещения его часового пояса. Если просто вывести эту дату пользователю, он увидит искаженные данные.
На различных форумах часто можно встретить решение, в котором к полученной универсальной дате вручную прибавляют секунды смещения стандартного и летнего времени с помощью соответствующих функций платформы. Выглядит это примерно так:
// ВНИМАНИЕ: Данный подход является устаревшим и не рекомендуется к использованию!
ЧасовойПоясЛокальный = ЧасовойПояс();
Смещение = СмещениеСтандартногоВремени(ЧасовойПоясЛокальный) + СмещениеЛетнегоВремени(ЧасовойПоясЛокальный);
ЛокальнаяДата = УниверсальнаяДата + Смещение;
Давайте проанализируем, почему этот метод считается устаревшим и потенциально ошибочным:
ЧасовойПояс() возвращает часовой пояс операционной системы, на которой выполняется код. В клиент-серверном варианте при выполнении кода на сервере функция вернет часовой пояс сервера. Если сервер физически расположен в Москве (UTC+3), а пользователь работает во Владивостоке (UTC+10), то вычисленное время лога окажется неверным для локального восприятия пользователя.Чтобы избежать ручных математических расчетов смещений и проблем со сменой законодательства, в платформе 1С предусмотрена встроенная функция МестноеВремя(). Она автоматически учитывает все особенности часового пояса и правила перехода на летнее/зимнее время на конкретную указанную дату.
Для определения часового пояса конкретного пользователя необходимо использовать функцию ЧасовойПоясСеанса() вместо общего метода ЧасовойПояс(). Это гарантирует корректность отображения времени независимо от того, где физически запущен рабочий процесс сервера 1С.
Разберем готовый и правильный алгоритм преобразования:
ВсегоМиллисекунд = 63723256363572;
// Преобразуем миллисекунды в секунды
Секунды = Цел(ВсегоМиллисекунд / 1000);
// Получаем дату по универсальному времени (UTC)
УниверсальнаяДата = Дата(1, 1, 1) + Секунды;
// Преобразуем универсальное время в локальное время сеанса пользователя
ЛокальноеВремя = МестноеВремя(УниверсальнаяДата, ЧасовойПоясСеанса());
// Форматируем для вывода пользователю
СтрокаВремени = Формат(ЛокальноеВремя, "ДФ='dd.MM.yyyy HH:mm:ss'");
// Результат будет соответствовать локальному времени события
Хотя для общего понимания времени миллисекунды могут казаться избыточными, при разборе логов высоконагруженных систем они играют решающую роль. Без них невозможно понять, какое из двух событий произошло раньше в рамках одной секунды.
Поскольку стандартный тип 1С Дата хранит время с точностью до секунды, при простом преобразовании миллисекунды отсекаются. Чтобы сохранить их при выводе, нам нужно вычислить остаток от деления исходного числа на 1000 и принудительно добавить его к результирующей строке.
Рассмотрим, как это реализовать на практике с получением красивой строки формата ДД.ММ.ГГГГ ЧЧ:ММ:СС.ссс:
ВсегоМиллисекунд = 63723256363572;
// Вычисляем чистые секунды и остаток миллисекунд
Секунды = Цел(ВсегоМиллисекунд / 1000);
Миллисекунды = ВсегоМиллисекунд % 1000;
// Получаем локальную дату
УниверсальнаяДата = Дата(1, 1, 1) + Секунды;
ЛокальнаяДата = МестноеВремя(УниверсальнаяДата);
// Форматируем дату и добавляем к ней миллисекунды с заполнением нулями слева
СтрокаМиллисекунд = Формат(Миллисекунды, "ЧЦ=3; ЧН=000; ЧВН=; ЧГ=");
РезультатСМиллисекундами = Формат(ЛокальнаяДата, "ДФ='dd.MM.yyyy HH:mm:ss'") + "." + СтрокаМиллисекунд;
// На выходе получим строку вида: "23.04.2020 19:32:43.572"
Если вы разрабатываете решение на базе типовой конфигурации 1С, в вашем распоряжении уже есть готовые инструменты БСП для работы с часовыми поясами. Использование стандартной библиотеки позволяет сделать код чище и безопаснее.
Например, для перевода локальной даты в международный формат ISO 8601 (часто требуемый при передаче логов во внешние системы мониторинга, такие как Elasticsearch или Kibana) можно использовать следующую функцию:
// Преобразуем дату со смещением относительно UTC
СтрокаISO = ОбщегоНазначения.ПредставлениеЛокальнойДатыСоСмещением(ЛокальнаяДата);
// Результат: "2020-04-23T19:32:43+03:00"
Если вам требуется получить текущее время на клиенте с минимальными затратами производительности (без постоянных обращений к серверу), БСП предоставляет метод ОбщегоНазначенияКлиент.ДатаСеанса(). Он использует оптимизированный кэш разницы во времени, полученный при запуске системы.
При интеграции 1С со сторонними веб-сервисами, написанными на JavaScript, Python или PHP, разработчики часто путают внутренние миллисекунды 1С и стандарт Unix Timestamp.
Разберем ключевые отличия:
Если передать число миллисекунд 1С во внешнюю систему без конвертации, она вернет некорректную дату в далеком будущем. Для правильной конвертации необходимо вычитать или прибавлять разницу между этими двумя точками отсчета.
Давайте посмотрим на алгоритмы взаимного перевода:
// 1. Конвертируем дату 1С в Unix Timestamp (в миллисекундах)
ДатаНачалаUnix = Дата(1970, 1, 1);
УниверсальнаяДата1С = Дата(1, 1, 1) + Цел(ВсегоМиллисекунд1С / 1000);
ОстатокМс = ВсегоМиллисекунд1С % 1000;
UnixTimestampMs = ((УниверсальнаяДата1С - ДатаНачалаUnix) * 1000) + ОстатокМс;
// 2. Обратная конвертация из Unix Timestamp в дату 1С
UnixTimestampMs_Вход = 1587669163572; // Пример Unix миллисекунд
Дата1С = Дата(1970, 1, 1) + (UnixTimestampMs_Вход / 1000);
ЛокальнаяДата1С = МестноеВремя(Дата1С);
Подводя итоги, отметим, что перевод системных миллисекунд 1С в читаемый формат — задача несложная, но требующая аккуратного отношения к часовым поясам. Использование связки математического деления, базовой даты Дата(1, 1, 1) и платформенной функции МестноеВремя() позволяет получить точный, надежный и устойчивый к законодательным изменениям результат.