Как устроена временная шкала в 1С и сколько секунд в сутках?

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

При работе со временем и датами в платформе 1С:Предприятие у начинающих разработчиков нередко возникает вопрос: почему конец дня определяется как 23:59:59, и означает ли это, что в сутках платформы содержится 86 399 секунд вместо положенных 86 400? Разберем математическую и программную модель временной оси 1С, выясним логику отсчета секунд, а также рассмотрим механизмы корректного позиционирования событий и получения итогов на границах периодов.

Дискретность типа Дата и логика отсчета секунд

В платформе 1С:Предприятие примитивный тип Дата хранит значение с точностью до одной секунды в формате ГГГГММДДччммсс (без сохранения долей секунд). Каждая сохраненная дата является не протяженным отрезком, а дискретной точкой на временной оси, обозначающей начало соответствующей секунды.

Проанализируем распределение секунд в пределах одних суток:

  1. 1-я секунда суток: начинается в 00:00:00 (охватывает интервал от 00:00:00.000 до 00:00:00.999...).
  2. 10-я секунда суток: начинается в 00:00:09.
  3. 3600-я секунда суток: начинается в 00:59:59.
  4. 86 400-я секунда суток: начинается в 23:59:59 (охватывает интервал от 23:59:59.000 до 23:59:59.999...).

Таким образом, утверждение о том, что в сутках 1С не хватает одной секунды — ошибочно. Отсчет времени начинается с нулевой координаты (00:00:00), поэтому последняя, 86 400-я секунда суток имеет индекс со смещением в 86 399 секунд от начала дня и отображается как 23:59:59.

Разница между точками во времени и длительностью интервала

Рассмотрим, почему при вычитании начала дня из конца дня получается число 86 399, а не 86 400:


Конец = КонецДня(ТекущаяДата()); // 23:59:59
Начало = НачалоДня(ТекущаяДата()); // 00:00:00
Разница = Конец - Начало; // 86 399 секунд

Операция вычитания дат возвращает расстояние между двумя точками на оси времени. Расстояние между началом 1-й секунды (00:00:00) и началом 86 400-й секунды (23:59:59) действительно равно ровно 86 399 секундам. Если же мы прибавим к началу дня полную длительность суток (86 400 секунд), то получим точку 00:00:00 уже следующих календарных суток:

СледующиеСутки = НачалоДня(ТекущаяДата()) + 86400; // 00:00:00 следующего дня

Разрешение коллизий внутри одной секунды: МоментВремени

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

Он состоит из двух ключевых компонентов:

  1. Значение даты и времени: точность до секунды.
  2. Ссылка на объект базы данных: уникальный идентификатор (GUID), который обеспечивает строгое и детерминированное упорядочивание событий внутри одной и той же секунды.

При проведении документов в оперативном режиме платформа гарантирует, что каждый новый документ получит момент времени, находящийся на оси строго позже всех ранее проведенных документов.

Использование объекта Граница в запросах к виртуальным таблицам

При получении срезов регистров (например, остатков номенклатуры или среза последних курсов валют) критически важно понимать, как платформа обрабатывает граничные условия. Если в виртуальную таблицу передать обычную дату, например, КонецДня(ВыбраннаяДата), платформа по умолчанию применит условие строгого неравенства и не включит движения, сделанные ровно в 23:59:59.

Чтобы гарантированно включить в выборку последнюю секунду периода, необходимо использовать объект Граница с видом границы ВидГраницы.Включая.

Посмотрим на практический пример передачи параметра периода в запрос:


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

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

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

Существует также альтернативный вариант получения остатков на конец суток без использования объекта Граница. Для этого в качестве точки расчета передают начало следующих суток со стандартным исключением границы:


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

В этом случае все записи, проведенные вплоть до 23:59:59 включительно, гарантированно попадут в расчет остатков, так как они хронологически предшествуют точке 00:00:00 следующего дня.

← На главную