代码之家  ›  专栏  ›  技术社区  ›  Eran Galperin

在PHP中处理时区

  •  20
  • Eran Galperin  · 技术社区  · 17 年前

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

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

    为了解决这个问题,我通常使用 UNIX_TIMESTAMP() 不支持时区的功能,允许我应用 日期() 直接在它上面-从而只应用一次时区偏移。

    我真的不喜欢这种“破解”,因为我无法再像往常一样检索这些列,也无法使用 * 获取所有列(有时它大大简化了查询)。此外,有时它根本不是一个使用选项 UNIX时间戳() (尤其是在与没有太多查询组合抽象的开源软件包一起使用时)。

    另一个问题是在存储时间戳时 当前时间戳 或 NOW() 这不是一个选项——存储PHP生成的时间戳会将其与我想避免的时区偏移一起存储。

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

    5 回复  |  直到 14 年前
        1
  •  12
  •   Misha Moroshko Amr Mostafa    14 年前

    几个月前,我们花了一些时间思考这个问题。我们最终采用的技术相当简单:

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

    我们使用Unix时间戳格式。但这并不重要。

        2
  •  7
  •   John Conde    13 年前

    从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
  •   user42092 user42092    17 年前

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

    不幸的是,我对strtotime/UNIX_TIMESTAMP的问题没有任何答案,事实上,我对Postgres也有同样的问题。

        4
  •  0
  •   Lucian D.    13 年前

    我在网上没有找到任何优雅的解决方案,所以我创建了一个 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>
    

    享受!

    推荐文章