При разработке алгоритмов закрытия периода, расчета амортизации, начисления износа или подготовки отчетности во встроенном языке 1С:Предприятия часто возникает необходимость выполнять определенные действия не каждый месяц, а строго раз в квартал (то есть в марте, июне, сентябре и декабре). В этой статье мы подробно разберем несколько практических способов реализации такого условия, проанализируем их достоинства и недостатки, а также рассмотрим, как правильно решать эту задачу в запросах.
Самым элегантным, понятным и надежным способом является сравнение окончания текущего месяца с окончанием текущего квартала. Этот метод использует стандартные функции платформы 1С и не зависит от математических вычислений, что делает код максимально читаемым.
Рассмотрим пример реализации:
ТекущаяДатаДокумента = СтруктураШапкиДокумента.Дата;
ЭтоМесяцНачисленияИзноса = (КонецКвартала(ТекущаяДатаДокумента) = КонецМесяца(ТекущаяДатаДокумента));
Как это работает: функция КонецКвартала возвращает дату и время последнего дня квартала (например, 31.03.2023 23:59:59). Функция КонецМесяца возвращает конец текущего месяца (например, для февраля это будет 28.02.2023 23:59:59, а для марта — 31.03.2023 23:59:59). Если эти две даты совпадают, значит, текущий месяц гарантированно является последним месяцем квартала.
Преимущества данного подхода:
Этот способ основан на том, что номера месяцев, завершающих квартал (3, 6, 9, 12), делятся на 3 без остатка. Во встроенном языке 1С для получения остатка от деления используется оператор %.
Посмотрим на пример кода:
НомерМесяца = Месяц(СтруктураШапкиДокумента.Дата);
ЭтоМесяцНачисленияИзноса = (НомерМесяца % 3 = 0);
Как это работает: мы получаем порядковый номер месяца с помощью функции Месяц и делим его на 3. Если остаток равен нулю, то условие выполняется. Например:
Этот способ работает очень быстро и занимает всего одну строку кода. Однако он требует от понимания математической логики и может быть чуть менее очевидным при беглом анализе кода другими разработчиками.
Если вам необходимо сделать код максимально прямолинейным, можно использовать обычное перечисление номеров месяцев через логический оператор ИЛИ.
Пример реализации:
НомерМесяца = Месяц(СтруктураШапкиДокумента.Дата);
ЭтоМесяцНачисленияИзноса = (НомерМесяца = 3)
ИЛИ (НомерМесяца = 6)
ИЛИ (НомерМесяца = 9)
ИЛИ (НомерМесяца = 12);
Хотя этот код работает абсолютно корректно, он перегружен лишними конструкциями. Автоматизированная проверка конфигурации (АПК) или код-ревьюер могут сделать замечание по поводу избыточности логических выражений. Использовать такой подход в промышленной разработке не рекомендуется, так как он загромождает листинг модуля.
Если вам требуется наложить условие «конец квартала» не в коде на сервере, а непосредственно при выборке данных из базы данных (в запросе), то вышеописанные методы встроенного языка работать не будут. В языке запросов 1С реализованы свои механизмы работы с периодами.
Выясним, как решить эту задачу в запросе двумя способами:
Вариант А. Через сравнение периодов (наиболее производительный):
ВЫБРАТЬ
Продажи.Ссылка КАК Документ,
Продажи.Дата КАК Дата
ИЗ
Документ.РеализацияТоваровУслуг КАК Продажи
ГДЕ
КОНЕЦПЕРИОДА(Продажи.Дата, КВАРТАЛ) = КОНЕЦПЕРИОДА(Продажи.Дата, МЕСЯЦ)
Вариант Б. С использованием оператора В и функции МЕСЯЦ:
ВЫБРАТЬ
Продажи.Ссылка КАК Документ
ИЗ
Документ.РеализацияТоваровУслуг КАК Продажи
ГДЕ
МЕСЯЦ(Продажи.Дата) В (3, 6, 9, 12)
Оба варианта в запросах работают быстро, но вариант А считается более универсальным, так как СУБД эффективнее оптимизирует запросы с функциями приведения периодов при наличии соответствующих индексов по полю даты.
Для повседневных задач во встроенном языке 1С 8.3 лучшим выбором будет использование конструкции КонецКвартала(Дата) = КонецМесяца(Дата). Она избавляет разработчика от написания лишних комментариев, легко читается и полностью соответствует стандартам разработки фирмы "1С". Математический метод с остатком от деления % 3 = 0 отлично подойдет в качестве компактной альтернативы для простых локальных вычислений.