views:

355

answers:

2

I have a clock feature in a VB.NET program that displays the time including the seconds. I currently have a timer constantly polling using NOW. I have to poll the system clock quite often because I need to have the second update in sync with the system clock.

Is there a more direct to access the time only when the seconds change?

Is there a more efficient way to write this code?

If you need more info let me know.

+4  A: 

Why not use the timer component? This assumes that you are using a GUI and not building a service.

You could call a synchronization routine that performed the polling to get the timer very close to the seconds changing, then delegate to the timer. You could call the sync routine once a minute or so to make sure that you aren't getting any OS drift.

That being said, I'm sure there is a way to detect the seconds changing event, I just don't know how to do it.

Update:

This link has an implementation similar to what I was envisioning. Just modify it so that you are not permanently stuck in a loop and voila! You have your sync routine.

Update 2:

Based on feedback from Shog9, I think this might be a better approach than polling:

Public Class Form1
   Private WithEvents clockTimer As New Timer
   Private currentTime As DateTime = DateTime.MinValue

   Private Sub ClockTick(ByVal sender As Object, _
      ByVal e As System.EventArgs) Handles clockTimer.Tick

      UpdateTimer()
      DisplayTimer()
   End Sub

   Private Sub UpdateTimer()
      currentTime = DateTime.Now

      clockTimer.Stop()
      clockTimer.Interval = 1000 - currentTime.Millisecond
      clockTimer.Start()
   End Sub

   Private Sub DisplayTimer()
      lblTime.Text = currentTime.ToString("T")
   End Sub

   Private Sub Form1_Load(ByVal sender As System.Object, _
      ByVal e As System.EventArgs) Handles MyBase.Load

      UpdateTimer()
      DisplayTimer()
   End Sub
End Class

Now, based on my preliminary tests, there is some sort of drift with each Tick event. On my machine, it varied between 12 and 20 milliseconds. If anyone has an idea on how to reliably correct the drift, I would be interested in learning.

Jason Z
You suggest sitting in a loop and polling the system clock?
Shog9
Only temporarily. After you determine the inflection point, you call a system timer that has events.
Jason Z
Um... why not just adjust the next timer interval by the distance in milliseconds from the last second?
Shog9
That, my friend, is a brilliant idea!
Jason Z
Thanks. FWIW, the drift is due to the default granularity of the Windows timer - 15ms. There can also be delays if message processing takes more than a few milliseconds, since timer messages are very low priority. BTW - i replaced your code with VB, since this is a VB question; hope you don't mind.
Shog9
I guess I can let you have the assist in converting to VB :)
Jason Z
A: 

Use a Timer object, set it's "interval" to 0, set it's "enabled" to true. That will fire roughly every 15 milliseconds (based on your hardware configuration). In that method, set MyLabel.Text = DateTime.Now.ToString() (or whatever you're doing).

That is perfectly performant.

Timothy Khouri
Performant... in that you don't notice the overhead on your machine? Or performant in that running semi-trivial code many, many times more than necessary just isn't a big deal for any application on any hardware?
Shog9