К статье
Практический материал

Разработка и Конфигурация · 11 мин

Миллисекунды в 1С: точность времени и способы её измерения

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

Вопрос «сколько в 1С миллисекунд» обычно возникает у разработчиков в двух ситуациях: когда нужно измерить время выполнения фрагмента кода с точностью до миллисекунд и когда требуется хранить метки времени точнее секунды. Здесь кроется важная особенность платформы: встроенный тип «Дата» в 1С имеет точность только до секунды, и миллисекунды в нём не хранятся и не отображаются.

Это ограничение не означает, что работать с миллисекундами невозможно. Платформа предоставляет несколько механизмов: функцию ТекущаяУниверсальнаяДатаВМиллисекундах(), замер производительности через технологический журнал, а также возможность хранить миллисекунды в числовых полях. Каждый способ имеет свои сценарии применения и ограничения.

Ниже разобраны практические приёмы: как замерить длительность операции, как зафиксировать точное время события, какие подводные камни возникают при сравнении дат и почему округление до секунд иногда ломает логику обмена данными.

Какая точность у типа «Дата» в 1С

Тип «Дата» во встроенном языке 1С содержит календарную дату и время суток, но минимальная единица хранения — одна секунда. Если вы присвоите переменной значение ТекущаяДата() и выведете его, то увидите формат вида «01.01.0001 0:00:00» без дробной части. Любые доли секунды отбрасываются платформой автоматически.

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

Практическое следствие: если бизнес-процесс требует различать события чаще одного раза в секунду (например, поток сообщений от оборудования или высокочастотный обмен), стандартного типа «Дата» недостаточно. Нужно либо хранить миллисекунды в отдельном числовом поле, либо проектировать регистрацию событий иначе — через последовательности, очереди или составные ключи.

Как замерить время выполнения кода в миллисекундах

Основной инструмент для точных замеров — функция ТекущаяУниверсальнаяДатаВМиллисекундах(). Она возвращает число типа «Число» — количество миллисекунд, прошедших с полуночи 1 января 0001 года по универсальному времени (UTC). Само по себе это число неудобно для чтения, но разность двух таких значений даёт точную длительность операции.

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

bsl
Начало = ТекущаяУниверсальнаяДатаВМиллисекундах();
// ... измеряемый код ...
Длительность = ТекущаяУниверсальнаяДатаВМиллисекундах() - Начало;
Сообщить("Выполнено за " + Длительность + " мс");

Функция доступна начиная с версии платформы 8.3.6, в том числе на клиенте и на сервере. Возвращаемое значение — целое число, поэтому точность замера ограничена одной миллисекундой, чего достаточно для подавляющего большинства задач оптимизации.

Порядок замера длительности операции
  1. 1
    Перед измеряемым кодом сохраните значение ТекущаяУниверсальнаяДатаВМиллисекундах() в переменную
  2. 2
    Выполните целевой фрагмент кода или вызов процедуры
  3. 3
    Вычислите разность между новым и сохранённым значением
  4. 4
    Повторите замер 3–5 раз и сравните результаты — одиночный прогон искажается кэшированием
  5. 5
    Зафиксируйте медианное или минимальное значение как ориентир производительности

Почему ТекущаяДата() не подходит для точных замеров

Функция ТекущаяДата() возвращает значение типа «Дата» с точностью до секунды. Если операция занимает меньше секунды, разность двух таких значений будет равна нулю — вы не увидите реальной длительности. Для быстрых операций (запросы к СУБД, обработка небольших таблиц) это делает замер бесполезным.

Вторая проблема — часовые пояса. ТекущаяДата() на сервере возвращает время сервера, на клиенте — время клиентского компьютера, и они могут различаться. Функция ТекущаяУниверсальнаяДатаВМиллисекундах() всегда отсчитывает от UTC, поэтому разность значений корректна независимо от настроек пояса, пока оба замера выполняются в одном сеансе.

Хранение миллисекунд в базе данных

Если требуется сохранить метку времени с точностью до миллисекунд, стандартный реквизит типа «Дата» не подойдёт. Рабочее решение — добавить числовой реквизит достаточной разрядности и хранить в нём значение ТекущаяУниверсальнаяДатаВМиллисекундах(). Число это большое (порядка 15–16 знаков), поэтому длину числового поля нужно задавать с запасом — не менее 18 разрядов.

Альтернативный подход — хранить пару полей: стандартную дату (для отбора, периодических регистров и отчётов) и число миллисекунд внутри секунды (для точного упорядочивания). Такой вариант удобен, когда миллисекунды нужны только для сортировки событий внутри одной секунды, а основная логика работает с обычными датами.

При обмене данными с внешними системами (веб-сервисы, очереди сообщений, оборудование) миллисекунды часто приходят в формате Unix timestamp — числа миллисекунд с 1 января 1970 года. Для конвертации в дату 1С разделите значение на 1000, получите секунды и прибавьте их к дате начала эпохи Unix через стандартные операции с датами. Дробная часть после деления — это и есть миллисекунды, которые в тип «Дата» не поместятся.

Типичные ошибки
01
Хранение Unix timestamp в миллисекундах в числовом поле длиной 10–12 знаков — значение обрезается, метки времени искажаются
02
Замер быстрых операций через ТекущаяДата() — результат всегда ноль, выводы о производительности неверны
03
Заведение регистра сведений с периодичностью до секунды для потока событий чаще раза в секунду — конфликты уникальности при записи
04
Сравнение миллисекундных меток с разных серверов без учёта расхождения системных часов

