Кварц CronTrigger - Получение следующего времени огня
Я использую средство Quartz CronTrigger для анализа строк формата расписания cron, чтобы определить, когда должно выполняться определенное задание. На самом деле я не использую Quartz для планирования работы.
В CronTrigger есть метод, называемый getFireTimeAfter (Date), который дает следующий раз, когда задание будет срабатывать после указанной даты. Это хорошо работает, когда поставляемая дата сейчас или в будущем. Но, похоже, это не работает, если дата в прошлом.
Date currTime = new Date();
CronTrigger tr = new CronTrigger();
tr.setCronExpression("0 0 23 3,18 * ? *");
Date nextFireAt = tr.getFireTimeAfter(currTime);
System.out.println("Reference time: " + currTime);
System.out.println("Next fire after reference time: " + nextFireAt);
Какое расписание cron должно срабатывать в 23:00 по 3 и 18 месяца. Так, например, если я сделал это сегодня (11 августа), я вижу:
Reference time: Thu Aug 11 10:04:25 MDT 2011
Next fire after reference time: Thu Aug 18 23:00:00 MDT 2011
Но если я установил контрольную дату в прошлое, это даст мне такое же следующее время огня.
Reference time: Wed Dec 31 17:00:00 MST 1969
Next fire after reference time: Thu Aug 18 23:00:00 MDT 2011
Я ожидал, что выход будет:
Reference time: Wed Dec 31 17:00:00 MST 1969
Next fire after reference time: Wed Aug 3 23:00:00 MDT 2011
Является ли метод просто не предназначенным для работы таким образом или я делаю что-то неправильно?
Спасибо!
Ответы
Ответ 1
Что вы действительно хотите использовать объект CronExpression напрямую, а не CronTrigger. Как вы обнаружили, он не будет вычислять следующее время выполнения в прошлом... но CronExpression будет!
CronExpression имеет метод: getNextValidTimeAfter. Это то, что вы хотите.
Ответ 2
В Spring вы можете следовать тому же подходу, который они используют в своих тестах интеграции.
CronTriggerTests
CronTrigger trigger = new CronTrigger();
trigger.setCronExpression("0 0 23 3,18 * ? *");
SimpleTriggerContext triggerContext = new SimpleTriggerContext();
triggerContext.update(null, null, new Date());
Date nextFireAt = trigger.nextExecutionTime(triggerContext);
Ответ 3
В соответствии с Quartz doc:
Возвращает следующий раз, когда CronTrigger будет срабатывать, по истечении заданного времени
"В случае пожара" подразумевается "в будущем". То есть, в следующий раз CronTrigger
будет срабатывать не в прошлом, а даты в прошлом не возвращаются.
Я точно не знаю, что вы пытаетесь принять, но вы носите в себе эти методы:
- getPreviousFireTime(): возвращает последний раз, когда триггер был запущен.
- getTimeBefore(): возвращает время срабатывания триггера до заданной даты (работает в прошлом) - Примечание: на данный момент это не реализовано
Ответ 4
Метод CronTrigger.getFireTimeAfter()
имеет механизм защиты для предотвращения того, чтобы указанное время было в прошлом.
Это можно обойти, вызвав setStartTime
firth с тем временем, которое вы оцениваете в прошлом. Тогда вызов getFireTimeAfter
должен вернуться с допустимым результатом.
Ответ 5
Это немного странно, но механизм защиты существует. Не знаю, почему команда Quartz провела эту проверку. Следующий тест проходит, только если я добавлю час на nxtDay
(nxtDay = nxtTrigger.Value.DateTime.AddHours(1);
)
var timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("GMT Standard Time");
//FREQUENCY OF SECONDS
var reccurrence = new Reccurrence
{
StartTime = new TimeSpan(9, 0, 0),
StopTime = new TimeSpan(11, 0, 0),
WeekDay = "MON-SUN",
TimeZoneInfo = timeZoneInfo,
Frequency = 15,
FrequencyUnit = FrequencyUnit.Seconds
};
var autoPublishDetail = new AutoPublishJobDetail("TestReccurence_Seconds", _log, null, reccurrence);
var trigger = autoPublishDetail.GetDailyTrigger();
var nxt = trigger.GetNextFireTimeUtc();
var jobSeconds = JobBuilder.Create().WithIdentity(new JobKey("TestReccurence_Seconds")).OfType(typeof(AutoPublishJob)).Build();
_scheduler.ScheduleJob(jobSeconds, trigger);
//This job sud run 4 times in a 60 secs and from 9 am to 11 am (Span of 3 hrs including 11 onwards to 11:59:59)
//Total runs = 4 x 60 x 3 = 720
var today = DateTime.Now;
var tomorrow = today.AddDays(1);
DateTime? nxtDay = new DateTime(tomorrow.Year, tomorrow.Month, tomorrow.Day);
int jobCnt = 0;
do
{
var nxtTrigger = trigger.GetFireTimeAfter(nxtDay.Value);
if (nxtTrigger.Value.Year.Equals(today.AddDays(2).Year) && nxtTrigger.Value.Month.Equals(today.AddDays(2).Month) && nxtTrigger.Value.Day.Equals(today.AddDays(2).Day))
break;
jobCnt++;
nxtDay = nxtTrigger.Value.DateTime.AddHours(1);
} while (true);
Assert.AreEqual(720, jobCnt);