PHP5 time zone solution

Time zone settings are normally not the first thing you think of when working on a web project with PHP, yet as soon as dates and specific times are relevant to your application and you possibly have users from different time zones, you suddenly realize how practical it would be if the times you work with could be presented in the user’s time zone – whatever time zone that may be.

PHP did not address this problem until 5.1.0, and then it introduced solutions which are not as easy at first glance as they could be. Yet, it is something you can work with, if you change your code accordingly – let me show you a solution.

Default time zone for script

First, you should set a default time zone in your PHP script with the function date_default_timezone_set – if you omit this you will most probably get a E_NOTICE or E_STRICT message. Just set it to the system’s time zone.

A default time zone is important because all the dates you work with have an “implicit” time zone – except for unix timestamps, yet the new date functions (the classes DateTimeZone and DateTime we use further below) only take date strings, not timestamps. A default time zone provides a starting point from which to generate dates.

Getting the time zone of the user

Next we need to find out the time zone of the user. One possibility is to ask the user – if registration is mandatory on your site and you include the time zone as a registration field, this is easy, just show the user a list of possible time zones, yet just noticing the time zone automatically would still be better, prevent errors and also work without registration.

The solution to this is Javascript – it can access time zone settings on the client. Unfortunately it can only get you time zone offsets (specified in minutes) for specific dates, no time zone name. So to pinpoint the correct time zone we also need to know if daylight saving time (DST) is being employed – this is the client side part of the solution:

var now = new Date();
var later = new Date();
// Set time for how long the cookie should be saved
later.setTime(now.getTime() + 365 * 24 * 60 * 60 * 1000);
// Set cookie for the time zone offset in minutes
setCookie("time_zone_offset", now.getTimezoneOffset(), later, "/");
// Create two new dates
var d1 = new Date();
var d2 = new Date();
// Date one is set to January 1st of this year
// Guaranteed to not be in DST
d1.setDate(1);
d1.setMonth(1);
// Date two is set to July 1st of this year
// Guaranteed to be in DST if DST exists for this time zone
d2.setDate(1);
d2.setMonth(7);
// If time zone offsets match, no DST exists for this time zone
if(parseInt(d1.getTimezoneOffset())==parseInt(d2.getTimezoneOffset()))
{
  setCookie("time_zone_dst", "0", later, "/");
}
// DST exists for this time zone - check if it is currently active
else {
  // Current date is still before or after DST, not containing DST
  if(parseInt(d1.getTimezoneOffset())==parseInt(now.getTimezoneOffset()))
  {
    setCookie("time_zone_dst", "0", later, "/");
  }
  // DST is active right now with the current date
  else {
    setCookie("time_zone_dst", "1", later, "/");
  }
}

We save the results as cookies, which can be accessed by our PHP script. You should include the above code on at least the first page a user accesses – I include it on every page to recognize (and adapt to) changes, even if such changes during a session are unlikely.

In PHP we can extract a valid time zone with a new function named timezone_name_from_abbr, available since PHP 5.1.3 – it either takes a time zone abbreviation or a combination of time zone offset (in seconds) and daylight saving time, and we have the latter combination:

$time_zone_name = timezone_name_from_abbr('', -$_COOKIE['time_zone_offset']*60, 
$_COOKIE['time_zone_dst']);

This will give you a correct time zone name for the user, if the data in the cookies is valid – note that there are many “duplicate” names, for example “Europe/Berlin” and “Europe/Zurich”, which have the exact same time zone settings (at least for now), and you may get either one of them for the appropriate offset and DST variables. The list of time zone names can be found in the List of supported time zones on php.net.

Creating date strings with a given time zone

With the name of the user’s time zone we now can use the PHP classes DateTimeZone and DateTime to finally create date strings with the correct time zone:

// Create time zone class
$time_zone_class = new DateTimeZone($time_zone_name);

// Create new date class with a given date
// Notice that the provided date will be regarded as being in the
// default time zone and converted accordingly
$new_date = new DateTime('2007-02-14 15:30:00', $time_zone_class);

// Print date with the user's time zone
echo $new_date->format('Y-m-d H:i:s');

Â

That’s it! With the new PHP functions you do not have to care about daylight saving time or other quirks – as long as you have the time zone name, PHP does it all for you. This is a rather simple example of course, for my projects I created an own Class which provides an interface to set the time zone and format date strings so it would feel more like the regular date()-function.

Possible problems

You need to check the cookie values for correct values, so you get a valid time zone name, otherwise the above example will fail. Additionally, if either Javascript or cookies are disabled you will not get any cookie values and should set a time zone based on a good guess (or other user information) – automatical detection will not be possible in that case. The percentage of people with disabled Javascript or cookies is quite low, though, so I think auto-detection is still worth it all the way

By the way, at first glance it may be tempting to not use the DateTime and DateTimeZone classes and just set date_default_timezone_set to the current time zone of the user and then use the date()-function as you would otherwise. This is a very bad idea: as soon as you have a date literal from a database (or anywhere else) things get screwed up, because when converting it to a timestamp in PHP the current time zone will be used as reference, not the time zone used originally, and that can create bugs which are hard to identify. Better make a wrapper class/function for dates which are displayed to the user (where a specific time zone applies) and use a default time zone for all database dates or also dates where no time zone is required (i.e. birthdates).

No related posts.

Related posts brought to you by Yet Another Related Posts Plugin.


Related Posts

Popular Posts


One Response

08.03.08

Where is the setCookie function? It is not a built-in JS function and I need it to get this script to work.

Leave Your Response

* Name, Email, Comment are Required