System.Timers.Timer和夏令时

本文关键字:夏令时 Timer Timers System | 更新日期: 2023-09-27 18:20:13

我有一些计时器,可以从表中读取HH:MM:SS,以确定何时每天运行。

例如:
计时器A需要在每周一13:00:00运行
计时器B需要在每周二02:00:00运行
计时器C需要每小时运行一次

因此,在我的代码中,我计算出当前时间,然后计算从DateTime.Now()到下一次计时器应该运行的时间的毫秒数。当计时器的Elapsed事件完成时,它会重新计算下一次应该运行的时间。由于时间的变化,这在本周末造成了一个问题。

有更好的方法吗?DateTime.UtcNow会是更好的选择吗?也许可以将数据库中的时间字符串转换为UTC时间,然后计算出DateTime.UtcNow()而不是DateTime.Now()之间的差异?

System.Timers.Timer和夏令时

您可以做几件事来解决这个问题。

一种是对所有计划的作业使用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;

然后,保存下一个Run DateTime值。稍后,您可以计算出距离下一次跑步还有多长时间。这是一个很好的方法。还有其他的。

var msUntilNextRun = (nextRun.Ticks - DateTime.Now.Ticks) / 10000;

如果msUntilNextRun值较小且为正,则可以一直睡到该运行为止。如果结果很小而且是负面的,你就睡过头了——立即跑步(睡过头很常见)。

将天数添加到当前的午夜值,然后将时间添加到该值,然后计算等待多长时间,这是一种即使在转换日也能获得合理运行时间的方法。