Как получить дату создания документа из его ссылки (UUID) и записать в таблицу значений

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

В практике разработки на платформе 1С часто возникает задача определить время создания документа или иного объекта, особенно если в самой конфигурации нет соответствующего реквизита. Платформа 1С:Предприятие генерирует ссылки (UUID) на основе стандарта RFC 4122 (версия 1), который включает в себя метку времени. В данной статье мы подробно разберем, как извлечь эту дату и эффективно записать ее в таблицу значений, избегая типичных ошибок производительности.

Понимание структуры UUID версии 1

Прежде чем переходить к коду, проанализируем ситуацию. Уникальный идентификатор версии 1 (UUID v1) состоит из временной метки (timestamp), которая представляет собой количество 100-наносекундных интервалов с 15 октября 1582 года (начало григорианского календаря). Платформа 1С переставляет байты в этом идентификаторе, поэтому для корректного извлечения даты нам необходимо выполнить определенные манипуляции со строковым представлением GUID.

Базовый алгоритм извлечения даты из ссылки

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


Функция ДатаСозданияСсылки(Ссылка) Экспорт
    Если НЕ ЗначениеЗаполнено(Ссылка) Тогда
        Возврат Неопределено;
    КонецЕсли;

    Момент = Дата(1, 1, 1);
    Попытка
        // Получаем строковое представление UUID
        УИ = Строка(Ссылка.УникальныйИдентификатор());
        УИ = ВРег(СтрЗаменить(УИ, "-", ""));

        // Проверяем 13-й символ: он должен быть равен "1" для UUID v1
        Если Сред(УИ, 13, 1) = "1" Тогда
            // Переставляем части строки согласно алгоритму формирования метки времени
            Значение16 = ВРег(Сред(УИ, 14, 3) + Сред(УИ, 9, 4) + Сред(УИ, 1, 8));
            
            // Преобразуем из 16-ричной системы в 10-тичную
            Цифры16 = "0123456789ABCDEF";
            Значение10 = 0;
            Длина16 = СтрДлина(Значение16);
            
            Для Ном = 1 По Длина16 Цикл
                Значение10 = Значение10 + Pow(16, Длина16 - Ном) * (Найти(Цифры16, Сред(Значение16, Ном, 1)) - 1);
            КонецЦикла;

            // Конвертируем интервалы в секунды и добавляем к базовой дате
            Значение10 = Значение10 / 10000000;
            Момент = Дата(1582, 10, 15, 3, 0, 0) + Значение10;
        КонецЕсли;
    Исключение
        // В случае ошибки возвращаем пустую дату
    КонецПопытки;

    Возврат Момент;
КонецФункции

Обратите внимание на важный нюанс: в коде выше используется смещение 3 часа (в строке Дата(1582, 10, 15, 3, 0, 0)). Это ручная корректировка под часовой пояс (например, MSK). В идеале следует получать время в UTC и использовать функцию МестноеВремя() для корректного отображения пользователю.

Запись данных в таблицу значений

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

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


// Предположим, Результат2 — это таблица значений с колонкой "ЗаказПокупателя"
Результат2.Колонки.Добавить("Момент", Новый ОписаниеТипов("Дата"));

Для Каждого СтрокаТЗ Из Результат2 Цикл
    // Вызываем нашу функцию для каждой строки
    СтрокаТЗ.Момент = ДатаСозданияСсылки(СтрокаТЗ.ЗаказПокупателя);
КонецЦикла;

Оптимизация производительности: Ускоряем в 10 раз

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

  1. Отказ от функции Pow(): Возведение в степень внутри цикла — очень дорогая операция. Начиная с платформы 8.3.10, в 1С появилась встроенная функция ЧислоИзШестнадцатеричнойСтроки().
  2. Прямое обращение к методу: Вместо Ссылка.УникальныйИдентификатор (как свойство) лучше использовать Ссылка.УникальныйИдентификатор() (как метод), чтобы избежать лишних обращений к базе данных.
  3. Минимизация объектов: Использование ЗаполнитьЗначенияСвойств со структурами внутри цикла создает лишнюю нагрузку на память. Прямое присваивание Строка.Момент = ... гораздо эффективнее.

Посмотрим на оптимизированный вариант функции конвертации:


Функция ДатаСозданияСсылкиОптимизированная(Ссылка) Экспорт
    УИ = СтрЗаменить(Строка(Ссылка.УникальныйИдентификатор()), "-", "");
    Если Сред(УИ, 13, 1) <> "1" Тогда
        Возврат Дата(1, 1, 1);
    КонецЕсли;
    
    // Формируем правильную последовательность байтов
    Стр16 = Сред(УИ, 14, 3) + Сред(УИ, 9, 4) + Сред(УИ, 1, 8);
    
    // Используем встроенную функцию платформы для скорости
    Тики = ЧислоИзШестнадцатеричнойСтроки(Стр16);
    Секунды = Тики / 10000000;
    
    // 12219292800 — это разница в секундах между 15.10.1582 и 01.01.0001
    Возврат Дата(1, 1, 1) + (Секунды - 12219292800); 
КонецФункции

Альтернативный подход: Использование СКД

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

Для этого выполним следующие шаги:

  1. Поместим функцию ДатаСозданияСсылки в общий модуль с включенным признаком "Сервер" и "Вызов сервера".
  2. В СКД на закладке "Вычисляемые поля" добавим новое поле ДатаСоздания.
  3. В выражении этого поля пропишем вызов функции модуля: ИмяОбщегоМодуля.ДатаСозданияСсылки(ЗаказПокупателя).

Этот метод предпочтительнее, так как 1С сама оптимизирует выборку данных и вывод результата.

Ограничения метода извлечения даты из UUID

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

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

← На главную