【问题标题】:Dealing with timezones in PHP在 PHP 中处理时区
【发布时间】:2010-09-25 16:42:15
【问题描述】:

PHP 中时区的一些问题已经在我脑海中浮现了一段时间,我想知道是否有比我目前正在做的更好的方法来处理它。

所有问题都围绕着重新格式化数据库存储日期:

在处理必须支持多个时区(对于用户)的站点时,为了规范存储时间戳的时区,我总是使用 CURRENT_TIMESTAMP 属性或 NOW() 函数将其与服务器时区一起存储。

这样我就不必考虑在输入时间戳时为 PHP 设置的时区(因为 PHP 时间函数可以识别时区)。对于每个用户,根据他的偏好,我使用以下命令在引导文件中的某处设置时区:

date_default_timezone_set($timezone);

当我希望使用 php date() 函数格式化日期时,必须进行某种形式的转换,因为 MySQL 当前以 Y-m-d H:i:s 格式存储时间戳。不考虑时区,您可以简单地运行:

$date = date($format,strtotime($dbTimestamp));

问题在于 date()strtotime() 都是时区感知函数,这意味着如果 PHP 时区设置与服务器时区不同,时区偏移量将应用两次(而不是我们想要的一次) )。

为了解决这个问题,我通常使用不支持时区的UNIX_TIMESTAMP() 函数检索 MySQL 时间戳,允许我直接在其上应用 date() - 从而只应用一次时区偏移量。

我不太喜欢这种“hack”,因为我不能再像往常一样检索这些列,或者使用* 来获取所有列(有时它可以大大简化查询)。此外,有时使用UNIX_TIMESTAMP() 根本不是一种选择(尤其是在使用没有太多抽象查询组合的开源包时)。

另一个问题是在存储时间戳时,如果不能使用 CURRENT_TIMESTAMPNOW() - 存储 PHP 生成的时间戳会将其与我希望避免的时区偏移一起存储。

我可能在这里遗漏了一些非常基本的东西,但到目前为止,我还没有想出一个通用的解决方案来处理这些问题,所以我不得不逐个处理它们。非常欢迎您的想法

【问题讨论】:

标签: php database timezone


【解决方案1】:

我没有在网上找到任何优雅的解决方案,所以我创建了一个 Timezone HTML select generator 脚本,这里是 output 直接。是这样的:

<select name="timezone" id="timezone">
    <optgroup label="UTC -11:00">
        <option value="Pacific/Midway">UTC -11:00 Midway</option>
        <option value="Pacific/Niue">UTC -11:00 Niue</option>
        <option value="Pacific/Pago_Pago">UTC -11:00 Pago_Pago</option>
    </optgroup>
    <optgroup label="UTC -10:00">
        <option value="America/Adak">UTC -10:00 Adak</option>
        <option value="Pacific/Honolulu">UTC -10:00 Honolulu</option>
        <option value="Pacific/Johnston">UTC -10:00 Johnston</option>
        <option value="Pacific/Rarotonga">UTC -10:00 Rarotonga</option>
        <option value="Pacific/Tahiti">UTC -10:00 Tahiti</option>
    </optgroup>
    . . . . . . . . . . . . . .
    <optgroup label="UTC +13:00">
        <option value="Pacific/Apia">UTC +13:00 Apia</option>
        <option value="Pacific/Enderbury">UTC +13:00 Enderbury</option>
        <option value="Pacific/Fakaofo">UTC +13:00 Fakaofo</option>
        <option value="Pacific/Tongatapu">UTC +13:00 Tongatapu</option>
    </optgroup>
    <optgroup label="UTC +14:00">
        <option value="Pacific/Kiritimati">UTC +14:00 Kiritimati</option>
    </optgroup>
</select>

享受吧!

【讨论】:

    【解决方案2】:

    从 PHP 5.2 开始,您可以使用 DateTime,这使得处理时区变得容易:

    $datetime = new DateTime($dbTimestamp, $timezone);
    echo $datetime->format('Y-m-d H:i:s');
    $datetime->setTimezone(new DateTimeZone('Pacific/Nauru'));
    echo $datetime->format('Y-m-d H:i:s');
    

    【讨论】:

      【解决方案3】:

      几个月前,我们花了一些时间思考这个问题。我们最终得到的技术非常简单:

      1. 以 GMT/UTC 存储日期(例如 0 时区偏移)。
      2. 从数据库中检索后应用当前用户时区偏移量(例如,在向用户显示之前或在您需要时)。

      我们使用 Unix 时间戳格式。但这没关系。

      【讨论】:

      • 我实际上更喜欢将它存储在服务器的时区中,并让 PHP 时区感知函数来处理偏移量计算。我的问题是时间戳没有以 PHP 想要的 date() 函数的数字形式保存
      • 经过一些研究,我们也使用了相同的解决方案。希望在这里人们使用过的替代品。
      【解决方案4】:

      您可以尝试使用 SET time_zone 强制 MySQL 在任何地方使用 UTC。

      不幸的是,我没有得到关于 strtotime/UNIX_TIMESTAMP 的任何答案,事实上我也遇到了与 Postgres 相同的问题。

      【讨论】:

      • 也许我们应该呼吁 SQL 标准委员会强制使用数字时间戳? ;)
      • 不,我确信 datetime 列的存在是有充分理由的。只是还没想好……
      猜你喜欢
      • 1970-01-01
      • 2011-06-27
      • 2016-10-17
      • 1970-01-01
      • 2012-11-21
      • 2012-08-28
      • 2019-05-05
      • 2023-03-15
      相关资源
      最近更新 更多