This clock sits on a Web page and continuously displays the correct time, despite the scourges of inaccurate client clock settings and buggy JavaScript implementations. Clicking on the clock toggles the seconds display. Even while showing only the minutes, it is still generally accurate to about one second. (The error may be greater if there is a long delay between hitting Reload/Refresh and actually starting to receive the page. Specifically, the time interval between the server starting to execute the page’s scripting code and client executing the first block of inline JavaScript code is lost.) For accuracy, the server itself should be synchronized to an NTP time server.
[Watch the Clock] (Note: uses cookies.)
Why is displaying the current time difficult? For one thing, we don’t want the clock to stand still after the page loads, even when hiding the seconds display. After a few minutes (or when the user follows a link and then clicks Back) it would become rather wrong. We could force the entire page to reload every minute, but that would cause a significant increase in server load for a busy home page, and would annoy the users if they happened to be trying to navigate the page at the time. So the solution is for client-side JavaScript and cross-browser DHTML to keep the clock current.
The simplest method from this point is to have the JavaScript code read the current time from the user’s clock. For an intranet home page, I actually did this, only to receive complaints from users that the clock on our home page was wrong--very, very wrong, sometimes off by days. Of course, those users really needed to fix their own clocks, but even if all of them did so, there were many more who didn’t notice at all because their clocks weren’t quite wrong enough. And why would they even think to distrust the home page? The clock on there certainly matched their own computer clock well enough. If any users did want to correct their own clocks or watches, it would certainly help to have an accurate clock to go by, not just one that parroted inaccurate times from their own computers and made them look official. Complicating matters further, a long-standing JavaScript bug in IE for Mac threw times off by exactly one hour during Daylight Savings Time and by even more if the machine had been to sleep.
The solution? Calculate the offset between the server clock and client clock at page load time, and from that point on, display the client’s clock corrected by that amount. We also sanity-check the successive differences in the client’s clock, so that if the user changes the time manually (for daylight-savings time, for example), we can reload instead of messing up the calculation. And since the date is on the page, we also reload at midnight (which would cause a spike in server load then if many users left their browsers open, but no other ill effects).
The local and server clocks are saved in a cookie, so that we can tell if we’re just reloading a locally cached page (since the stale server clock embedded in the page will match the cookie). We should have been able to use headers to prevent caching and force a reload, but they didn’t have any effect when using the Back button in tested versions of IE for Windows (but not other browsers). The cookie method saves server traffic anyway.
If we used repeated setTimeout()s with a fixed interval of one second to update the clock, the display would gradually start to lag behind real time then skip ahead two seconds at once, giving a jerky appearance. We could use setInterval() to avoid this, but if the seconds were hidden, the clock would update sixty times more often than necessary, bogging down slow computers. We could then decide to switch the interval to one minute whenever the seconds were hidden, but the minute display would change over too late (by an average of 30 seconds), depending on how many seconds we were into the minute on page load.
There is a solution that avoids all these problems: after each update, calculate the number of milliseconds remaining until the next minute or second boundary (depending on whether seconds are hidden) and use setTimeout() to schedule the update function for that exact time.
If the browser doesn’t support JavaScript 1.2, the clock will still show up, but will be static.
There is a small amount of server-side support code. I provided it in two languages: ASP-JScript (best for Windows IIS servers) and PHP (for all other servers). The ASP version, through its use of JavaScript instead of VBScript, has the interesting property of allowing the server-side time formatting function to be an exact copy of the client-side function. In PHP, the function had to be rewritten, though it did end up shorter. For fun, you can compare the two.
There is one remaining problem, to which Macintouch (2002-10-12) recently alerted me. In addition to the daylight-savings bug in Mac IE, which the code successfully works around, there is a nasty sleep bug, which in my tests reproducibly caused local time to stand still over the entire interval from sleep to wake. So if the clock is already loaded when the machine goes to sleep, it ends up being slow after wake, with no jump in local time to allow the code to even detect that sleep occurred. Reloading the page updates the time from the server and fixes the problem. Any ideas on how to fix this in code would be appreciated; please use my contact page.
Version 2.1.2 fixes an intermittent bug in loading the clock in the PHP version. More details to come.
Language | JavaScript (client-side) and either ASP-JavaScript or PHP (server-side). |
Compatibility | Browser: Internet Explorer 4 and up, Netscape 4 and up, Mozilla, and other DOM-compliant browsers. Server: Windows NT 4 and 2000 with IIS (for the ASP version), any OS with Apache and PHP 4 (for the PHP version; tested under Linux and Mac OS X). |
Techniques | Client-side cookie parsing, setTimeout(), cross-browser DHTML, ASP to PHP translation. |
Cost | Free. |
Download | [View Source - ASP] | [View Source - PHP] |
Installation | Copy the page content from one of the above links and paste it into a new empty file in a text editor, saving the result on your web server with the appropriate filename extension (".asp" or ".php"). Reposition the two <div>s and add your own content to suit. |