haixunMaster/lib/automation/cron-match.ts

65 lines
2.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 極簡 5 欄位 cron 比對minute hour day-of-month month day-of-week。
// 支援星號、步進(星號斜線n)、列表(a,b,c)、範圍(a-b)、單一數字。
// 給 worker 每分鐘輪詢時判斷規則是否「到點」。
function fieldMatches(field: string, value: number, min: number, max: number): boolean {
if (field === "*") return true;
for (const part of field.split(",")) {
const token = part.trim();
if (token === "") continue;
// step: */n 或 a-b/n 或 */n
const stepMatch = token.match(/^(\*|\d+(?:-\d+)?)\/(\d+)$/);
if (stepMatch) {
const step = parseInt(stepMatch[2], 10);
if (step <= 0) continue;
let rangeStart = min;
let rangeEnd = max;
if (stepMatch[1] !== "*") {
const rangeParts = stepMatch[1].split("-");
rangeStart = parseInt(rangeParts[0], 10);
rangeEnd = rangeParts[1] !== undefined ? parseInt(rangeParts[1], 10) : max;
}
if (value < rangeStart || value > rangeEnd) continue;
if ((value - rangeStart) % step === 0) return true;
continue;
}
// range: a-b
const rangeMatch = token.match(/^(\d+)-(\d+)$/);
if (rangeMatch) {
const start = parseInt(rangeMatch[1], 10);
const end = parseInt(rangeMatch[2], 10);
if (value >= start && value <= end) return true;
continue;
}
// single
if (/^\d+$/.test(token) && parseInt(token, 10) === value) return true;
}
return false;
}
export function isValidCron(expr: string): boolean {
const fields = expr.trim().split(/\s+/);
return fields.length === 5;
}
export function cronMatches(expr: string, date: Date = new Date()): boolean {
const fields = expr.trim().split(/\s+/);
if (fields.length !== 5) return false;
const [minute, hour, dom, month, dow] = fields;
const normalizedDow = date.getDay(); // 0-6 (Sun=0)
return (
fieldMatches(minute, date.getMinutes(), 0, 59) &&
fieldMatches(hour, date.getHours(), 0, 23) &&
fieldMatches(dom, date.getDate(), 1, 31) &&
fieldMatches(month, date.getMonth() + 1, 1, 12) &&
fieldMatches(dow, normalizedDow, 0, 6)
);
}