1

シカゴでの先物市場の閉鎖後に毎日コードを実行する機能をプログラムに追加しようとしています。これは、東部時間の 5 時 35 分頃 (市場のある中央時間の 4 時 35 分) にコードを実行することを意味します。これはもちろん、サマータイムが発生すると、EST (UTC -5) と EST (UTC -4) の間で切り替えられます。

似たような質問がたくさんあることは知っていますが、どれも私が使用できる解決策を提供していないようです。主な提案は、タスク スケジューラまたはクォーツを使用することですが、プログラムにそれらを実装することはできません。最も有望な解決策はTimeZoneInfo、 、DateTime、およびの組み合わせを使用TimeSpanして、適切な時間にトリガーされるタイマーを毎日スケジュールすることだと思います。私が現在持っている解決策はこれです:

    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 は終了しました。プログラムから多くの内部値にアクセスする必要があるため、タスク スケジューラは使用できません。別のアプリケーションを起動し、それらの値をそのアプリケーションに公開すると、これがメリットだと思うよりもはるかに複雑になります。

4

7 に答える 7

9

Windows のスケジュールされたタスクをセットアップします。長時間実行されるタイマーは問題が発生する傾向があり、このような単純なジョブに対しては確かに過度に複雑です。

于 2013-10-29T17:48:50.823 に答える
3

正しい解決策は、Quartz.net または Windows タスク スケジューラを使用することですが、あなたはそれができないと言ったので、他に何ができるかを考えてみましょう。

  • プログラムは常に実行されている必要があります。これは、バックグラウンドの Windows サービス アプリケーションである必要があることを意味します。アプリケーションを閉じるユーザーに対処したくないため、ユーザーアプリケーションにしたくありません。また、誰もログインしていなくても実行する必要があります。

  • 長時間のタイマーは使用しないでください。代わりに、定期的に実行される短いタイマーを使用して、イベントを実行する時間になったかどうかを確認します。ショートタイマーはどのくらいの頻度で実行する必要がありますか? これは、アイドル時に消費したいリソースの量と、タスクで許容される潜在的な遅延の量との間のトレードオフです。設定した時間から数分以内に実行する必要がある場合は、1 分に 1 回、または 5 分に 1 回程度の頻度でチェックすることをお勧めします。

  • 可能であれば、データから「次回の実行時間」を 1 回だけ取得する必要があります。したがって、定期的にチェックする場合、毎回データベースにアクセスする必要はありません。ただし、この値が揮発性である場合は、ローカルにキャッシュされた値を期限切れにする方法が必要になることに注意してください。

  • DST とタイム ゾーンに関しては、特定の UTC 時間または特定の現地時間に実行するようにスケジュールされているタスクを区別する必要があります。たとえば、1 時間ごとのタスクがある場合は、UTC を使用して、DST の変更によって混乱しないようにすることもできます。毎日のタスクがある場合は、おそらく現地時間を使用する必要があります。これは、コンピューターの現地時間である場合もあれば、特定のタイム ゾーンの現地時間である場合もあります。それはあなた次第です。また、スプリングフォワード DST 移行によって作成されたギャップ中に実行するようにスケジュールされたタスク、またはフォールバック移行によって作成されたあいまいな時間中に実行するようにスケジュールされたタスクに対処するための戦略が必要になります。DST タグ wikiも参照してください。

  • ここまでを振り返ってみると、Quartz.NET に相当する独自のコードを記述したことがわかります。既存のものの上に構築することはできないと本当に確信していますか? なぜ車輪を再発明するのですか?

于 2013-10-29T20:24:34.163 に答える
1

他のすべての回答のフィードバックに感謝し、 Quartz または 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 ,
       ...);
于 2013-10-29T20:38:30.890 に答える
1

Quartz.netなどのタスク スケジューリング フレームワークを使用する

于 2013-10-29T17:49:05.163 に答える
0

Windows サービスを作成してシステムにインストールできます。

于 2013-10-29T17:50:25.993 に答える