The frequency of the hardware system timer is ~1.193 MHz. The Windows timer is implemented by decrementing a 16 bit int on each tick and sending a WM_TIMER message when it hits zero. The frequency of the messages is therefore 1,193,180 / 65,536 = 18.20648 times per second, or roughly every 55msec.
This was true for the Win9x kernel. I'm pretty sure that OSes based on the NT kernel (WinNT/2K/XP) use a (somewhat) higher resolution timer, something like 10ms or 20ms.
I've posted the complete source code for JBIClock <a href="http://justbrewit.net/trstuff/jbiclock.zip">here</a>. It's a zipped MS Developer Studio 6 project that was generated with Developer Studio's "MFC AppWizard" tool. Most of the interesting stuff happens in the CJbiclockDlg::OnTimer() function:
void CJbiclockDlg::OnTimer(UINT nIDEvent)
// TODO: Add your message handler code here and/or call default
time_t t = time(NULL);
struct tm *tmPtr = localtime(&t);
if (newTime != timeStr)
timeStr = newTime;
This function gets invoked every time a WM_TIMER message gets posted; in the CJbiclockDlg::OnInitDialog() function I request that a timer message be posted every 20ms (though the actual rate is dependent on the resolution of the OS clock and on system load). In a nutshell, this says "get a formatted string containing the current time, and if it has changed since the last time we were called, update the contents of the static control in the dialog with the new value". Since this is done much more frequently than once per second, any syncopation effects should be small, and invisible to the naked eye.
While it may seem somewhat wasteful to be processing timer messages every 20ms to update a display with only 1s resolution, the CPU load is negligible. Even on my old 500MHz K6-III, it shows 0% CPU usage in Task Manager.