CronジェネレーターをJavaScriptで作った話|「0 10 * * 1-5」が読めるようになる

CronジェネレーターをJavaScriptで作った話|「0 10 * * 1-5」が読めるようになる

こんな文字列を見たことはありませんか?

0 10 * * 1-5

「何かの呪文?」と思うかもしれません。これは Cron式(クーロン式) と呼ばれる、「いつ実行するか」を表すスケジュール記法です。

この記事では、Lapis Tech Toolsの Cronジェネレーター を題材に、Cron式の読み方・書き方とJavaScriptでの実装を完全初心者向けに解説します。


1. Cronとは何か

Cron(クーロン) は、LinuxやMacOSに標準搭載されているジョブスケジューラーです(crontabコマンドの詳細はIT用語辞典へ)。「毎日夜11時にバックアップを取る」「毎週月曜の朝9時にメールを送る」といった定期的な処理を自動実行するために使います。

エンジニアの仕事でCronを使う場面は無数にあります:

場面具体例
Linux crontabサーバーのバックアップ・ログ削除・SSL証明書更新
AWS EventBridgeLambda関数の定期実行・バッチ処理
GitHub Actions定期的なテスト実行・依存パッケージの更新確認
Google Apps Scriptスプレッドシートへの自動データ取得

なぜ「Cron」という名前なのか?

ギリシャ語で「時間」を意味する「Chronos(クロノス)」が語源です。1975年にAT&Tベル研究所のBrian Kernighanが開発したと言われています。半世紀近く経った今も、クラウド・CI/CDで現役のツールです。


2. Cron式の5つのフィールド

Cron式は左から順に「分・時・日・月・曜日」の5つのフィールドで構成されます:

┌─────── 分 (0-59)
│ ┌───── 時 (0-23)
│ │ ┌─── 日 (1-31)
│ │ │ ┌─ 月 (1-12)
│ │ │ │ ┌ 曜日 (0-6、0=日曜)
│ │ │ │ │
0 10 * * 1-5

これを読むと:「毎月・毎日(*)の月〜金(1-5)の10時0分に実行」= 平日の毎朝10時


3. 特殊文字の意味

Cron式には5つの特殊文字があります:

文字意味
*すべて(任意)* * * * * = 毎分
,リスト(複数指定)0,30 * * * * = 毎時0分と30分
-範囲1-5 = 1〜5(月〜金)
/ステップ(間隔)*/15 = 15の倍数(0, 15, 30, 45)
?指定なし(日・曜日のどちらかのみ有効に)AWSのCron式で使用

よく使うパターン

* * * * *        → 毎分
0 * * * *        → 毎時0分(1時間ごと)
0 9 * * *        → 毎日9時0分
0 9 * * 1        → 毎週月曜9時0分
0 9 1 * *        → 毎月1日9時0分
0 9 * * 1-5      → 平日(月〜金)9時0分
*/30 * * * *     → 30分おき(0分、30分)
0 0,12 * * *     → 毎日0時と12時

なぜ / がステップを意味するのか?

*/15 は「0から始めて15ずつ進む」という意味です。数学の等差数列のような考え方です。5/15 なら「5から始めて15ずつ進む = 5, 20, 35, 50分」になります。


4. JavaScriptの実装:Cron式を日本語に翻訳する

このツールの核心は「Cron式 → 人間が読める日本語」への変換処理です。

function translateCron(cron) {
  const parts = cron.trim().split(/\s+/);
  if (parts.length !== 5) throw new Error('5つのフィールドが必要です');

  const [minute, hour, day, month, weekday] = parts;

  // 各フィールドを日本語に変換
  const minuteStr = translateField(minute, '分', 0, 59);
  const hourStr   = translateField(hour, '時', 0, 23);
  const dayStr    = translateField(day, '日', 1, 31);
  const monthStr  = translateField(month, '月', 1, 12);
  const weekStr   = translateWeekday(weekday);

  return `${monthStr}${dayStr}${weekStr}の${hourStr}${minuteStr}に実行`;
}

フィールドごとの翻訳関数

function translateField(value, unit, min, max) {
  if (value === '*') return `毎${unit}`;

  // "*/15" → 「15分ごと」
  if (value.startsWith('*/')) {
    return `${value.slice(2)}${unit}ごと`;
  }

  // "1-5" → 「1〜5月」
  if (value.includes('-')) {
    const [start, end] = value.split('-');
    return `${start}〜${end}${unit}`;
  }

  // "1,15" → 「1,15月」
  if (value.includes(',')) {
    return `${value}${unit}`;
  }

  // "10" → 「10時」
  return `${value}${unit}`;
}

なぜフィールドを分割して個別に処理するのか?

Cron式の5フィールドはそれぞれ独立したルールを持っています。一度に全体をパースしようとすると、条件分岐が爆発的に複雑になります。「フィールドを分割して、それぞれを専用の関数で処理する」という分割統治の考え方はプログラミングの基本原則です。


5. UIの設計:5つの独立した入力欄

ツールの上部には「Cron式をそのまま入力する」テキストボックス、下部には「5つの欄を別々に入力する」UIがあります。

どちらを操作しても、もう一方が即座に更新されます。

