2013-10-29 68 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。你真的确定你不能只建立一个已经存在的?为什么重新发明轮子?

相关问题