PHP 5.4无法自行确定时区

时间:2012-07-31 19:37:34

标签: php datetime timezone

我只是想对此进行一些澄清。 PHP 5.4消除了TZ环境变量和date_default_timezone_get曾经做过的“猜测”。所以现在我觉得根本没办法得到服务器的时区。

所以我的问题是:是否可以在PHP 5.4中获取服务器时区?我知道我可以在php.ini中手动设置它,但是当一台计算机完全能够知道它的时间时,这似乎有点傻。我希望答案是“不”,所以也许有人可以解释为什么编程语言无法确定其时区(如果是这种情况)。

6 个答案:

答案 0 :(得分:4)

没有可靠的方法来猜测每个系统的时区。不同的系统使用不同的约定,有时甚至是不同的时区定义(例如Unix和Windows),有时会有冲突的时区说明符(相同的3个字母的区域缩写在不同的地方可能意味着不同的东西)。因此,如果您希望在系统之间拥有可移植的代码,那么可靠地执行此操作的唯一方法就是询问用户。请参阅此线程: http://marc.info/?t=132356551500002&r=1&w=2 关于它的一些问题(查找来自Derick Rethans的电子邮件 - 他是PHP日期时间扩展维护者)。

如果您有办法找出您信任的时区(例如TZ变量),那么您可以随时date_default_timezone_set($_SERVER['TZ']);。但是一般来说这不是一种可靠的方法,所以你决定信任它,PHP无法为你做到。

答案 1 :(得分:2)

如果查看here,您可以看到PHP 5.3中的代码,它会尝试猜测系统时区。它没有那么多,但似乎删除猜测的原因主要与DST有关,因为这是问题似乎浮现的地方。

整个猜测过程的细分如下:

  • 检查是否已全局定义(php.ini或之前的猜测)(第851-853行)
  • 检查TZ环境变量(很少根据我的经验定义)(第855-858行)
  • 从php.ini检查date.default_timezone(特殊情况,因为它应该已经定义)(第860-872行)
  • 尝试通过将time()localtime()进行比较来猜测系统的时区。该规范似乎表示设置时区是可选的,因为此调用的线程版本可能存在问题(第873-890行)
  • Win32:调用WinAPI函数GetTimeZoneInformation()并尝试确定系统时区(第893-928行)
  • Netware:检查_timezone值(如果已定义)(第929-937行)
  • 如果以上检查均未成功,则回退到UTC

我只能推测,但也许他们只是删除它,因为这是一个猜测开始并不总是可靠的。

同样由于PHP的受欢迎程度,它几乎安装在每个基于Linux的共享主机方案中,客户通常与服务器不在同一时区,因此对于那些人来说,回到服务器时区并不比使用UTC更好默认。然后它只会引起混淆,因为这些客户必须来到SO询问为什么PHP的时间错误。

我对C和标准不够熟悉,但似乎基于localtime的猜测时区存在多线程代码问题,或者在某些情况下不可用。因为在非Windows平台上,这是确定时区的最佳方法,如果说它没有返回任何内容或者导致多线程PHP出现问题的一半时间没有意义。

当然,在某些地方存在DST问题,其中时区和偏移量根据一年中的时间而不同。

希望有所帮助。

答案 2 :(得分:0)

不,此时无法在PC上检索时区。

答案 3 :(得分:0)

我最近从头开始为一个项目构建了几台服务器。由于之前服务器使用本地时区的其他项目的经验,我选择强制每台服务器使用“UTC”时区。虽然这导致日志文件在7小时(UTC - PST)之前关闭,但它确实消除了设置本地时区(来自上一个项目)的不一致。

强制一致性证明在OS和app层有用。对于OS层,可以从集中位置(通过udp上的syslog)查看所有日志文件条目,而不管它们的物理位置如何。在应用程序层,将每个时间戳存储为UTC更容易,然后为指定时区的用户转换渲染。这种单向转换比双向转换要简单得多,您必须在保存时从服务器的本地时区将时间戳转换为UTC,然后在渲染时将其转换为用户选定的时区。

因此,除非有一个非常令人信服的理由让您的服务器知道时区,否则我会选择坚持使用UTC,这是5.4之前的默认值:“如果以上都不成功,则date_default_timezone_get()将返回默认时区UTC。“

答案 4 :(得分:0)

这只是一个疯狂的猜测。你能否通过以下方式获得时区:

date('H', 0);或类似的东西?我的意思是因为unixtime标记在所有区域都是相同的,但Hour不同,你不应该根据时间知道使用哪个时区吗?

答案 5 :(得分:0)

在Windows服务器上,可以通过一些数学运算来获取本地系统时区:

<?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');
?>

在撰写本文时,从我的语言环境(UTC-05)开始,此代码的输出为:

22:16:41
17:16:41
05

有一点需要注意:时间戳有时会偏差1秒,导致$offset变量有4:59:59。一致地获得正确的时区应该进行一些舍入以确保安全。