1、需求
以上是原型。与前端协商,存储就用cron表达式。
案例如下:
//每天
String cronExpression = "0 37 13 * * ?";
//周
MON TUE WED THU FRI SAT SUN
String cronExpression = "0 0 14 ? * TUE";
//月
String cronExpression = "0 22 15 9 * ?";
业务逻辑中,当前时间于下次执行时间小于等于一分钟,创建任务。并且需要根据cron表达式知道上一次执行时间。二个时间是作为业务逻辑判断的条件。
2、编码
2.1所需资源
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.3.2</version>
</dependency>
2.2 下次执行时间与当前时间小于一分钟
/**
* corn near one minutes
* @param cronExpression corn
* @param now current
* @return true yes
*/
private static boolean isNextExecutionWithinOneMinute(String cronExpression, Date now) {
CronTrigger trigger = new CronTrigger(cronExpression);
TriggerContext context = new SimpleTriggerContext(now, null, null);
Date nextExecutionTime = trigger.nextExecutionTime(context);
if (nextExecutionTime == null) {
return false;
}
Duration durationUntilNextExecution = Duration.between(Instant.ofEpochMilli(now.getTime()), Instant.ofEpochMilli(nextExecutionTime.getTime()));
//精确到毫秒级,durationUntilNextExecution 刚好一分钟才会返回0,多1毫秒,都是大于0
return durationUntilNextExecution.compareTo(Duration.ofMinutes(1)) <= 0;
}
这边的now需要传入,因为需要忽略程序执行的毫秒级,所以需要每次对同一个时间进行操作。传入。
2.3&2.4方法参考此文,但是此文中提供的代码存在问题。
我给予修正了,符合自己的项目需求。
2.3 cron表达式与当前时间得出下次执行时间
public static long getNextTriggerTime(String cron){
if(!CronExpression.isValidExpression(cron)){
return 0;
}
CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity("Caclulate Date").withSchedule(CronScheduleBuilder.cronSchedule(cron)).build();
Date time0 = trigger.getStartTime();
Date time1 = trigger.getFireTimeAfter(time0);
return time1.getTime();
}
2.4 cron表达式与当前时间得出上次执行时间
这边我做了调整。扩展循环次数来确保覆盖足够的周期。
public static long getLastTriggerTime(String cron){
if(!CronExpression.isValidExpression(cron)){
return 0;
}
CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity("Caclulate Date").withSchedule(CronScheduleBuilder.cronSchedule(cron)).build();
Date now = trigger.getStartTime();
Date nextTime = trigger.getFireTimeAfter(now);
Date preTime = nextTime;
for (int i = 0; i < 47; i++) {
Date temp = trigger.getFireTimeAfter(preTime);
preTime = temp;
}
return preTime.getTime() - (trigger.getFireTimeAfter(preTime).getTime() - nextTime.getTime());
}
3、测试
public static void main(String[] args) throws Exception{
String cronDay = "0 37 13 * * ?";
System.out.println("Last execution time _ day " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(getLastTriggerTime(cronDay)));
System.out.println("Next execution time _ day " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(getNextTriggerTime(cronDay)));
String cronWeek = "0 0 14 ? * TUE";
System.out.println("Last execution time _ week " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(getLastTriggerTime(cronWeek)));
System.out.println("Next execution time _ week " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(getNextTriggerTime(cronWeek)));
String cronMonth = "0 22 15 9 * ?";
System.out.println("Last execution time _ month " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(getLastTriggerTime(cronMonth)));
System.out.println("Next execution time _ month " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(getNextTriggerTime(cronMonth)));
}
月周日,都在符合预期。