All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.jquicker.timer.CronUtils Maven / Gradle / Ivy

There is a newer version: 1.1.0
Show newest version
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