8

好的,所以我想安排一个任务在每个月的最后一天上午 10:10 运行。我的 cron 表达式是

0 10 10 L * ?

现在的问题是CronSequenceGenerator为“L”值抛出 NumberFormatException。这意味着 Spring 的 CronSequenceGenerator 不支持这种表达式。如何以任何其他方式执行此操作(解决方法)。我不想使用石英或 Spring 的将在新版本中支持这一点。

这是完整的堆栈跟踪:

Exception in thread "main" java.lang.NumberFormatException: For input string: "L"
    at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
    at java.lang.Integer.parseInt(Integer.java:492)
    at java.lang.Integer.valueOf(Integer.java:582)
    at org.springframework.scheduling.support.CronSequenceGenerator.getRange(CronSequenceGenerator.java:324)
    at org.springframework.scheduling.support.CronSequenceGenerator.setNumberHits(CronSequenceGenerator.java:297)
    at org.springframework.scheduling.support.CronSequenceGenerator.setDays(CronSequenceGenerator.java:275)
    at org.springframework.scheduling.support.CronSequenceGenerator.setDaysOfMonth(CronSequenceGenerator.java:266)
    at org.springframework.scheduling.support.CronSequenceGenerator.parse(CronSequenceGenerator.java:239)
    at org.springframework.scheduling.support.CronSequenceGenerator.<init>(CronSequenceGenerator.java:81)
    at org.springframework.scheduling.support.CronTrigger.<init>(CronTrigger.java:54)
    at org.springframework.scheduling.support.CronTrigger.<init>(CronTrigger.java:44)
    at com.hcdc.coedp.datantar.scheduler.SchedulerUtil.start(SchedulerUtil.java:75)
    at com.hcdc.coedp.datantar.scheduler.SchedulerUtil.changeTrigger(SchedulerUtil.java:106)
    at com.hcdc.coedp.datantar.scheduler.SchedulingService.scheduleTransfer(SchedulingService.java:70)
    at com.hcdc.coedp.datantar.scheduler.Scheduler.schedule(Scheduler.java:107)
    at main.Main.main(Main.java:47)

更新:

以下是我的调度方法

 /**
    * Schedule a task {@link Task} with a specified cron expression.
    * @param task {@link Task}
    * @param cronExpression cron expression to be applied must be a vaild one.
    * @param taskName
    * @return 
    */
     public String start(Task task, String cronExpression, String taskName) {
        CronTrigger trigger = new CronTrigger(cronExpression);//line 2

        CronSequenceGenerator generator = new CronSequenceGenerator(cronExpression, TimeZone.getTimeZone("GMT+5:30"));
        List<Date> dateList = new ArrayList<>(5);
        Date currentDate = new Date();
        for (int i = 0; i < 5; i++) {
            currentDate = generator.next(currentDate);
            dateList.add((currentDate));
            System.out.println("Next Exceution times are" + currentDate);
        }
        ScheduledFuture sf = tps.schedule(task, trigger);

        //TODO Save this scheduled future with a specific task name.
        ContextHolder.schduledFutureMap.put(taskName, sf);
        return cronExpression;
    }

在第 2 行,当我传递指定的 cron 表达式时,它会抛出 NumberFormatException。

4

4 回答 4

8

此功能不在标准 cron 表达式语法中。所以可能 Spring 永远不会实现它。查看代码,我看不到任何扩展的手术CronSequenceGenerator解决方案。那么为什么你不使用 Quartz,因为它是一个特殊的功能

根据您的确切需要,您可以实现自己的Trigger。就像是:

import java.util.Date;

import org.joda.time.LocalDate;
import org.joda.time.LocalTime;
import org.springframework.scheduling.Trigger;
import org.springframework.scheduling.TriggerContext;

public class LastDayOfMonthTrigger implements Trigger {

    private final LocalTime time;

    public LastDayOfMonthTrigger(LocalTime time) {
        this.time = time;
    }

    @Override
    public Date nextExecutionTime(TriggerContext ctx) {
        Date last = ctx.lastScheduledExecutionTime();
        LocalDate date = last == null ? new LocalDate() : new LocalDate(last).plusDays(1);
        LocalDate lastDay = date.dayOfMonth().withMaximumValue();
        return lastDay.toDateTime(time).toDate();
    }
}
于 2013-08-12T23:36:12.107 回答
6

作为一种解决方法,我会安排所有日期的执行

0 10 10 * * ?

并在预定方法中检查了实际日期

public void scheduledTask() {
    Calendar c = Calendar.getInstance();
    if (c.get(Calendar.DATE) == c.getActualMaximum(Calendar.DATE)) {
        ...
    }
}
于 2013-08-06T11:57:45.053 回答
2

仅在一个月的最后一天运行的优化版本:

@Scheduled(cron = "0 55 23 28-31 * ?")
public void doStuffOnLastDayOfMonth() {
    final Calendar c = Calendar.getInstance();
    if (c.get(Calendar.DATE) == c.getActualMaximum(Calendar.DATE)) {
        // do your stuff
    }
}
于 2016-08-16T07:36:19.123 回答
0

还有另一种解决方案:

生成一个月的数据。该程序应在下个月的第一天运行,以确保捕获整个月的所有数据。

import org.apache.commons.lang3.time.DateUtils;

@Scheduled(cron = "0 0 0 1 * ?") // runs on the first day of each month

public void doStuffOnFirstDayOfMonth() {

    Date now = DateUtils.addDays(new Date(), -1); // "now" is now on the last day of the month

}
于 2019-10-28T03:14:52.653 回答