当前位置: 代码迷 >> 综合 >> Cron Expressions 详解
  详细解决方案

Cron Expressions 详解

热度:118   发布时间:2023-11-16 21:56:56.0

作用

cron表达式被用来配置CronTrigger实例,用法如下:

		// 建立一个触发器,每隔两分钟,每天上午8点至下午5点之间:trigger = newTrigger().withIdentity("trigger3", "group1").withSchedule(cronSchedule("0 0/2 8-17 * * ?")).forJob("myJob", "group1").build();

表达式内各字段解析

cron表达式是字符串类型,用空格隔开,可以拆分为六个或七个子串,分别表示:
秒 时 分 日 月 周 年
cron表达式中可以出现特殊字符,含义如下:
“*”:指定所有的值。比如,Minutes 设置为 *,表示每分钟
“,”:表示列出枚举值值。例如:在Minutes域使用“5,20”,则意味着在5和20分每分钟触发一次。
“-”:表示范围。例如在Minutes域使用“5-20”,表示从5分到20分钟每分钟触发一次 。
“/”:表示为“间隔”。使用该符号,可以确定几个有规律的时间点,job在这些时间点触发,这些时间点是同级的。如“0/50”确定两个时间点“0、50”,job会在这两个点执行,时间点先后无必然关系,假如程序在(0,50)间启动,那就先在时间点50执行job。还要符合一定的规则,比如在描述秒时,使用“0/70”,就会抛异常。
递增检测规则如下:

package org.quartz;
// class CronExpression
private void checkIncrementRange(int incr, int type, int idxPos) throws ParseException {if (incr > 59 && (type == SECOND || type == MINUTE)) {throw new ParseException("Increment > 60 : " + incr, idxPos);} else if (incr > 23 && (type == HOUR)) {throw new ParseException("Increment > 24 : " + incr, idxPos);} else if (incr > 31 && (type == DAY_OF_MONTH)) {throw new ParseException("Increment > 31 : " + incr, idxPos);} else if (incr > 7 && (type == DAY_OF_WEEK)) {throw new ParseException("Increment > 7 : " + incr, idxPos);} else if (incr > 12 && (type == MONTH)) {throw new ParseException("Increment > 12 : " + incr, idxPos);}}

“?”:表示每月的某一天,或第周的某一天。只有这两个字段可以用,其他字段使用会抛异常。并且有且只能有一个字段为“?”。源码如下:

if (c == '?') {i++;if ((i + 1) < s.length() && (s.charAt(i) != ' ' && s.charAt(i + 1) != '\t')) {throw new ParseException("Illegal character after '?': "+ s.charAt(i), i);}if (type != DAY_OF_WEEK && type != DAY_OF_MONTH) {throw new ParseException("'?' can only be specified for Day-of-Month or Day-of-Week.",i);}if (type == DAY_OF_WEEK && !lastdayOfMonth) {int val = daysOfMonth.last();if (val == NO_SPEC_INT) {throw new ParseException("'?' can only be specified for Day-of-Month -OR- Day-of-Week.",i);}}addToSet(NO_SPEC_INT, -1, 0, type);return i;}

“L”:用于day-of-month,表示每月最后一天。用于day-of-week,表示每周的最后一天(每周最后一天为7,或"SAT",即周六)。或每个月的最后一个星期几如“6L”表示“每月的最后一个星期五”。范围[1,7],1周日,2周一,,,7周六。此外,可以在day-of-month中使用"L-3",表示从倒数第一天往前数三天,即每月倒数第四天;此形式用在day-of-week中,无效,依旧表示每周最后一天。

“W”:表示为最近的工作日(周一到周五),如“15W”放在每月(day-of-month)字段上表示为“到本月15日最近的工作日”

“#”:用于确定每个月第几个星期几,只能出现在DayofMonth域。例内容为"6#3" or “FRI#3” 则表示“每月第三个星期五”

if (c == '#') {if (type != DAY_OF_WEEK) {throw new ParseException("'#' option is not valid here. (pos=" + i + ")", i);}······
}

“LW”:这两个字符可以连用,表示在某个月最后一个工作日。用在DAY_OF_MONTH域。

注意

  • day-of-week 和 a day-of-month必须有且只有一个为"?"
  • "-“可以左大右小,用"22-2"表示晚上10点到凌晨到凌晨两点,同样,也可以使用"NOV-FEB”。使用这种方式一定要明确cron表达式的含义。示例:“0 0 14-6 ? * FRI-MON”。"50-10/5 * * * * ?"表示在50-10秒之间,每隔五秒执行一次
  • 在午夜设置命中时间时要小心。由于“夏令时”时间会向后还是向前跳跃,可能会导致跳过或重复。

cron表达式示例

每隔5秒执行一次:*/5 * * * * ?
每隔1分钟执行一次:0 */1 * * * ?
每天23点执行一次:0 0 23 * * ?
每天凌晨1点执行一次:0 0 1 * * ?
每月1号凌晨1点执行一次:0 0 1 1 * ?
每月最后一天23点执行一次:0 0 23 L * ?
在26分、29分、33分执行一次:0 26,29,33 * * * ?
每天的0点、13点、18点、21点都执行一次:0 0 0,13,18,21 * * ?
每天的7点到21点都执行一次:0 0 7-21 * * ?

在每天下午2点到下午2:59期间的每1分钟触发:0 * 14 * * ?
在每天下午2点到下午2:05期间的每1分钟触发 :0 0-5 14 * * ?
每年三月的星期三的下午2:10和2:44触发 :0 10,44 14 ? 3 WED
周一至周五的上午10:15触发 :0 15 10 ? * MON-FRI
每月的最后一个星期五上午10:15触发 :0 15 10 ? * 6L
每月的第三个星期五上午10:15触发 :0 15 10 ? * 6#3
在每个周三和周五的10:30,11:30,12:30触发:0 30 10-13 ? * WED,FRI

注意,对于单独触发器来说,有些日程需求可能过于复杂而不能用表达式表述,例如:9:00到10:00之间每隔5分钟触发一次,下午1:00到10点每隔20分钟触发一次。这个解决方案就是创建两个触发器,两个触发器都运行相同的任务。

其他

可以使用CronExpression实例中的isSatisfiedBy(Date date)方法来确定给定的时间是否在cron表达式中包括。

/*** Indicates whether the given date satisfies the cron expression. Note that* milliseconds are ignored, so two Dates falling on different milliseconds* of the same second will always have the same result here.* * @param date the date to evaluate* @return a boolean indicating whether the given date satisfies the cron*         expression*/public boolean isSatisfiedBy(Date date) {Calendar testDateCal = Calendar.getInstance(getTimeZone());testDateCal.setTime(date);testDateCal.set(Calendar.MILLISECOND, 0);Date originalDate = testDateCal.getTime();testDateCal.add(Calendar.SECOND, -1);Date timeAfter = getTimeAfter(testDateCal.getTime());return ((timeAfter != null) && (timeAfter.equals(originalDate)));}
  相关解决方案