Cronwise

Специальные символы Quartz: L, W и # — подробный разбор

Глубокое руководство по операторам L, W и # в Quartz для создания точных расписаний без сюрпризов во время выполнения.

Открыть генератор Quartz

Почему специальные символы Quartz важны

Большинство ошибок cron возникают ещё до развёртывания, когда замысел расписания расходится с синтаксисом. Стандартный 5-полевой cron охватывает минуты, часы, день месяца, месяц и день недели. Quartz расширяет это полем секунд, полем года и тремя специальными символами — L, W и #, — которые обеспечивают точность планирования, недоступную стандартному cron.

Эти символы ведут себя по-разному в зависимости от того, в каком поле они используются, и небольшие недопонимания каскадно превращаются в расписания, срабатывающие в неправильный день или полностью пропускающие запуски. Эта статья объясняет каждый символ с практическими примерами, проверками валидации и конкретными действиями в генераторе Quartz Cronwise.

Символ L: последний день и последний рабочий день

L означает «последний» (last) и допустим в двух полях: день месяца и день недели. Его значение меняется в зависимости от места использования.

L в поле дня месяца

При использовании отдельно L означает последний день месяца. Выражение 0 0 18 L * ? срабатывает в 18:00 в последний день каждого месяца — будь то 28-е, 29-е, 30-е или 31-е число. Вам не нужно жёстко задавать длину месяцев.

Можно комбинировать L с отрицательным смещением. L-3 означает три дня до последнего дня. В 31-дневном месяце это 28-е число; в феврале невисокосного года — 25-е. Это полезно для окон закрытия биллинга.

L в поле дня недели

В поле дня недели L используется в паре с номером дня: 6L означает последнюю пятницу месяца. Выражение 0 0 9 ? * 6L срабатывает в 9:00 в последнюю пятницу каждого месяца — полезно для обработки зарплат или отчётов на конец месяца, которые должны приходиться на конкретный день недели.

Символ W: ближайший рабочий день

W допустим только в поле дня месяца. Он выбирает ближайший рабочий день (с понедельника по пятницу) к указанной дате. Запишите 15W, чтобы обозначить «рабочий день, ближайший к 15-му числу».

Как разрешается W

Если 15-е число выпадает на субботу, расписание сдвигается на пятницу 14-го. Если выпадает на воскресенье — на понедельник 16-го. Разрешение никогда не пересекает границы месяца: если 1-е — суббота, 1W разрешается в понедельник 3-го, а не в пятницу предыдущего месяца.

Комбинация L и W

Quartz позволяет комбинацию LW, означающую «последний рабочий день месяца». Это идеально для финансовых закрытий на конец месяца, которые должны выполняться в рабочий день. Если последний день — суббота, LW разрешается в пятницу. Обратите внимание: W нельзя комбинировать со списком или диапазоном — выражения вроде 1W,15W недопустимы.

Символ #: N-й день недели месяца

# допустим только в поле дня недели и указывает N-е вхождение дня недели в месяце. Синтаксис: день#N, где день — номер дня недели (1–7, от воскресенья до субботы), а N — порядковый номер вхождения (1–5).

Практические примеры

0 0 10 ? * 2#1 срабатывает в 10:00 в первый понедельник каждого месяца. 0 0 14 ? * 6#3 срабатывает в 14:00 в третью пятницу. Эти паттерны заменяют хрупкие обходные решения с диапазонами дней месяца и условной логикой.

Когда N превышает фактическое количество вхождений

Если вы указали 2#5 (пятый понедельник), расписание не сработает в месяцах, где только четыре понедельника. Quartz расценивает это как отсутствие совпадения, а не ошибку — тихий пропуск, делающий мониторинг количества запусков необходимым.

Символ # не может использоваться в поле дня месяца и не комбинируется со списками, диапазонами или инкрементами. Каждое поле дня недели принимает максимум одну спецификацию #.

Поведение на границах и режимы сбоев