Замер производительности: дополнительные инструменты

Ручные замеры через ТекущаяУниверсальнаяДатаВМиллисекундах() удобны для точечной проверки, но для системного анализа производительности платформа предлагает более мощные средства. Замер производительности в конфигураторе показывает длительность каждой строки кода и каждого вызова с детализацией до миллисекунд и долей миллисекунд, включая частоту вызовов.

Технологический журнал фиксирует события с точными временными метками: длительность запросов к СУБД, вызовов сервера, транзакций. Это основной инструмент диагностики «медленных» операций в рабочей базе, где нельзя вставлять отладочный код. Настройка выполняется через файл logcfg.xml, а события DBMSSQL, DBPOSTGRS, SDBL и CALL содержат поле длительности в микросекундах.

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

Способы измерения времени

ТекущаяУниверсальнаяДатаВМиллисекундах()

Точечные замеры в коде, логирование длительности операций. Ограничение: требует изменения кода

Замер производительности в конфигураторе

Анализ узких мест при разработке. Ограничение: только в отладочном сеансе, замедляет выполнение

Технологический журнал

Диагностика на рабочем сервере без изменения кода. Ограничение: требует настройки и разбора логов

Подсистема оценки производительности (БСП)

Постоянный мониторинг ключевых операций. Ограничение: доступна в конфигурациях на БСП

Частые задачи и их решения

Пауза в выполнении кода

Встроенной функции задержки (аналога Sleep) во встроенном языке нет. Если нужна пауза — например, при опросе внешнего сервиса — используют цикл ожидания с проверкой ТекущаяУниверсальнаяДатаВМиллисекундах() или внешние компоненты. Учтите: активный цикл ожидания блокирует сеанс и нагружает процессор, поэтому для длительных пауз правильнее использовать фоновые задания с повторным запуском.

Уникальные метки для событий

Когда миллисекундной метки недостаточно для уникальности (несколько событий в одну миллисекунду), комбинируйте метку времени с уникальным идентификатором или порядковым номером. Это стандартный приём для журналов событий интеграций и очередей сообщений.

Вывод длительности в читаемом виде

Разность в миллисекундах удобно приводить к секундам делением на 1000 с округлением до нужного знака. Для длительных операций форматируйте результат в минуты и секунды — пользователю проще воспринимать «2 мин 15 с», чем «135000 мс».

Контрольные точки

Как проверить корректность замера

Повторяемость результата
Норма

При 3–5 прогонах длительность отличается в пределах 10–20%

Тревожный признак

Значения скачут в разы — мешает кэш, фоновые процессы или сеть

Порядок величины
Норма

Длительность соответствует ожиданиям от операции (запрос — миллисекунды, обмен — секунды)

Тревожный признак

Нулевое значение при явно долгой операции — вероятно, замер через ТекущаяДата()

Разрядность хранения
Норма

Числовое поле вмещает 15–16 знаков без округления

Тревожный признак

Значения в базе обрезаны или хранятся в экспоненциальной форме

Ограничения и риски

Точность ТекущаяУниверсальнаяДатаВМиллисекундах() зависит от разрешения системного таймера операционной системы. На реальном оборудовании фактическая дискретность может составлять несколько миллисекунд, поэтому замеры короче 5–10 мс следует трактовать как приблизительные и усреднять по серии прогонов.

Не используйте миллисекундные метки как единственный критерий упорядочивания в распределённых системах. Часы разных серверов расходятся, и событие с более поздней меткой могло произойти раньше. Для строгого порядка применяйте серверные счётчики, номера сообщений или механизмы очередей.

Итог

Что важно запомнить

Тип «Дата» в 1С точен только до секунды. Миллисекунды доступны через ТекущаяУниверсальнаяДатаВМиллисекундах() — для замеров и хранения в числовых полях. Для системного анализа производительности используйте замер в конфигураторе и технологический журнал.

Частые вопросы

Можно ли вывести миллисекунды в формате даты, например «12:30:45.123»?

Стандартное форматирование даты такой дробной части не покажет, поскольку в типе «Дата» её нет. Решение — формировать строку вручную: отдельно выводить дату и отдельно число миллисекунд из числового значения, склеивая их строковой конкатенацией.

Работает ли ТекущаяУниверсальнаяДатаВМиллисекундах() в тонком и веб-клиенте?

Да, функция доступна на тонком клиенте, веб-клиенте, толстом клиенте и на сервере. Это делает её универсальным инструментом замеров в клиент-серверных сценариях.

Как перевести Unix timestamp в миллисекундах в дату 1С?

Разделите значение на 1000, чтобы получить секунды, затем прибавьте их к дате начала эпохи Unix (1 января 1970 года) стандартным сложением даты и числа секунд. Остаток от деления — миллисекунды, которые при необходимости сохраняйте отдельным числовым полем.

Почему два замера подряд одной операции дают разные значения?

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

Можно ли создать регистр сведений с периодичностью до миллисекунд?

Нет, максимальная периодичность регистра сведений — в пределах секунды. Если события происходят чаще, храните их в независимом регистре с числовым полем миллисекунд или используйте уникальные идентификаторы для различения записей.

Чем замерить длительность запроса к базе без изменения кода?

Включите технологический журнал с отбором событий СУБД (DBMSSQL, DBPOSTGRS и аналогичных) — в каждом событии фиксируется длительность выполнения. В конфигураторе аналогичную информацию показывает замер производительности с детализацией по строкам кода.