在 PHP/MySQL 中将日期时间存储为 UTC

Posted

技术标签:

【中文标题】在 PHP/MySQL 中将日期时间存储为 UTC【英文标题】:Storing datetime as UTC in PHP/MySQL 【发布时间】:2010-11-23 20:55:36 【问题描述】:

我读到的所有关于将时间转换为用户时区的文章都说,最好的方法是以 UTC 存储日期和时间,然后将用户的时区偏移量添加到这个时间。

如何以 UTC 时间存储日期?我使用 mysql DATETIME 字段。

在我的 php 代码中向 MySQL 添加新记录时,我会使用 now() 插入 MySQL DATETIME。

我是否需要使用不同于 now() 的东西来存储 UTC 时间?

【问题讨论】:

如果你走这条路,别忘了考虑夏令时——即对于给定用户的位置,时区偏移不一定是恒定的。 是的,我已经阅读了很多关于在 PHP 中处理时区的令人困惑和矛盾的事情,这似乎是 php 需要改进的事情之一 对于那些正在寻找更多信息的人,我链接到这些精彩的文章:infiniteundo.com/post/25326999628/… 和 infiniteundo.com/post/25509354022/… 【参考方案1】:

随机:UTC_TIMESTAMP(6) 时间为 6 位微秒。

MySQL 5.7+

【讨论】:

【参考方案2】:

我建议在 UTC 时区插入日期。这将为您省去很多日后夏令时问题的麻烦。

INSERT INTO abc_table (registrationtime) VALUES (UTC_TIMESTAMP())

当我查询我的数据时,我使用以下 PHP 脚本:

<?php

while($row = mysql_fetch_array($registration))  

  $dt_obj = new DateTime($row['message_sent_timestamp'] ." UTC");
  $dt_obj->setTimezone(new DateTimeZone('Europe/Istanbul'));
  echo $formatted_date_long=date_format($dt_obj, 'Y-m-d H:i:s');

?>

您可以将DateTimeZone 值替换为可用的PHP timezones 之一。

【讨论】:

+1 但您需要转义时区文字,即 ." \U\T\C" 以避免与当前的未来格式字符发生任何冲突。 这个很棒的解决方案处理时间戳字段,但是如果表从客户端存储日期和时间,是否有类似的优雅解决方案?即在存储 dateimtes 时,日期时间文字来自客户端(使用客户端的 tz)。 DateTime 构造函数接受时区的第二个参数。例如$date = new DateTime('2000-01-01', new DateTimeZone('UTC')); 您可以在某处保留 UTC 时区对象的静态副本,这样您就不必继续重新构建它。 添加一个答案,其中包含有关其工作原理以及如何插入来自 PHP 的日期的一些详细信息。【参考方案3】:

正如@Haluk 建议的那样,您可以将日期存储为UTC datetime。 对于您要插入的日期来自 PHP 代码的情况,我正在补充他的答案,并添加一些有关其工作原理的详细信息:

$pdo = new PDO('mysql:host=mydbname.mysql.db;dbname=mydbname', 'myusername', 'mypassword');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

$insertStmt = $pdo->prepare("insert into test (last_modified)"
    ." values(:last_modified)");
$insertStmt->bindParam(':last_modified', $lastModified, PDO::PARAM_STR);
$lastModified = gmdate("Y-m-d H:i:s");
$insertStmt->execute();

实际上,PHP 中的datetime 没有与之关联的时区。传递给 PDO 的只是一个字符串,采用 MySQL 识别的格式之一,表示 UTC 时区中的日期。例如,如果日期是2015-10-21 19:32:33 UTC+2:00,上面的代码只是告诉 MySQL 插入2015-10-21 17:32:33gmtdate("Y-m-d H:i:s") 以这种格式为您提供当前日期。在任何情况下,您需要做的就是构建代表您想要在 UTC 时间中插入的日期的字符串。

然后,当您读取日期时,您必须告诉 PHP 您刚刚检索到的日期的时区是 UTC。为此,请使用 Haluk 答案中的代码。

【讨论】:

【参考方案4】:

MySQL:UTC_TIMESTAMP()