// 個別フィールド → Cron式を更新
document.querySelectorAll('.cron-part').forEach(input => {
  input.addEventListener('input', () => {
    const parts = [...document.querySelectorAll('.cron-part')]
      .map(el => el.value || '*');
    cronInput.value = parts.join(' ');
    updateTranslation(cronInput.value);
  });
});

// Cron式 → 個別フィールドを更新
cronInput.addEventListener('input', () => {
  const parts = cronInput.value.trim().split(/\s+/);
  if (parts.length === 5) {
    document.querySelectorAll('.cron-part').forEach((el, i) => {
      el.value = parts[i];
    });
  }
  updateTranslation(cronInput.value);
});

なぜ2つの入力方法を用意したのか?

Cron式を知っている人は直接テキストで入力したい。知らない人は「分」「時」「曜日」を別々のフォームで入力したい。どちらのユーザーにも対応することで、初心者から上級者まで同じツールを使えるようにしています。「Cron式とは何か知らないけど、週次バッチを設定したい」という人でも使えます。


6. エラーハンドリング

不正な入力に対しては明確なエラーメッセージを表示します:

function validateCronPart(value, min, max) {
  // *、*/n、n-m、n,m,k、単一の数値のみ許可
  const patterns = [
    /^\*$/,           // *
    /^\*\/\d+$/,      // */n
    /^\d+-\d+$/,      // n-m
    /^[\d,]+$/,       // n,m,k
    /^\d+$/,          // n
  ];
  
  if (!patterns.some(p => p.test(value))) {
    throw new Error(`"${value}" は有効なCron式ではありません`);
  }
}

なぜ正規表現(RegExp)を使うのか?

Cron式のフィールドには複数の書き方があります。* */5 1-5 1,3,5 30 — これらすべてを if 文で判定しようとすると、条件分岐が5つ必要です。正規表現を使うと「このパターンに一致するか」を1行で表現できます。パターンマッチングは正規表現の得意分野です。


7. 実際の使い場面

Linux crontabでの設定

# crontabを編集
crontab -e

# 毎日深夜2時にバックアップスクリプトを実行(スクリプトのパーミッションは chmod +x で設定)
0 2 * * * /home/user/backup.sh

# 毎週月曜朝9時にレポートを送信
0 9 * * 1 python3 /home/user/send_report.py

# 5分ごとにサーバー死活監視
*/5 * * * * /home/user/health_check.sh

AWS EventBridgeでの設定

AWSではCron式の前に cron(...) を付ける独自形式を使います(6フィールド):

cron(0 10 ? * MON-FRI *)

         日の代わりに ? を使う(AWSの仕様)

なぜAWSのCron式は違うのか?

AWSのEventBridgeは「日」と「曜日」を同時に指定できないという制約があります。どちらかを ?(指定なし)にする必要があります。また曜日は MON-FRI のような英語表記も使えます。標準Cronとは少し異なるため、注意が必要です。

GitHub Actionsでの設定

on:
  schedule:
    # 平日の毎朝9時(UTC = 日本時間18時)に実行
    - cron: '0 9 * * 1-5'

タイムゾーンに注意

LinuxのCronはサーバーのタイムゾーン、GitHub ActionsやAWS EventBridgeはUTC(協定世界時)で動作します。日本時間(JST = UTC+9)でスケジュールするには、時刻から9を引いた値を設定します。「日本時間9時」→「UTC 0時」= 0 0 * * *


8. まとめ:Cron式から学べること

知識の種類学べる内容
Linux/インフラcrontab・定期実行の仕組み・タイムゾーン
クラウドAWS EventBridge・GitHub Actions のスケジューリング
JavaScript文字列分割・正規表現・双方向バインディング
UI設計異なる習熟度のユーザーへの対応・双方向入力

Cron式は最初は暗号のように見えますが、5フィールドの構造と4つの特殊文字さえ覚えれば読めるようになります。0 10 * * 1-5 = 平日の毎朝10時、ぜひ覚えてみてください。

スクリプトのパーミッション設定で詰まったときはchmodパーミッション計算機を、バッチ処理のJSONポリシー記述にはJSONフォーマッターを合わせて使うのがおすすめです。

→ Cronジェネレーターを使ってみる


ツール解説シリーズ:第1回・IP計算機 | 第2回・Base64エンコーダー | 第3回・chmod計算機 | 第4回・JSONフォーマッター | 今ここ(第5回・Cronジェネレーター) | 第6回・正規表現テスター | 第7回・UUIDジェネレーター | 第8回・Markdownプレビュー

この記事をシェアする

関連記事


CHECK IT OUT

Members Only

サブスク加入者限定の コンテンツを配信中

  • 毎月のAI・自動化トレンドレポート
  • クリエイター向け業務効率化テンプレート
  • ツール選定・SaaS比較まとめ(限定公開)
Discord サーバー & LINE 公式の両方で通知します
クリエイター・個人事業主向け 受付中

「これ自動化できないかな?」 そのアイデア、ITで実現できます。

業務の自動化・お客様向けツール開発・AI活用まで、クリエイター・個人事業主専門のITコンサルタントが対応します。まずは気軽にご相談ください。

LINEで相談 フォームで相談