System.Timers.Timer 和夏令时
Posted
技术标签:
【中文标题】System.Timers.Timer 和夏令时【英文标题】:System.Timers.Timer and Daylight Saving Time 【发布时间】:2016-02-02 22:37:42 【问题描述】:我有一些计时器可以从表格中读取HH:MM:SS
,以确定每天何时运行。
例如: 定时器 A 需要在每周一 13:00:00 运行 定时器 B 需要在每周二 02:00:00 运行 定时器 C 需要每小时运行一次
所以在我的代码中,我计算出当前时间是多少,然后计算从DateTime.Now()
到下一次计时器应该运行的毫秒数。当计时器的Elapsed
事件完成时,它会重新计算下一次应该运行的时间。由于时间变化,这在本周末造成了一个问题。
有没有更好的方法来做到这一点? DateTime.UtcNow
会是更好的选择吗?也许将数据库中的时间字符串转换为UTC时间,然后找出DateTime.UtcNow()
而不是DateTime.Now()
之间的区别?
【问题讨论】:
是的,UTC,但为什么您的日期或时间被存储为字符串而不是数据库中的日期? 但是,你现在的想法是什么。当您以 UTC 存储时间时,在 DST 上您将有另一个运行时间。这个主题有很多可用的信息,起点是野田时间的创建者的 Hanselminutes 播客:hanselminutes.com/485/…。但codeofmatt.com/2015/03/06/… 也提供了很多信息。 首先,您需要一个规范。一个好。一种准确涵盖代码在各种情况下的行为方式,包括更改为 DST 或从 DST 更改。如果您切换到 UTC,那么您提供的任何示例都不会受到更改的影响。所以这是一种选择。但是需要每隔一小时运行一次的计时器呢?还是需要每天凌晨 2 点或周日凌晨 2 点运行的计时器?等等。如前所述,您的问题过于宽泛,尤其是因为您甚至没有完全指定所需的行为。 将 Quartz.NET 用于您的触发器是一个想法吗? 你为什么要谈论计时器?计时器是短暂的。它们不适用于安排活动数小时或数天。这只是您的措辞,还是您实际上是在尝试使用System.Timers.Timer
来标记问题?
【参考方案1】:
你可以做几件事来解决这个问题。
一种方法是对所有计划的作业使用 UTC。这为您提供了一个强大且可预测的系统,没有很多复杂性或测试负担。但夏季周一 03:00 运行的作业将在冬季 02:00 运行。如果没问题,那么 UTC 策略是一个不错的策略。
(测试时区切换用例很痛苦,如果您对所有事情都使用 UTC,您的测试负担就会减轻。)
另一个是认真对待你的日期算术,并且要非常小心。即使在转换日期,C# 的 DateTime 类也能很好地进行日期运算。
因此,假设您需要在周日的 01:30 每周运行一次进程。那是在美国的噩梦时刻......它不会发生在春季转换中,它会在秋季转换中发生两次。但您仍然希望进程运行一次。
您要做的是:保留“下一个预定时间”值。每次完成运行作业时,计算下一次运行的“下一次计划时间”值。这可能会像这样工作:
var today = DateTime.Today.AddDays(7); /* midnight a week from now */
TimeSpan runTime = TimeSpan.Parse("01:30");
var nextRun = today + runTime;
然后,保存 nextRun DateTime 值。稍后您可以计算出距离下一次运行还有多长时间。这是一个很好的方法。还有其他的。
var msUntilNextRun = (nextRun.Ticks - DateTime.Now.Ticks) / 10000;
如果 msUntilNextRun 值相当小且为正值,您可以休眠直到运行时间。如果它出现小而负面,你睡过头了——立即跑(睡过头是非常常见的)。
将天数添加到当前的午夜值,然后将时间添加到该值,然后计算等待多长时间,即使在转换日也是一种获得合理运行时间的方法。
【讨论】:
抱歉,但是“C# 的 DateTime 类即使在转换日期也能很好地完成日期算术” 是不正确的。DateTime
根本不考虑夏令时。一般来说,永远不要使用本地 DateTime
值进行数学运算,例如 DateTime.Now
。请阅读Five Common Daylight Saving Time Antipatterns of .NET Developers 和The case against DateTime.Now 中的#1。以上是关于System.Timers.Timer 和夏令时的主要内容,如果未能解决你的问题,请参考以下文章
System.Windows.Forms.TimerSystem.Timers.TimerSystem.Threading.Timer
为啥 System.Timers.Timer 能在 GC 中存活,而 System.Threading.Timer 不能?
使用System.Timers.Timer类实现程序定时执行