Quartz特殊文字:L、W、#の解説
QuartzのL、W、#演算子の詳細なトークンレベルガイダンス。実行時の驚きなく正確なスケジュールを構築できます。
Quartzジェネレーターを開くQuartz特殊文字が重要な理由
ほとんどのcronミスはデプロイ前に始まります。スケジュールの意図と構文が乖離するのです。標準5フィールドcronは分、時、日、月、曜日をカバーします。Quartzはこれを秒フィールド、年フィールド、そして標準cronでは不可能なスケジューリング精度を実現する3つの特殊文字 — L、W、# — で拡張します。
これらの文字は、配置されるフィールドによって異なる動作をし、小さな誤解がスケジュールの間違った日の実行や実行スキップにつながります。この記事では、実践的な例、バリデーションチェック、CronwiseのQuartzジェネレーターで実行できる明確なアクションとともに、各文字を説明します。
L文字:最終日と最終曜日
Lは「最終(Last)」を意味し、日と曜日の2つのフィールドで有効です。配置場所によって意味が変わります。
日フィールドでのL
単独で使用した場合、Lは月の最終日を意味します。式0 0 18 L * ?は毎月の最終日の午後6:00に実行されます — 28日、29日、30日、31日のいずれでも。月の長さをハードコードする必要はありません。
Lを負のオフセットと組み合わせることもできます。L-3は最終日の3日前を意味します。31日ある月では28日に解決され、うるう年でない2月では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番目の出現を指定します。構文はday#Nで、dayは曜日番号(1–7、日曜日から土曜日)、Nは出現回数(1–5)です。
実践的な例
0 0 10 ? * 2#1は毎月第1月曜日の午前10:00に実行されます。0 0 14 ? * 6#3は第3金曜日の午後2:00に実行されます。これらのパターンは、日の範囲と条件ロジックに依存する脆弱な回避策を置き換えます。
Nが実際の出現数を超えた場合
2#5(第5月曜日)を指定した場合、月曜日が4回しかない月ではスケジュールは実行されません。Quartzはこれをエラーではなく不一致として扱います — サイレントなスキップであるため、実行回数のモニタリングが不可欠です。
#文字は日フィールドには使用できず、リスト、範囲、インクリメントと組み合わせることもできません。各曜日フィールドは最大1つの#指定を受け入れます。
エッジ動作と障害モード
これらの文字に関する微妙なミスは、バリデーションエラーをトリガーすることはまれですが、意図からサイレントに逸脱します。
よくある落とし穴
| 式 | 期待 | 実際 | 修正 |
|---|---|---|---|
0 0 9 L * 6 | 金曜日が最終日の場合 | 競合:両方の日フィールドが設定 | 一方の日フィールドに?を使用 |
0 0 9 1W * ?(1日が土曜日) | 前の金曜日 | 3日の月曜日(月を跨がない) | 次回実行プレビューで確認 |
0 0 9 ? * 2#5 | 毎月第5月曜日 | 月曜日が5回ある月のみ | 実行回数モニタリングを追加 |
0 0 9 LW * ?(2月) | 最終平日 | 年によって26日、27日、または28日 | タイムゾーン対応プレビューを確認 |
最も危険なエラーは、?をプレースホルダーとして使用せずに日と曜日の両方に値を指定することです。Quartzは正確に1つの日フィールドに?を要求します。省略すると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回の実行を確認 | 月の境界の驚きを表面化 | すべての日付が意図と一致 |
| タイムゾーンの整合性を確認 | サーバー vs ビジネスTZの不一致 | 実行がターゲットタイムゾーンと一致 |
?の配置を確認 | 両方の日フィールドがアクティブは未定義 | 1つの日フィールドに?あり |
| サイレントスキップを確認 | #5は年12回未満の実行になる可能性 | 年間回数をドキュメント化 |
Cronwiseの次回実行プレビューは、選択したタイムゾーンで次回10回の実行を返し、テストジョブをデプロイせずにこれらの基準を確認できます。チームがタイムゾーンをまたいで運用している場合は、追加のガイダンスとしてグローバルチームのためのCronタイムゾーン解説をご覧ください。
すべてをまとめて
QuartzのL、W、#文字は、標準cronでは不可能なスケジューリングの力を提供します。Lは可変の月の長さに適応し、Wは営業日に実行を整合させ、#は特定の曜日の出現に実行を固定します。正しく使用すれば、脆弱な回避策を排除し、スケジュールの意図を式自体で明確にします。
主要な決定ルールは簡単です。月末ロジックにはLを使用。最近接平日が必要な場合はWを使用。月のN番目の曜日には#を使用。使用しない日フィールドには常に?を配置。そしてデプロイ前に常に次回実行プレビューで確認。
Quartzスケジュールを構築またはバリデーションする準備はできましたか?Cronwise Quartzジェネレーターを開いて、ビジュアルに式を構築し、わかりやすい説明を確認し、ターゲットタイムゾーンで実行時刻をプレビューしましょう。さらに多くのcronスケジューリングガイドと詳細な解説は、Cronwiseのすべてのcron記事を閲覧してください。