Syncronizing A Web Page's JavaScript Clock To Official Time Via AJAX / DOM

Recently asked on Yahoo! Answers:

Are there any JavaScripts to sync the date with time.gov?

I have the script to sync the date displayed with the visitor’s local computer.

Is there a way to “sync”, or display the date (i.e. march 8, 2007), on your web site automatically?

JavaScript clocks on Web pages are very popular; my quickie demo site uses one. And as I’ve discussed in previous entries, the problem — as this questioner notes — is that you never know what time a user’s computer may be showing, and it’s whatever time that user’s computer believes it to be that JavaScript will display on a Web page.

What we need is a reliable source of time from some knowledgeable arbiter — and some method of getting that information on a Web page, that can be updated every second. Thanks to AJAX, PHP and the US Naval Observatory’s Time Department, we have all those ingredients.

Basically, what we’re going to do is visit a simple HTML page the USNO has on its Web site, get the UTC time from that page, then figure out, from that “good” time, what time we’ll display on the page.

First step: The PHP page that scrapes the USNO’s HTML time information.

A quick aside on Internet time: There’s a standard out there called the Network Time Protocol, or NTP, which is used to synchronize computers and similar networked devices to a common timestamp. And, had I been adventurous, I probably could have used PHP’s socket functions to directly query one of the National Institute of Standards and Technology‘s time servers; it’s NIST that powers time.gov in concert with USNO.

But I didn’t want to spend that kind of time, and the purpose of this exercise is not to demonstrate how to use sockets; the purpose is simply to get a timestamp in a reliable manner and print it on a Web page.

Which brings me to the slightly bastardized method of simply scraping an HTML page that is consistently formatted, and creating a timestamp from that scrape.

My PHP page uses curl to obtain the Web page from USNO, split it into an array around the various line breaks that divide each time reported on the page, and then pump out a JavaScript-style timestamp (that is, the number of milliseconds since January 1, 1970), which I’ll use in my AJAX script.

(Note that in the script below, I’ve been forced to add spaces to the curl_exec function, because it interferes with WordPress otherwise. Just remove the spaces.)

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'http://tycho.usno.navy.mil/cgi-bin/timer.pl');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$response = curl _e xec($ch);
curl_close($ch);

$response = strtolower($response);
$temp = explode('
', $response); foreach($temp as $item) { if(strpos($item, 'utc')) { $out = trim($item); break; } } $out = strtotime($out); $out *= 1000; header('Content-type: text/xml'); echo "$out";

Now that I have a timestamp from the Naval Observatory’s Web site, I can go ahead and ask for it in my HTML page, which I do with a standard AJAX HTTP Request object function. The one below is basically lifted directly from Mozilla’s AJAX introduction page:

function getUSNOTime() {
	var httpRequest;
	var url = 'get_time.php';

	if (window.XMLHttpRequest) {
		httpRequest = new XMLHttpRequest();
	}
	else if (window.ActiveXObject) {
		try {
			httpRequest = new ActiveXObject("Msxml2.XMLHTTP");
		}
		catch (e) {
			try {
				httpRequest = new ActiveXObject("Microsoft.XMLHTTP");
			}
			catch (e) {}
		}
	}

	if (!httpRequest) {
		alert('Cannot create an XMLHTTP instance');
		return false;
	}
	httpRequest.onreadystatechange = function() {
			eventListener(httpRequest);
		};
	httpRequest.open('GET', url, true);
	httpRequest.send(null);
}

The event listener function is also about as basic as it gets. It simply waits for a 200 OK response from the HTTP request object, and as soon as it gets it, gets from the PHP helper page, above, the JavaScript timestamp we scraped from the Naval Observatory.

To do that, we use eval(), JavaScript’s handy function that basically says, “take this string (or, in our case, HTTP response text) and treat it as though it were JavaScript.”

function eventListener(httpRequest) {
	if (httpRequest.readyState == 4) {
		if (httpRequest.status == 200) {
			tempTime = eval(httpRequest.responseText);
			computeTime();
		}
		else {
			alert('Server error attempting to get server time');
		}
	}
}

Then, once we have a good timestamp, we go ahead and call computeTime(), the function that will actually display our clocks on our Web page.

For reasons that will become apparent shortly, we set the timeOut — that is, the interval, in milliseconds, of how often we want this script to run — in a variable. We also create variables that reference three DIVs in our document, which will display the clocks:

function computeTime() {
	var timeOut = 1000;

	var localDiv = document.getElementById('localUTC');
	var realDiv = document.getElementById('realUTC');
	var derivedDiv = document.getElementById('derivedUTC');

The easiest thing to do is to get the local time, and simply display it as UTC time:

	var now = new Date();
	localDiv.innerHTML = 'Current UTC time, per user's computer: ' +  now.toUTCString();

We could, in theory, just keep scraping the USNO clock page every time we call this script, but that’s very inefficient, likely to cause errors and actually will be less accurate than simply calling the clock page once.

So, to avoid calling the USNO clock page time and again, we ask for it first, and once we get a satisfactory response, then work with local time. That reduces errors and increases efficiency. And, all we need to do is increment our original timestamp by the script timeout, and we’ll always have an accurate timestamp (at least, as accurate as the processor on the user’s computer can make it).

	tempTime += timeOut;
	var realTime = new Date();
	realTime.setTime(tempTime);
	realDiv.innerHTML = 'Current UTC time, per US Naval Observatory: ' + realTime.toUTCString();

The final part is to figure out what the local time for the user’s computer should be, based on the “real” UTC time we got from the Naval Observatory, plus the time zone offset of the user’s computer. (Yes, this method will only be as accurate as the user’s computer settings allow it to be. But unless you want to work exclusively with UTC, you have to trust the user to some degree.)

	var localOffset = now.getTimezoneOffset() / 60;
	localOffset = Math.floor(localOffset);
	var derivedTemp = tempTime + (localOffset * 3600);
	var derivedTime = new Date();
	derivedTime.setTime(derivedTemp);
	derivedDiv.innerHTML = 'Current local time, per user's timezone setting and USNO UTC time: ' + derivedTime.toLocaleString();

Last, but not least, we set the timeout for the script, so our clock will update:

	setTimeout('computeTime()', timeOut);
}

That’s it. You can see a working demo here:

http://www.dougv.com/demo/ajax_utc_clock/

I have also provided the code for both the HTML and PHP page in a ZIP archive you can download: Syncronizing A Web Page’s JavaScript Clock To Official Time Via AJAX / DOM Demo Code. I distribute code under the GNU GPL version 3.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Current ye@r *