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 严重不准确

使用System.Timers.Timer类实现程序定时执行

C# System.Timers.Timer 类已用事件和定时器的一般注意事项

System.Timers.Timer