В практике разработки отчетов на базе Системы компоновки данных (СКД) часто возникает задача расчета коэффициентов, зависящих от времени нахождения объекта на учете. Типичный пример: товар поступил на склад в середине месяца, и нам необходимо рассчитать долю этого месяца, в течение которой товар фактически находился в остатке. Если товар был на складе весь месяц, коэффициент равен 1, если только часть — значение должно быть дробным (например, 0.5 за полмесяца).
В данной статье мы разберем, как правильно реализовать этот расчет в языке запросов и вычисляемых полях СКД, учитывая тонкости работы с датами и особенности деления целых чисел в 1С.
Для того чтобы получить процентную долю периода, нам необходимо выполнить следующие шаги:
Рассмотрим пример из обсуждения: дата поступления товара — 08.07.2018, а отчет формируется на 01.08.2018. Нам нужно понять, какую долю июля товар «прожил» на складе. Проанализируем ситуацию: в июле 31 день. Если считать с 8-го числа включительно, это 24 дня. Доля составит 24 / 31 ≈ 0.77.
Для реализации этой логики в запросе мы используем функцию РАЗНОСТЬДАТ. Однако здесь кроется важный нюанс: целочисленное деление. Если вы просто разделите одну разность дат на другую, 1С округлит результат до целого числа (в большинстве случаев до 0), что нам не подходит. Чтобы получить дробь, нужно умножить числитель на 1.0.
Посмотрим на пример кода, который можно использовать в запросе:
ВЫБРАТЬ
(РАЗНОСТЬДАТ(&ДатаПоступления, КОНЕЦПЕРИОДА(&ДатаПоступления, МЕСЯЦ), ДЕНЬ) + 1) * 1.0
/
РАЗНОСТЬДАТ(НАЧАЛОПЕРИОДА(&ДатаПоступления, МЕСЯЦ), ДОБАВИТЬКДАТЕ(КОНЕЦПЕРИОДА(&ДатаПоступления, МЕСЯЦ), ДЕНЬ, 1), ДЕНЬ)
КАК ДоляПериода
Разберем подробнее, что происходит в этом выражении:
РАЗНОСТЬДАТ(&ДатаПоступления, КОНЕЦПЕРИОДА(&ДатаПоступления, МЕСЯЦ), ДЕНЬ) + 1 — мы вычисляем количество дней с даты поступления до конца месяца. Добавление +1 критически важно, так как функция РАЗНОСТЬДАТ считает количество переходов (границ) между датами. Если товар поступил и выбыл в один и тот же день, функция вернет 0, хотя фактически это 1 день нахождения.1.0 переводит результат в тип Число с плавающей точкой, позволяя избежать потери точности при делении.ДОБАВИТЬКДАТЕ к началу или концу месяца позволяет универсально обрабатывать февраль и високосные годы.Если логика отчета требует расчета коэффициента уже после получения данных из базы, мы можем перенести формулу в Вычисляемые поля СКД. В СКД синтаксис функций работы с датами немного отличается от чистого SQL-запроса 1С.
Проанализируем пример выражения для вычисляемого поля:
РазностьДаты(НачалоПериода(ПартияДата, "Месяц"), &КонецПериода, "День") /
РазностьДаты(НачалоПериода(ПартияДата, "Месяц"), КонецПериода(ПартияДата, "Месяц"), "День")
Важный момент: В выражениях СКД названия периодов (МЕСЯЦ, ДЕНЬ) должны указываться в кавычках как строки, в то время как в тексте запроса они пишутся без кавычек. Если вы ошибетесь, система выдаст ошибку при попытке скомпоновать результат.
При расчете долей важно заранее выяснить требования заказчика к точности. Рассмотрим два подхода:
30.Если мы используем календарный расчет, рекомендуется определять количество дней в месяце следующим универсальным способом:
// Количество дней в месяце текущей даты
РАЗНОСТЬДАТ(НАЧАЛОПЕРИОДА(&Дата, МЕСЯЦ), ДОБАВИТЬКДАТЕ(НАЧАЛОПЕРИОДА(&Дата, МЕСЯЦ), МЕСЯЦ, 1), ДЕНЬ)
Этот метод надежнее, чем просто разница между НАЧАЛОПЕРИОДА и КОНЕЦПЕРИОДА, так как он четко вычисляет разницу между первым числом текущего месяца и первым числом следующего.
Проанализируем ситуацию, когда дата поступления товара не заполнена. Если такая запись попадет в расчет, мы получим деление на ноль или некорректное огромное число. Чтобы избежать этого, всегда используйте конструкцию ВЫБОР:
ВЫБОР
КОГДА ПартияДата = ДАТАВРЕМЯ(1, 1, 1) ТОГДА 0
ИНАЧЕ ВЫРАЗИТЬ((РАЗНОСТЬДАТ(ПартияДата, КОНЕЦПЕРИОДА(ПартияДата, МЕСЯЦ), ДЕНЬ) + 1) * 1.0 / 30 КАК ЧИСЛО(15, 2))
КОНЕЦ
Функция ВЫРАЗИТЬ(... КАК ЧИСЛО(15, 2)) позволяет ограничить количество знаков после запятой. В отчетах СКД избыточная точность (15 знаков) часто только мешает восприятию данных пользователем, поэтому округление до 2-го или 3-го знака является «хорошим тоном» разработки.
Для успешного вывода неполного месяца в СКД мы рекомендуем:
РАЗНОСТЬДАТ с добавлением единицы для учета текущего дня.1.0 для обхода ограничений целочисленного деления в запросах.ВЫРАЗИТЬ для эстетичного вида отчета.Применяя эти шаги, вы сможете создавать точные и гибкие управленческие отчеты, которые корректно отражают временные интервалы и коэффициенты в ваших информационных базах 1С.