com.jquicker.timer.CronUtils Maven / Gradle / Ivy
package com.jquicker.timer;
import java.util.Calendar;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.jquicker.commons.util.StringUtils;
import com.jquicker.exception.CronException;
import com.jquicker.timer.TimerEnum.Cron;
/**
* cronExpression工具类
* @author OL
*/
public final class CronUtils {
static final String numReg = "\\d{1,2}";
static final String allowed_special = "[ ,-/*?#LWC0-9]*"; // \\d\\,-/\\?#LWC
/**
* Seconds Minutes Hours DayofMonth Month DayofWeek (Year)
*
* 名称 是否必须 允许值 特殊字符
* 秒(Second) Y 0-59 , - * /
* 分(Minute) Y 0-59 , - * /
* 时(Hour) Y 0-23 , - * /
* 日(DayofMonth) Y 1-31 , - * / ? L W C
* 月(Month) Y 1-12 或 JAN-DEC , - * /
* 周(DayofWeek) Y 1-7 或 SUN-SAT , - * / ? L C #
* 年(Year) N 空 或 1970-2099 , - * /
*
* ,: 表示列出枚举值值,例如在Minutes域使用5,20则意味着在5和20分每分钟触发一次
* -: 表示范围,例如在Minutes域使用5-20,表示从5分到20分钟每分钟触发一次
* *:表示匹配该域的任意值,假如在Minutes域使用*,即表示每分钟都会触发事件
* /:表示起始时间开始触发,然后每隔固定时间触发一次,例如在Minutes域使用5/20,则意味着5分钟触发一次,而25,45等分别触发一次
*
* ?: 只能用在DayofMonth和DayofWeek两个域,它也匹配域的任意值,但实际不会,因为DayofMonth和DayofWeek会相互影响,例如想在每月的20日触发调度,不管20日到底是星期几,则只能使用如下写法: 13 13 15 20 * ?, 其中最后一位只能用?,而不能使用*,如果使用*表示不管星期几都会触发,实际上并不是这样
*
* L: 表示最后,只能出现在DayofWeek和DayofMonth域,如果在DayofWeek域使用5L,意味着在最后的一个星期四触发
* W: 表示有效工作日(周一到周五),只能出现在DayofMonth域,系统将在离指定日期的最近的有效工作日触发事件,例如:在 DayofMonth使用5W,如果5日是星期六,则将在最近的工作日:星期五,即4日触发,如果5日是星期天,则在6日(周一)触发,如果5日在星期一到星期五中的一天,则就在5日触发,另外一点,W的最近寻找不会跨过月份
* LW: 这两个字符可以连用,表示在某个月最后一个工作日,即最后一个星期五
*
* C: 表示Canlendar,即日历,例如"1C"在星期位上就是包括日历上的星期日
*
* #: 用于确定每个月第几个星期几,只能出现在DayofMonth域,例如在4#2,表示某月的第二个星期三
*/
public static void check(String cronExpression){
String[] array = cronExpression.split(" ");
// 整体校验 (不能出现连续的/)
if(!cronExpression.matches(allowed_special)){
throw new CronException("The cron expression contains characters that are not allowed.");
}
if(cronExpression.contains("//")){
throw new CronException("The \"//\" characters are not allowed.");
}
if(cronExpression.contains("**")){
throw new CronException("The \"**\" characters are not allowed.");
}
if(array.length > 7){
throw new CronException("The cron expression was more than 7 region.");
}
// 分段校验
for (int i = 0; i < array.length; i++) {
String region = array[i];
check(i, region);
}
}
/**
* 获取下一次触发的时间
* @param cronExpression
* @author OL
*/
public static TimerTrigger getTrigger(String cronExpression){
String[] array = cronExpression.split(" ");
String second = array[0];
String minute = array[1];
String hour = array[2];
String dayOfMonth = array[3];
String month = array[4];
String dayOfWeek = array[5];
String year = array.length == 6 ? null : array[6];
TimerTrigger trigger = new TimerTrigger();
trigger.setCronExpression(cronExpression);
Calendar calendar = Calendar.getInstance();
if(year != null){
if(year.equals("*")){
} else if(year.matches("[0-9]+")){
calendar.set(Calendar.DAY_OF_WEEK, Integer.valueOf(dayOfWeek));
} else if(year.matches("([0-9]+,)+[0-9]+")){
String[] years = year.split(",");
calendar.set(Calendar.DAY_OF_WEEK, Integer.valueOf(years[0]));
} else if(year.matches("[0-9]+-[0-9]+")){
String[] years = year.split("-");
calendar.set(Calendar.DAY_OF_WEEK, Integer.valueOf(years[0]));
} else if(year.matches("[0-9]+/[0-9]+")){
String[] years = year.split("/");
calendar.set(Calendar.DAY_OF_WEEK, Integer.valueOf(years[0]));
trigger.setPeriod(Long.valueOf(years[1]) * 60 * 60 * 24 * 30); // 不是乘30了
trigger.setPeriodic(true);
}
}
if(dayOfWeek.equals("*")){
trigger.setPeriod(1 * 60 * 60 * 24L);
trigger.setPeriodic(true);
}
if(dayOfWeek.equals("?")){
}
if(dayOfWeek.matches("[0-9]+")){
calendar.set(Calendar.DAY_OF_WEEK, Integer.valueOf(dayOfWeek));
}
if(dayOfWeek.matches("([0-9]+,)+[0-9]+")){
String[] dayOfWeeks = dayOfWeek.split(",");
calendar.set(Calendar.DAY_OF_WEEK, Integer.valueOf(dayOfWeeks[0]));
}
if(dayOfWeek.matches("[0-9]+-[0-9]+")){
String[] dayOfWeeks = dayOfWeek.split("-");
calendar.set(Calendar.DAY_OF_WEEK, Integer.valueOf(dayOfWeeks[0]));
}
if(dayOfWeek.matches("[0-9]+/[0-9]+")){
String[] dayOfWeeks = dayOfWeek.split("/");
calendar.set(Calendar.DAY_OF_WEEK, Integer.valueOf(dayOfWeeks[0]));
trigger.setPeriod(Long.valueOf(dayOfWeeks[1]) * 60 * 60 * 24 * 30); // 不是乘30了
trigger.setPeriodic(true);
}
if(month.equals("*")){
}
if(month.matches("[0-9]+")){
calendar.set(Calendar.MONTH, Integer.valueOf(month));
}
if(month.matches("([0-9]+,)+[0-9]+")){
String[] monthes = month.split(",");
calendar.set(Calendar.MONTH, Integer.valueOf(monthes[0]));
}
if(month.matches("[0-9]+-[0-9]+")){
String[] monthes = month.split("-");
calendar.set(Calendar.MONTH, Integer.valueOf(monthes[0]));
}
if(month.matches("[0-9]+/[0-9]+")){
String[] monthes = month.split("/");
calendar.set(Calendar.MONTH, Integer.valueOf(monthes[0]));
trigger.setPeriod(Long.valueOf(monthes[1]) * 60 * 60 * 24 * 30); // 不是乘30了
trigger.setPeriodic(true);
}
if(dayOfMonth.equals("*")){
}
if(dayOfWeek.equals("?")){
}
if(dayOfMonth.matches("[0-9]+")){
calendar.set(Calendar.DAY_OF_MONTH, Integer.valueOf(dayOfMonth));
}
if(dayOfMonth.matches("([0-9]+,)+[0-9]+")){
String[] dayOfMonthes = dayOfMonth.split(",");
calendar.set(Calendar.DAY_OF_MONTH, Integer.valueOf(dayOfMonthes[0]));
}
if(dayOfMonth.matches("[0-9]+-[0-9]+")){
String[] dayOfMonthes = dayOfMonth.split("-");
calendar.set(Calendar.DAY_OF_MONTH, Integer.valueOf(dayOfMonthes[0]));
trigger.setPeriod(1 * 60 * 60 * 24L);
trigger.setPeriodic(true);
}
if(dayOfMonth.matches("[0-9]+/[0-9]+")){
String[] dayOfMonthes = dayOfMonth.split("/");
calendar.set(Calendar.DAY_OF_MONTH, Integer.valueOf(dayOfMonthes[0]));
trigger.setPeriod(Long.valueOf(dayOfMonthes[1]) * 60 * 60 * 24);
trigger.setPeriodic(true);
}
if(hour.equals("*")){
trigger.setPeriod(1 * 60 * 60L);
trigger.setPeriodic(true);
}
if(hour.matches("[0-9]+")){
calendar.set(Calendar.HOUR_OF_DAY, Integer.valueOf(hour));
}
if(hour.matches("([0-9]+,)+[0-9]+")){
String[] hours = hour.split(",");
calendar.set(Calendar.HOUR_OF_DAY, Integer.valueOf(hours[0]));
}
if(hour.matches("[0-9]+-[0-9]+")){
String[] hours = hour.split("-");
calendar.set(Calendar.HOUR_OF_DAY, Integer.valueOf(hours[0]));
trigger.setPeriod(1 * 60 * 60L);
trigger.setPeriodic(true);
}
if(hour.matches("[0-9]+/[0-9]+")){
String[] hours = hour.split("/");
calendar.set(Calendar.HOUR_OF_DAY, Integer.valueOf(hours[0]));
trigger.setPeriod(Long.valueOf(hours[1]) * 60 * 60);
trigger.setPeriodic(true);
}
if(minute.equals("*")){
trigger.setPeriod(1 * 60L);
trigger.setPeriodic(true);
}
if(minute.matches("[0-9]+")){
calendar.set(Calendar.MINUTE, Integer.valueOf(minute));
}
if(minute.matches("([0-9]+,)+[0-9]+")){
String[] minutes = minute.split(",");
calendar.set(Calendar.MINUTE, Integer.valueOf(minutes[0]));
}
if(minute.matches("[0-9]+-[0-9]+")){
String[] minutes = minute.split("-");
calendar.set(Calendar.MINUTE, Integer.valueOf(minutes[0]));
trigger.setPeriod(1 * 60L);
trigger.setPeriodic(true);
}
if(minute.matches("[0-9]+/[0-9]+")){
String[] minutes = minute.split("/");
calendar.set(Calendar.MINUTE, Integer.valueOf(minutes[0]));
trigger.setPeriod(Long.valueOf(minutes[1]) * 60);
trigger.setPeriodic(true);
}
if(second.equals("*")){
trigger.setPeriod(1L);
trigger.setPeriodic(true);
}
if(second.matches("[0-9]+")){
calendar.set(Calendar.SECOND, Integer.valueOf(second));
}
if(second.matches("([0-9]+,)+[0-9]+")){
String[] seconds = second.split(",");
calendar.set(Calendar.SECOND, Integer.valueOf(seconds[0]));
}
if(second.matches("[0-9]+-[0-9]+")){
String[] seconds = second.split("-");
calendar.set(Calendar.SECOND, Integer.valueOf(seconds[0]));
trigger.setPeriod(1L);
trigger.setPeriodic(true);
}
if(second.matches("[0-9]+/[0-9]+")){
String[] seconds = second.split("/");
calendar.set(Calendar.SECOND, Integer.valueOf(seconds[0]));
trigger.setPeriod(Long.valueOf(seconds[1]));
trigger.setPeriodic(true);
}
// trigger.setFirstTime(calendar.getTimeInMillis());
// trigger.setPrevTime(trigger.getPrevTime());
// trigger.setNextTime(calendar.getTimeInMillis());
return trigger;
}
public static boolean isFixedPeriod(String cronExpression){
return false;
}
private static void check(int i, String content) {
String result = null;
// 基本校验
switch (i) {
case 0:
String not_allowed_Second = "[^0-9,\\-/*]";
result = matcher(content, not_allowed_Second);
break;
case 1:
String not_allowed_Minute = "[^0-9,\\-/*]";
result = matcher(content, not_allowed_Minute);
break;
case 2:
String not_allowed_Hour = "[^0-9,\\-/*]";
result = matcher(content, not_allowed_Hour);
break;
case 3:
String not_allowed_DayofMonth = "[^0-9,\\-/*?LWClwc]";
result = matcher(content, not_allowed_DayofMonth);
break;
case 4:
String not_allowed_Month = "[^0-9,\\-/*]";
result = matcher(content, not_allowed_Month);
break;
case 5:
String not_allowed_DayofWeek = "[^0-9,\\-/*?#LClc]";
result = matcher(content, not_allowed_DayofWeek);
break;
case 6:
String not_allowed_Year = "[^0-9,\\-/*]";
result = matcher(content, not_allowed_Year);
break;
default:
break;
}
if(StringUtils.isNotEmpty(result)){
throw new CronException("Illegal character on " + Cron.getName(i) + " region (" + result + ").");
}
// 深度校验
if(content.matches(".*-.*-.*")){
throw new CronException("The - Appeared two or more times on " + Cron.getName(i) + " region.");
}
if(content.matches("(.*(-|,|/))|((-|,|/).*)")){
throw new CronException("Can not start or end with [- , /] on " + Cron.getName(i) + " region.");
}
if(content.matches(".*\\*.*\\*.*")){
throw new CronException("The * Appeared two or more times on " + Cron.getName(i) + " region.");
}
if(content.matches(".*(\\*|/).*(\\*|/).*")){
// throw new CronException("Their [- * /] exist at the same time on " + CronEnum.getName(i) + " region.");
}
}
private static String matcher(String content, String regex){
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(content);
StringBuilder result = new StringBuilder();
while (matcher.find()) {
result.append(matcher.group(0));
}
return result.toString();
}
public static void main(String[] args) {
String cronExpression = "0 0/1 * W * ? *";
check(cronExpression);
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy