【问题标题】:Storing dates and times in UTC and converting them local time in PHP/MySQL以 UTC 存储日期和时间并在 PHP/MySQL 中转换它们的本地时间
【发布时间】:2012-03-10 07:29:35
【问题描述】:

在我对如何处理日期和时间进行全面重构之前,我想问问这是否可行。

为了表达我的问题,这是我的问题...... 我将用户采取的“操作”存储在历史记录表中。这些操作上有一个时间戳。用户可以来自世界各地,因此有不同的时区。我想显示历史记录中的项目并显示当地时区的时间戳。

另外,我知道我可以使用日期时间字段并简单地存储 UTC 时间格式,但我选择使用时间戳,因此我可以将默认值设置为当前时间。

这对我的问题有用吗?

  1. 我的服务器时区是洛杉矶

  2. 将时间戳存储为 MySQL 中的时间戳。我的理解是时间戳始终存储为 UTC。记录将默认存储为 creation_date 或者我将明确设置 UTC_TIMESTAMP()。实际上,数据库中的所有记录都是UTC。

  3. 当用户登录时,我将获取他们的时区(我将其作为用户设置存储在数据库中)。 对于此示例,假设此人在纽约。

这是我的问题所在。这些都行吗?

  1. a) 获取历史数据。所有时间戳将自动从 UTC 转换为洛杉矶时间。 Foreach 历史项目,将洛杉矶时间戳转换为纽约时间戳并回显。

  1. b) 将 php 时区“date_default_timezone_set”设置为纽约。获取历史数据。所有时间戳仍然是洛杉矶时间,服务器仍然是洛杉矶时间。对于每个历史项目,只需回显时间戳,因为“date_default_timezone_set”会自动将洛杉矶时间戳转换为纽约。

选项 4b 会起作用吗?有没有更好的方法将洛杉矶时间转换为纽约时间?

一般来说有没有更好的方法来做到这一点?

【问题讨论】:

  • 以 UTC 存储,向用户显示本地是主流解决方案。

标签: php mysql timestamp utc datetime-conversion


【解决方案1】:

您是对的,Unix 时间戳始终采用 UTC。如果您以 UTC 格式将时间戳存储在数据库中,那么您只需将 PHP 中的时区更改为用户本地的时区即可在本地时间输出。您无需对时间戳进行任何转换。

<?php

$timeStampFromDatabase = 1325448000;  // 01 Jan 2012 20:00:00 GMT

date_default_timezone_set('America/Los_Angeles');
echo date('r', $timeStampFromDatabase); // Sun, 01 Jan 2012 12:00:00 -0800

date_default_timezone_set('Asia/Hong_Kong');
echo date('r', $timeStampFromDatabase); // Mon, 02 Jan 2012 04:00:00 +0800

您可以即时更改您的时区并继续以日期格式输出时间戳,它们将根据 PHP 中设置的时区“转换”。很简单,不需要做任何特殊处理,在哪里设置时区也无所谓,只要在输出日期之前做,但可以在设置时区之前阅读。

【讨论】:

  • date_default_timezone_set 用于设置默认时区。我不会设置它超过一次。我认为最好创建一个DateTime 对象并使用DateTime::setTimezone()php.net/manual/en/function.date-timezone-set.php
  • 我只是改变它来说明这一点。我认为它只会在应用程序中设置一次,但您可以多次切换。如果您在切换时小心,您可以随时更改它,然后将其更改回之前的值,没有任何问题。
  • 非常感谢您的帮助。关于 date_default_timezone_set 函数的新问题。这是仅影响当前用户的设置还是全局系统变量?如果它是一个全局变量,它不会在不同时区的所有用户中引起问题吗?
  • 在 PHP 脚本中使用 date_default_timezone_set 设置时区只会影响调用它的 PHP 进程。它不会影响 PHP 或其他用户的后续调用,只会影响当前正在执行脚本的用户。当脚本结束时它会被重置。默认情况下,PHP 总是将时区设置为 php.ini 中 date.timezone 指令中指定的时区。
【解决方案2】:

不幸的是,“date_default_timezone_set”并没有像我想象的那样工作。根据前面的示例,如果我正在使用的日期已经是 unix 时间戳格式,它将起作用。但是,它们的格式为“Y-m-d H:i:s”,唯一会改变的是 GMT 偏移量,这显然不起作用。

经过几个小时的烦躁,这就是我能够处理时间转换的方法。

$datetime = new DateTime($date_to_convert);
$usertimezone = new DateTimeZone($_SESSION['timezone']); //each user has their own timezone i store in a session (i.e. - "Americas/Los_Angeles")
$datetime->setTimezone($usertimezone);
echo $datetime->format("Y-m-d H:i:s");

我想我也可以做到以下几点:

Pseudo code
strtotime($datetime)
date_default_timezone_set($user_timezone)
echo date(format, $datetime)

我认为,上述内容会强制日期函数在给定的 $user_timezone 中处理它的逻辑。事后看来,我必须翻译每个 $datetime -> unix_timestamp -> $datetime_converted,这听起来并不比我选择做的更好。

【讨论】:

    【解决方案3】:

    始终将您的时间戳以 UTC 格式存储在数据库中。这是一个时区和夏令时独立的时间点。要在他们的时区将其显示给用户,只需执行以下操作:

    $users_timezone = 'Europe/London'; // See PHP documentation for names that can be used.
    $date = new DateTime();
    $date->setTimestamp($timestamp_from_database);
    $date->setTimezone(new DateTimeZone($users_timezone));   
    echo $date->format("H:ia jS F Y");
    

    【讨论】:

      【解决方案4】:

      默认情况下,Unix 时间戳始终采用 UTC。如果我们将时间戳以 UTC 格式存储在数据库中,我们只需要使用以下 PHP 脚本:

      <?php
      
      $TZ_UTC = new DateTimeZone('UTC'); //-->Database Timezone;
      $TZ_LOCAL = new DateTimeZone('America/New_York'); //-->Expected Local Timezone from user settings;
      
      //--Example Database Query--
      while($row = mysqli_fetch_array($result, MYSQLI_ASSOC)) {
          //---If we want to show UTC timezone directy----
          echo $row['action_timestamp'];
      
          //---If we want to show LOCAL timezone from user settings----
          $dateObj = new DateTime($row['action_timestamp'], $TZ_UTC);
          $dateObj->setTimezone($TZ_LOCAL); //--> Here is the conversion!
          echo $dateObj->format("Y-m-d H:i:s T");
      }
      ?>
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-07-09
        • 2016-07-29
        • 1970-01-01
        • 2011-04-17
        相关资源
        最近更新 更多