2010-04-26 105 views
6

Java中有找到從Cron表達式中找到「上次觸發時間」的方法。在Java中使用Cron表達式尋找上次觸發時間

例如如果現在= 2010年4月25日晚上10點,cron表達式「0 15 10?* *」(quartz)應該返回給我25-Apr-2010 10:15 am

注意: 1)我不在乎我們是否使用標準的cron表達式(如Unix和Quartz)或者不太受歡迎的表達式,如果它們能夠獲取正確的「最後觸發時間」 2)另外它不是字面上的「最後觸發時間」,因爲觸發器可能沒有觸發,但邏輯上應該作爲最後一次(最終)發射的一種方式。

回答

2

首先,我不知道現有的庫支持這一點。 Quartz可能會,但標準的Java類庫肯定不會。

二,嚴格說來你 要求 最初要求是不可能的。圖書館可以告訴你的最好的是,cron表達式將會有應該有被解僱。唯一可能的(理論上)告訴你最後一次實際觸發的cron表達式是調度器實例本身。

+0

嗨斯蒂芬,感謝您的反饋。我在我的問題筆記中添加了更多信息以清除我的問題。 – 2010-04-27 02:21:32

1

Quartz似乎對cron表達式有一些庫支持。

參見the Javadoc for the CronExpression class,其具有稱爲getTimeBefore的方法。即,

CronExpression cron = new CronExpression("0 15 10 ? * *"); 
Date today = new Date(); 
Date previousExecution = cron.getTimeBefore(today); 

這可能取決於石英版本是否可行。

查看最新的源代碼(編寫本文時的版本2.1.0)此方法尚未實現並始終返回null。

2

我在Quartz中找到的解決方案是返回觸發器的一個時間間隔,並計算下一次觸發時間。通過遍歷所有觸發器,可以確定觸發器應該在過去觸發的最近時間。


計算每個發射間隔:

Date nextFireTime = trigger.getNextFireTime(); 
Date subsequentFireTime = trigger.getFireTimeAfter(nextFireTime); 
long interval = subsequentFireTime.getTime() - nextFireTime.getTime(); 

查找下一個發射時間爲一週時間,直到在過去的時間間隔:

Date previousPeriodTime = new Date(System.currentTimeMillis() - interval); 
Date previousFireTime = trigger.getFireTimeAfter(previousPeriodTime); 

我發現,如果你正在使用這可以防止你在過去要求火災時間。要解決此我修改了啓動時間,所​​以上面的代碼變成:

Date originalStartTime = trigger.getStartTime(); // save the start time 
Date previousPeriodTime = new Date(originalStartTime.getTime() - interval); 
trigger.setStartTime(previousPeriodTime); 
Date previousFireTime = trigger.getFireTimeAfter(previousPeriodTime); 
trigger.setStartTime(originalStartTime); // reset the start time to be nice 

迭代通過所有的觸發器,找到一個是最近過去:

for (String groupName : scheduler.getTriggerGroupNames()) { 
    for (String triggerName : scheduler.getTriggerNames(groupName)) { 
     Trigger trigger = scheduler.getTrigger(triggerName, groupName); 
     // code as detailed above... 
     interval = ... 
     previousFireTime = ... 
    } 
} 

我將它作爲練習留給讀者將其重構爲輔助方法或類。實際上,我使用上述算法在一個子類的委託觸發器中,然後我將它放在一個按前面的觸發時間排序的集合中。在https://github.com/devbhuwan/cron-micro-utils

+2

隨後的火災之間的差異總是不一樣。 – Ahamed 2013-12-17 19:23:45

0
public class CronMircoUtils { 

    /** 
    * Use this method to calculate previous valid date for cron 
    * @param ce CronExpression object with cron expression 
    * @param date Date for find previous valid date 
    * @return 
    */ 
    public static Date getPreviousValidDate(CronExpression ce, Date date) { 
     try { 
      Date nextValidTime = ce.getNextValidTimeAfter(date); 
      Date subsequentNextValidTime = ce.getNextValidTimeAfter(nextValidTime); 
      long interval = subsequentNextValidTime.getTime() - nextValidTime.getTime(); 
      return new Date(nextValidTime.getTime() - interval); 
     } catch (Exception e) { 
      throw new IllegalArgumentException("Unsupported cron or date", e); 
     } 
    } 
} 

源代碼是一個開源的Java庫來分析,驗證,遷移支持你所需要的操作crons。 爲了從一個cron以前的日期只是一個給定的時間之前:

//Get date for last execution 
DateTime now = DateTime.now(); 
ExecutionTime executionTime = ExecutionTime.forCron(parser.parse("* * * * * * *")); 
DateTime lastExecution = executionTime.lastExecution(now)); 

記住,在目前的狀態是有點馬車,不得用於更復雜的cron表達式正確計算。

+0

這隻適用於定期點火。當沒有「subsequentNextValidTime」或發射不規則時會發生什麼(例如10,12,11,17,37分鐘發生火災)? – 2016-01-11 13:35:35

2
+0

hi Joao, 即使工作不運行(例如:服務器脫機),這工作? – Marin 2016-09-14 12:53:13

+1

@NunoMarinho是的,這只是從cron表達式計算以前的日期。庫本身不知道你在用cron表達做什麼。這個庫不會安排要執行的動作或作業,它只是基於cron表達式計算日期。我很久沒有使用這個庫了,請確保它適合您的需求,並在使用後徹底測試您的應用程序。 – 2016-09-14 13:08:16

+0

ObrigadoJoão:D – Marin 2016-09-14 13:36:14

0

如果您正在使用org.quartz,可以使用context.getPreviousFireTime();

例子:

public class TestJob implements Job { 

    @Override 
    public void execute(JobExecutionContext context) throws JobExecutionException { 

     context.getPreviousFireTime(); 
    } 
} 

如果您正在使用context.getTrigger().getPreviousFireTime(),您將擁有在運行作業的觸發時間此時此刻。