В процессе разработки на платформе 1С:Предприятие программисты часто сталкиваются со стандартным ограничением типа данных Дата. В системе 1С этот тип данных всегда хранит время с точностью до секунды. Это накладывает ограничение на использование периодических регистров сведений: вы не можете штатно записать две разные записи в одну секунду для одного набора измерений, так как система посчитает их дублями или просто перезапишет старую запись новой.
Такая потребность возникает при создании систем высокочастотного логирования, протоколирования обменов данными, записи замеров производительности или при работе с внешним оборудованием. Разберем подробно, как обойти это ограничение и реализовать «сверхсекундную» точность.
Проанализируем самый распространенный и надежный способ. Поскольку мы не можем изменить поведение системного поля Период, нам необходимо создать структуру, которая позволит различать записи внутри одной секунды. Для этого мы создаем непериодический регистр сведений (или оставляем его периодическим, если это удобно, но добавляем уникальный ключ).
Рассмотрим по шагам добавление измерения для хранения долей секунды:
ДатаСобытия с типом Дата (состав даты — Дата и время).Миллисекунды (или Микросекунды) с типом Число. Длина — 3 (для миллисекунд) или 6 (для микросекунд), точность — 0, неотрицательное.Теперь в программном коде при записи данных мы будем разделять время на две составляющие. Посмотрим на пример кода получения точного времени:
// Получаем текущую универсальную дату в миллисекундах (доступно в новых версиях платформы)
ВсегоМиллисекунд = ТекущаяУниверсальнаяДатаВМиллисекундах();
// Вычисляем компоненты для записи
ТекущаяДатаСекунды = ТекущаяДата(); // Стандартная дата
ДолиСекунды = ВсегоМиллисекунд % 1000; // Остаток от деления — это наши миллисекунды
// Запись в регистр
МенеджерЗаписи = РегистрыСведений.НашЛогСобытий.СоздатьМенеджерЗаписи();
МенеджерЗаписи.ДатаСобытия = ТекущаяДатаСекунды;
МенеджерЗаписи.Миллисекунды = ДолиСекунды;
// ... заполнение остальных измерений и ресурсов
МенеджерЗаписи.Записать();
В ситуациях, когда нам не важна астрономическая точность (конкретная миллисекунда), а важна лишь последовательность записей внутри одной секунды, можно использовать измерение-счетчик. Рассмотрим ситуацию: в одну секунду происходит 10 событий. Нам нужно, чтобы они выстроились в строгом порядке.
В этом случае мы добавляем измерение Порядок (тип Число). При записи каждой следующей порции данных в рамках одной транзакции или одного процесса мы инкрементируем это число. Это гарантирует уникальность ключа записи и позволяет сортировать данные в правильном хронологическом порядке.
Выясним, как эту задачу решают разработчики фирмы 1С. В БСП существует регистр сведений ЗамерыПроизводительности. Если мы проанализируем его структуру, то увидим, что основным ключевым полем там выступает не дата, а числовое поле большой разрядности, куда записывается момент времени в микросекундах.
Для получения таких данных используются специализированные функции платформы. Рассмотрим пример получения момента времени высокой точности:
// Использование встроенной функции платформы для высокоточных замеров
МоментНачала = ТекущаяУниверсальнаяДатаВМиллисекундах();
// Выполнение полезной нагрузки
// ...
МоментОкончания = ТекущаяУниверсальнаяДатаВМиллисекундах();
Продолжительность = МоментОкончания - МоментНачала;
Такой подход позволяет полностью отказаться от типа Дата в качестве измерения, если вам требуется только математическая разница между событиями или их строгая сортировка.
Поскольку наш регистр теперь фактически не является периодическим (с точки зрения платформы), мы теряем возможность использовать виртуальную таблицу СрезПоследних. Разберем, как написать запрос, который вернет актуальные данные с учетом долей секунды.
Нам потребуется использовать вложенный запрос для поиска максимального момента времени. Проанализируем этот алгоритм:
ВЫБРАТЬ
МаксимальныеДаты.Измерение1,
МАКС(Лог.Миллисекунды) КАК МаксМиллисекунды
ПОМЕСТИТЬ ВТ_МаксимальныеМоменты
ИЗ
(ВЫБРАТЬ
Измерение1,
МАКС(ДатаСобытия) КАК МаксДата
ИЗ
РегистрСведений.НашЛогСобытий
ГРУППИРОВАТЬ ПО
Измерение1) КАК МаксимальныеДаты
ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.НашЛогСобытий КАК Лог
ПО МаксимальныеДаты.Измерение1 = Лог.Измерение1
И МаксимальныеДаты.МаксДата = Лог.ДатаСобытия
ГРУППИРОВАТЬ ПО
МаксимальныеДаты.Измерение1;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
Регистр.ДатаСобытия,
Регистр.Миллисекунды,
Регистр.РесурсЗначение
ИЗ
РегистрСведений.НашЛогСобытий КАК Регистр
ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_МаксимальныеМоменты КАК Тмп
ПО Регистр.Измерение1 = Тмп.Измерение1
И Регистр.Миллисекунды = Тмп.МаксМиллисекунды
Важный нюанс: Для обеспечения высокой скорости таких запросов необходимо, чтобы измерения ДатаСобытия и Миллисекунды были проиндексированы. В настройках регистра сведений установите свойство Индексировать у соответствующих полей.
При работе с высокочастотными регистрами следует учитывать несколько критических факторов:
УникальныйИдентификатор. Это гарантирует, что записи никогда не совпадут, однако GUID не обеспечивает хронологического порядка при сортировке. Поэтому для временных шкал лучше использовать именно числовые микросекунды или инкрементный индекс.Подводя итог, можно сказать: хотя штатного механизма «миллисекундного периода» в 1С нет, комбинация непериодического регистра и дополнительного числового измерения полностью решает задачу, обеспечивая при этом высокую производительность и точность данных.