Как 1С работает с отметками времени и как упорядочиваются документы внутри одной секунды

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

В среде разработчиков 1С вопросы хронологии часто вызывают дискуссии. Основная сложность заключается в том, что стандартное разрешение времени в платформе составляет 1 секунду. Однако в высоконагруженных системах в одну и ту же секунду могут записываться десятки документов. Как система понимает, какой из них был "первым", и как это влияет на остатки и последовательности? Рассмотрим эти механизмы подробно.

Понятие разрешения времени и Момент времени

Разберем базовое определение. В 1С:Предприятии для любого события в базе данных минимальным квантом времени является секунда. Это означает, что в реквизите Дата документа невозможно хранить миллисекунды. Если мы программно попытаемся записать время с точностью до миллисекунд из внешней системы, платформа принудительно отсечет дробную часть.

Для того чтобы выстроить документы в однозначную очередь внутри этой секунды, используется объект МоментВремени. Проанализируем его состав:

Момент времени = Дата + Ссылка на объект

Когда мы говорим, что система определяет последовательность исходя из ссылок, мы имеем в виду техническую реализацию в СУБД. На уровне SQL-запроса, когда платформа запрашивает данные, упорядоченные по моменту времени, происходит сортировка сначала по полю _Date_Time, а затем по бинарному представлению поля _IDRRef (уникальный идентификатор GUID).

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

Оперативное проведение и "прыжки" во времени

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

  1. При создании нового документа система устанавливает ему текущую дату сеанса и "нулевое" время (00:00:00), если это начало дня.
  2. В момент оперативного проведения система запрашивает у сервера приложений текущее время.
  3. Если это время больше, чем время последнего проведенного оперативно документа, документу присваивается текущее время сервера.
  4. Если в эту же секунду уже проводился другой документ, система выполняет "прыжок": она может сместить время документа или использовать внутренние механизмы, чтобы гарантировать, что новый документ станет в конец очереди текущего дня.

Проанализируем ситуацию: если время на сервере будет переведено назад, система заблокирует оперативное проведение документов до тех пор, пока реальное время не "догонит" последнюю зафиксированную оперативную отметку. Это защищает целостность итогов регистров.

Конкуренция за ресурсы: кто захватит остатки?

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

Разберем последовательность событий в транзакции:


// Упрощенная логика проведения
Процедура ОбработкаПроведения(Отказ, Режим)
    
    // 1. Установка управляемой блокировки на остатки
    Блокировка = Новый БлокировкаДанных;
    ЭлементБлокировки = Блокировка.Добавить("РегистрНакопления.ТоварыНаСкладах");
    ЭлементБлокировки.УстановитьПараметр("Номенклатура", ВыбранныйТовар);
    Блокировка.Заблокировать();
    
    // 2. Чтение остатков
    // 3. Проверка достаточности
    // 4. Запись движений
    
КонецПроцедуры

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

При этом МоментВремени у этих документов может быть распределен иначе: второй пользователь может иметь GUID "меньше", чем у первого, и по логике 1С его документ будет стоять в списке "раньше", хотя фактически он списал остатки вторым. Это критически важно для понимания работы партионного учета.

Как вычислить последовательность программно?

Посмотрим на пример того, как можно программно получить документы в их истинном хронологическом порядке, даже если они записаны в одну секунду. Для этого в запросах следует использовать упорядочивание по полю МоментВремени.


ВЫБРАТЬ
    РеализацияТоваровУслуг.Ссылка КАК ДокументСсылка,
    РеализацияТоваровУслуг.МоментВремени КАК Момент
ИЗ
    Документ.РеализацияТоваровУслуг КАК РеализацияТоваровУслуг
ГДЕ
    РеализацияТоваровУслуг.Дата МЕЖДУ &НачалоПериода И &КонецПериода
УПОРЯДОЧИТЬ ПО
    Момент

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

Особенности получения ссылки до записи

Разберем важный нюанс, упомянутый в дискуссии: ссылку можно получить до фактической записи документа в базу данных. Метод УстановитьСсылкуНового() или ПолучитьСсылкуНового() позволяет заранее определить GUID объекта.

Это означает, что программист может влиять на будущий МоментВремени документа. Если вы заранее создадите ссылку, которая при бинарном сравнении будет "меньше" существующих в этой секунде, ваш документ "влезет" в начало очереди внутри этой секунды после записи. Однако на практике это используется крайне редко, в основном при сложных обменах данными.

Резюме для разработчика

  1. Минимальный квант — 1 секунда. Все, что "точнее", хранится в ссылке (GUID).
  2. Момент времени — это единственный надежный способ сравнить два документа на оси времени.
  3. Оперативное проведение всегда двигает границу времени вперед, предотвращая ввод документов "задним числом" в рамках текущего сеанса.
  4. Блокировки важнее ссылок: физический захват ресурсов определяется очередностью входа в транзакцию, а не тем, какая ссылка у документа.
  5. Для получения остатков "с учетом текущего документа" всегда передавайте в параметры виртуальных таблиц Новый Граница(МоментВремени, ВидГраницы.Включая).

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

← На главную