Как получить срез данных справочника на произвольную дату, если дата создания не фиксировалась?

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

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

Способ 1. Извлечение даты создания из GUID (UUID) объекта

Рассмотрим самый технологичный и зачастую единственный способ восстановить дату создания элемента «задним числом». В системе «1С:Предприятие 8» при создании нового объекта стандартными средствами генерируется уникальный идентификатор (GUID) версии 1. Этот стандарт подразумевает, что внутри идентификатора зашифровано время его создания (количество 100-наносекундных интервалов с момента начала Григорианского календаря).

Проанализируем структуру GUID: bdb62d89-cede-11e4-b12b-d4ae52b5e909. Временная метка содержится в первых трех группах символов, но в перевернутом виде. Для получения даты нам необходимо переставить блоки в порядке 11e4-cede-bdb62d89, убрать технический символ версии и перевести полученное шестнадцатеричное число в десятичный формат секунд.

Разберем реализацию этого метода на языке 1С. Посмотрим на функцию, которая позволяет с высокой точностью (до секунды) восстановить дату:


Функция ПолучитьДатуИзУникальногоИдентификатора(Ссылка) Экспорт
    
    ГУИД = Ссылка.УникальныйИдентификатор();
    СтрокаГ = Строка(ГУИД);
    
    // Алгоритм разбора версии 1 UUID
    // Извлекаем временные блоки: time-high, time-mid, time-low
    // И приводим их к формату: 1e4 cede bdb62d89
    Строка16 = Сред(СтрокаГ, 15, 4) + Сред(СтрокаГ, 10, 4) + Сред(СтрокаГ, 1, 8);
    
    // Убираем флаг версии (первый символ седьмого октета)
    Строка15 = Сред(Строка16, 2);
    
    // Переводим из 16-ричной системы в десятичную (секунды)
    ЧислоСек = 0;
    Для Позиция = 1 По СтрДлина(Строка15) Цикл
        Символ = Сред(Строка15, Позиция, 1);
        Значение = Найти("0123456789abcdef", Символ) - 1;
        ЧислоСек = ЧислоСек + Значение * Pow(16, СтрДлина(Строка15) - Позиция);
    КонецЦикла;
    
    // 100-наносекундные интервалы переводим в секунды
    ЧислоСек = ЧислоСек / 10000000;
    
    // Начало отсчета для UUID - 15 октября 1582 года
    ДатаСоздания = Дата(1582, 10, 15, 0, 0, 0) + ЧислоСек;
    
    // Корректировка часового пояса (при необходимости)
    Возврат ДатаСоздания + СмещениеСтандартногоВремени();
    
КонецФункции

Важное ограничение: этот метод работает только для объектов, созданных непосредственно в текущей базе. Если контрагенты загружались через обмен (РИБ, XML), они сохраняют GUID из базы-источника. Также, если GUID был сгенерирован программно методом Новый УникальныйИдентификатор() без параметров, это может быть UUID версии 4 (случайный), из которого дату извлечь невозможно.

Способ 2. Использование механизмов версионирования (БСП)

Если в вашей конфигурации используется «Библиотека стандартных подсистем» (БСП) и для справочника «Контрагенты» включено версионирование объектов, задача значительно упрощается. Выясним, как получить данные в этом случае.

Данные о версиях хранятся в регистре сведений СведенияОВерсияхОбъектов. Чтобы получить срез на дату, нам необходимо:

  1. Найти самую свежую версию объекта, дата которой меньше или равна целевой дате.
  2. Прочитать данные этой версии (обычно они хранятся в виде сжатого XML в ресурсе ВерсияОбъекта).
  3. Десериализовать объект и получить его состояние на тот момент.

Преимущество этого метода в том, что мы получаем не просто факт наличия контрагента на дату, но и все его реквизиты (ИНН, КПП, Наименование), которые могли измениться позже.

Способ 3. Платформенный механизм «История данных»

В современных версиях платформы 1С (начиная с 8.3.11) реализован системный механизм ИсторияДанных. В отличие от версионирования БСП, он работает на уровне ядра СУБД и оптимизирован по производительности.

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


Выборка = ИсторияДанных.Выбрать(Ссылка, ДатаСреза);
Если Выборка.Следующий() Тогда
    // Получаем состояние объекта на указанный момент
    ОбъектНаДату = Выборка.Данные;
КонецЕсли;

Важный нюанс: как и в случае с БСП, история данных должна быть включена до того, как объекты начали создаваться или изменяться. Задним числом платформа историю не восстановит.

Способ 4. Анализ первого упоминания в документах

Если ни версионирование, ни метод анализа GUID не подходят (например, данные загружены из сторонней системы), можно прибегнуть к методу «косвенного определения». Проанализируем транзакционную активность.

Логично предположить, что контрагент появляется в базе незадолго до оформления первого документа с его участием. Мы можем написать запрос к основным регистрам (Закупки, Продажи, Взаиморасчеты) или метаданным документов, чтобы найти самую раннюю дату записи, где фигурирует наш объект Ссылка.

Пример структуры такого запроса:

  1. Выбрать Минимум(Дата) из Документ.РеализацияТоваровУслуг, где Контрагент = &Ссылка.
  2. Выбрать Минимум(Дата) из Документ.ПоступлениеТоваровУслуг.
  3. Сравнить полученные даты и взять наименьшую.

Это даст нам «бизнес-дату» появления контрагента, которая для большинства управленческих отчетов будет более значимой, чем техническая дата создания записи.

Подведение итогов

Выбор метода зависит от конфигурации и истории ведения базы:

Для предотвращения подобных сложностей в будущем, рекомендуем добавить в справочник общий реквизит ДатаСоздания и заполнять его в событии ПриУстановкеНовогоКода или ПередЗаписью (если это новый объект).

← На главную