Как функция РАЗНОСТЬДАТ() в 1С считает дни и секунды, и можно ли передать в нее Границу?

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

При работе с запросами в платформе «1С:Предприятие» разработчики регулярно сталкиваются с необходимостью вычисления временных интервалов. Одной из самых часто используемых функций для этого является РАЗНОСТЬДАТ(). Однако ее поведение при работе с граничными значениями времени (например, между началом и концом одних суток) или при попытке использовать сложные типы данных часто вызывает вопросы и приводит к досадным ошибкам в коде. В этой статье мы подробно разберем, как именно функция производит расчеты, выясним особенности взаимодействия с объектом Граница и развенчаем один из самых устойчивых мифов платформы 1С.

Как функция РАЗНОСТЬДАТ() считает дни и секунды

Для начала проанализируем базовый синтаксис функции. Она принимает три параметра: начальную дату, конечную дату и тип разности (период, в котором необходимо получить результат). Особенность работы функции заключается в том, что расчет крупных периодов (таких как ГОД, КВАРТАЛ, МЕСЯЦ, ДЕНЬ) производится по календарным границам (пересечениям рубежей), а не по фактическому астрономическому времени.

Рассмотрим подробнее поведение платформы на конкретных примерах:

  1. Расчет разницы в днях (ДЕНЬ). При указании этого типа разности платформа полностью игнорирует (отбрасывает) время в обеих датах, сравнивая исключительно календарные дни.

    Если мы берем в качестве параметров 01.01.2026 00:00:00 (начало дня) и 01.01.2026 23:59:59 (конец того же дня), то после отбрасывания времени обе даты превращаются в 01.01.2026. Очевидно, что разница между одной и той же датой составит 0 дней. Сутки еще не сменились, календарная граница не пройдена.

    Напротив, если мы возьмем даты 01.01.2026 23:59:59 и 02.01.2026 00:00:01, астрономическая разница между которыми составляет всего 2 секунды, функция РАЗНОСТЬДАТ() вернет результат 1 день. Это происходит потому, что даты принадлежат разным календарным суткам и рубеж между ними был пройден.

  2. Расчет разницы в секундах (СЕКУНДА). При подсчете мелких единиц времени (секунды, минуты, часы) временная составляющая дат учитывается полностью.

    Если измерить разницу между 00:00:00 и 23:59:59 одних и тех же суток в секундах, мы получим вполне ожидаемый результат — 86399 секунд (поскольку полные сутки содержат в себе 86400 секунд).

Давайте посмотрим на простой пример запроса, который наглядно демонстрирует эту разницу в поведении функции:


ВЫБРАТЬ
    РАЗНОСТЬДАТ(&ДатаНачала, &ДатаОкончания, ДЕНЬ) КАК РазницаДней,
    РАЗНОСТЬДАТ(&ДатаНачала, &ДатаОкончания, СЕКУНДА) КАК РазницаСекунд

Передав в параметры &ДатаНачала значение 01.01.2026 00:00:00, а в &ДатаОкончания — 01.01.2026 23:59:59, мы получим в колонке «РазницаДней» значение 0, а в колонке «РазницаСекунд» — 86399.

Совместимость РАЗНОСТЬДАТ() с объектом Граница

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

Важное ограничение платформы: передавать объект типа Граница напрямую в функцию РАЗНОСТЬДАТ() внутри текста запроса строго запрещено. Платформа ожидает на входе исключительно значения типа Дата. Попытка передать границу приведет к падению запроса с ошибкой несовместимости типов данных.

Выясним причину такого поведения. Объект Граница — это сложный тип платформы, который помимо даты и времени несет в себе дополнительное свойство — вид границы (включая или исключая указанный момент времени). База данных (СУБД) на физическом уровне не имеет аналогичного сложного типа, поэтому функция РАЗНОСТЬДАТ() просто не умеет обрабатывать подобные объекты.

Как же правильно обойти это ограничение в коде? Разберем по шагам алгоритм подготовки параметров перед выполнением запроса:

  1. Перед передачей параметров в запрос необходимо проверить тип имеющейся переменной во встроенном языке 1С.
  2. Если тип переменной равен Граница, следует извлечь ее дату через свойство Значение.
  3. Если тип переменной равен МоментВремени, дату извлекают через свойство Дата.
  4. Уже очищенную от дополнительных свойств дату передают в качестве параметра запроса.

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


// Предположим, что у нас есть переменная КонечныйПериод, которая может быть Датой или Границей
КонечнаяДатаЗапроса = Неопределено;

Если ТипЗнч(КонечныйПериод) = Тип("Граница") Тогда
    КонечнаяДатаЗапроса = КонечныйПериод.Значение;
ИначеЕсли ТипЗнч(КонечныйПериод) = Тип("МоментВремени") Тогда
    КонечнаяДатаЗапроса = КонечныйПериод.Дата;
Иначе
    КонечнаяДатаЗапроса = КонечныйПериод; // Если это уже Дата
КонецЕсли;

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

Запрос.УстановитьПараметр("НачалоПериода", НачальнаяДата);
Запрос.УстановитьПараметр("КонецПериода", КонечнаяДатаЗапроса);
Результат = Запрос.Выполнить();

При этом важно понимать: когда мы извлекаем «чистую» дату из объекта Граница, мы теряем информацию о виде границы (включая/исключая). Для функции РАЗНОСТЬДАТ() этот признак не имеет значения, так как она работает только с точками на оси времени.

Развенчание мифа: «Граница "Включая" — это следующая секунда»

Среди начинающих (а иногда и опытных) разработчиков 1С циркулирует миф о том, что вид границы ВидГраницы.Включая на уровне платформы эквивалентен прибавлению одной секунды к значению даты. Соответственно, бытует ошибочное мнение, что если бы функция РАЗНОСТЬДАТ() поддерживала объект Граница, то передача туда границы «Включая» с датой 23:59:59 приводила бы к автоматическому переходу на следующую секунду (то есть на 00:00:00 следующего дня) и возвращала бы разность в 1 день вместо 0.

Это утверждение абсолютно неверно. Проанализируем ситуацию и разберемся, как на самом деле работает механизм границ на уровне СУБД:

Платформа 1С никогда не прибавляет секунды к датам при обработке объектов типа Граница. Вместо этого при трансляции запроса на язык SQL платформа формирует различные условия сравнения операторов в зависимости от вида границы:

Почему подход «прибавим секунду» был бы критической ошибкой? Представим себе работу виртуальной таблицы СрезПоследних или получение остатков по регистру накопления на конец дня 31.12.2025 23:59:59.

Если бы система транслировала границу «Включая» как прибавление одной секунды (то есть превращала бы время в 01.01.2026 00:00:00), то в результаты выборки попали бы документы и движения, проведенные ровно в первую секунду Нового года (в полночь). Это привело бы к серьезным искажениям в бухгалтерских итогах и финансовых отчетах. Использование же математических операторов сравнения (<=) позволяет СУБД выбирать ровно те записи, которые актуальны на указанный момент времени, не захватывая лишние данные из будущего.

Таким образом, использование объекта Граница решает задачи правильного позиционирования внутри конкретной секунды (или на конкретном документе, если граница строится по позиции документа) при получении срезов и остатков, но не имеет никакого отношения к математическому расчету разницы между датами.

← На главную