如何在每天的给定时间执行代码?

我正在尝试为我的程序添加一个function,该function将在芝加哥期货市场关闭后每天执行代码。 这意味着我想在美国东部时间早上5:35(市场所在的中部时间4:35)运行代码。 当然,当夏令时发生时,这将在EST(UTC -5)和EST(UTC -4)之间来回切换。

我知道有很多类似的问题,但是它们似乎都没有提供我可以使用的解决方案。 主要的建议似乎是使用Task Scheduler或Quartz,但是,我无法在我的程序中实现它们。 我认为最有希望的解决方案是使用TimeZoneInfoDateTimeTimeSpan的组合来安排每天将在合适的时间触发的计时器。 我目前的解决方案是:

  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因为我无法包含第三方库而退出。 任务计划程序已经出局,因为我需要访问程序中的许多内部值。 启动另一个应用程序并将这些值暴露给该应用程序会增加比我认为的更复杂的复杂性。

设置Windows计划任务。 长时间运行的计时器往往是有问题的,并且对于这种直接的工作而言肯定过于复杂。

您错过了Windows任务计划程序的要点。 您没有在您的应用程序中实现它。 您编写应用程序,然后使用任务计划程序在每天的设定时间运行它。

不幸的是,为了回应您关于日程安排和应用程序性质的说明,您强调需要重新考虑您的应用程序。 构建一个必须一直运行并且不断添加function的整体应用程序并不是一个好主意。

相反,为什么不重新考虑应用程序的结构。 您可以拥有核心function,它需要一直运行,作为服务运行。 然后,其他组件可以通过例如rest接口与其通信。 然后可以停止启动应用程序的用户界面方面,而不必担心影响服务,无论如何都可以继续运行。 此外,添加额外的function(例如在一天的特定时间执行特定tsaks的计划应用程序)变得更加容易。

正确的解决方案是使用Quartz.net或Windows任务计划程序,但既然你说不能这样做,那么让我们考虑一下你可能做的其他事情。

  • 您的程序需要一直运行。 这意味着它应该是后台Windows服务应用程序。 您不希望将其设置为用户应用程序,因为您不希望处理关闭应用程序的用户,即使没有人登录,它也应该运行。

  • 你不应该使用长计时器。 而是使用定期运行的计时器来检查是否是执行事件的时间。 短计时器应该多久运行一次? 这是您想要在空闲时消耗多少资源以及您的任务可接受多少潜在延迟之间的权衡。 如果它需要在设定时间的几分钟内运行,您可能只想每分钟检查一次,或者每五分钟检查一次。

  • 如果可能,您应该从数据中获取一次“下次执行时间”。 因此,当您定期检查时,您不必每次都访问数据库。 但要小心,如果此值是易变的,那么您将需要一种方法来使本地缓存值到期。

  • 关于DST和时区,您需要区分计划在特定UTC时间或特定本地时间运行的任务。 例如,如果您有一个每小时任务,您也可以使用UTC,这样您就不会被DST更改所抛弃。 如果您有日常任务,则应该使用当地时间。 这可能是计算机的本地时间,也可能是特定时区的本地时间。 这取决于你管理。 此外,您还需要一种策略来处理计划在由Spring-forward DST转换创建的间隙期间运行的任务,或者计划在由回退转换创建的模糊时间内运行的任务。 另请参阅DST标记wiki 。

  • 现在回顾一下这一切,并意识到你刚刚编写了自己的Quartz.NET。 你真的相信你不能只建立一个已存在的吗? 为什么重新发明轮子?

使用Quartz.net等任务调度框架

我很欣赏所有其他答案的反馈,并想指出任何偶然发现石英或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 , ...); 

您可以创建Windows服务并将其安装在您的系统上。

由于您不能使用第三方库,或者将内部暴露给另一个应用程序,是否可以选择公开通信端点(WCF,UDP,命名管道等)? 或者您可以监视另一个应用程序创建的“命令文件”的文件夹? (使用FileSystemWatcher或简单的计时器)

单独的应用程序可以向此端点/文件夹发送消息,Windows任务计划程序可以安排此应用程序。