При разработке отчетов по эксплуатации техники часто возникает задача рассчитать количество дней, в течение которых объект находился в работе в рамках определенного периода. Сложность заключается в том, что автомобиль мог быть введен в эксплуатацию задолго до начала периода отчета или, наоборот, в середине этого периода. Рассмотрим детально, как реализовать этот расчет в запросе 1С и в Системе компоновки данных (СКД).
Основным инструментом для решения нашей задачи является функция РАЗНОСТЬДАТ. Проанализируем ее синтаксис в языке запросов:
РАЗНОСТЬДАТ(ДатаНачала, ДатаОкончания, ТипРазности)
Важно понимать, как именно система вычисляет результат. Если мы передаем в функцию две одинаковые даты (например, 01.01.2023 и 01.01.2023), функция вернет 0. Это происходит потому, что 1С (и лежащий в основе SQL-сервер) считает количество "границ" или переходов между датами. Для задач учета эксплуатации, где день начала и день окончания должны включаться в расчет, нам необходимо прибавлять единицу.
Посмотрим на пример простейшего кода в запросе:
ВЫБРАТЬ
РАЗНОСТЬДАТ(&ДатаНачала, &ДатаОкончания, ДЕНЬ) + 1 КАК КоличествоДней
ИЗ
Справочник.Автомобили КАК Автомобили
Выясним причину, по которой расчет может выдавать странные результаты. В системе 1С тип Дата всегда содержит время. Если в параметре &ДатаОкончания передано значение "25.03.2022 00:00:00", а фактическая эксплуатация завершилась в конце дня, расчет может потерять целые сутки или выдать дробное значение при использовании других методов.
Чтобы гарантировать точность, разберем метод нормализации дат. Мы должны всегда приводить сравниваемые значения к началу дня. Проанализируем ситуацию: если мы используем функцию НАЧАЛОПЕРИОДА, мы обнуляем время, делая сравнение "чистым".
Рассмотрим более сложный, но универсальный метод расчета через секунды, который предложили участники обсуждения:
ВЫБРАТЬ
(РАЗНОСТЬДАТ(НАЧАЛОПЕРИОДА(&ДатаНачала, ДЕНЬ), КОНЕЦПЕРИОДА(&ДатаОкончания, ДЕНЬ), СЕКУНДА) + 1) / 86400 КАК Дни
В данном примере число 86400 — это количество секунд в сутках (24 * 3600). Такой подход позволяет избежать проблем с округлением, которые иногда возникают в различных СУБД (Microsoft SQL Server vs PostgreSQL).
Часто задача звучит сложнее: нужно посчитать дни эксплуатации автомобиля, учитывая, что дата его ввода в эксплуатацию (ДатаЭксплуатации) может попадать внутрь выбранного периода (&ДатаНачала — &ДатаОкончания).
Рассмотрим три сценария:
&ДатаНачала до &ДатаОкончания.ДатаЭксплуатации до &ДатаОкончания.Для реализации такой логики в запросе используем конструкцию ВЫБОР. Посмотрим на пример кода:
ВЫБРАТЬ
Автомобиль,
ВЫБОР
// Если дата ввода позже конца периода - эксплуатации еще нет
КОГДА ДатаЭксплуатации > &ДатаОкончания ТОГДА 0
// Иначе вычисляем разницу между "Фактическим началом" и "Концом периода"
ИНАЧЕ РАЗНОСТЬДАТ(
ВЫБОР
КОГДА ДатаЭксплуатации > &ДатаНачала ТОГДА ДатаЭксплуатации
ИНАЧЕ &ДатаНачала
КОНЕЦ,
&ДатаОкончания,
ДЕНЬ) + 1
КОНЕЦ КАК ДниВЭксплуатации
ИЗ
Справочник.Автомобили
Разберем по шагам, что здесь происходит. Вложенный ВЫБОР определяет "точку старта". Если автомобиль уже работал на момент начала отчета, мы берем дату начала отчета. Если он был введен позже — берем дату ввода. Внешний ВЫБОР отсекает ситуации, когда эксплуатация еще не началась.
Если вы решаете задачу в СКД, проанализируем дополнительные возможности. В СКД можно использовать параметры типа СтандартныйПериод. Это удобно для пользователя, но в запросе нам все равно нужны отдельные даты.
Важные моменты для СКД:
&ДатаОкончания можно прописать выражение КОНЕЦПЕРИОДА(&ДатаОкончания, "ДЕНЬ").ТекущаяДата().СУММА(ВычислитьВыражение(...)), если автомобиль встречается в нескольких строках, или просто СУММА(ДниВЭксплуатации).Проанализируем ситуацию с "пустыми" датами. В 1С пустая дата — это 01.01.0001. Если в справочнике у автомобиля не заполнена ДатаЭксплуатации, функция РАЗНОСТЬДАТ вернет огромное число (количество дней от начала нашей эры), что приведет к ошибке в отчете.
Всегда добавляйте проверку на заполнение даты. В запросе это выглядит так:
ГДЕ
ДатаЭксплуатации <> ДАТАВРЕМЯ(1, 1, 1)
Или обрабатывайте это внутри ВЫБОР, возвращая 0 при пустом значении. Это критически важно для стабильной работы информационной системы.
Мы проанализировали основные подходы к подсчету дней. Самый надежный метод — использование РАЗНОСТЬДАТ с добавлением единицы и обязательной проверкой дат на вхождение в интервал через ВЫБОР. Не забывайте про нормализацию времени с помощью НАЧАЛОПЕРИОДА, чтобы избежать случайных ошибок в расчетах на стыке суток.