При решении прикладных задач в 1С часто возникает необходимость представить отчетный период (например, месяц или квартал) в виде последовательности календарных недель. Рассмотрим, как реализовать этот алгоритм, чтобы правильно выделить границы интервалов, учитывая начало и конец исходного периода.
Для корректного определения границ недели в 1С существуют встроенные функции НачалоНедели() и КонецНедели(). Использование этих методов предпочтительнее ручного расчета через секунды (86400 в сутках), так как платформа автоматически учитывает календарные особенности и привязку к началу недели (понедельнику).
Разберем один из самых понятных подходов — использование цикла Пока для последовательного перебора интервалов. Такой метод позволяет гибко управлять границами и корректно «обрезать» первый и последний интервалы, чтобы они не выходили за рамки установленного пользователем периода.
Для реализации логики нам потребуется инициализировать начальную и конечную даты и в цикле наращивать их до тех пор, пока мы не достигнем конца целевого периода.
// Пример алгоритма для разбиения периода
НачалоТекущейНедели = Объект.НачалоПериода;
// Вычисляем конец первой неполной недели
КонецТекущейНедели = НачалоНедели(НачалоТекущейНедели) + 6*24*60*60;
КонецТекущейНедели = Мин(КонецТекущейНедели, Объект.КонецПериода);
Пока НачалоТекущейНедели <= Объект.КонецПериода Цикл
// Вывод или запись интервала
Сообщить("" + НачалоТекущейНедели + " - " + КонецТекущейНедели);
// Переход к следующей неделе
НачалоТекущейНедели = КонецТекущейНедели + 1;
КонецТекущейНедели = Мин(НачалоТекущейНедели + 6*24*60*60, Объект.КонецПериода);
Если НачалоТекущейНедели > Объект.КонецПериода Тогда
Прервать;
КонецЕсли;
КонецЦикла;
Многие начинающие разработчики пытаются считать недели, просто прибавляя 7 * 86400 к дате. Давайте выясним, почему это приводит к ошибкам:
НачалоНедели() делает ваш код самодокументированным и понятным для других разработчиков.Если в вашем отчете пользователь может выбирать детализацию (день, неделя, месяц), удобно вынести логику в отдельную функцию, возвращающую ТаблицаЗначений. Рассмотрим структуру такой функции:
Функция ПолучитьТаблицуИнтервалов(ДатаНачала, ДатаОкончания, УровеньДетализации)
ТЗ = Новый ТаблицаЗначений;
ТЗ.Колонки.Добавить("ДатаНачала");
ТЗ.Колонки.Добавить("ДатаОкончания");
ТекущаяДата = ДатаНачала;
Пока ТекущаяДата <= ДатаОкончания Цикл
Строка = ТЗ.Добавить();
Строка.ДатаНачала = ТекущаяДата;
Если УровеньДетализации = "Неделя" Тогда
Строка.ДатаОкончания = Мин(КонецНедели(ТекущаяДата), ДатаОкончания);
ТекущаяДата = КонецНедели(ТекущаяДата) + 1;
КонецЕсли;
КонецЦикла;
Возврат ТЗ;
КонецФункции
В случаях, когда данные находятся в базе данных (например, обороты товаров или документов), правильнее использовать возможности языка запросов. Вместо того чтобы перебирать даты в коде, можно сгруппировать данные по периоду недели:
ВЫБРАТЬ
НАЧАЛОПЕРИОДА(ТаблицаДанных.Дата, НЕДЕЛЯ) КАК НачалоНедели,
МИНИМУМ(ТаблицаДанных.Дата) КАК РеальноеНачало,
МАКСИМУМ(ТаблицаДанных.Дата) КАК РеальноеОкончание
ИЗ ТаблицаДанных ГДЕ ...
СГРУППИРОВАТЬ ПО НАЧАЛОПЕРИОДА(ТаблицаДанных.Дата, НЕДЕЛЯ)
Этот подход работает быстрее и позволяет платформе самой оптимизировать вычисление границ, что особенно актуально для больших объемов данных. Всегда анализируйте, требует ли задача сложной обработки в коде или её можно решить декларативно с помощью конструктора запросов.