CRON是什么?
Quartz官网CENTOS下的CRON服务及CRONTAB命令的区别
SpringBoot - 集成Quartz框架之Quartz简介(一)SpringBoot - 集成Quartz框架之常用配置(二)SpringBoot - 集成Quartz框架之具体步骤(三)SpringBoot - 集成Quartz框架之独立数据源(四)SpringBoot - 集成Quartz框架之常见问题(五)SpringBoot - 集成Quartz框架之@DisallowConcurrentExecution注解详解(六)
CRON表达式
CRON表达式是一个字符串,字符串由5个或6个空格隔开,分为6个或7个域,每一个域代表一个含义,表达如如下:
秒 分 时 天(day-of-month) 月 周(day-of-week) 年[可选]
常用示例
*/5 * * * * ?:每隔 5 秒执行一次
0 */1 * * * ?:每隔 1 分钟执行一次
0 0 2 1 * ? *:每月 1 日的凌晨 2 点执行一次
0 15 10 ? * MON-FRI:周一到周五每天上午 10:15 执行一次
0 15 10 ? * 6L 2002-2006:2002 年至 2006 年的每个月的最后一个星期五上午 10:15 执行一次
0 0 23 * * ?:每天 23 点执行一次
0 0 1 * * ?:每天凌晨 1 点执行一次
0 0 1 1 * ?:每月 1 日凌晨 1 点执行一次
0 0 23 L * ?:每月最后一天 23 点执行一次
0 0 1 ? * L:每周星期天凌晨 1 点执行一次
0 26,29,33 * * * ?:在 26 分、29 分、33 分执行一次
0 0 0,13,18,21 * * ?:每天的 0 点、13 点、18 点、21 点都执行一次
0 0 10,14,16 * * ?:每天上午 10 点,下午 2 点,4 点执行一次
0 0/30 9-17 * * ?:朝九晚五工作时间内每半小时执行一次
0 0 12 ? * WED:每个星期三中午 12 点执行一次
0 0 12 * * ?:每天中午 12 点执行一次
0 15 10 ? * *:每天上午 10:15 执行一次
0 15 10 * * ?:每天上午 10:15 执行一次
0 15 10 * * ? *:每天上午 10:15 执行一次
0 15 10 * * ? 2005:2005 年的每天上午 10:15 执行一次
0 * 14 * * ?:每天下午 2 点到 2:59 期间的每 1 分钟执行一次
0 0/5 14 * * ?:每天下午 2 点到 2:55 期间的每 5 分钟执行一次
0 0/5 14,18 * * ?:每天下午 2 点到 2:55 期间和下午 6 点到 6:55 期间的每 5 分钟执行一次
0 0-5 14 * * ?:每天下午 2 点到 2:05 期间的每 1 分钟执行一次
0 10,44 14 ? 3 WED:每年三月的星期三的下午 2:10 和 2:44 执行一次
0 15 10 ? * MON-FRI:周一至周五的上午 10:15 执行一次
0 15 10 15 * ?:每月 15 日上午 10:15 执行一次
0 15 10 L * ?:每月最后一日的上午 10:15 执行一次
0 15 10 ? * 6L:每月的最后一个星期五上午 10:15 执行一次
0 15 10 ? * 6L 2002-2005:2002 年至 2005 年的每月的最后一个星期五上午 10:15 执行一次
0 15 10 ? * 6#3:每月的第三个星期五上午 10:15 执行一次
翻译CRON表达式
import java.text.ParseException;
import java.util.Date;
import org.quartz.CronExpression;
/**
* CRON表达式工具类
* @author ROCKY
*/
public class CronUtils {
/**
* 返回一个布尔值代表一个给定的CRON表达式是否有效
*/
public static boolean isValid(String cronExpression) {
return CronExpression.isValidExpression(cronExpression);
}
/**
* 返回一个字符串值, 表示该消息无效CRON表达式给出有效性
*/
public static String getInvalidMessage(String cronExpression) {
try {
new CronExpression(cronExpression);
return null;
} catch (ParseException pe) {
return pe.getMessage();
}
}
/**
* 返回下一个执行时间根据给定的CRON表达式
*/
public static Date getNextExecution(String cronExpression) {
try {
CronExpression cron = new CronExpression(cronExpression);
return cron.getNextValidTimeAfter(new Date(System.currentTimeMillis()));
} catch (ParseException e) {
throw new IllegalArgumentException(e.getMessage());
}
}
/**
* 将一个给定的CRON表达式翻译成中文
*/
private final static String[] CRON_EXPRESSION_DOMAIN = new String[]{"秒", "分", "时", "日", "月", "周", "年"};
public static String translate(String expression) {
if (StringUtils.isEmpty(expression)) {
return expression;
}
String[] expressions = expression.split(" ");
StringBuffer result = new StringBuffer();
if (expressions.length == 6 || expressions.length == 7) {
// 1. 年
if (expressions.length == 7) {
String year = expressions[6];
if ((!year.equals("*") && !year.equals("?"))) {
result.append(year).append(CRON_EXPRESSION_DOMAIN[6]);
}
}
// 2. 月
String months = expressions[4];
if (!months.equals("*") && !months.equals("?")) {
if (months.contains("/")) {
result.append("从").append(months.split("/")[0]).append("日开始")
.append(",每").append(months.split("/")[1]).append(CRON_EXPRESSION_DOMAIN[4]);
} else {
if (result.toString().contains("-")) {
result.append("每年");
}
result.append(months).append(CRON_EXPRESSION_DOMAIN[4]);
}
}
// 3. 周
String dayOfWeek = expressions[5];
if (!dayOfWeek.equals("*") && !dayOfWeek.equals("?")) {
if (dayOfWeek.contains(",")) {// 多个数字,逗号隔开
result.append("每周的第").append(dayOfWeek).append(CRON_EXPRESSION_DOMAIN[3]);
} else if (dayOfWeek.contains("L") && dayOfWeek.length() > 1) {// 1L-7L
String index = dayOfWeek.split("L")[0];
String name = Weeks.name(index);
result.append("每月最后一周的");
result.append(name);
} else if (dayOfWeek.contains("-")) {
String[] split = dayOfWeek.split("-");
String one = Weeks.name(split[0]);
String two = Weeks.name(split[1]);
result.append("每周").append(one).append("到").append(two);
} else if (dayOfWeek.contains("#")) {
String[] split = dayOfWeek.split("#");
// 前面数字表示周几
String index = split[0];
// 后面的数字表示每月的第几周(1-4)
String weekOfMonth = split[1];
String name = Weeks.name(index);
result.append("每月第").append(weekOfMonth).append(CRON_EXPRESSION_DOMAIN[5]).append("的").append(name);
} else {
if ("L".equals(dayOfWeek)) {
// L表示每周的最后一天
dayOfWeek = "7";
}
result.append("每周的");
result.append(Weeks.name(dayOfWeek));
}
}
// 4. 日
String days = expressions[3];
if (!days.equals("*") && !days.equals("?")) {
if (days.contains("/")) {
result.append("每周从第").append(days.split("/")[0]).append("天开始")
.append(",每").append(days.split("/")[1]).append(CRON_EXPRESSION_DOMAIN[3]);
} else if ("L".equals(days)) {
// L表示每月的最后一天
result.append("每月最后一天");
} else if ("W".equals(days)) {
// TODO 关于W的处理
result.append(days);
} else {
result.append("每月").append(days).append("日");
}
} else {
if ((result.toString().length() == 0 || expressions.length == 7) && !result.toString().contains("星期")) { // 前面没有内容的话,拼接下
result.append("每").append(CRON_EXPRESSION_DOMAIN[3]);
}
}
// 5. 时
String hours = expressions[2];
if (!hours.equals("*")) {
if (hours.contains("/")) {
result.append(getHourMinuteSecond(hours, 24, 2));
} else {
if (!(result.toString().length() > 0)) { // 对于 , 的情况,直接拼接
result.append("每天").append(hours).append(CRON_EXPRESSION_DOMAIN[2]);
} else {
result.append(hours).append(CRON_EXPRESSION_DOMAIN[2]);
}
}
}
// 6. 分
String minutes = expressions[1];
if (!minutes.equals("*")) {
if (minutes.contains("/")) {
result.append(getHourMinuteSecond(minutes, 60, 1));
} else if (minutes.equals("0")) {
} else if (minutes.contains("-")) {
String[] splitMinute = minutes.split("-");
result.append(splitMinute[0]).append(CRON_EXPRESSION_DOMAIN[1]).append("到").append(splitMinute[1])
.append(CRON_EXPRESSION_DOMAIN[1]).append("每分钟");
} else {
result.append(minutes).append(CRON_EXPRESSION_DOMAIN[1]);
}
}
// 7. 秒
String seconds = expressions[0];
if (!seconds.equals("*")) {
if (seconds.contains("/")) {
result.append(getHourMinuteSecond(seconds, 60, 0));
} else if (!seconds.equals("0")) {
result.append(seconds).append(CRON_EXPRESSION_DOMAIN[0]);
}
}
if (result.toString().length() > 0) {
result.append("执行一次");
}
}
return result.toString();
}
private static String getHourMinuteSecond(String time, int length, int index) {
StringBuffer result = new StringBuffer();
String[] split = time.split("/");
String start = split[0];
// 间隔
String gap = split[1];
String end = String.valueOf(length + (start.equals("*") ? 0 : Integer.parseInt(start)) - Integer.parseInt(gap));
String unit1 = CRON_EXPRESSION_DOMAIN[index];
String unit2 = CRON_EXPRESSION_DOMAIN[index];
if (index == 1) {
unit2 = "分钟";
} else if (index == 2) {
unit2 = "小时";
}
result.append("从").append(start.equals("*") ? 0 : Integer.parseInt(start)).append(unit1).append("开始").append("到").append(end)
.append(unit1).append("范围内").append(",每隔").append(gap).append(unit2);
return result.toString();
}
enum Weeks {
SUN("1", "SUN", "星期天"),
MON("2", "MON", "星期一"),
TUE("3", "TUE", "星期二"),
WED("4", "WED", "星期三"),
THU("5", "THU", "星期四"),
FRI("6", "FRI", "星期五"),
SAT("7", "SAT", "星期六");
private String index1;
private String index2;
private String name;
Weeks(String index1, String index2, String name) {
this.index1 = index1;
this.index2 = index2;
this.name = name;
}
public String getIndex1() {
return index1;
}
public String getIndex2() {
return index2;
}
public String getName() {
return name;
}
public static String name(String index) {
return Arrays.stream(Weeks.values()).filter(m -> m.getIndex1().equals(index) || m.getIndex2().equals(index)).map(m -> m.getName()).findFirst().get();
}
}
}