cron式スケジュール設定を具体例で0から学ぶ

# はじめに
この記事はcron式のスケジュール設定に関する記事です。
今回はcronのスケジュール設定に焦点を当てているので、cronの詳細な仕組み等は解説しません。

スケジュールの記述方法だけでなく具体例も載せているので、スケジュール設定をまだしたことがない、もしくは自信がない方にはぜひ読んでいただきたいです！

# cronのスケジュール設定方法
cronのスケジュールは以下のように設定します。
```
○ ○ ○ ○ ○
│ │ │ │ │
│ │ │ │ └─ 曜日 (0 - 7) (0: 日曜日、1: 月曜日, …, 7: 日曜日)
│ │ │ └─── 月 (1 - 12)
│ │ └───── 日 (1 - 31)
│ └────── 時 (0 - 23)
└──────── 分 (0 - 59)
```

スケジュール設定の具体的なイメージをつけるために具体例を見ていきましょう。
## 具体例
```
30 12 1 1 ?  
```
上記の例であれば「1月1日、12時30分」に何らかの処理が実行されるようなスケジュールになっています。
※曜日の箇所にクエスチョンマークが使用されている理由は、「特殊文字：　?」の項目で説明します。今はとりあえず流しておいてください。

これで、基本的なスケジュール設定をイメージできたと思います。
ただ、以下のようなニーズの場合、どのようにしてスケジュール設定をすればよいのでしょうか？
- 毎日12時に処理を実行したい
- 平日の12時に処理を実行したい
- 30分ごとに処理を実行したい
などなど

このようなニーズに応えるため「特殊文字」というものが存在しています。

## 特殊文字

特殊文字は以下のようにたくさんあります。
一つずつ例を出して説明していきます。

| 記号 | 役割 |
|:-----------:|:------------|
| ,      | 複数の値を追加できる       |
| -      | 各フィールドに対して「一定期間実行し続ける」というスケジュールを指定できる       |
| *       | ワイルドカード (該当フィールドで使用可能なすべての値)を指定できる       |
| /     | 等間隔で処理を実行できる     |
| ?       | 各フィールドが持つスケジュールの条件を無効化できる|
| L         | 日と曜日フィールドで使用でき、各フィールドに設定可能な「最後、又は最大の値」を指定できる |
| #       | 曜日フィールドで使用でき、その月の「第 n 番目のX 曜日」を指定できる      |
| W    | その日に一番近い平日 (月曜～金曜) を指定できる     |

### 特殊文字：　,
カンマは複数の値を追加する際に使用します。

**例「1月1日、12時20分と12時50分」**
```
20,50 12 1 1 ?
```
### 特殊文字：　-
ハイフンは各フィールドに対して「一定期間実行し続ける」スケジュールを設定するために使用します。

**例「1月1日、10時から12時の間、30分になったタイミング（10時半、11時半、12時半）」**
```
30 10-12 1 1 ?
```

### 特殊文字：　*
ワイルドカードは「全て」を意味します。毎分や毎時に処理を処理を実行したい際に使用します。

**例「1月1日、毎時30分」**
```
30 * 1 1 ?
```

### 特殊文字：　/
スラッシュは「等間隔で処理を実行する」スケジュールを設定するために使用します。

**例1 「1月1日、12時0分から15分おき（12時0分、15分、30分、45分）」**

```
0/15 12 1 1 ?
```
<br>

**例2 「1月1日、12時5分から15分おき（12時5分、20分、35分、50分）」**
```
5/15 12 1 1 ?
```

### 特殊文字：　?
クエスチョンマークは各フィールドが持つスケジュールの条件を無効化する際に使用します。

例えば、「毎月10日」に処理が実行されるようなスケジュールを設定したい場合、日には「10」、月には「*」を入れると思います。この際、曜日を指定する必要はありません。
こういった場合にクエスチョンマークを使用します。
以下が今回の場合のスケジュールの例です。

```
30 12 10 * ?  
```
<br>

では、日付と曜日の両方に値を設定した場合はどういったスケジュールになるのでしょうか。
例えば「13日の金曜日に処理を実行したい」というニーズがあったとします。
そこで以下のようなスケジュールを設定しました。
これは正しいでしょうか？
```
0 0 13 * 6
```
答えはNOです。
このスケジュール設定だと「毎月13日or金曜日の0時0分」に処理が実行されてしまいます。

つまり、**日フィールドと曜日フィールドはor条件になってしまうのです**
なので、cronのスケジュール設定だけだと13日の金曜日に処理を実行することはできません。
どうしても実現したい場合は、アプリケーションやコマンド側で条件を絞らないといけません。


### 特殊文字：　L
この特殊文字は、各フィールドに設定可能な「最後、又は最大の値」を指定する際に使用します。
ただし、この特殊文字は**日と曜日**のフィールドでのみ使用可能です。

**例1：日フィールドで使用する場合 「毎月の最終日、12時半」**
```
30 12 L * ?
```

もちろんこれは閏年にも対応しているので、2月の場合は最終日が「28」もしくは「29」となります。
<br>

**例2：曜日フィールドで使用する場合 「毎月の最終水曜日、12時半」**
```
30 12 ? * 3L
```

曜日フィールドの場合は、曜日の指定とセットで「L」を使用します。
曜日フィールドにおける値は「0:日曜, 1:月曜...6:土曜」でしたね。
これに「L」をつけることで「その月の最終○曜日」というスケジュールを設定することができます。

### 特殊文字：　#
シャープは曜日フィールドで使用でき、その月の「第 n 番目のX 曜日」を指定する際に使用します。
表記方法は「X#n」です。

**例：「1月の第3金曜日、12時半」**

```
30 12 ? 1 6#3
```

※月によっては第5週が存在しないことがあるため、例えば 5#5（第5金曜日）などを指定した場合、その月に第5金曜日がないと処理は実行されません。

### 特殊文字：　W
この特殊文字は、「指定した日に一番近い平日 (月曜～金曜) 」を指定する際に使用します。
**例：「毎月の15日に一番近い平日、12時30分」**

```
30 12 15W * ?
```
例えば、15日が土曜であれば、14日の金曜日に処理が実行されます。
もちろん15日が平日（月〜金）であればその日に処理が実行されます。

## 特殊文字同士の組み合わせ
先ほど紹介した特殊文字は同一フィールドで使用できる場合があるので、いくつか例を紹介します。

**例1：「1月1日、10時0分と15時から20時の間の0分」**
```
0 10,15-20 1 1 ?
```

**例2：「1月1日の12時0分から30分の間で5分おき」**
```
0-30/5 12 1 1 ?
```
**例3：「1月最後の平日、12時0分」**
```
0 12 ? 1 LW
```

他にも組み合わせ次第で様々なスケジュールを設定できるので興味があれば試してみてください！