Как рассчитать и вывести долю неполного месяца в СКД

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

В практике разработки отчетов на базе Системы компоновки данных (СКД) часто возникает задача расчета коэффициентов, зависящих от времени нахождения объекта на учете. Типичный пример: товар поступил на склад в середине месяца, и нам необходимо рассчитать долю этого месяца, в течение которой товар фактически находился в остатке. Если товар был на складе весь месяц, коэффициент равен 1, если только часть — значение должно быть дробным (например, 0.5 за полмесяца).

В данной статье мы разберем, как правильно реализовать этот расчет в языке запросов и вычисляемых полях СКД, учитывая тонкости работы с датами и особенности деления целых чисел в 1С.

Разбор базовой логики расчета

Для того чтобы получить процентную долю периода, нам необходимо выполнить следующие шаги:

  1. Определить количество фактически прошедших дней с даты события до конца текущего месяца (или начала следующего периода).
  2. Определить общее количество календарных дней в интересующем нас месяце.
  3. Разделить первое значение на второе.

Рассмотрим пример из обсуждения: дата поступления товара — 08.07.2018, а отчет формируется на 01.08.2018. Нам нужно понять, какую долю июля товар «прожил» на складе. Проанализируем ситуацию: в июле 31 день. Если считать с 8-го числа включительно, это 24 дня. Доля составит 24 / 31 ≈ 0.77.

Реализация в языке запросов 1С

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

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


ВЫБРАТЬ
    (РАЗНОСТЬДАТ(&ДатаПоступления, КОНЕЦПЕРИОДА(&ДатаПоступления, МЕСЯЦ), ДЕНЬ) + 1) * 1.0 
    / 
    РАЗНОСТЬДАТ(НАЧАЛОПЕРИОДА(&ДатаПоступления, МЕСЯЦ), ДОБАВИТЬКДАТЕ(КОНЕЦПЕРИОДА(&ДатаПоступления, МЕСЯЦ), ДЕНЬ, 1), ДЕНЬ) 
    КАК ДоляПериода

Разберем подробнее, что происходит в этом выражении:

  1. РАЗНОСТЬДАТ(&ДатаПоступления, КОНЕЦПЕРИОДА(&ДатаПоступления, МЕСЯЦ), ДЕНЬ) + 1 — мы вычисляем количество дней с даты поступления до конца месяца. Добавление +1 критически важно, так как функция РАЗНОСТЬДАТ считает количество переходов (границ) между датами. Если товар поступил и выбыл в один и тот же день, функция вернет 0, хотя фактически это 1 день нахождения.
  2. Умножение на 1.0 переводит результат в тип Число с плавающей точкой, позволяя избежать потери точности при делении.
  3. В знаменателе мы вычисляем полное количество дней в месяце. Обратите внимание, что использование ДОБАВИТЬКДАТЕ к началу или концу месяца позволяет универсально обрабатывать февраль и високосные годы.

Использование вычисляемых полей в СКД

Если логика отчета требует расчета коэффициента уже после получения данных из базы, мы можем перенести формулу в Вычисляемые поля СКД. В СКД синтаксис функций работы с датами немного отличается от чистого SQL-запроса 1С.

Проанализируем пример выражения для вычисляемого поля:


РазностьДаты(НачалоПериода(ПартияДата, "Месяц"), &КонецПериода, "День") / 
РазностьДаты(НачалоПериода(ПартияДата, "Месяц"), КонецПериода(ПартияДата, "Месяц"), "День")

Важный момент: В выражениях СКД названия периодов (МЕСЯЦ, ДЕНЬ) должны указываться в кавычках как строки, в то время как в тексте запроса они пишутся без кавычек. Если вы ошибетесь, система выдаст ошибку при попытке скомпоновать результат.

Учет «инклюзивности» и финансовых стандартов

При расчете долей важно заранее выяснить требования заказчика к точности. Рассмотрим два подхода:

  1. Астрономический (календарный) расчет: Мы берем фактическое количество дней в конкретном месяце (28, 29, 30 или 31). Это наиболее точный способ для складского учета.
  2. Финансовый стандарт (30/360): В некоторых видах управленческого и бухгалтерского учета (особенно при расчете процентов по займам или амортизации) принимается, что в любом месяце ровно 30 дней. В этом случае знаменатель в нашей формуле всегда будет равен 30.

Если мы используем календарный расчет, рекомендуется определять количество дней в месяце следующим универсальным способом:


// Количество дней в месяце текущей даты
РАЗНОСТЬДАТ(НАЧАЛОПЕРИОДА(&Дата, МЕСЯЦ), ДОБАВИТЬКДАТЕ(НАЧАЛОПЕРИОДА(&Дата, МЕСЯЦ), МЕСЯЦ, 1), ДЕНЬ)

Этот метод надежнее, чем просто разница между НАЧАЛОПЕРИОДА и КОНЕЦПЕРИОДА, так как он четко вычисляет разницу между первым числом текущего месяца и первым числом следующего.

Обработка пустых значений и округление

Проанализируем ситуацию, когда дата поступления товара не заполнена. Если такая запись попадет в расчет, мы получим деление на ноль или некорректное огромное число. Чтобы избежать этого, всегда используйте конструкцию ВЫБОР:


ВЫБОР 
    КОГДА ПартияДата = ДАТАВРЕМЯ(1, 1, 1) ТОГДА 0 
    ИНАЧЕ ВЫРАЗИТЬ((РАЗНОСТЬДАТ(ПартияДата, КОНЕЦПЕРИОДА(ПартияДата, МЕСЯЦ), ДЕНЬ) + 1) * 1.0 / 30 КАК ЧИСЛО(15, 2))
КОНЕЦ

Функция ВЫРАЗИТЬ(... КАК ЧИСЛО(15, 2)) позволяет ограничить количество знаков после запятой. В отчетах СКД избыточная точность (15 знаков) часто только мешает восприятию данных пользователем, поэтому округление до 2-го или 3-го знака является «хорошим тоном» разработки.

Краткие итоги

Для успешного вывода неполного месяца в СКД мы рекомендуем:

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

← На главную