这篇博客将介绍Java 如何根据Cron表达式获取近几次任务执行时间。实际上使用 quartz 包 CronSequenceGenerator 以及TriggerUtils.computeFireTimes 俩种方法进行时间获取;
1. 效果图
2. 源码
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.3.0</version>
</dependency>
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.quartz.CronExpression;
import org.quartz.TriggerUtils;
import org.quartz.impl.triggers.CronTriggerImpl;
import org.springframework.scheduling.support.CronSequenceGenerator;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
/*****************************
* Class Name: CronUtil
* Description: <获取Cron表达式最近几次执行的时间>
* @Author: Seminar
* @create: 2022/11/02
* @since: 1.0.0
***************************/
@Slf4j
public class CronUtil {
public void getTime() {
String cronExpress = "0 */30 * * * ?";//此处为cron表达式
cronExpress = "0 0/30 * * * ?";
try {
CronExpression cronExpression = new CronExpression(cronExpress);//导包import org.quartz.CronExpression;
Date date = cronExpression.getTimeAfter(new Date());
//将date转换为指定日期格式字符串
SimpleDateFormat dataFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dateString = dataFormat.format(date);
//dateString为转换后的日期格式
log.info("{} {}", cronExpress, dateString);
} catch (Exception e) {
log.error("cron获取下次执行时间异常" + e);
}
}
/**
* 列出近cronCount次的执行时间
*
* @param cronExpression cron表达式
* @param cronCount cron时间次数
* @param maxCronCount 最大cron时间次数
* @return
*/
public static List<String> listCronRunTime(String cronExpression, Integer cronCount, Integer maxCronCount) {
if (StringUtils.isBlank(cronExpression)) {
throw new RuntimeException("Cron 表达式不能为空!");
}
if (!CronSequenceGenerator.isValidExpression(cronExpression)) {
throw new RuntimeException("Cron格式不正确,Cron: " + cronExpression);
}
if (cronCount < 1) {
cronCount = 1;
}
if (maxCronCount < 1) {
maxCronCount = 100;
}
if (cronCount > maxCronCount) {
cronCount = maxCronCount;
}
CronSequenceGenerator cronSequenceGenerator = new CronSequenceGenerator(cronExpression);
List<String> cronTimeList = new ArrayList<>();
Date nextTimePoint = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
for (int i = 0; i < cronCount; i++) {
nextTimePoint = cronSequenceGenerator.next(nextTimePoint);
cronTimeList.add(sdf.format(nextTimePoint));
}
return cronTimeList;
}
/**
* 列出近numTimes次的执行时间
*
* @param cronExpression cron表达式
* @param numTimes 下几次运行时间
* @return
*/
public static List<String> getNextExecTime(String cronExpression, Integer numTimes) {
List<String> list = new ArrayList<>();
CronTriggerImpl cronTriggerImpl = new CronTriggerImpl();
try {
cronTriggerImpl.setCronExpression(cronExpression);
} catch (ParseException e) {
e.printStackTrace();
}
// 这个是重点,一行代码搞定
List<Date> dates = TriggerUtils.computeFireTimes(cronTriggerImpl, null, numTimes);
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
for (Date date : dates) {
list.add(dateFormat.format(date));
}
return list;
}
/**
* Java8 通过foreach 遍历List,同时输出下标
* 利用BiConsumer实现foreach循环支持index
*
* @param biConsumer
* @param <T>
* @return
*/
public static <T> Consumer<T> forEachWithIndex(BiConsumer<T, Integer> biConsumer) {
/*这里说明一下,我们每次传入forEach都是一个重新实例化的Consumer对象,在lambada表达式中我们无法对int进行++操作,
我们模拟AtomicInteger对象,写个getAndIncrement方法,不能直接使用AtomicInteger哦*/
class IncrementInt {
int i = 0;
public int getAndIncrement() {
return i++;
}
}
IncrementInt incrementInt = new IncrementInt();
return t -> biConsumer.accept(t, incrementInt.getAndIncrement());
}
public static void main(String[] args) {
CronUtil cronUtil = new CronUtil();
cronUtil.getTime();
String cron = "0 0/30 * * * ?"; // 0 0/30 * * * ? 每隔30分钟执行一次 同 0 */30 * * * ?
cron = "0 0/5 14 * * ?"; // 0 0/5 14 * * ? 在每天下午2点到下午2:55期间的每5分钟触发
log.info("cron: {}", cron);
List<String> timeList = listCronRunTime(cron, 10, 100);
timeList.stream().forEach(forEachWithIndex((item, index) -> {
log.info("{} {}", index + 1, item);
}));
List<String> time2List = getNextExecTime(cron, 10);
time2List.stream().forEach(x -> {
log.info("---- {}", x);
});
}
}