cron式の5フィールドを業務でハマらず読めるようになる

約6分

cron 式は「読めば分かる」と思って毎回読み直してしまう代表格です。0 */6 * * * を見て即座に「6時間おき」と分かる人でも、0 0 1,15 * 1-5 あたりになると首をかしげる仕様で、ドキュメントの再確認が習慣になりやすい構文でもあります。本記事では cron 式の構文を、つまずきやすいポイント中心に整理します。

基本構造:5つのフィールドをスペース区切り

標準的な cron 式は5つのフィールドからなり、左から順に時間の小さい単位 → 大きい単位という並びです。

*  *  *  *  *
│  │  │  │  │
│  │  │  │  └── 曜日 (0-6, 0=日曜)
│  │  │  └───── 月 (1-12)
│  │  └──────── 日 (1-31)
│  └─────────── 時 (0-23)
└────────────── 分 (0-59)

注意点として:

  • 秒のフィールドは標準 cron には無い。Quartz スケジューラや一部のフレームワーク独自拡張だと「6フィールドで秒が先頭」になりますが、Linux の crond は5フィールドが標準です
  • 曜日は 0=日曜が一般的 ですが、いくつかの実装では 7=日曜も受け付けます。07 の両方を試すのは避けて、ドキュメントを確認する癖をつけたほうが安全です
  • 月と曜日は名前で書ける実装もある(JAN-DEC / SUN-SAT)。ただし可搬性は下がります

4つの記号:* , - /

各フィールドで使える記号は4つだけ覚えれば十分です。

* :すべての値

* * * * * は「毎分実行」になります。各フィールドの取りうる値全部を意味するので、分フィールドの *0-59 と等価です。

, :複数の特定値

0 9,12,18 * * * で「毎日 9時・12時・18時」のように、不連続な複数の値を指定できます。

- :範囲

0 9-17 * * 1-5 で「平日の 9時から17時の毎正時」になります。範囲の両端は含まれます(inclusive)。

/ :刻み幅(ステップ)

*/15 * * * * で「15分おき」、0 */6 * * * で「6時間おき」になります。*/N は「N で割り切れる値で実行」という意味で、*/15 の場合は 0, 15, 30, 45 分で実行されます(毎時14分の起動時に最初の実行が15分後、ではない点に注意)。

/* 以外とも組み合わせられて、30-50/5 * * * * のように「30〜50分の範囲を5分刻み」とも書けます。あまり使う機会はないですが、組み合わせ可能と知っておくと読むときに迷いません。

最大の落とし穴:日と曜日の OR 結合

cron で最も誤解を生むのが、日(3番目)と曜日(5番目)の組み合わせは AND ではなく OR という挙動です。

0 0 1 * 1

これは直感的には「毎月1日かつ月曜日(つまり1日と月曜日が重なる日)」と読めますが、実際は「毎月1日 OR 毎週月曜日」になります。両方とも * でないとき、cron はどちらかを満たせば実行する仕様です。

両方とも * の場合(例:0 0 * * *)は単に「毎日 0時」で、AND・OR の議論が発生しません。片方だけ * の場合もシンプルで、* でないほうのフィールドだけが効きます。問題は両方とも * でないケースで、ここで OR が発動します。

「毎月第一月曜日」を素直に表現できない

この OR 仕様のせいで、「毎月第一月曜日」のような自然な要件を標準 cron で簡潔に書く方法はありません。よくある回避策:

# 月曜日に実行し、シェル側で日付を確認する
0 0 * * 1 [ "$(date +%d)" -le 7 ] && /path/to/job

この限界が嫌で、Quartz cron のような拡張版では # 記号で「第N週の特定曜日」を表現できるようになっています(例:0 0 0 * MON#1)。標準 cron に同じ機能は無いので、複雑な定期実行が必要なら最初から Quartz や別のスケジューラを検討したほうが幸せになれます。

よくある書き間違いと、その挙動

実装やレビューで頻出するミスを並べます。

書いたもの意図実際の挙動
* */1 * * *1時間に1回毎分実行(分が *
0 0 * * *1時間ごと1日1回(午前0時のみ)
0 9-17/2 * * *9, 11, 13, 15, 17時9, 11, 13, 15, 17時(これは正しい)
0 0 * * 7日曜0時実装による(標準cronは6まで)

「1時間ごと」は 0 * * * *(分が0のときだけ起動)です。* */1 * * * は分が * なので毎分起動してしまい、CI で気付かずに検証ジョブが大量に走る、という事故が起きやすいパターンです。

システムを跨ぐと挙動が違う

cron 実装によって細部の挙動が違う点は最後まで気をつけたほうがいいです。

  • タイムゾーン:crond はホストの TZ に従いますが、AWS EventBridge や GitHub Actions は UTC固定です。「9時に実行」のつもりが UTC 9時 = JST 18時、というのはあるある
  • 存在しない日0 0 31 * * は1月・3月・5月などの31日にだけ実行される(30日までしかない月はスキップ)
  • DST(夏時間):夏時間がある国では、時刻が飛ばされたり繰り返されたりした時間帯のジョブの扱いが実装ごとに違う
  • 同時実行:crond は前回の実行が終わっていなくても次の時刻が来たら新しいプロセスを起動する。重ねたくない場合は flock などでロック処理を入れる

書いた式が意図通りか確かめたいときは、本サイトの cron 式チェッカーで次の何回かの実行時刻を表示させるのが手早く、机上で読み下すよりミスに気付きやすくなります。