Java ScheduledExecutorService.scheduleAtFixedRate并将initialDelay设置为过去的日期

Java ScheduledExecutorService.scheduleAtFixedRate并将initialDelay设置为过去的日期,java,timer,futuretask,Java,Timer,Futuretask,我正在用Java开发一个调度系统,它根据开始日期、结束日期和事件(每小时、每天、每周、每月、周一等)发送提醒。最初,我使用Timer和TimerTask类来安排提醒: Timer timer = new Timer(); timer.scheduleAtFixedRate(reminder, firstDate, period); 我最近切换到ScheduledExecutorService,这样我就可以更好地控制取消事件。ScheduledExecutorService对于定期提醒运行良好,

我正在用Java开发一个调度系统,它根据开始日期、结束日期和事件(每小时、每天、每周、每月、周一等)发送提醒。最初,我使用Timer和TimerTask类来安排提醒:

Timer timer = new Timer();
timer.scheduleAtFixedRate(reminder, firstDate, period);
我最近切换到ScheduledExecutorService,这样我就可以更好地控制取消事件。ScheduledExecutorService对于定期提醒运行良好,但以前有一次使用startDate重新安排提醒。scheduleAtFixedRate函数仅允许您为initialDelay指定长值,而不是实际的日期对象:

这带来了一个问题,因为传入负initialDelay仍然会导致事件立即触发,从而导致事件在now+期间而不是startDate+期间再次发生


有什么办法可以(重新)用过去的开始日期安排提醒吗?

只需快速检查一下日期是否在过去,然后创建一个新的临时开始日期时间,它是现在开始时间的增量。

我通过在启动时运行一次,然后在我每天想要的时间运行来解决这个问题:

// check once initial on startup
doSomething();

// and then once every day at midnight utc
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
LocalDateTime firstRun = LocalDate.now(ZoneOffset.UTC).atStartOfDay().plusDays(1);
Duration durationUntilStart = Duration.between(LocalDateTime.now(ZoneOffset.UTC), firstRun);
scheduler.scheduleAtFixedRate(
        () -> doSomething(),
        durationUntilStart.getSeconds() + 1,
        Duration.ofDays(1).getSeconds(),
        TimeUnit.SECONDS
);

谢谢你的回复,看起来这样就行了。下面是计算initialDelay的代码片段:Calendar now=Calendar.getInstance();日历开始=提醒。getStartCalendar();while(start.before(now)){start.add(Calendar.millis秒,(int)remement.getPeriod();}long initialDelay=start.getTimeInMillis()-now.getTimeInMillis();ScheduledExecutorService scheduler=执行者。newSingleThreadScheduledExecutor();this.scheduler.scheduleAtFixedRate(提醒、initialDelay、提醒.getPeriod()、时间单位.毫秒);
// check once initial on startup
doSomething();

// and then once every day at midnight utc
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
LocalDateTime firstRun = LocalDate.now(ZoneOffset.UTC).atStartOfDay().plusDays(1);
Duration durationUntilStart = Duration.between(LocalDateTime.now(ZoneOffset.UTC), firstRun);
scheduler.scheduleAtFixedRate(
        () -> doSomething(),
        durationUntilStart.getSeconds() + 1,
        Duration.ofDays(1).getSeconds(),
        TimeUnit.SECONDS
);