結論
書式が足りない部分はデフォルトの値が適用される。
簡単に言えば、書式設定が右にずれる。
多すぎた場合はこの少なかったとき用の計算が意図せず働き、設定が左にずれる。
例えば、
書式が5個と通常よりひとつ少なかった場合。
1 2 3 4 5
本来秒数指定の場所の左端の値(1)は、右にずれて分数指定の記述として扱われる。
(秒数指定にはデフォルト値の0が指定される)
0 1 2 3 4 5
書式が7個と通常よりひとつ多かった場合。
1 2 3 4 5 6 7
本来日数として指定された値は、左にずれて時数指定の記述として扱われる。
(週の指定にはデフォルト値の*
が指定される)
2 3 4 5 6 7 *
Linuxなどのcrontabは値を5つ指定する(standard cron syntaxと表現)=node-cronではできる秒数指定ができない。
node-cronにstandard cron syntaxが指定されたとき、エラーと意図の相違なくパースさせる処理が、渡しすぎた場合にエラーなく意図と相違あるパースになってしまった。
ライブラリ
kelektiv/node-cron: Cron for NodeJS.
Cron Ranges
==
When specifying your cron values you'll need to make sure that your values fall
within the ranges. For instance, some cron's use a 0-7 range for the day of
week where both 0 and 7 represent Sunday. We do not.
- Seconds: 0-59
- Minutes: 0-59
- Hours: 0-23
- Day of Month: 1-31
- Months: 0-11 (Jan-Dec)
- Day of Week: 0-6 (Sun-Sat)
指定できる場所は6個あることが特徴です。
バージョン
"cron": "^1.4.0"
コード
node-cron/cron.js at 1ec1e81eba34fc0b2c034ea65c943ba62b3e16b4 · kelektiv/node-cron
var timeUnits = [
'second',
'minute',
'hour',
'dayOfMonth',
'month',
'dayOfWeek'
];
CronTime.parseDefaults = ['0', '*', '*', '*', '*', '*'];
CronTime.prototype = {
_parse: function() {
var aliases = CronTime.aliases;
var source = this.source.replace(/[a-z]{1,3}/gi, function(alias) {
alias = alias.toLowerCase();
if (alias in aliases) {
return aliases[alias];
}
throw new Error('Unknown alias: ' + alias);
});
var split = source.replace(/^\s\s*|\s\s*$/g, '').split(/\s+/);
var cur;
var i = 0;
var len = timeUnits.length;
for (; i < timeUnits.length; i++) {
// If the split source string doesn't contain all digits,
// assume defaults for first n missing digits.
// This adds support for 5-digit standard cron syntax
cur = split[i - (len - split.length)] || CronTime.parseDefaults[i];
this._parseField(cur, timeUnits[i], CronTime.constraints[i]);
}
},
source
が渡した書式です。
* * * * *
ならStandard cron syntax。左端は分です。
* * * * * *
ならcron-node用のsyntax。左端は秒です。
0 0 0 * * * *
これが今回誤って渡していた書式です。毎日0時に実行してほしいつもりが、毎時実行になっていました。
cur = split[i - (len - split.length)] || CronTime.parseDefaults[i];
このコード、len
は6で固定です。
node-cronのsyntaxが渡された場合、(len - split.length)
は常に0なので、そのままの値が順番に渡されます。
Standard cron syntaxが渡されたとき、i = 0
、秒数のパースの際は、
cur = split[0 - (6 - 5)] || CronTime.parseDefaults[0];
とsplit[-1]
が参照されることになり、当然undefined
なのでparseDefaults[0]
が適用されます。
以降、Standard cron syntaxで指定された分数指定、split[0]は、i = 1
のとき、
cur = split[1 - (6 - 5)] || CronTime.parseDefaults[1];
となりsplit[0]
がnode-cronのsyntaxでの分数([1]
)として入り、整合性がとれます。
0 0 0 * * * *
を渡した場合。
split.length
は7で、(len - split.length)
は常に-1
。
- (len - split.length)
なので常に+1
されることになります。
i = 0
の場合、
cur = split[0 + 1] || CronTime.parseDefaults[0];
で秒数にsplit[1]、分と考えていたものがズレて入りました。
時を指定するi = 2
では
cur = split[2 + 1] || CronTime.parseDefaults[2];
でsplit[3] = *
が時間の値として処理され、毎時実行になりました。
コードのコメントにあるように、この引き算は5-digit standard cron syntax
をサポートするためのものです。
なので、7-digit cron syntax
などという不正な書式はエラーにしてしまうことが、本来は正しいのかもしれません。
CronTime day of week is non-standard (Sunday is 1, not 0) · Issue #36 · kelektiv/node-cron
サポートが入った経緯。