Я взял очень интересный ответ Рона и улучшил метод getTimeAfter, чтобы настроить его на время работы сервера GMT и возможные различия при планировании выражений cron «Один раз в год».
@Override
public Date getTimeAfter(Date date) {
Date nextDate = super.getTimeAfter(date);
if(nextDate == null){
return null;
}
DateTime date1 = new DateTime(nextDate);
if (getTimeZone().inDaylightTime(date1.toDate()) && !getTimeZone().inDaylightTime(date)) {
DateTimeZone dtz = DateTimeZone.forTimeZone(getTimeZone());
DateTime dstEndDateTime = new DateTime(new Date(dtz.nextTransition(date.getTime())));
int dstEndHour = dstEndDateTime.getHourOfDay();
int dstDuration = (dtz.getOffset(date1.getMillis()) - dtz.getStandardOffset(date1.getMillis())) / (60 * 60 * 1000);
int hour = date1.getHourOfDay();
// Verifies if the scheduled hour is within a phantom hour (dissapears upon DST change)
if (hour < dstEndHour && hour >= dstEndHour-dstDuration){
// Verify if the date is a skip, otherwise it is a date in the future (like threads that run once a year)
if(dstEndDateTime.getDayOfYear() == date1.minusDays(1).getDayOfYear()){
return dstEndDateTime.toDate();
}else{
return nextDate;
}
}else{
return nextDate;
}
} else{
return nextDate;
}
}
Обратите внимание на мой серверработает в режиме GMT, поэтому я не использую некоторые из преобразований смещения, присутствующих в ответе Рона.
Также я обнаружил ошибку Quartz, в которой, если вы используете следующую конфигурацию, она потерпит неудачу, потому что она не способнаправильной обработки выражения cron:
SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
String cron = "0 15 2 8 3 ? 2015";
FailsafeCronExpression cronExpression = new FailsafeCronExpression(cron);
cronExpression.setTimeZone(DateTimeZone.forID("America/Vancouver"));
DateTime nextDate = new DateTime(cronExpression.getTimeAfter(sdf.parse("12/11/2014 10:15:00")));
Похоже, это действительно происходит из-за того, что изменение летнего времени происходит в Ванкувере 9 марта в 2 часа ночи и кажется, что внутренняя реализация Quartz метода super.getTimeAfter (date) всегда будетотправить ноль.
Я надеюсь, что эта информация полезна.