Cron 式の構文を解説
cron 式は、開発者が一度学んで詳細を忘れ、その後 6 か月ごとに再度調べる類のトピックの 1 つです。30 9 * * 1-5 のような 5 文字の文字列は、驚くほど特定のスケジュールをエンコードできます — 「平日 9:30 AM」 — しかし、構文には実際の混乱を引き起こすのに十分なエッジケースがあります: 0 インデックスと 1 インデックスのフィールド、日曜日が 0 と 7 の両方であること、Unix 標準と Quartz の 6 フィールド拡張の違い、そしてステップ値と範囲を組み合わせたときの微妙な動作。
このガイドでは、cron 構文を第一原則からカバーし、その後、すべての特殊文字を具体的な例で説明します。Linux デーモン用の cron ジョブを書く場合でも、GitHub Actions スケジュールを設定する場合でも、AWS EventBridge ルールをセットアップする場合でも、同じ基礎概念が適用されます — 途中でいくつかの重要なプラットフォームの違いも説明します。
5 つの標準フィールド
標準的な cron 式は、左から右に読む、スペースで区切られた 5 つのフィールドを持ちます: 分、時、日、月、曜日。各フィールドは、その次元に沿ってジョブが実行されるタイミングを制約します。5 つのフィールドすべてが同時に一致したときにのみジョブが実行されます。
# フィールド 位置 範囲 特殊文字
# ─────────────────────────────────────────────────
# 分 1 0-59 * / , -
# 時 2 0-23 * / , -
# 日 3 1-31 * / , - ? L W
# 月 4 1-12 または JAN-DEC * / , -
# 曜日 5 0-7 (0=7=日) または SUN-SAT * / , - ? L # 30 9 * * 1-5 のような式を読む: 分 30、時 9、任意の日、任意の月、曜日 1 から 5 (月曜日から金曜日)。結果: 毎平日 9:30 AM。
フィールド 1: 分 (0–59)
分フィールドは、ジョブが実行されるべき時の分を指定します。0 は時の最初、30 は半過ぎ、59 は時が変わる 1 分前を意味します。* を使用すると、毎分ジョブを実行します。
フィールド 2: 時 (0–23)
時は 24 時間制を使用します。0 は深夜、12 は正午、23 は 11:00 PM です。cron に AM/PM はありません — 9:00 AM のジョブは時 9 であり、9:00 PM のジョブは時 21 です。
フィールド 3: 日 (1–31)
他のフィールドとは異なり、日は 0 ではなく 1 から始まります。有効な値は 1 から 31 です。特定の月に存在しない日 (たとえば 4 月の 31 日) を指定すると、ジョブはその月に実行されないだけです。Quartz では、特殊文字 L は、何日あるかに関係なく、月の最終日を表します。
フィールド 4: 月 (1–12)
月の値は 1 (1 月) から 12 (12 月) まで実行されます。多くのスケジューラーは、3 文字の略語も受け入れます: JAN、FEB、MAR、APR、MAY、JUN、JUL、AUG、SEP、OCT、NOV、DEC。これらはほとんどの実装で大文字小文字を区別しません。
フィールド 5: 曜日 (0–7)
これは最も多くの歴史的な荷物を持つフィールドです。0 と 7 の両方が日曜日を表します — これは初期の Unix からの互換性の癖です。月曜日は 1、火曜日は 2、土曜日は 6 までです。3 文字の名前もここで動作します: SUN、MON、TUE、WED、THU、FRI、SAT。
日と曜日の両方が指定されている (どちらも * ではない) 場合、ほとんどの Unix cron デーモンは OR ロジックを使用します: いずれかのフィールドが一致するとジョブが実行されます。これは多くの開発者を驚かせます。「15 日、ただし平日のみ」が欲しい場合は、cron 式ではなくジョブスクリプト自体でそれを処理する必要があります。
特殊文字
アスタリスク (*) — すべての値
アスタリスクは、フィールドのすべての有効な値に一致します。分フィールドでは、* は分 0 から 59 を意味します。月フィールドでは、12 か月すべてを意味します。これは cron 式で最も一般的な文字です。
スラッシュ (/) — ステップ値
スラッシュはステップ間隔を定義します。分フィールドの */5 は「5 分ごと」を意味します。より正確には、「範囲内の最初の値から始まる 5 で割り切れる範囲内のすべての値」を意味します。したがって、分の */5 は 0、5、10、15、20、25、30、35、40、45、50、55 と評価されます。
ステップは範囲と組み合わせることができます: 分フィールドの 10-30/5 は、分 10 と分 30 の間の 5 分ごとを意味し、10、15、20、25、30 を生成します。ステップは範囲の下限から始まります。
カンマ (,) — 値のリスト
カンマは特定の値のリストを作成します。月フィールドの 1,3,5 は 1 月、3 月、5 月を意味します。時フィールドの 9,17 は 9:00 と 17:00 を意味します。必要な数の値をリストでき、他の構造と組み合わせることができます。
ダッシュ (-) — 範囲
ダッシュは包含的な範囲を指定します。曜日フィールドの 1-5 は月曜日から金曜日を意味します。時フィールドの 9-17 は 9 AM から 5 PM を意味します。範囲は両端で包含的です。
クエスチョンマーク (?) — 特定の値なし (Quartz のみ)
標準 Unix cron は ? をサポートしません。Quartz Scheduler では、日または曜日フィールドで「このフィールドは気にしない」を意味するために使用されます。Quartz は日と曜日の間の競合を常に解決できないため、もう一方が指定されたときに 2 つのうち 1 つを ? に設定する必要があります。0 0 15 * ? は「毎月 15 日、任意の曜日」を意味します。0 0 ? * MON は「毎週月曜日、任意の日」を意味します。
L — 最後 (Quartz のみ)
日フィールドの L は月の最終日を意味します。曜日フィールドの L は土曜日、または数字 (例: 5L) と組み合わせると、月内のその曜日の最後の出現を意味します。5L は月の最後の金曜日です。
W — 最も近い平日 (Quartz のみ)
日フィールドの W は、指定された日に最も近い平日 (月曜日から金曜日) を見つけます。15W は 15 日に最も近い平日を意味します。15 日が土曜日の場合、ジョブは 14 日 (金曜日) に実行されます。日曜日の場合は、16 日 (月曜日) に実行されます。W は月境界を越えません。
ハッシュ (#) — 月の N 番目の曜日 (Quartz のみ)
# は月内の曜日の N 番目の出現を指定します。5#2 は月の 2 番目の金曜日を意味します。2#1 は最初の火曜日を意味します。指定された出現が特定の月に存在しない場合、ジョブはその月に実行されません。
一般的な cron パターン
# 毎分
* * * * *
# 毎日深夜 (00:00)
0 0 * * *
# 毎日 9:30 AM
30 9 * * *
# 毎週月曜日 8:00 AM
0 8 * * 1
# 毎月 1 日正午
0 12 1 * *
# 15 分ごと
*/15 * * * *
# 平日 6:00 PM
0 18 * * 1-5 これらのいずれも、任意の式の次の 5 つの実行時間を表示し、無効な構文をハイライトする Cron パーサーツールを使ってテストおよび検証できます。特定の Unix タイムスタンプがローカルタイムゾーンで何に対応するかを確認する必要がある場合は、タイムスタンプ変換ツールを使用します。
6 フィールド拡張: Quartz Scheduler
Quartz Scheduler — Java エコシステムで頻繁に使用され、多くのエンタープライズスケジューラーで採用されています — は、式の先頭に必須の秒フィールドを追加します。形式は次のようになります: 秒 分 時 日 月 曜日。
# Quartz 6 フィールド: 秒 分 時 日 月 曜日
# 毎時、0 秒、30 分に実行
0 30 * * * ?
# 毎日深夜に実行
0 0 0 * * ?
# 5 秒ごとに実行
0/5 * * * * ?
# 月末日の 10:00 AM
0 0 10 L * ?
# 月の最後の金曜日 3:00 PM
0 0 15 ? * 6L
標準 cron との主な違い: 秒フィールド (0–59) が最初で必須です。曜日は 0–6 ではなく 1 (日曜日) から 7 (土曜日) を使用します。もう一方が指定されているとき、日または曜日のいずれかに ? が必要です。そして L、W、# が有効な特殊文字です。
秒フィールドを削除し、曜日の番号付けを調整せずに、Quartz 式を Unix crontab に貼り付けないでください。パーサーは交換可能ではありません。
異なるシステムでの cron
Linux/Unix crontab (Vixie cron)
元の最も一般的な形式。5 つのフィールド、スペース区切り、続いてコマンド。CRON_TZ や TZ のような環境変数がタイムゾーンを設定します。ユーザー crontab は crontab -e で編集します。システム crontab は /etc/cron.d/ にあります。@reboot、@daily、@hourly、@weekly、@monthly のショートカットは、一般的なパターンのエイリアスとして広くサポートされています。
GitHub Actions
GitHub Actions は標準の 5 フィールド cron 構文を使用しますが、タイムゾーンは常に UTC です — 式自体でローカルタイムゾーンを指定する方法はありません。式はジョブごとではなくリポジトリレベルで評価されます。GitHub のインフラストラクチャの高負荷期間中、スケジュールされたワークフローは数分遅延する可能性があることに注意してください。
# GitHub Actions スケジュール構文 (5 フィールド UTC のみ)
on:
schedule:
# 毎日 02:30 UTC に実行
- cron: '30 2 * * *'
# 毎週月曜日 09:00 UTC に実行
- cron: '0 9 * * 1' 公式の GitHub Actions cron ドキュメントは、最小間隔が 5 分であることを記しています — それより頻繁に実行される式は静かに無視されます。
AWS EventBridge (CloudWatch Events)
AWS EventBridge はレート式 (rate(5 minutes)) と cron 式の両方をサポートします。その cron バリアントは 6 フィールドですが Quartz とは異なります: 曜日は Sun–Sat 名または 1 が日曜日の 1–7 を使用します。すべての時刻は UTC で、日または曜日のうち少なくとも 1 つは ? でなければなりません。AWS は W や # 文字をサポートしません。
# AWS EventBridge (UTC の cron、6 フィールドバリアント)
# 毎日 10:00 AM UTC に実行
cron(0 10 * * ? *)
# 毎月最後の平日の 6:00 PM に実行
cron(0 18 L-1 * ? *) Kubernetes CronJob
Kubernetes CronJob は標準の 5 フィールド cron 構文を使用します。タイムゾーンはデフォルトで kube-controller-manager プロセスのタイムゾーン (マネージドクラスターでは通常 UTC) になります。Kubernetes 1.25 は CronJob 仕様に timeZone フィールドを追加し、システムタイムゾーンに依存せずにジョブごとのタイムゾーン設定を可能にしました。
Node.js (node-cron / cron npm)
人気の node-cron パッケージは、標準の 5 フィールド式とオプションの 6 番目の秒フィールドを先頭に追加してサポートします。cron パッケージは Quartz 互換です。両方ともコンストラクターオプションとしてタイムゾーン文字列 (例: America/New_York) をサポートします。期待する形式を確認するには、特定のパッケージのドキュメントを確認してください。
よくある落とし穴
タイムゾーンの前提
cron はサーバーまたはコンテナのタイムゾーンで実行され、クラウド環境では頻繁に UTC です。「9 AM 業務時間」に実行することを意図したジョブが 0 9 * * * として設定されると、9 AM UTC に実行されます — オフセットと DST によっては、ローカルタイムゾーンで 4 AM、5 AM、または 11 AM になる可能性があります。常に CRON_TZ を設定するか、スケジューラーのタイムゾーンフィールドを使用するか、ターゲット時刻を明示的に UTC に変換してください。タイムゾーン変換ツールは、任意のタイムゾーン全体で任意のローカル時刻の UTC 相当を見つけるのに役立ちます。
日 / 曜日の OR ロジック
Unix cron では、日と曜日の両方のフィールドが * でない場合、デーモンはいずれかが一致するとジョブを実行します。したがって、0 9 15 * 1 は毎月 15 日 AND 毎週月曜日に実行されます — 15 日にあたる月曜日のみではありません。AND ロジックを実現するには、ジョブスクリプト内に追加チェックを実装する必要があります。
ステップ値と範囲の混同
*/5 は「0 から始まる 5 分ごと」 (0、5、10 ...) を意味します。5/5 は「5 から始まる 5 分ごと」 (5、10、15 ...) を意味します。5-30/5 は「分 5 と分 30 の間の 5 分ごと」 (5、10、15、20、25、30) を意味します。開始値について意図的でない場合、これらを範囲と混合すると予期しない結果が生じる可能性があります。
「毎秒」の罠
標準 5 フィールド形式の cron の最小解像度は 1 分です。crontab を使って毎秒または数秒ごとに実行する cron ジョブをスケジュールすることはできません。サブ分のスケジューリングには、cron ではなく言語レベルのタイマー (Node.js の setInterval、Python の APScheduler) または専用のキューシステムを使用します。30 秒ごとが必要な場合、2 つの cron ジョブを実行します: 1 つは * * * * * で、もう 1 つは実行前に 30 秒待機します。
月の番号付けの見落とし
標準 cron では、月は 1 (1 月) から 12 (12 月) まで実行されます。一部のプログラミング言語の日付 API では、月は 0 インデックス (0 = 1 月、11 = 12 月) です。日付オブジェクトからプログラム的に cron 式を生成している場合、月フィールドで 1 つずれていないか再確認してください。
式を検証する
Toova の Cron パーサーは、任意の式の次の 5 つのスケジュールされた実行時間を表示し、5 フィールドと 6 フィールド Quartz 構文の両方をサポートし、無効な値をインラインでフラグします。素早い健全性チェックには、平易な英語で式を説明する有名なインタラクティブツールである crontab.guru があります。両方ともブックマークしておく価値があります。
タイムスタンプとスケジュールされた時間を扱うとき、タイムスタンプ変換ツールは任意のタイムゾーン全体で Unix タイムスタンプと人間が読める日付の間を変換します。タイムゾーンに敏感なスケジューリングを伴うジョブでは、最終的な式を書く前にオフセット、DST 遷移、UTC 相当を検証するために、タイムゾーン変換ツールと組み合わせて使用してください。