Как разбить период на отдельные месяцы в 1С 7.7?

Программист 1С v7.7 IT и автоматизация бизнеса
← На главную

При разработке внешних отчетов и обработок в платформе 1С 7.7 нередко возникает задача разбить выбранный пользователем интервал дат (например, полгода или год) на отдельные месячные отрезки. Это необходимо для пошаговой обработки данных, построения помесячных колонок или последовательной обработки итогов.

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

Способ 1. Организация цикла по месяцам с помощью функций работы с датами

Проанализируем базовый подход, при котором вычисление границ каждого месяца происходит с помощью встроенных функций НачМесяца, КонМесяца и ДобавитьМесяц.

Основная задача — задать начальную и конечную точку отрезка, а затем на каждом шаге цикла смещать дату на один месяц вперед. Рассмотрим рабочий пример кода:


НачалоМесяца = НачМесяца(НачДата);
КонецМесяца  = КонМесяца(НачДата);

Пока КонецМесяца <= КонМесяца(КонДата) Цикл
    
    // Выполнение нужных действий с интервалом [НачалоМесяца, КонецМесяца]
    
    НачалоМесяца = НачМесяца(ДобавитьМесяц(НачалоМесяца, 1));
    КонецМесяца  = КонМесяца(ДобавитьМесяц(КонецМесяца, 1));
КонецЦикла;

Разберем особенности работы этого алгоритма:

  1. Перед входом в цикл переменные НачалоМесяца и КонецМесяца инициализируются первыми и последними днями месяца для даты начала периода (НачДата).
  2. В условии цикла проверяется, не превышает ли текущий КонецМесяца конец месяца даты окончания (КонДата).
  3. Переход к следующему месяцу осуществляется функцией ДобавитьМесяц. При этом инкремент применяется именно к началу месяца, чтобы избежать ошибок с разным количеством дней в месяцах.

Важная особенность функции ДобавитьМесяц и учет произвольных дат

При работе с датами в 1С 7.7 следует учитывать особенность смещения дней. Если вызывать функцию ДобавитьМесяц для даты, находящейся на конце месяца (например, 31 января), она вернет 28 февраля (или 29 февраля в високосный год). Если продолжать последовательно прибавлять месяц к этой же переменной, числовой день зафиксируется на 28-м числе и больше не вернется к 31-му. Именно поэтому прибавлять месяц следует строго к началу месяца (НачМесяца).

Кроме того, если пользователь выбрал произвольные даты (например, с 15 января по 10 марта), обычный цикл по целым месяцам обработает лишние дни вне выбранного интервала. Чтобы корректно учитывать границы, установленные пользователем, разберем усовершенствованный алгоритм:


ТекДата = НачМесяца(НачДата);
Пока ТекДата <= КонДата Цикл
    ДатНачМес = Макс(НачДата, НачМесяца(ТекДата));
    ДатКонМес = Мин(КонДата, КонМесяца(ТекДата));
    
    // Выполнение действий для интервала [ДатНачМес, ДатКонМес]
    
    ТекДата = ДобавитьМесяц(ТекДата, 1);
КонецЦикла;

В данном случае функции Макс и Мин гарантируют, что для первого и последнего месяцев интервала будут взяты точные даты, введенные пользователем, а для промежуточных месяцев — их полные границы.

Оптимизация работы и альтернативные решения

Выполнение запросов или обращений к базе данных внутри цикла по месяцам может существенно снизить производительность отчета. Разберем более эффективные альтернативы:

  1. Использование единого запроса с группировкой по месяцам. Вместо многократного вызова запросов в цикле предпочтительнее выполнить один общий запрос за весь период С НачДата ПО КонДата; с условием Группировка Месяц Все;. Ключевое слово Все гарантирует попадание в выборку всех месяцев периода, даже тех, по которым не было движений.
  2. Использование объекта БухгалтерскиеИтоги. Если отчет формируется по бухгалтерским данным, метод ВыполнитьЗапрос позволяет сразу указать периодичность "Месяц" и затем обходить периоды штатным способом:

Ит.ВыполнитьЗапрос(НачДата, КонДата, Счет, , , "Месяц");
Ит.ВыбратьПериоды();
Пока Ит.ПолучитьПериод() = 1 Цикл
    // Обработка данных текущего месяца
КонецЦикла;

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

← На главную