Detecting timezone with javascript and PHP.
While working on Boxed Thoughts last night, I came across a problem. The auto-detection I had previously written for finding a timezone had broke. After a bit of pondering I decided to scrap the entire thing and redo it from scratch. Easy? Not really.
On BT, every date is printed through a function that formats, times, and adds appropriate data to the date.
echo display_date(time(), $format, ...);
There is just one vital problem with finding a timezone server-side: you can’t.
Javascript was my alternative. So, after attempting to create/finding buggy scripts that would do the deed in javascript, I stubbled upon Jeff Bezos’s blog post.
After a bit of reading, learning, and eventually falling in love, I packaged his idea up in a simple function:
function determineTimezone() {
var rightNow = new Date();
var jan1 = new Date(rightNow.getFullYear(), 0, 1, 0, 0, 0, 0);
var temp = jan1.toGMTString();
var jan2 = new Date(temp.substring(0, temp.lastIndexOf(" ")-1));
var std_time_offset = (jan1 - jan2) / (1000 * 60 * 60);
var june1 = new Date(rightNow.getFullYear(), 6, 1, 0, 0, 0, 0);
temp = june1.toGMTString();
var june2 = new Date(temp.substring(0, temp.lastIndexOf(" ")-1));
var daylight_time_offset = (june1 - june2) / (1000 * 60 * 60);
var dst;
if (std_time_offset == daylight_time_offset) {
dst = "0"; // daylight savings time is NOT observed
} else {
dst = "1"; // daylight savings time is observed
}
}
Now that we have the actual javascript done, how do we translate this information to the server for PHP to work with?
I had two methods. The first was to use an AJAX request to send that data to the server for it to store in the user session. I disliked this, though, because it required additional calls to the server, and at BT, we’re all about not wasting and reserving resources.
The second method I chose was to create two cookies, one containing the offset information and the other containing the daylight savings information.
function determineTimezone() {
var rightNow = new Date();
var jan1 = new Date(rightNow.getFullYear(), 0, 1, 0, 0, 0, 0);
var temp = jan1.toGMTString();
var jan2 = new Date(temp.substring(0, temp.lastIndexOf(" ")-1));
var std_time_offset = (jan1 - jan2) / (1000 * 60 * 60);
var june1 = new Date(rightNow.getFullYear(), 6, 1, 0, 0, 0, 0);
temp = june1.toGMTString();
var june2 = new Date(temp.substring(0, temp.lastIndexOf(" ")-1));
var daylight_time_offset = (june1 - june2) / (1000 * 60 * 60);
var dst;
if (std_time_offset == daylight_time_offset) {
dst = "0"; // daylight savings time is NOT observed
} else {
dst = "1"; // daylight savings time is observed
}
//We use jquery's cookie plugin.
$.cookie('timezone_offset', daylight_time_offset);
$.cookie('timezone_daylightsavings', dst);
return null;
}
Now we go to the server end:
class common {
...
public static function fetchTimezone() {
$offset = $_COOKIE['timezone_offset']; //
$time_zone_dst = $_COOKIE['timezone_daylightsavings'];
$offset *= 3600;
$zone = timezone_name_from_abbr('', $offset, $time_zone_dst);
return $zone;
}
...
}
PHP can happily read the data placed by javascript now. So we push the contents of the cookies into timezone_name_from_abbr(); and get a nice little location. For example, in my case you get “america/chicago”.
Just as a note, I suggest you save your cookies in the user session, just as a time saver.
Last but not least, we actually need to display the date:
function display_date($date, $format, ...) {
...
$time_zone_name = common::fetchTimezone();
$datetime = new DateTime($date);
$datetime->setTimezone(new DateTimeZone($time_zone_name));
return $datetime->format($format);
}
First we get the result of common::fetchTimezone(); that we created above. Then we can use PHP’s nifty DateTime and DateTimeZone classes to do the hard work for us. and last, you return the format, exactly the same as you would with date();
The only drawback to this method is that on the first page load, PHP will not have a cookie to get the timezone:
Server side executed [reads nonexistent cookie]
| |
v v
HTML/Javascript rendered [sets the cookie]
Therefore it will default to your server’s original timezone on the first load. Other than that, there shouldn’t be any problems. Of course, you’ll need to splice some of the above into your own code, but it should be similar.
Chatter