Тонкие ошибки с этими символами редко вызывают ошибки валидации, но молча отклоняются от замысла.

Типичные подводные камни

ВыражениеОжидаетсяФактическиИсправление
0 0 9 L * 6Последний день, если пятницаКонфликт: оба поля дней заданыИспользуйте ? в одном поле дней
0 0 9 1W * ? (1-е — суббота)Предыдущая пятницаПонедельник 3-го (без пересечения месяцев)Проверьте предварительным просмотром
0 0 9 ? * 2#5Пятый понедельник ежемесячноТолько в месяцах с пятью понедельникамиДобавьте мониторинг количества запусков
0 0 9 LW * ? в февралеПоследний рабочий день26-е, 27-е или 28-е число в зависимости от годаПроверьте предварительный просмотр с часовым поясом

Самая опасная ошибка — указание значений в обоих полях дней без использования ? как заполнителя. Quartz требует, чтобы ровно одно поле дней содержало ?. Его отсутствие приводит к ошибке разбора или неопределённому поведению в зависимости от версии Quartz.

Фреймворк выбора: какой символ использовать

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

ТребованиеСимволПолеПример
Запуск в последний день каждого месяцаLДень месяца0 0 18 L * ?
Запуск за N дней до конца месяцаL-NДень месяца0 0 18 L-3 * ?
Запуск в последний конкретный день неделиnLДень недели0 0 9 ? * 6L
Запуск в ближайший рабочий день к датеWДень месяца0 0 9 15W * ?
Запуск в последний рабочий день месяцаLWДень месяца0 0 17 LW * ?
Запуск в N-й день недели месяца#День недели0 0 10 ? * 2#1

Когда требование чисто по дате («15-е число»), специальные символы не нужны вовсе. Используйте W только при необходимости привязки к рабочим дням. Используйте # только когда конкретное вхождение дня недели важнее фиксированной даты. А L — когда логика конца месяца должна автоматически адаптироваться к переменной длине месяцев.

Подготовка к продакшену: проверки перед развёртыванием

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

Контрольный список проверки

ПроверкаПочему это важноКритерий прохождения
Разбор без ошибокПодтверждает синтаксическую корректностьНет исключений парсера
Проверить 10 ближайших запусковВыявляет сюрпризы на границах месяцевВсе даты соответствуют замыслу
Проверить соответствие часового поясаНесовпадение серверного и бизнес-часового поясаЗапуски совпадают с целевым часовым поясом
Подтвердить размещение ?Оба поля дней активны — неопределённое поведениеОдно поле дней содержит ?
Проверить тихие пропуски#5 может срабатывать < 12 раз в годГодовое количество запусков задокументировано

Предварительный просмотр Cronwise возвращает 10 ближайших запусков в выбранном часовом поясе, позволяя проверить эти критерии без развёртывания тестовой задачи. Если ваша команда работает в нескольких часовых поясах, ознакомьтесь с Часовые пояса в cron для глобальных команд для дополнительного руководства.

Всё вместе

Символы L, W и # в Quartz дают мощность планирования, недоступную стандартному cron. L адаптируется к переменной длине месяцев, W привязывает выполнение к рабочим дням, а # фиксирует запуски на конкретных вхождениях дней недели. При правильном использовании они устраняют хрупкие обходные решения и делают замысел расписания явным в самом выражении.

Ключевые правила выбора просты. Используйте L для логики конца месяца. Используйте W, когда нужен ближайший рабочий день. Используйте # для N-го дня недели месяца. Всегда размещайте ? в поле дней, которое не используете. И всегда проверяйте предварительным просмотром запусков перед развёртыванием.

Готовы собрать или проверить ваше Quartz-расписание? Откройте генератор Quartz Cronwise для визуального создания выражений, просмотра описаний на понятном языке и предварительного просмотра запусков в целевом часовом поясе. Больше руководств по cron-планированию и углублённых разборов — все статьи по cron на Cronwise.