Displaying timezones without using UTC

I've been reading up on how to do this all morning, and the general consensus is this: store your timestamps in UTC and calculate the offset from there.

However, like most people, I am maintaining an existing codebase and I can't change the way we store our dates. At least, not in the allotted time frame.

So my question is, can I safely do something like this?

// this is my time zone
$timestamp = strtotime($timestampFromDatabase);
date_default_timezone_set('America/New York');
$tz = date_default_timezone_get();

// this is theoretically their timezone, which will eventually
// be taken from a session variable
date_default_timezone_set('Europe/Paris');
$offset = time() - $timestamp;
$timestamp -= $offset;

// now that I have the offset, display dates like this
date('r', $timestamp);

Some people have advised against doing date arithmetic, but is what I'm doing here wrong? Is there a better way? Are there pitfalls I need to watch out for? I'm particularly interested in what kind of bugs this method could produce, and if any, who will they affect?

My boss is the kind of guy that doesn't care if the bug only affects 1% of the user base.

Edit: Can I make this any clearer? I don't seem to have too many takers on this. Anyone? Even a vague suggestion or a link would be immensely helpful.

13.10.2009 17:42:51
1 ОТВЕТ
РЕШЕНИЕ

The short answer is that timezones are tricky to work with and no-one wants to tackle the difficult questions!

The longer, answer is this:

Firstly, you need to create a representation of your date, in their current timezones. The following are equivalent:

date_default_timezone_set('America/New York');

$date = new DateTime(null);

OR

$date = new DateTime(null, new DateTimeZone('America/New York'));   

This gives you a date with zone set to America/New York. We can easily convert it to the user timezone, in this case Europe/Paris with the next line:

$date->setTimezone(new DateTimeZone('Europe/London'));

You can use the following line to get the date/time represented at any point.

echo $date->format('d/m/Y H:i:s');

I strongly recommend this over arithmetic, as the built in PHP functions have knowledge of daylight saving times and lots of complicated things that you won't get right.


My test script in full:

date_default_timezone_set('America/Belize');

$date = new DateTime(null);

echo $date->format('d/m/Y H:i:s') . '<br>';

$date->setTimezone(new DateTimeZone('Europe/London'));

echo $date->format('d/m/Y H:i:s') . '<br>';
5
13.10.2009 20:10:47
You could also use this approach to update your database to UTC in a one off job for future use.
David Snabel-Caunt 13.10.2009 20:13:42
This is awesome. However, suppose I'm running PHP 5.14, which doesn't have this object. Is there another way?
Alt-Rock Ninja Cowgirl 13.10.2009 20:32:17
Zend Framework has a php based solution in Zend_Date, but asks for PHP 5.2.4 as a general requirement for the framework. It might work. Can you upgrade or recompile PHP?
David Snabel-Caunt 13.10.2009 20:37:58
That was the first thing I asked. Boss says I am not allowed to upgrade PHP right now :(
Alt-Rock Ninja Cowgirl 13.10.2009 20:40:26