DateTime using the wrong time zone

In my application, I am trying to calculate the time until midnight GMT (UK time). At the moment I am doing this:

$now = new DateTime(); $timeToMidnight = $now->setTimezone(new DateTimeZone('Europe/London'))->diff(new DateTime('tomorrow'))->format('%h hours, %i minutes and %s seconds'); 

The code works, however it is one hour behind (using GMT -1). At this point in time, the user is 11:49, and this result:

 1 hours, 10 minutes and 36 seconds 

I double checked my php.ini and I also have a timezone set to GMT:

 date.timezone = Europe/London 

This is also confirmed by the phpinfo() check.

What gives? Why is my application not using the correct time zone?

+8
timezone php datetime
source share
1 answer

I tested this on Linux PHP 5.5.5, with Europe/London set as the timezone in php.ini . In fact, I set the clock to four hours to do this too. The minimum code I used to play was:

 $d = new DateTime('tomorrow'); echo $d->format('c e'); 

Output (correct):

 2013-10-27T00:00:00+01:00 Europe/London 

I am going to find an error in PHP or an error in timezone data. To find out what, we will see what some other program is doing today at midnight in London. Epoch Converter tells me that this should have a Unix timestamp from 1382828400. To double check this timestamp, I ran into PHP:

 $d = new DateTime('27-10-2013'); echo $d->format('U'); 

He also returned 1382828400. So, let's see what it should show ...

 TZ=Europe/London date --date="@1382828400" +%c 

The output was:

 Sun 27 Oct 2013 12:00:00 AM BST 

Correctly! Therefore tzdata is fine. So let's look at PHP.

I ran your sample code along with the date command and got the following output:

 1 hours, 29 minutes and 53 seconds Sat Oct 26 21:30:07 UTC 2013 Sat Oct 26 22:30:07 BST 2013 

This, of course, is correct.

I think that at that moment we eliminated errors in both tzdata and PHP, and you need to look at configuration problems and programmer expectations.


Firstly, as I noted earlier, Europe / London is not UTC, which does not have the concept of daylight saving time and, therefore, it does not change twice a year. Since this does not cause such problems, it is recommended to use servers in UTC no matter what time zone their users are in, and it is best to use programs for internal use of UTC, and then convert to / from local time zones for display and user input.

My best guess is that your server running PHP is actually configured to use UTC rather than Europe / London as its default time zone. This is the only configuration in which I could reproduce your problem. The results of this test were as follows:

 date.timezone = UTC 2 hours, 24 minutes and 36 seconds Sat Oct 26 21:35:24 UTC 2013 Sat Oct 26 22:35:24 BST 2013 

Forward, you should work in UTC (and with Unix timestamps), where it is practically possible, and convert to local time at the beginning of processing user input and display it as late as possible. A rare case like this when daylight saving time is nearing completion may be an exception, but you should be especially careful that every new DateTime object you create has the correct time zone when you create it, and also keep in mind that they will have such problems.

See also the huge and informative best practices for daylight saving time and time zones.


Finally, to “fix” your code, do the following:

 $tz = new DateTimeZone('Europe/London'); $now = new DateTime('now', $tz); $midnight = new DateTime('tomorrow', $tz); $timeToMidnight = $now->diff($midnight); echo $timeToMidnight->format('%h hours, %i minutes and %s seconds'); 
+20
source share

All Articles