Зачем использовать объект Граница при получении остатков на дату в 1С

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

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

Механизм работы виртуальных таблиц остатков на уровне СУБД

Для понимания логики работы платформы проанализируем, как параметры виртуальной таблицы транслируются в реальные запросы к СУБД (SQL):

  1. Передача обычной даты без границы: если в параметр Период виртуальной таблицы остатков передать обычное значение типа Дата (например, КонецДня(ТекущаяДата()), то есть 31.01.2025 23:59:59), платформа 1С всегда формирует SQL-запрос со строгим неравенством: Период < @ПараметрДата. Это означает, что все записи и движения, совершенные ровно в 23:59:59, в выборку не попадут.
  2. Передача объекта Граница с видом Включая: если передать объект Новый Граница(КонецДня(ТекущаяДата()), ВидГраницы.Включая), условие в SQL-запросе меняется на нестрогое неравенство: Период <= @ПараметрДата. В таком случае движения на последнюю секунду периода гарантированно учитываются при расчете итогов.
  3. Передача объекта Граница с видом Исключая: полностью аналогична передаче обычной даты со строгим неравенством (Период < @ПараметрДата) при работе с датой, либо отсекает текущий документ при передаче ссылки или момента времени.

Почему прибавление 1 секунды — опасная практика

В некоторых обучающих материалах встречается обходной прием: вместо создания объекта Граница разработчики просто добавляют к концу дня одну секунду (КонецДня(Дата) + 1), получая 00:00:00 следующего дня. Выясним причину, почему такой подход считается грубой ошибкой и приводит к скрытым багам в учетных системах:

  1. Смещение на границу хранения итогов: в регистрах накопления и бухгалтерии таблицы итогов по умолчанию хранятся с периодичностью в один месяц (на 00:00:00 первого числа каждого месяца). Если к дате 31.01.2025 23:59:59 прибавить одну секунду, запрос будет адресован на 01.02.2025 00:00:00. Платформа переключит алгоритм с выборки движений текущего месяца на использование итогов следующего месяца, что может кардинально изменить план выполнения запроса СУБД и повысить нагрузку на сервер.
  2. Захват документов на начало следующего дня: пользователи или регламентные механизмы могут вводить документы (например, документы ввода начальных остатков, корректировки регистров или регламентные операции) строго на 00:00:00 следующего числа. Прибавив секунду к концу текущего дня, запрос ошибочно захватит или отсечет движения, относящиеся уже к следующему дню.
  3. Неуниверсальность для объектов МоментВремени: дата в 1С дискретна до одной секунды, однако внутри одной секунды может быть зарегистрировано множество документов. Добавление секунды к дате не решает задачу позиционирования между документами внутри одной секунды, тогда как объект Граница в сочетании с МоментВремени обеспечивает точное разделение записей.

Правильные сценарии использования объекта Граница в коде

Рассмотрим типовые примеры правильного получения остатков в программном коде 1С.

Пример 1. Получение остатков на конец дня или месяца:

Когда требуется рассчитать остаток на конец определенной даты с учетом всех движений, зарегистрированных в этот день:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	ТоварыНаСкладахОстатки.Номенклатура КАК Номенклатура,
    |	ТоварыНаСкладахОстатки.КоличествоОстаток КАК КоличествоОстаток
    |ИЗ
    |	РегистрНакопления.ТоварыНаСкладах.Остатки(&ГраницаОстатков, ) КАК ТоварыНаСкладахОстатки";

ДатаКонцаДня = КонецДня(ТекущаяДата());
Запрос.УстановитьПараметр("ГраницаОстатков", Новый Граница(ДатаКонцаДня, ВидГраницы.Включая));

РезультатЗапроса = Запрос.Выполнить();

Пример 2. Контроль остатков при проведении документа:

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


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	ОстаткиНоменклатуры.Номенклатура КАК Номенклатура,
    |	ОстаткиНоменклатуры.КоличествоОстаток КАК КоличествоОстаток
    |ИЗ
    |	РегистрНакопления.ТоварыНаСкладах.Остатки(&ГраницаКонтроля, ) КАК ОстаткиНоменклатуры";

// Исключаем движения текущего документа
Запрос.УстановитьПараметр("ГраницаКонтроля", Новый Граница(ЭтотОбъект.МоментВремени(), ВидГраницы.Исключая));

РезультатЗапроса = Запрос.Выполнить();

Пример 3. Формирование печатной формы или акта сверки с учетом документа:

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


ГраницаПечати = Новый Граница(СсылкаНаДокумент.МоментВремени(), ВидГраницы.Включая);
Запрос.УстановитьПараметр("ПериодГраница", ГраницаПечати);

Особенности работы с Границей в Системе компоновки данных (СКД)

При разработке отчетов на СКД разработчики часто сталкиваются с ситуацией, когда стандартный период отчета не захватывает движения на 23:59:59. Разберем, как это обрабатывается в СКД:

  1. Если параметр виртуальной таблицы связан со стандартным диалогом выбора периода (тип СтандартныйПериод), СКД на этапе компоновки макета автоматически трансформирует правую границу в значение типа Граница со свойством ВидГраницы.Включая.
  2. Если дата в СКД передается через отдельный параметр типа Дата, в выражении параметра схемы компоновки данных необходимо явно использовать функцию приведения к концу периода: КонецПериода(&КонецПериода, "ДЕНЬ"), либо формировать программную передачу параметра в коде перед выполнением компоновки:
    
    ПараметрПериод = КомпоновщикНастроек.Настройки.ПараметрыДанных.Элементы.Найти("Период");
    Если ПараметрПериод <> Неопределено Тогда
        ПараметрПериод.Значение = Новый Граница(КонецДня(ВыбраннаяДата), ВидГраницы.Включая);
        ПараметрПериод.Использование = Истина;
    КонецЕсли;
    

Ограничения объекта Граница

Важно помнить о технических ограничениях объекта Граница:

  1. Существование только во время исполнения: Граница является сугубо программным объектом оперативной памяти (runtime-объектом). Его нельзя назначить типом реквизита в метаданных конфигурации или сохранить непосредственно в реквизит справочника или документа.
  2. Ограничения в динамических списках: в динамических списках пользователь не может вручную выбрать объект Граница в стандартном окне настройки параметров запроса. Передавать границу в параметры запроса динамического списка возможно только программно через свойства компоновщика настроек.

Таким образом, использование объекта Граница(Дата, ВидГраницы.Включая) — это не избыточность, а стандарт платформы 1С, гарантирующий математическую строгость запросов к СУБД и отсутствие ошибок при получении итогов на срезе времени.

← На главную