一、Cron表達式生成器
Cron表達式是一種在定時任務中經常使用的語法,它可以用來指定被執行的時間,像“每小時執行一次”或“每周星期五晚上10點執行”等等。由於Cron表達式的語法比較複雜,因此通常需要使用Cron表達式生成器來幫助用戶快速生成想要的表達式。
下面是一個簡單的Cron表達式生成器的示例,它可以讓用戶選擇任務執行的時間單位、時間點和重複頻率,然後根據用戶的選擇生成對應的Cron表達式:
function generateCronExpression() { // 獲取用戶的選擇 let timeUnit = document.getElementById("time-unit-select").value; let timePoint = document.getElementById("time-point-input").value; let repeatFrequency = document.getElementById("repeat-frequency-input").value; // 根據用戶選擇生成Cron表達式 let cronExp = ""; if (timeUnit === "hourly") { cronExp = `0 ${timePoint} 0/${repeatFrequency} * * *`; } else if (timeUnit === "daily") { cronExp = `0 ${timePoint} * * * *`; } else if (timeUnit === "weekly") { cronExp = `0 ${timePoint} * * ${repeatFrequency} *`; } else if (timeUnit === "monthly") { cronExp = `0 ${timePoint} ${repeatFrequency} * * *`; } document.getElementById("result").innerHTML = cronExp; }
二、Cron表達式解析成時間
除了生成Cron表達式之外,我們還需要將Cron表達式解析成對應的時間點,以便於查看任務執行的計劃。下面是一個簡單的解析器,它可以將Cron表達式解析成下一次執行的時間點:
function getNextExecutionTime(cronExp) { let cronArr = cronExp.split(" "); let now = Date.now(); // 解析分鐘表達式 let minuteExp = cronArr[0]; let nextMinute = getNextValidValue(minuteExp, new Date(now).getMinutes()); // 解析小時表達式 let hourExp = cronArr[1]; let nextHour = getNextValidValue(hourExp, new Date(now).getHours()); // 解析日表達式 let dayExp = cronArr[2]; let nextDay = getNextValidValue(dayExp, new Date(now).getDate()); // 解析月表達式 let monthExp = cronArr[3]; let nextMonth = getNextValidValue(monthExp, new Date(now).getMonth() + 1); // 解析星期表達式 let weekExp = cronArr[4]; let nextWeekDay = getNextValidValue(weekExp, new Date(now).getDay()); // 解析年表達式 let yearExp = cronArr[5]; let nextYear = getNextValidValue(yearExp, new Date(now).getFullYear()); // 計算下一次執行的時間點(注意要考慮到月份和年份的變化) let nextDate = new Date(nextYear, nextMonth - 1, nextDay, nextHour, nextMinute); while (nextDate.getTime() 12) { nextMonth = 1; nextYear++; } nextDate.setFullYear(nextYear, nextMonth - 1, nextDay); } return nextDate; } function getNextValidValue(exp, currentValue) { // TODO:根據表達式解析出下一個合法的值 // 略去具體實現 return 0; }
三、Cron表達式在線解析
為了方便用戶查詢指定Cron表達式的下一次執行時間點,我們可以提供一個在線的解析工具,用戶只需要將表達式粘貼到輸入框中,即可得到下一次的執行時間:
function parseCronExpression() { let cronExp = document.getElementById("cron-exp-input").value; let nextExecutionTime = getNextExecutionTime(cronExp); document.getElementById("next-execution-time").innerHTML = nextExecutionTime; }
四、Cron表達式每5分鐘
有時候我們需要將任務設置成每5分鐘一次執行,這時候就需要使用*/5來指定:
0 */5 * * * *
五、Cron表達式解析
對於Cron表達式的解析,其實就是將表達式的各個部分解析出來,並根據這些部分計算下一次的執行時間點。下面是一個完整的Cron表達式解析器的實現,它可以解析所有Cron表達式,並計算出下一次的執行時間點:
function parseCronExpression(cronExp) { let cronArr = cronExp.split(" "); let now = Date.now(); // 解析分鐘表達式 let minuteExp = cronArr[0]; let nextMinute = getNextValidValues(minuteExp, new Date(now).getMinutes()); // 解析小時表達式 let hourExp = cronArr[1]; let nextHour = getNextValidValues(hourExp, new Date(now).getHours()); // 解析日表達式 let dayExp = cronArr[2]; let nextDay = getNextValidValues(dayExp, new Date(now).getDate()); // 解析月表達式 let monthExp = cronArr[3]; let nextMonth = getNextValidValues(monthExp, new Date(now).getMonth() + 1); // 解析星期表達式 let weekExp = cronArr[4]; let nextWeekDay = getNextValidValues(weekExp, new Date(now).getDay()); // 解析年表達式 let yearExp = cronArr[5]; let nextYear = getNextValidValues(yearExp, new Date(now).getFullYear()); let nextExecutionTimes = []; for (let i = 0; i < nextMinute.length; i++) { for (let j = 0; j < nextHour.length; j++) { for (let k = 0; k < nextDay.length; k++) { for (let l = 0; l < nextMonth.length; l++) { let date = new Date(nextYear[0], nextMonth[l] - 1, nextDay[k], nextHour[j], nextMinute[i]); while (date.getTime() < now) { // 如果時間已經過去了,則需要加上一個周期 if (monthExp === "*" && weekExp === "*") { // 每天執行的任務 date.setDate(date.getDate() + 1); } else if (monthExp === "*" && weekExp !== "*") { // 每周某一天執行的任務 date.setDate(date.getDate() + 7); } else if (monthExp !== "*" && weekExp === "*") { // 每月某一天執行的任務 let tempDate = new Date(date.getFullYear(), date.getMonth() + 1, 0); date.setDate(tempDate.getDate() + 1); if (date.getMonth() + 1 !== nextMonth[l]) { // 某個月沒有對應日期,需要調整到下一個合法日期 date.setDate(1); date.setMonth(date.getMonth() + 1); } } else { // 每年某一天執行的任務 let tempDate = new Date(date.getFullYear(), nextMonth[l], 0); date.setDate(tempDate.getDate() + 1); if (date.getMonth() + 1 !== nextMonth[l] || date.getDay() !== nextWeekDay[0]) { // 某個月沒有對應的星期,或者對應的星期不是指定的星期,需要調整到下一個合法日期 date.setDate(1); date.setMonth(date.getMonth() + 1); while (date.getDay() !== nextWeekDay[0]) { date.setDate(date.getDate() + 1); } } } } nextExecutionTimes.push(date); } } } } return nextExecutionTimes; } function getNextValidValues(exp, currentValue) { let result = []; if (exp === "*") { // 如果表達式為*,則返回對應取值範圍內的所有值 for (let i = getMinValue(exp); i <= getMaxValue(exp); i++) { result.push(i); } } else if (exp.indexOf("/") !== -1) { // 如果表達式中包含/,則按照步長來獲取合法值 let arr = exp.split("/"); let startValue = getMinValue(arr[0]); let step = parseInt(arr[1]); for (let i = startValue; i <= getMaxValue(exp); i += step) { result.push(i); } } else if (exp.indexOf(",") !== -1) { // 如果表達式中包含,,則將其拆分成多個子表達式 let arr = exp.split(","); for (let i = 0; i < arr.length; i++) { result = result.concat(getNextValidValues(arr[i], currentValue)); } result = Array.from(new Set(result)); // 去重 result.sort(function(a, b) { return a - b; }); // 排序 } else if (exp.indexOf("-") !== -1) { // 如果表達式中包含-,則按照範圍來獲取合法值 let arr = exp.split("-"); let minValue = parseInt(arr[0]); let maxValue = parseInt(arr[1]); for (let i = minValue; i <= maxValue; i++) { result.push(i); } } else { // 如果表達式為單個數值,則直接返回該值 result.push(parseInt(exp)); } // 對於星期表達式,還需要特殊處理,因為星期的取值範圍是0~6,但是Date對象中的星期是從0開始的 // 因此需要將所有星期的值+1,如果越界了則取模 if (exp.startsWith("0") && result.indexOf(7) !== -1) { result.push(0); } else if (exp.startsWith("7") && result.indexOf(0) !== -1) { result.push(7); } result = result.map(function(value) { return (value === 7 ? 0 : value + 1); }); for (let i = 0; i < result.length; i++) { result[i] %= 7; } // 如果當前值不在合法值的範圍內,需要找到比它大的第一個合法值 let index = result.indexOf(currentValue); if (index === -1) { for (let i = 0; i currentValue) { index = i; break; } } } // 如果當前值在合法值的範圍內,直接從它開始向後找到下一個合法值 if (index !== -1) { for (let i = index; i = currentValue) { result = result.slice(i); break; } } } // 如果找不到合法值,說明下一次執行時間已經超過了指定的時間範圍,這時候需要將結果清空 if (result.length === 0) { result.push(getMinValue(exp)); } return result; } function getMinValue(exp) { // TODO:根據表達式獲取取值範圍的最小值 // 略去具體實現 return 0; } function getMaxValue(exp) { // TODO:根據表達式獲取取值範圍的最大值 // 略去具體實現 return 59; }
六、Cron表達式在線生成器
除了簡單的Cron表達式生成器之外,我們還可以提供一個功能更加強大的在線生成器,讓用戶可以通過界面來選擇更加複雜的任務執行計劃:
// 界面部分
// 略...// 事件處理部分
function generateCronExpression() {
let minuteExp = getCronExp("minute");
let hourExp = getCronExp("hour");
let dayExp = getCronExp("day");
let monthExp = getCronExp("month");
let weekExp = getCronExp("week");let
原創文章,作者:OOOV,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/145245.html