При закрытии периода или расчете регламентных операций (например, при учете НДС) разработчики нередко сталкиваются с ситуацией, когда итоговый документ должен гарантированно проводиться самым последним в месяце. Однако при попытке записать его на 23:59:59 он может оказаться в журнале или выборке раньше других документов, созданных на ту же секунду. Разберем, как устроена работа со временем в платформе «1С:Предприятие» и какие решения позволяют выстроить правильную хронологию.
Выясним причину такого поведения платформы. В «1С:Предприятии» тип данных Дата хранит значение с дискретностью строго до одной секунды (в формате ГГГГММДДччммсс). Никаких долей секунды, миллисекунд или микросекунд во встроенном языке и СУБД для этого типа не существует.
Когда мы сравниваем два документа или упорядочиваем их на временной оси, платформа использует объект МоментВремени. Он состоит из двух частей:
UUID).Если дата и секунда у двух документов совпадают (например, оба имеют время 31.01.2024 23:59:59), их взаимное расположение определяется исключительно двоичным сравнением их ссылок. Так как UUID генерируется платформой с использованием сетевых параметров и случайных значений, документ, созданный позже реального времени, вполне может получить идентификатор, который при сравнении окажется «меньше». Полагаться на порядок ввода документов внутри одной и той же секунды категорически нельзя.
Проанализируем самый надежный и простой способ решения проблемы. Если один документ логически должен проводиться строго после другого, им необходимо назначить разное время в рамках последней минуты месяца.
Например, в типовых конфигурациях регламентные документы выстраиваются по фиксированной секундной сетке:
23:59:58.23:59:59.Посмотрим на пример установки нужного времени в модуле документа или подписке на событие ПередЗаписью:
Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
// Устанавливаем время на предпоследнюю секунду месяца
КонецТекущегоДня = КонецДня(ЭтотОбъект.Дата);
ЭтотОбъект.Дата = КонецТекущегоДня - 1; // 23:59:58
КонецПроцедуры
Если требуется управлять позицией документа относительно других документов дня при интерактивной или программной записи, можно использовать метод УстановитьВремя():
// Установка времени документа последним в пределах указанной даты
ДокументОбъект.УстановитьВремя(РежимАвтоВремя.Последним, Истина);
ДокументОбъект.Записать(РежимЗаписиДокумента.Проведение);
Часто задача поставить документ «в самую последнюю долю секунды» возникает из-за необходимости собрать остатки или обороты регистра строго со всеми движениями текущего месяца. Если передать в параметры виртуальной таблицы МоментВремени() документа на 23:59:59, часть движений других документов этой же секунды может выпасть из-за меньшего значения их UUID.
Чтобы гарантированно включить все движения за весь месяц, сформируем объект Граница на начало следующего месяца с видом Исключая:
// Получаем первую секунду следующего месяца
НачалоСледующегоМесяца = НачалоМесяца(ДобавитьМесяц(ДатаДокумента, 1));
// Создаем границу, исключающую первую секунду следующего месяца
ПараметрПериод = Новый Граница(НачалоСледующегоМесяца, ВидГраницы.Исключая);
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Остатки.Счет,
| Остатки.СуммаОстаток
|ИЗ
| РегистрБухгалтерии.Хозрасчетный.Остатки(&Период, , , ) КАК Остатки";
Запрос.УстановитьПараметр("Период", ПараметрПериод);
В этом случае запрос учтет абсолютно все движения, совершенные вплоть до 23:59:59 включительно, независимо от внутренних идентификаторов документов.
Когда требуется обеспечить строгий логический порядок проведения разнородных документов без привязки к секундам, используют объект метаданных Последовательность.
Использование последовательностей полностью исключает зависимость логики учета от случайного совпадения времени документов.