2013-10-29 117 views
1

我正在嘗試爲我的程序添加一個功能,該功能將在芝加哥期貨市場關閉後每天執行代碼。這意味着我想在東部時間5:35左右(市場所在的中心時間4:35)運行代碼。隨着夏令時間的發生,這當然會在EST(UTC -5)和EST(UTC -4)之間來回切換。如何在特定時間每天執行代碼?

我知道有很多類似的問題,但是他們都沒有提供我可以使用的解決方案。主要建議似乎是使用任務計劃程序或Quartz,但是,我無法在我的程序中實施這些建議。我認爲最有希望的解決方案是使用TimeZoneInfo,DateTimeTimeSpan的組合來安排每天在正確的時間觸發的計時器。該解決方案我現在有是這樣的:

DateTime now = DateTime.Now; 
    DateTime currentDateTime = now.DateTime.Date; 
    DateTime expiryDateTime = currentDateTime 
     .AddHours(17) 
     .AddMinutes(35) 
     .AddDays(
      now.DateTime.Hour >= 18 + utcOffset 
      || (now.DateTime.Hour == 17 && now.DateTime.Minute >= 35) ? 1 : 0); 
    Timer timer = new Timer(
     ..., 
     null, 
     expiryDateTime - DateTime.Now, 
     ...); 

我想這這將土崩瓦解,但是,如果我的代碼是不是東部時間以外的時間區域中運行。我還擔心這種情況在時區從EST切換到EDT時的23或25小時內不會正常工作,反之亦然。

有沒有比我目前正在處理調度更好的方法?我怎樣才能讓這段代碼更健壯,可以處理在任何時區運行,但始終在東部時間執行?如上所述,任務計劃程序和Quartz不是選項。石英出來了,因爲我無法包含第三方庫。任務計劃程序已經關閉,因爲我需要從我的程序中訪問很多內部值。啓動另一個應用程序並將這些值公開給該應用程序增加了比我認爲的更好的複雜性。

+0

'主要的建議似乎是使用任務計劃程序或然而,Quartz,我無法在我的程序中實現這些。「,請問爲什麼?是否因爲沒有足夠的文檔來滿足您的需求? **更具體地說,爲什麼不能使用Quartz?** –

+1

只需將所有程序狀態存儲在配置文件或數據庫中,以便任務調度程序不需要將其傳入或知道任何事情。 – Servy

+0

我同意服務。此外,可能的代碼異味,因爲即使你需要通過DB,你應該有一個可重用的DL,所以事情保持簡單。 –

回答

1

我感謝所有其他答案的反饋,並想指出任何人在這一點,石英或Windows任務調度確實是更好的選擇,如果你可以用它們誰無意中發現。然而,我沒有這個選擇,所以這裏是我如何最終實現每次找到合適的時間並安排定時器運行:

//This code block is designed to schedule a timer for 5:35pm Eastern Time, regardless of whether is is Daylight Savings (EDT, UTC-4) or not (EST, UTC-5). 
    // When understanding this code it is important to remember that a DateTime in UTC time represents an ABSOLUTE point in time. Any UTC time can only occur once. 
    // A date time measured in local time (here we force Eastern Standard) is NOT ABSOLUTE. The same local time can occur twice (2am Nov 3nd 2013 for example) 
    //Gets Eastern Timezone to be used in conversions 
    TimeZoneInfo easternTimeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time"); 
    //Grabs the current time (UTC) 
    DateTime utcNowDateTime = DateTime.Now.ToUniversalTime(); 
    //Gets current time in Eastern Time (could be UTC-4 or -5 depending on time of year) 
    DateTime easternNowDateTime = TimeZoneInfo.ConvertTime(utcNowDateTime, easternTimeZoneInfo); 
    //Gets todays date 
    DateTime easternNowDate = easternNowDateTime.Date; 
    //Gets 5:35pm today or tomorrow depending on whether we are past 5:35pm or not. 
    // Even though there are actually 18 hours from midnight to 5:35pm on Nov 2 2014 and 16 hours from midnight to 5:35pm on March 9 2014, 
    // this will still end up at 5:35pm on those days because DateTime DOESNOT take into account the movement of the clocks (foreward or backward) when calling 
    // .AddHours(), etc 
    DateTime easternExpiryDateTime = easternNowDate.AddHours(17).AddMinutes(35).AddDays(easternNowDateTime.Hour >= 18 || (easternNowDateTime.Hour == 17 && easternNowDateTime.Minute >= 35) ? 1 : 0); 
    //Convert the Easter Time date time to UTC. When subtracting this time from another UTC DateTime you will get the correct TimeSpan for use with a timer 
    // (even on 23 such as March 10th and 25 hour days such as November 3rd 2013) 
    DateTime utcExpiryDateTime = easternExpiryDateTime.ToUniversalTime(); 
    //Set the timer to trigger at the desired point in the future. 
    Timer timer = new Timer(
     ..., 
     null, 
     utcExpiryDateTime - utcNowDateTime , 
     ...); 
