在使用spring的CronSequenceGenerator获取表达式是否正确以及表达式的下一个触发日期时报错
java.lang.NumberFormatException: For input string: "L"
其实就是spring的CronSequenceGenerator在构造函数中设置表达式的时候解析异常
首先将表达式按照空格分隔,其次再一个一个解析,解析中对于L
字符串没有处理导致的
其实L就是最后一天,用在不同的字段有不同的含义,我这个地方是每个月的最后一天,所以对于天进行特殊处理。对于星期其他地方的这里没有处理,不过可以参考这种思路。
首先对L进行转换,转换为28号(因为每个月都有28号),其次获取当月的最后一天再设置一下即可
import org.quartz.impl.triggers.CronTriggerImpl;
import org.springframework.scheduling.support.CronSequenceGenerator;
import java.util.Calendar;
import java.util.Date;
public class CronUtil {
/**
* cron表达式是否正确
*
* @param cron 表达式
* @return
*/
public static boolean isValidExpression(String cron) {
CronTriggerImpl trigger = new CronTriggerImpl();
try {
trigger.setCronExpression(cron);
Date date = trigger.computeFirstFireTime(null);
return date != null && date.after(new Date());
} catch (Exception e) {
}
return false;
}
/**
* cron表达式的下一次执行日期
* @param cron 表达式
* @return
*/
public static Date nextCron(String cron) {
return nextCron(cron, new Date());
}
/**
* cron表达式的下一次执行日期
* @param cron 表达式
* @param date 相对日期
* @return
*/
public static Date nextCron(String cron, Date date) {
if (cron.contains("L")) {
cron = cron.replace("L", "28");
Date tmpData = new CronSequenceGenerator(cron).next(date);
final Calendar cal = Calendar.getInstance();
cal.setTime(tmpData);
final int last = cal.getActualMaximum(Calendar.DAY_OF_MONTH);
cal.set(Calendar.DAY_OF_MONTH, last);
return cal.getTime();
}
return new CronSequenceGenerator(cron).next(date);
}
}
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.3.0</version>
</dependency>
测试
@Test
public void isValidExpression() {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String cron = "0 15 10 L * ?";
System.out.println(CronUtil.isValidExpression(cron));
System.out.println(sdf.format(CronUtil.nextCron(cron)));
System.out.println(sdf.format(CronUtil.nextCron(cron, DateUtil.localDateTimeToDate(LocalDateTime.now().minusMonths(2)))));
}