A common technique that is used to implement this timer loop is to have a fairly fast Timer control (typically 10 or 20 Hz) raise an event. (There are actually other techniques for doing this same thing, but for this example I am using a Timer control.) The event handler for this fast Timer control will compare the current time with the last time the application executed its processing loop. If the difference between these two times exceeds the application’s timer loop frequency setting, the application will begin its processing logic. If the difference between these two times is less than the application’s timer loop, the application will go back to sleep and wait for the next Timer event to fire.
Here is some sample VB.NET code that implements this:
Private Sub Timer1_Tick( _
ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Timer1.Tick
Const cRunEverySeconds As Integer = 120
Static sLastRunDateTime As Date
If Date.Now >= sLastRunDateTime.AddSeconds(cRunEverySeconds) Then
' Remember Last Run Date & Time
sLastRunDateTime = Date.Now
' Perform Processing
End If
End Sub
This technique works great except for the day daylight saving time starts or ends. In the example above assume sLastRunDateTime contains a time of 1:59:58 AM. Normally the processing would execute two minutes later at 2:01:58 AM, but today is the day daylight saving time ends. When the system clock hits 2:00 AM, it will automatically go back to 1:00 AM. Therefore instead of waiting 2 minutes between processing cycles, the application will wait 1 hour and 2 minutes. Depending on the application this may or may not be a problem, but it is not ideal. (This same problem plagues applications that are running on laptops that may move from one time zone to another.)
The way to solve this problem is actually very easy. In .NET framework languages all you have to do is replace the Date.Now function call with Date.UtcNow. Coordinated Universal Time (UTC) is not affected by silly things like daylight savings time or time zone changes. Time never moves backward or skips an hour in UTC.
The following is the same code listed above with the Date.Now function calls replaced with Date.UtcNow function calls:
Private Sub Timer1_Tick( _
ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Timer1.Tick
Const cRunEverySeconds As Integer = 120
Static sLastRunDateTime As Date
If Date.UtcNow >= sLastRunDateTime.AddSeconds(cRunEverySeconds) Then
' Remember Last Run Date & Time
sLastRunDateTime = Date.UtcNow
' Perform Processing
End If
End Sub