12

I'm just looking for a little clarification on this. PHP 5.4 eliminated the TZ environmental variable and the "guessing" that date_default_timezone_get used to do. So now it appears to me there's no way to get the server's timezone at all.

So my question is this: is it possible to get the server timezone in PHP 5.4? I know I can manually set it in php.ini, but that seems kind of silly when there's a computer that's perfectly capable of knowing what time it is. I expect the answer is "no", so perhaps somebody can shed some light on why a programming language would be unable to determine its time zone if that's the case.

hakre
  • 193,403
  • 52
  • 435
  • 836
Andrew
  • 1,571
  • 17
  • 31
  • [How to automatically detect user's timezone?][1] [1]: http://stackoverflow.com/questions/5203382/how-to-automatically-detect-users-timezone – Siamak Motlagh Jul 31 '12 at 19:55
  • Why is it silly to properly configure PHP? It's not like a server's timezone is dynamic... – nickb Jul 31 '12 at 19:55
  • @nickb: What if you have multiple servers in various timezones, be difficult to share a default php.ini across them. – Mike Purcell Jul 31 '12 at 20:30
  • @MikePurcell - Keep all the common configuration in PHP.ini and override what's necessary in server configuration. – nickb Jul 31 '12 at 20:35
  • It just seems to me the user picked a time zone when they got their server, so why should I ask them to repeat it? But also, say I pre-installed my code, now the user has to change the time zone in two places. I understand it's just an inconvenience, but it's an inconvenience that was INTRODUCED in 5.4. It worked just fine before. – Andrew Jul 31 '12 at 20:50
  • @nickb: What do you mean by "server configuration"? – Mike Purcell Jul 31 '12 at 23:47
  • It is possible to get the UTC offset on a Windows server with a bit of math (answer added). – nicholas Jan 14 '13 at 22:20

6 Answers6

4

There is no reliable way to guess timezone on every system. Different systems use different conventions and sometimes even different timezone definitions (such as Unix and Windows), sometimes have conflicting timezone specifiers (the same 3-letter zone abbreviation can mean different things in different places). So if you want to have code that is portable between systems, the only way to reliably do it is to ask the user. See for example this thread: http://marc.info/?t=132356551500002&r=1&w=2 on some of the issues with it (look for emails from Derick Rethans - he is the PHP datetime extension maintainer).

If you have a way to find out timezone that you trust - such as TZ variable - then you could always do date_default_timezone_set($_SERVER['TZ']);. However in general this is not a reliable method, so it must be your decision to trust it, PHP can not make it for you.

StasM
  • 10,593
  • 6
  • 56
  • 103
  • 1
    Woof. I just went through all those e-mails. At least Oleg is on my side. So the answer is essentially, they got rid of it because it wasn't portable. I think it's silly to eliminate functionality for that reason. What if I don't care about portability? If we can't do something on every system, we can't do it on any system? Oh well. – Andrew Aug 01 '12 at 15:36
  • @Andrew well, you'd have to set something. The server can't magically guess what timezone it's in. On unix, you (or whoever sets up the server) usually set up timezone on server setup and then it's in TZ variable. But on some systems it's different - Mac OS X, for example, doesn't do it. And Windows too. And maybe others... – StasM Aug 02 '12 at 06:36
  • Well I'm using Windows and the TZ variable isn't set, but the computer definitely knows what time zone it's set to, because the time settings show it correctly. The problem is PHP removed the ability to ask the system because it's not "portable" enough. For my purposes, it was working perfectly fine before. – Andrew Aug 08 '12 at 18:23
  • I'm going to select this as the answer because I think that e-mail thread gives a good insight into why they did it. It seems like a stupid reason to me (Like I said, "If we can't do something on every system, we can't do it on any system?") But a bad excuse is still an excuse! – Andrew Aug 08 '12 at 18:25
2

If you look here you can see the code from PHP 5.3 that would attempt to guess the system timezone. There isn't that much to it, but it appears the reasons for removing the guessing is mostly related to DST as that is where the issues seem to surface.

A breakdown of the whole guessing process looks like:

  • Checks to see if it's already defined globally (php.ini or previous guess) (line 851-853)
  • Check TZ environment variable (rarely ever defined from my experience) (line 855-858)
  • Check date.default_timezone from php.ini (special case as it should already be defined) (line 860-872)
  • Try to guess the timezone from the system by comparing the time() against the localtime(). The spec seems to say setting the timezone is optional, as there could be issues with threaded versions of this call (line 873-890)
  • Win32: Call WinAPI function GetTimeZoneInformation() and try to determine system time zone (line 893-928)
  • Netware: Check the _timezone value if defined (line 929-937)
  • Fallback to UTC if none of the above checks succeeded

I can only speculate, but maybe they only removed it since it was a guess to begin with and isn't always reliable.

Also due to PHP's popularity, it is installed on almost every Linux based shared hosting plan where the customers are often not in the same timezone as the server so falling back to the server timezone for those people is no better than using UTC by default. Then it only causes confusion as these customers have to come to SO to ask why the time is wrong in PHP.

I'm not familiar enough with C and the standard, but it seems like guessing timezone based on localtime has issues with multithreaded code or isn't available in some cases. Since on non-Windows platforms, this is the best way to determine the timezone, it doesn't make sense to do if say half the time it doesn't return anything or causes problems for multi-threaded PHP.

Then of course there is the issue of DST in some places where the timezone and offset is different based on the time of year.

Hope that helps.

drew010
  • 68,777
  • 11
  • 134
  • 162
  • Hmmm... well I happen to be using Windows, so that GetTimeZoneInformation() function interests me. If I could figure out how to call that directly it would probably solve my problem. Of course doing it the other way would probably be more proper and simpler at that point. – Andrew Jul 31 '12 at 21:52
  • Most of the packages for calling Windows API functions are no longer maintained or very old, so its unlikely you'll find a way to call this function from PHP short of writing some program to do it for you and then `exec()`ing that program. – drew010 Jul 31 '12 at 21:55
  • I think your answer answers the first part of the question. The answer is basically there's no portable way to do it, but if you don't care about portability it's certainly possible if you have some spare time. But it's going to be way harder than it was in PHP 5.3 and it's probably better to just set it in the config (ini) file. – Andrew Aug 01 '12 at 15:44
  • 2
    The problem with localtime() is not threading. The problem is that having current offset says next to nothing on your actual timezone - multiple timezones with different rules can at the same moment have the same offset, and timezone is much more than one offset at one point of time. It may lead to situation where the user code works today, but will stop working in a month when different timezone rules diverge. So people come back and complain "PHP broke my code, it worked 2 days ago, I changed nothing and now it doesn't work! PHP sucks!". Explicit message tells people where the problem is. – StasM Aug 08 '12 at 22:12
  • @StasM Thanks for clearing that up, makes good sense and speaks loudly to why PHP removed the guessing of TZ. – drew010 Aug 08 '12 at 22:30
0

No, there is no way to retrieve the timezone on a PC at this time.

  • 4
    "I expect the answer is "no", so perhaps somebody can shed some light on why a programming language would be unable to determine its time zone if that's the case." – Zar Jul 31 '12 at 19:42
0

I recently built several servers for a project, from the ground up. Due to previous experience on other projects where servers were using local-timezones I opted to force every server to use the 'UTC' timezone. Although this resulted in log files being off by 7 hours (UTC - PST), it did remove the inconsistency that setting local timezones caused (from the previous project).

The forced consistency proved helpful at the OS and app layers. For the OS layer, all log file entries can be viewed from a centralized location (via syslog over udp) regardless of their physical location. And at the application layer it was much easier to store every timestamp as UTC, then convert on the render for users who specified a timezone. This one way conversion is much simpler than a two way conversion, where you would have to convert the timestamp to UTC from the server's local-timezone upon save, then convert it to the user's selected timezone upon render.

So unless there is a very compelling reason for your servers to timezone aware, I would opt to stick with UTC, which was the default previous to 5.4: "If none of the above succeed, date_default_timezone_get() will return a default timezone of UTC."

Mike Purcell
  • 19,847
  • 10
  • 52
  • 89
  • But prior to 5.4 it also worked by "querying the host operating system". So I have code that was previously working reliably that now not only doesn't work, but can't be replicated at all by any code. – Andrew Jul 31 '12 at 21:02
  • Well by "doesn't work" I mean it puts the time in UTC when previously it was America/New_York. And I can't replicate the previous behavior in code because PHP is now blind to the OS timezone. – Andrew Jul 31 '12 at 21:08
  • @Andrew it worked in some cases, didn't work in others. So it didn't work "reliably" - it might have worked for you, but not for others. If you need OS timezone on Unix and you have TZ var, do date_default_timezone_set($_ENV['TZ']) or something like that. – StasM Jul 31 '12 at 21:10
  • The point I am trying to make is, what damage is occurring now that the timezone is UTC? Maybe it's as a simple as adding a timezone conversion script upon render. Does your application allow users to specify timezones? – Mike Purcell Jul 31 '12 at 21:11
  • @StasM Yes, it worked reliably for my purposes. My application is run only on specific servers and it worked on those. And Mike, yes, the applications allows the user to specify the timezone. The problem is with the default. I'm a lowly programmer, my job is to make sure it works like it did before :) – Andrew Jul 31 '12 at 21:42
  • If the user is allowed to specify a timezone, which I assume is stored in a persistent storage (mysql). Then when you pull the data from mysql, you can convert it from UTC to their local timezone. – Mike Purcell Jul 31 '12 at 21:47
0

This is just a wild guess. Could you be able to get the timezone with:

date('H', 0); or something like that? I mean since the unixtime stamp is the same in all regions but the Hour differs, shouldn't you be able to base on the hour know which timezone is used?

Robin Castlin
  • 10,956
  • 1
  • 28
  • 44
0

On a Windows server, it is possible to get the local system time zone with a little bit of math:

<?php
  date_default_timezone_set('UTC');

  $nowUTC = new DateTime();
  $nowSys = new DateTime(exec('echo %time%'));
  $offset = $nowUTC->diff($nowSys);

  echo $nowUTC->format('H:i:s') . '<br />';
  echo $nowSys->format('H:i:s') . '<br />';
  echo $offset->format('%H');
?>

From my locale (UTC-05) at the time of writing the output of this code is:

22:16:41
17:16:41
05

There is one caveat: the timestamps can sometimes be off by 1 second, causing the $offset variable to have 4:59:59. Getting the correct timezone consistently should do a little bit of rounding to be safe.

nicholas
  • 2,969
  • 20
  • 39