При разработке запросов в системе «1С:Предприятие» нередко возникает необходимость получить отношение двух временных интервалов. На первый взгляд, самое логичное решение — поделить одну функцию РазностьДат на другую. Однако на практике такая конструкция часто приводит к аварийному завершению запроса с ошибкой. Давайте подробно разберем, почему это происходит, проанализируем скрытые нюансы работы с датами и выясним причину такого поведения платформы.
Основная проблема, с которой сталкиваются разработчики при использовании конструкции вида РазностьДат() / РазностьДат() — это ошибка деления на ноль. Знаменатель может стать равным нулю, даже если визуально даты различаются. Рассмотрим подробнее, как именно функция считает интервалы.
Функция РазностьДат в 1С вычисляет не абсолютное физическое время между точками, а количество пересечений границ указанного периода (дней, месяцев, лет). Посмотрим на пример:
МЕСЯЦ и сравниваем «31 января» и «1 февраля», результатом будет 1, так как граница месяца была пересечена.Если такая пара дат попадает в функцию, которая находится в знаменателе, запрос попытается выполнить деление на ноль и немедленно завершится с ошибкой.
Разберем еще один критически важный нюанс. В языке запросов 1С результат выполнения функции РазностьДат всегда является целым числом. Если мы делим одно целое число на другое, результат также будет приведен к целому типу путем отсечения дробной части.
Проанализируем ситуацию: если первая разность дат составляет 5 дней, а вторая разность — 2 дня, то при прямом делении 5 / 2 результатом в запросе станет 2, а не ожидаемое 2.5. Это может привести к серьезным логическим ошибкам в расчетах коэффициентов.
Чтобы обойти эту проблему и получить точный результат с десятичными знаками, числитель необходимо предварительно умножить на число с плавающей точкой (например, на 1.0). Таким образом мы неявно преобразуем тип значения.
Проанализируем ситуацию, когда данные для дат берутся из левых или полных соединений таблиц. Если одна из дат, участвующих в расчете знаменателя, не заполнена (имеет значение 01.01.0001) или содержит NULL, результат вычисления может быть непредсказуемым.
Деление на NULL в языке запросов само по себе не вызывает фатальной ошибки (результатом просто станет NULL). Однако, если из-за пустых дат функция возвращает математический ноль, система выдаст ошибку деления. Поэтому всегда рекомендуется проверять даты на заполненность.
Иногда ошибка может быть связана со слишком большими числами. Результат функции РазностьДат ограничен типом данных Integer (32 бита). Если мы попытаемся вычислить разность в секундах между датами, разрыв между которыми составляет более 70 лет, возникнет ошибка переполнения типа.
Также не забывайте про порядок аргументов. Если вторая дата меньше первой, функция вернет отрицательное число. Если бизнес-логика предполагает строго положительные коэффициенты, это исказит итоговые показатели.
Чтобы избежать всех описанных выше проблем, создадим безопасную конструкцию обхода. Нам необходимо использовать оператор ВЫБОР КОГДА. Разберем по шагам правильный подход:
0 или NULL в зависимости от задачи).1.0 для получения дробного результата.Посмотрим на пример итогового кода, который гарантированно избавит от ошибки:
ВЫБОР
КОГДА РазностьДат(Дата3, Дата4, ДЕНЬ) = 0
ТОГДА 0
ИНАЧЕ
(РазностьДат(Дата1, Дата2, ДЕНЬ) * 1.0) / РазностьДат(Дата3, Дата4, ДЕНЬ)
КОНЕЦ
В этом примере мы решаем сразу две задачи: полностью исключаем возможность падения запроса из-за деления на ноль и обеспечиваем корректное вычисление дробного результата (без потери точности из-за целочисленного деления). Используйте этот шаблон при любых вычислениях отношений временных интервалов в ваших запросах 1С.