0 3 * * 1-5 というたった一行で、「平日の午前3時に実行」というスケジュールを表現できる――それがCron式です。Linuxのcrontab、GitHub Actions、Kubernetes CronJob、各種クラウドのスケジューラまで、定期実行の世界はほぼこの文法で動いています。

Cron式の書き方マスターガイド:5つのフィールドと特殊文字を実例で理解する

この記事では、Cron式の5つのフィールドと特殊文字を実際の式とその意味をセットで見ながら整理します。最後に、現場でハマりやすい落とし穴とよくある質問もまとめました。

Cron式の基本構造:5つのフィールド

標準的なcrontabのCron式は、半角スペースで区切られた5つのフィールドで構成されます。

┌───────────── 分        (0 - 59)
│ ┌───────────── 時      (0 - 23)
│ │ ┌───────────── 日    (1 - 31)
│ │ │ ┌───────────── 月  (1 - 12)
│ │ │ │ ┌───────────── 曜日 (0 - 7, 0と7は日曜)
│ │ │ │ │
* * * * *

各フィールドが取れる値の範囲は次のとおりです。

フィールド範囲補足
0–59
0–230が深夜0時、23が23時
1–31月の日付
1–12JANDEC も可(環境による)
曜日0–70と7が日曜、1が月曜。SUNSAT も可

補足: GitHub ActionsやKubernetesも基本はこの5フィールド形式です。一方、QuartzやAWS EventBridgeは「秒」や「年」を加えた6〜7フィールド形式を使うため、後述する ?L などの特殊文字が必要になります。

特殊文字の意味を実例で理解する

Cron式の表現力は、各フィールドに書ける特殊文字から生まれます。

記号意味読み方
*すべての値* * * * *毎分
,値の列挙0 9,12,18 * * *毎日 9時・12時・18時
-範囲0 9-17 * * *毎日 9時〜17時の毎正時
/間隔(ステップ)*/15 * * * *15分おき
?指定なし(日/曜日用)0 0 ? * MON毎週月曜0時(日は不問)
L最終(last)0 0 L * *毎月末日の0時
W直近の平日0 0 15W * *15日に最も近い平日
#第n週の曜日0 9 ? * MON#1第1月曜の9時

?LW# はQuartz系スケジューラ(Spring、Jenkins、EventBridgeなど)の拡張で、標準のcrontabでは使えない点に注意してください。

/(ステップ)の読み方

*/15 は「0から始めて15ごと」、つまり 0,15,30,45 を意味します。範囲と組み合わせると、開始位置を指定できます。

*/15 * * * *     → 0,15,30,45分(15分おき)
5/10 * * * *     → 5,15,25,35,45,55分(5分から10分おき)
0 9-17/2 * * *   → 9,11,13,15,17時(9〜17時の2時間おき)

よく使うスケジュール例

そのままコピーして使える、現場で頻出のパターンです。

やりたいことCron式
毎分* * * * *
5分おき*/5 * * * *
毎時0分0 * * * *
毎日 午前0時0 0 * * *
毎日 午前9時30分30 9 * * *
平日 午前3時0 3 * * 1-5
平日 9〜18時の30分おき*/30 9-18 * * 1-5
毎週月曜 午前9時0 9 * * 1
毎月1日 午前0時0 0 1 * *
毎月末 午前0時(Quartz系)0 0 L * *
第1月曜 午前9時(Quartz系)0 9 ? * MON#1

現場でハマりやすい落とし穴

1. 「日」と「曜日」を両方指定するとOR条件になる

0 0 1 * 1 は「1日 または 月曜の午前0時」です。「1日が月曜のとき」というAND条件ではありません。直感に反するため、どちらか一方だけを指定し、もう片方は *(Quartz系では ?)にするのが安全です。

2. タイムゾーンは実行環境に依存する

多くのcronはサーバーのタイムゾーン、コンテナやCIはUTCで動くことが珍しくありません。0 0 * * * と書いても、JSTの0時ではなくUTCの0時(=JST午前9時)に動く、という事故は頻発します。JSTの深夜2時に動かしたいなら、UTC基準では 0 17 * * * です。

3. 分のフィールドを * にすると毎分実行される

* 3 * * *(毎日3時に1回のつもり)は、3時台の60回実行されます。「3時ちょうどに1回」なら 0 3 * * * です。

4. 短すぎる間隔の重複実行

5分おきのジョブが5分以内に終わらないと、前回が走っている間に次が起動して多重実行になります。処理時間に余裕を持った間隔設定か、ロック機構を検討してください。

ツールで「保存前の不安」を解消する

Cron式は読み書きに慣れが必要で、特に上記の落とし穴は目視では気づきにくいものです。Cron式パーサー では、入力したCron式を日本語の説明に変換し、直近の実行日時をシミュレーションして確認できます。デプロイ前に「本当に意図したスケジュールか」を一目で検証できます。

よくある質問

Cron式の曜日は0と7のどちらが日曜ですか?

多くの実装で0と7の両方が日曜を指します。月曜は1、土曜は6です。混乱を避けるため、SUN MON のような英語3文字表記が使える環境ではそちらを使うと安全です。

「毎月最終日」はどう書きますか?

QuartzやEventBridgeなど L をサポートする環境なら 0 0 L * * で表せます。標準のcrontabには L がないため、月初に翌月末を計算する、あるいは月末候補日(28〜31日)を実行してスクリプト側で判定する、といった回避策が必要です。

UTCとJSTのずれはどう扱えばよいですか?

JSTはUTC+9です。JSTの時刻からUTCのCron式を作るには時フィールドから9を引きます(マイナスになる場合は前日扱いで+24)。例えばJSTの深夜2時はUTCの前日17時なので 0 17 * * * です。スケジューラにタイムゾーン指定があれば、それを使うのが最も確実です。

*/50/5 は同じですか?

分フィールドではどちらも「5分おき(0,5,10,…)」で実質同じです。*/5 は「全範囲を5刻み」、0/5 は「0から5刻み」という意味で、開始位置をずらしたいとき(例 7/15)に明示的な開始指定が役立ちます。