使用PHP 5.3安装新的XAMPP时出现时区问题


Timezone issues on new XAMPP install with PHP 5.3

为了回应WordPress 3.2(本月晚些时候发布)将需要PHP 5.2.4+的消息,我今天将我的Windows测试机从XAMPP 1.5.5升级到1.7.4,这反过来又将我的PHP 5.2.0提升到5.3.5。

我几乎所有的东西都恢复了工作,但有一个测试页面的行为很奇怪。我有一个MySQL表,其中包含按国家代码排列的tz标识符,下面的脚本确定并显示每个时区的当前时间:

<?php
  echo "<table>";
  $result = mysql_query("SELECT * FROM zone_data ORDER BY `id` ASC;");
  while ($row = mysql_fetch_assoc($result)) {
    putenv("TZ=".$row['zone_name']);
    echo "<tr>";
      echo "<th>".$row['zone_code']."</th>";
      echo "<td>".$row['zone_name']."</td>";
      echo "<td>".date("D j M Y / H:i T",$_GET['t']);
        if (date("I") == 1) { echo "*"; } // asterisk if in DST
      echo " (".date("P",$_GET['t']).")</td>";
    echo "</tr>";
  }
  echo "</table>";
?>

在PHP 5.2.17的生产服务器上运行良好的预期输出应该如下所示:

Z   Etc/UTC          Fri 3 Jun 2011 / 03:22 UTC (+00:00)
AD  Europe/Andorra   Fri 3 Jun 2011 / 05:22 CEST* (+02:00)
AE  Asia/Dubai       Fri 3 Jun 2011 / 07:22 GST (+04:00)
AF  Asia/Kabul       Fri 3 Jun 2011 / 07:52 AFT (+04:30)
AG  America/Antigua  Thu 2 Jun 2011 / 23:22 AST (-04:00)
...

但相反,我被告知时间与我的系统时间相同,America/New_York(目前为UTC-4)在每个区域:

Z   Etc/UTC          Thu 2 Jun 2011 / 23:22 EDT* (-04:00)
AD  Europe/Andorra   Thu 2 Jun 2011 / 23:22 EDT* (-04:00)
AE  Asia/Dubai       Thu 2 Jun 2011 / 23:22 EDT* (-04:00)
...

现在,我注意到XAMPP 1.7.4安装的新php.ini的第1001行原来包含date.timezone = Europe/Berlin,所以我用date.timezone = America/New_York替换了它。但在这两种情况下,date()函数的每个实例都由该设置指定,而不管我对putenv()做了什么其他说明。对于使用date()的所有其他页面也是如此(尽管gmdate()显然按预期返回GMT)。

我试着注释掉那一行,但PHP 5.3.5抛出了可爱的错误,称"依赖系统的时区设置是不安全的",并且要求我在php.ini中使用date.timezone指令,尽管我在使用date()或类似函数时总是使用putenv()

被迫设置"超级全局"有点令人沮丧,尤其是在这样的情况下,整个要点是暂时进入一个新的TZ环境并从中收集一些有用的信息。

所以有没有什么方法可以让date.timezone指令作为默认指令,被putenv()重写,这样后者就不会被完全忽略?你能想到还有什么可能导致上述意外/怪异行为的原因吗?

我倾向于认为,这只是一些服务器设置需要更改,以允许putenv()继续在PHP 5.3.5中工作,就像在5.2.0中一样(在5.2.17中也是如此)。当然,如果有一个"更好的方法",我不介意听它(我一直喜欢学习新东西!)。但最重要的是,我希望我的旧代码能在我的新安装中工作。

如果你需要更多关于我的设置的信息,请告诉我。

TZ环境变量在PHP 5.3中被忽略。(date_default_timezone_get的PHP手册页面描述了各种设置的考虑顺序,包括TZ仅适用于PHP<5.3)

简单的解决方案:使用date_default_timezone_set设置不同的时区,而不是putenv

以上是putenv的最直接替代,但DateTime类提供了在不同时区进行日期操作的更好方法,同时不会影响其他日期操作的"当前"时区。DateTime的构造函数可以采用只影响该特定对象的时区的DateTimeZone参数(也可以使用setTimezone():设置

$date = new DateTime(null, new DateTimeZone('Europe/Andorra'));
echo $date->format(/* your date format */);