Cron 表达式解析
在进行定时任务的时候,经常会使用到Cron表达式。Cron表达式是一个字符串,包含六个或七个时间字段和一个命令,用于指定在何时运行任务。它非常常用的应用场景有定时邮件、数据备份、定时清理等。
一个基本的 Cron 表达式通常由六部分组成,分别是:
<秒> <分钟> <小时> <一个月中的第几天> <一个星期中的第几天> <年份>
其中,年份这个部分是可选的,如果不填,则表示无限制。
每个部分都是用空格分隔的一些数字或特殊字符,具体含义如下:
<秒>
:0~59 的整数<分钟>
:0~59 的整数<小时>
:0~23 的整数<一个月中的第几天>
:1~31 的整数<一个星期中的第几天>
:0~7 的整数(0和7都代表星期日,1代表星期一,2代表星期二,以此类推)<年份>
:1970~2099 的整数
每个部分还可以使用特殊符号来表示一些特殊含义:
*
:代表任意值,* * * * * *
表示每秒都执行一次/
:代表步进值,0 0/5 * * * *
表示每隔5分钟执行一次,
:代表枚举值,0 0 1,15 * * *
表示在每个月的1日和15日的凌晨1点执行一次-
:代表区间值,0 0 0 1-31/2 * *
表示在每个月的1日、3日、5日等日期执行一次?
:代表没有特定的值,仅在<一个月中的第几天>
和<一个星期中的第几天>
中使用,0 0 ? * MON *
表示在每个星期一的凌晨执行一次
根据上述规则,我们可以编写出很多的Cron表达式。比如,下面这个例子代表的是每天的凌晨1点:
0 0 1 * * *
接下来,我们来看看如何用程序自动解析Cron表达式。
Cron 表达式解析
如果要自动解析Cron表达式,我们可以采用现成的开源库——cron-utils。它可以帮助我们进行表达式的解析和格式化,同时还提供了一些实用的工具方法来得到指定时间范围内符合要求的所有时间点。
首先,在使用前需要引入依赖,我们在 pom.xml 文件中添加如下依赖:
<dependency>
<groupId>com.cronutils</groupId>
<artifactId>cron-utils</artifactId>
<version>10.6.0</version>
</dependency>
接下来,我们来看一下如何使用 cron-utils 解析 Cron 表达式。我们可以写一个简单的方法,输入一个 Cron 表达式,输出一个解析结果对象:
import com.cronutils.descriptor.CronDescriptor;
import com.cronutils.model.Cron;
import com.cronutils.model.definition.CronDefinitionBuilder;
import com.cronutils.parser.CronParser;
import java.util.Locale;
public class CronExpressionParser {
public static String parse(String cronExpression) {
CronParser parser = new CronParser(CronDefinitionBuilder.instanceDefinitionFor(CronDefinitionBuilder.CronType.QUARTZ));
Cron cron = parser.parse(cronExpression);
return CronDescriptor.instance(Locale.getDefault()).describe(cron).replaceAll("^At ", "");
}
}
这个方法的作用是将输入的 Cron 表达式解析为一个 Cron 对象,并使用 CronDescriptor 对象将其格式化为一个人类可读的描述。其中,CronDefinitionBuilder.instanceDefinitionFor(CronDefinitionBuilder.CronType.QUARTZ) 指定了 Cron 表达式的类型为 Quartz,Quartz 也是一个非常常用的定时框架。
现在,我们可以在任何需要解析 Cron 表达式的地方使用上面这个方法,比如:
String cronExpression = "0 0 1 * * *";
String description = CronExpressionParser.parse(cronExpression);
System.out.println(description);
输出:
每天的 1:00 AM
不仅如此,cron-utils 还提供了一些实用的工具方法来计算符合要求的时间点。比如,我们可以用如下方式得到下一个符合要求的时间点:
import com.cronutils.model.CronType;
import com.cronutils.model.definition.CronDefinitionBuilder;
import com.cronutils.parser.CronParser;
import com.cronutils.utils.VisibleForTesting;
import java.time.LocalDateTime;
public class CronExpressionUtils {
public static LocalDateTime getNextExecution(String cronExpression) {
CronParser parser = new CronParser(CronDefinitionBuilder.instanceDefinitionFor(CronType.QUARTZ));
com.cronutils.model.Cron cron = parser.parse(cronExpression);
org.threeten.bp.ZonedDateTime next = cron.nextOrSame(org.threeten.bp.ZonedDateTime.now()).toInstant().atZone(org.threeten.bp.ZoneId.systemDefault());
return LocalDateTime.of(next.getYear(), next.getMonth(), next.getDayOfMonth(), next.getHour(), next.getMinute(), next.getSecond());
}
}
这个方法的作用是得到下一个符合要求的时间点,并将其转换为 Java 8 的 LocalDateTime 对象。需要注意的是,这里使用了一个第三方依赖 ThreeTenBP,因为它提供了更好的时间处理方式。
现在,我们可以在任何需要计算符合要求的时间点的地方使用上面这个方法,比如:
String cronExpression = "0 0 1 * * *";
LocalDateTime nextExecution = CronExpressionUtils.getNextExecution(cronExpression);
System.out.println(nextExecution);
输出:
2022-08-02T01:00
结论
本文介绍了 Cron 表达式以及如何使用 cron-utils 库来解析 Cron 表达式和计算符合要求的时间点。Cron 表达式是一种非常常用的定时任务配置方式,它可以轻松帮助我们实现诸如定时邮件、数据备份、定时清理等常见的定时任务。如果你需要在 Java 项目中解析 Cron 表达式,可以使用上面介绍的方式,它可以帮助你节省大量的时间和精力。