Как правильно использовать МоментВремени и Границу для получения остатков и оборотов в 1С?

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

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

Понятие Момента времени и позиционирование документа

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

Здесь на сцену выходит МоментВремени. Это специальный объект платформы, который состоит из двух составляющих: даты (со временем) и ссылки на документ (регистратор). Рассмотрим подробнее, как платформа выстраивает документы в «линейку времени»:

  1. Дата и время: Первичный критерий сортировки.
  2. Тип метаданных: Если время совпадает, 1С сравнивает внутренние идентификаторы типов документов. Важно понимать, что этот порядок зашит в конфигурации. Например, документы типа ПриходнаяНакладная могут всегда стоять перед РасходнаяНакладная при одинаковом времени, просто в силу их внутреннего ID в дереве метаданных.
  3. Уникальный идентификатор ссылки: Если совпадает и время, и тип документа, то финальным критерием становится GUID ссылки.

Таким образом, МоментВремени — это уникальная «координата» документа на временной оси, которая позволяет системе четко сказать, какие записи регистра были сделаны до него, а какие после (поможет групповое перепроведение документов и восстановление последовательности).

Объект Граница: Включая или Исключая?

Сам по себе МоментВремени просто указывает на точку. Но когда мы передаем эту точку в запрос (например, в параметры виртуальной таблицы), нам нужно уточнить: хотим ли мы видеть данные «по эту точку включительно» или «строго до этой точки»? Для этого используется объект Граница.

Рассмотрим два варианта использования ВидГраницы:

  1. ВидГраницы.Включая: Если мы передаем момент времени документа с этим видом границы, система учтет все движения, сделанные этим документом, и всеми документами, которые стоят в очереди до него.
  2. ВидГраницы.Исключая: В этом случае система возьмет все движения документов, стоящих в очереди ПЕРЕД текущим, но движения самого указанного документа в расчет не попадут.

Посмотрим на пример создания такого объекта в коде:


// Получаем момент времени конкретного документа
МоментДокумента = Объект.Ссылка.МоментВремени();

// Создаем границу, которая включает движения документа
ГраницаВключая = Новый Граница(МоментДокумента, ВидГраницы.Включая);

// Создаем границу, которая НЕ включает движения документа
ГраницаИсключая = Новый Граница(МоментДокумента, ВидГраницы.Исключая);

Особенности работы виртуальной таблицы Остатки

Виртуальная таблица Остатки имеет свои правила «по умолчанию», которые часто сбивают с толку новичков. Для этой задачи есть выявление и контроль ошибок в учёте товаров. Выясним причину странного поведения, когда при передаче даты остатки получаются «не те», используя для отладки управляемую консоль запросов.

Если в параметр Период таблицы Остатки передать обычную Дата, система всегда трактует это как исключая. То есть, если вы передадите '2023-12-31 23:59:59', остатки будут рассчитаны на начало этой секунды. Все движения, сделанные в 59-ю секунду, учтены не будут.

Для получения корректных остатков на конец дня или на момент документа, а также для таких задач, как интерактивное формирование текста запроса для иерархии, проанализируем следующие подходы:

Поведение в таблице Обороты

В отличие от остатков, виртуальная таблица Обороты работает по принципу инклюзивности. Параметры НачалоПериода и КонецПериода по умолчанию включают указанную дату или момент времени.

Разберем ситуацию: если вы укажете в качестве конца периода МоментВремени документа (без использования Граница), то обороты этого документа попадут в выборку. Это логично для отчетов, но требует внимательности при совмещении данных из таблиц остатков и оборотов в одном запросе.

Техническая реализация на уровне SQL

Многие задаются вопросом: как 1С превращает объект Граница в SQL-запрос? Понимание этого процесса снимает магию с «моментов времени». На уровне СУБД 1С не хранит тип «Момент времени». Платформа разворачивает условие по границе в составной фильтр по полям Period (Дата) и Recorder (Ссылка).

Например, условие Граница(МоментВремениДокумента, Включая) трансформируется в SQL примерно так:


WHERE (Period < ДатаДокумента) 
   OR (Period = ДатаДокумента AND Recorder <= СсылкаДокумента)

Именно сравнение ссылок (Recorder <= СсылкаДокумента) позволяет системе точно определить местоположение границы внутри одной секунды. При этом сравнение ссылок идет по их внутреннему двоичному представлению.

Практические советы и производительность

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

  1. Пустые ссылки: Никогда не пытайтесь получить МоментВремени от нового, еще не записанного в базу документа. Поле Ссылка у него будет пустым, и результат работы Границы в запросе будет непредсказуемым (скорее всего, запрос вернет пустой результат или ошибку). Сначала Записать(), потом получение остатков.
  2. Производительность: Получение остатков на МоментВремени — операция достаточно быстрая, так как поле Период и Регистратор входят в индексы таблиц итогов и движений. Однако помните, что расчет на конкретный момент требует от системы «докрутки» оборотов от ближайшей точки хранения итогов (начала месяца).
  3. Сравнение в коде: В языке 1С вы можете сравнивать два момента времени напрямую: Если Момент1 > Момент2 Тогда.... Система сама корректно сравнит даты, а при их равенстве — приоритеты документов.

Подводя итог, можно сказать: всегда используйте Граница(МоментВремени, ВидГраницы.Включая), когда вам нужно получить состояние системы после конкретного события, и МоментВремени (или Исключая), когда нужно состояние до него. Использование простых дат в параметрах периодов — верный путь к трудноуловимым ошибкам в расчетах.

← На главную