Timezones in PHP

Let me start this off my saying how much I dislike coding anything to do with timezones. More specifically, I hate coding anything to do with daylight savings. However, recently I think I have worked out a few simple ways of dealing with the issues that multi-site software presents and I have written them down here both for my own benefit when I forget all this in a few months, and for the benefit of others who are trying do the same thing.

We have struggled for a long time to cope with multiple timezones in PHP, and although the language seemed to support everything we needed from 5.3, it has taken a couple of years for us to be able to actually get things working in a pure-PHP environment; and by this I mean without using any of our own hackish look-ups to a database.

Our software is mostly written in PHP with a javascript-heavy front end. We primarily use MySQL as our database and it is used by lots of media companies who have sites that share the same data.

The problems we faced are primarily:

  1. Our software is primarily a scheduling system with many resources being scheduled on a variety of jobs for varying durations (minimum duration of 15 minutes).
  2. The application is used in multiple time zones by many users at one time.
  3. Resources are based in and are scheduled for use in specific locations (in various time zones).
  4. Sometimes resources may be scheduled over a daylight saving change (which may or may not be apparent to a user viewing that schedule from another time zone).

I realise that this is mentioned in a lot of other blog posts and help sites, but it is very important that you store all your dates in UTC. It is essential if you want to use the sample code below, and it also really helps to know that everything in your database is using the same standard. There have been a few head-scratching moments where just knowing that times were in UTC really helped.

You also need to tell PHP to assume all dates in your application are in UTC. To do this, just add this code to your index.php.

date_default_timezone_set("UTC");

We needed to be able to display all dates in the user’s local time zone. We have always managed to do this by doing a few hacks. The code worked, but never felt right. This was basically a case of knowing which location the user was based in, and then having a look-up for each location containing the offset against UTC.

This actually worked surprisingly well – though it made for some slow pages as we had to look up the offset for every date/time we displayed. For the schedule page, there may be 100 resources, for 3 months, with a one job per day per resource! Thankfully MySQL is a fast little database and it it has allowed us to get away with more than we probably should have.

So now, what we have come up with is a means of using PHP’s built in timezone features. The main function we have is a means of converting UTC times to the users local time, and vice versa.

function convert_utc($sql_date, $direction, $format = "Y-m-d h:iA") {

    //decide which direction we are converting (from UTC or to UTC)
    if ($direction == 'from') {
        $from_time_zone = "UTC";
        $to_time_zone   = get_my_time_zone();
    } else {
        $from_time_zone = get_my_time_zone();
        $to_time_zone   = "UTC";
    }

    //create a new DateTime in the timezone we are converting from
    $uct_start_date     = new DateTime($sql_date, new DateTimeZone($from_time_zone)); 

    //set the default timezone to the one we are converting to
    date_default_timezone_set($to_time_zone); 

    //pull out the date in the format required
    $new_date           = date($format, $uct_start_date->format('U')); 

    return $new_date;
}

 

Now the get_my_time_zone() function is something else we have written, which simply returns the users current timezone in a PHP standard format. eg. “Europe/London” or “America/New_York”. You could easily have this as another parameter or a global.

The reason why we need to reset the date_default_timezone_set() in the index.php file is because we temporarily change it to get the above code to work.

With this simple function we are able to quickly convert dates. The really great thing is that PHP even takes care of daylight saving which can be a total nightmare if you ever try to code it yourself. This might not seem like a big deal, but you have to consider that the start time of a job might be on the opposite side of a daylight-saving change to the end of the same job. Knowing the precise UTC value of the local times you are saving is essential, as if a job is paid per hour – you need to get the duration right!

The above function can be used to pull values out of the database and convert them in the users local timezone format. We can also take something from the display and convert it to UTC ready to save back in to the databse.

Just writing all this down now makes me realise just how much wasted time and effort we have spend on this over the last few years. Admittedly, PHP’s functionality has massively improved since we started writing this program – but I can not begin to explain the pain this has caused us since our software went international!

This article was moved from my other website:
www.getdowntonight.co.uk
.