web-dev-qa-db-ja.com

Quartz 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);

毎月3日と18日の23:00に起動するcronスケジュールです。たとえば、今日(8月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

メソッドはそのように機能することを意図していないのですか、それとも私は何か間違っているのですか?

ありがとう!

21
cambo

CronTriggerではなくCronExpressionオブジェクトを直接使用したいもの。あなたが発見したように、それは過去の次の実行時間を計算しません...しかし、CronExpressionは計算します!

CronExpressionには、getNextValidTimeAfterというメソッドがあります。これはあなたが望むものです。

40
Jason Clawson

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);
5
ibai

CronTrigger.getFireTimeAfter()メソッドには、指定された後の時間が過去になるのを防ぐための保護メカニズムがあります。

これは、評価している過去の時間でsetStartTime firthを呼び出すことで回避できます。次に、getFireTimeAfterを呼び出すと、有効な結果が返されます。

1
darrenmc

これは奇妙なことですが、保護メカニズムが存在します。 Quartz Teamがそのようなチェックを行う理由はわかりません。以下のテストは、nxtDaynxtDay = nxtTrigger.Value.DateTime.AddHours(1);)に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);
0
user3603550

Quartz doc によると:

指定された時間の後、CronTriggerが次に起動する時間を返します

「意志の火」は「将来」を意味します。つまり、CronTriggerが次に起動するのは過去ではなく、過去の日付は返されません。

私はあなたが何を達成しようとしているのか正確にはわかりませんが、あなたは夜それらの方法に興味があります:

  • getPreviousFireTime():トリガーが最後に起動された時刻を返します
  • getTimeBefore():指定された日付の前にトリガーが起動した時間を返します(過去に機能します)-注:これは今のところ実装されていないようです
0
Vivien Barousse