9

設置窗口計劃任務。長時間運行的計時器往往是有問題的,而且對於這樣一個簡單的工作肯定過於複雜。

+0

感謝您的反饋。請參閱我的編輯,以瞭解爲什麼我不認爲Windows計劃任務可以工作。 – GBleaney

1

使用任務調度框架,如Quartz.net

+0

感謝您的反饋,但我無法加入第三方庫。 – GBleaney

7

你缺少Windows任務調度點。你不會在你的應用程序中實現它。您編寫一個應用程序,然後使用任務計劃程序每天在特定時間運行它。

爲了迴應您對計劃和應用程序性質的說明,不幸的是,您強調需要重新考慮您的應用程序。構建一個必須始終運行且不斷添加功能的龐大應用程序並不是一個好主意。

相反,爲什麼不重新考慮你的應用程序的結構。您可以擁有需要始終運行的核心功能,作爲服務運行。然後其他組件可以通過例如寧靜的界面與它交談。然後可以停止並開始應用程序的用戶界面方面,而不用擔心會影響服務,而不管服務如何。另外,增加額外的功能,例如在一天的特定時間執行特定tsak的預定應用程序變得更容易。

+0

感謝您的反饋。請參閱我的編輯,以瞭解爲什麼我不認爲Windows計劃任務可以工作。 – GBleaney

0

您可以創建Windows服務並將其安裝在您的系統上。

0

由於您不能使用第三方庫或將您的內部結構暴露給其他應用程序,是否可以公開通信端點(WCF,UDP,命名管道等)?或者,也許你可以監視一個文件夾中的其他應用程序創建的「命令文件」?(使用FileSystemWatcher或簡單的定時器)

單獨的應用程序可以將消息發送到此端點/文件夾,並且Windows任務計劃程序可以安排此應用程序。

3

正確解決方案是使用Quartz.net或Windows任務計劃程序,但既然你說過你不能那樣做,那麼讓我們考慮一下你可能會做什麼。

  • 您的程序需要一直運行。這意味着它應該是一個後臺Windows服務應用程序。你不想讓用戶的應用程序,因爲你不希望處理用戶關閉應用程序,它應該運行,即使沒有人登錄。

  • 你應該使用長計時器。相反,請使用定期運行的定時器來檢查是否該執行事件。短時間計時器應該多久運行一次?這是在空閒時想要消耗多少資源與您的任務可接受多少潛在延遲之間的折中。如果需要在規定時間的幾分鐘內運行,則可能只需要每分鐘檢查一次,或每五分鐘左右檢查一次。

  • 如果可能,您應該從數據中取一次「下一次執行時間」。所以當你定期檢查時,你不必每次都去碰到數據庫。但要小心,如果這個值是不穩定的,那麼你需要一種方法來使你的本地緩存值過期。

  • 關於DST和時區,您需要區分計劃在特定UTC時間或特定當地時間運行的任務。例如,如果您每小時執行一次任務,則不妨使用UTC,這樣您就不會被DST更改拋棄。如果你有每日任務,你應該使用當地時間。這可能是電腦的本地時間,也可能是特定時區的本地時間。這取決於你的管理。另外,您需要一個策略來處理計劃在彈簧轉發DST轉換創建的差距期間運行的任務,或計劃在由回退轉換創建的模糊時間期間運行的任務。另請參閱the DST tag wiki

  • 現在回頭看看所有這些,並意識到你剛剛編寫了自己的Quartz.NET。你真的確定你不能只建立一個已經存在的?爲什麼重新發明輪子?

相關問題