返回当前 UTC 日期和时间 作为 'YYYY-MM-DD HH:MM:SS' 中的值或 YYYYMMDDHHMMSS.uuuuuu 格式, 取决于功能是否 在字符串或数字上下文中使用

PHP:gmdate()

PHP 中还使用 PHP date_default_timezone_set() 来设置脚本的当前时区。您可以将其设置为客户端时区,以便所有格式化函数返回其本地时间的时间。

事实上,虽然我很难让它发挥作用,而且总是会遇到一些问题。例如。从 MySQL 返回的时间信息未格式化为“UTC”,因此如果您不小心,strtotime 会将其转换为本地时间。我很想知道是否有人有针对此问题的可靠 解决方案,当日期跨越媒体边界时不会中断(HTTP->PHP->MySQL 和 MySQL->PHP->HTTP ),同时考虑 XML 和 RSS/Atom。

【讨论】:

不确定是否有人得到了万无一失的解决方案! 如果我的 php 脚本使用gmdate() 获取 UTC 时间,这将返回一个字符串。这不会和在 MySQL 中设置字段类型为DATETIME 冲突吗? @whatwhatwhat 什么?看看手册dev.mysql.com/doc/refman/5.7/en/date-and-time-literals.html【参考方案5】:

https://dba.stackexchange.com/questions/20217/mysql-set-utc-time-as-default-timestamp

在删除的情况下引用上面链接中的所有答案:

与@ypercube 的评论一致,即CURRENT_TIMESTAMP 存储为UTC 但检索为当前时区,您可以使用--default_time_zone 检索选项影响服务器的时区设置。这使您的检索始终采用 UTC。

默认情况下,选项是“SYSTEM”,这是您的系统时区的设置方式(可能是也可能不是 UTC!):

mysql> SELECT @@global.time_zone, @@session.time_zone;
+--------------------+---------------------+
| @@global.time_zone | @@session.time_zone |
+--------------------+---------------------+
| SYSTEM             | SYSTEM              |
+--------------------+---------------------+
1 row in set (0.00 sec)

mysql> SELECT CURRENT_TIMESTAMP();
+---------------------+
| CURRENT_TIMESTAMP() |
+---------------------+
| 2012-09-25 16:28:45 |
+---------------------+
1 row in set (0.00 sec)

您可以动态设置:

mysql> SET @@session.time_zone='+00:00';
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT @@global.time_zone, @@session.time_zone;
+--------------------+---------------------+
| @@global.time_zone | @@session.time_zone |
+--------------------+---------------------+
| SYSTEM             | +00:00              |
+--------------------+---------------------+
1 row in set (0.00 sec)

或者永久保存在你的 my.cnf 中:

[mysqld]
**other variables**
default_time_zone='+00:00'

重启你的服务器,你会看到变化:

mysql> SELECT @@global.time_zone, @@session.time_zone;
+--------------------+---------------------+
| @@global.time_zone | @@session.time_zone |
+--------------------+---------------------+
| +00:00             | +00:00              |
+--------------------+---------------------+
1 row in set (0.00 sec)

mysql> SELECT CURRENT_TIMESTAMP();
+---------------------+
| CURRENT_TIMESTAMP() |
+---------------------+
| 2012-09-25 20:27:50 |
+---------------------+
1 row in set (0.01 sec)

【讨论】:

【参考方案6】:

NOW() 为您提供运行数据库的系统的时间(包括时区偏移量)。要获取 UTC 日期/时间,您应该使用 UTC_TIMESTAMP(),如 MySQL Reference Manual 中所述。

【讨论】:

以上是关于在 PHP/MySQL 中将日期时间存储为 UTC的主要内容,如果未能解决你的问题,请参考以下文章

在 iOS 中将 UTC 日期时间转换为本地日期时间

在python中将日期时间从PDT转换为UTC

在 MySQL 中将 UTC 格式的日期时间转换为 GMT+7

在 Swift 中将日期从 GMT+1 转换为 UTC 时的困惑

在填充的数据表中将 datetime 列从 utc 转换为本地时间

无法在JavaScript中将String BST日期格式转换为UTC