Как и в случае с нынешней версией java SE 8 с отличным API с датами времени с java.time
, такие вычисления можно сделать проще, вместо использования java.util.Calendar
и java.util.Date
.
Теперь в качестве образца, например, для планирования задания с прецеденту:
LocalDateTime localNow = LocalDateTime.now();
ZoneId currentZone = ZoneId.of("America/Los_Angeles");
ZonedDateTime zonedNow = ZonedDateTime.of(localNow, currentZone);
ZonedDateTime zonedNext5 ;
zonedNext5 = zonedNow.withHour(5).withMinute(0).withSecond(0);
if(zonedNow.compareTo(zonedNext5) > 0)
zonedNext5 = zonedNext5.plusDays(1);
Duration duration = Duration.between(zonedNow, zonedNext5);
long initalDelay = duration.getSeconds();
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
scheduler.scheduleAtFixedRate(new MyRunnableTask(), initalDelay,
24*60*60, TimeUnit.SECONDS);
initalDelay
вычисляется задать планировщик, чтобы задержать выполнение в TimeUnit.SECONDS
. Вопросы разницы во времени с единицами миллисекунд и ниже, по-видимому, незначительны для этого варианта использования. Но вы можете использовать duration.toMillis()
и TimeUnit.MILLISECONDS
для обработки вычислений вычислений в миллисекундах.
А также TimerTask лучше для этого или ScheduledExecutorService?
NO:ScheduledExecutorService
, казалось бы, лучше, чем TimerTask
. StackOverflow has already an answer for you.
От @PaddyD,
У вас еще есть вопрос, в котором вы должны перезапустить это два раза в год , если вы хотите, чтобы работать в нужное местное время. scheduleAtFixedRate не разрешит его, если вы не удовлетворены тем же временем UTC в течение всего года.
Как это верно и @PaddyD уже дали обходной путь (+1 к нему), я обеспечиваю рабочий пример с датой Java8 времени API с ScheduledExecutorService
.Using daemon thread is dangerous
class MyTaskExecutor
{
ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);
MyTask myTask;
volatile boolean isStopIssued;
public MyTaskExecutor(MyTask myTask$)
{
myTask = myTask$;
}
public void startExecutionAt(int targetHour, int targetMin, int targetSec)
{
Runnable taskWrapper = new Runnable(){
@Override
public void run()
{
myTask.execute();
startExecutionAt(targetHour, targetMin, targetSec);
}
};
long delay = computeNextDelay(targetHour, targetMin, targetSec);
executorService.schedule(taskWrapper, delay, TimeUnit.SECONDS);
}
private long computeNextDelay(int targetHour, int targetMin, int targetSec)
{
LocalDateTime localNow = LocalDateTime.now();
ZoneId currentZone = ZoneId.systemDefault();
ZonedDateTime zonedNow = ZonedDateTime.of(localNow, currentZone);
ZonedDateTime zonedNextTarget = zonedNow.withHour(targetHour).withMinute(targetMin).withSecond(targetSec);
if(zonedNow.compareTo(zonedNextTarget) > 0)
zonedNextTarget = zonedNextTarget.plusDays(1);
Duration duration = Duration.between(zonedNow, zonedNextTarget);
return duration.getSeconds();
}
public void stop()
{
executorService.shutdown();
try {
executorService.awaitTermination(1, TimeUnit.DAYS);
} catch (InterruptedException ex) {
Logger.getLogger(MyTaskExecutor.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
Примечание:
MyTask
представляет собой интерфейс с функцией execute
.
- При остановке
ScheduledExecutorService
, всегда используйте awaitTermination
после вызова shutdown
на нем: всегда есть вероятность, что ваша задача застряла/зашла в тупик, и пользователь будет ждать вечно.
В предыдущем примере я дал с Календаре был просто идея которой я Упоминание, я избегал точного расчета времени и Daylight Saving вопросы. Обновлено решение по жалобе @PaddyD
использовать что-то вроде Quartz вместо этого. – millimoose