在 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:33
。 gmtdate("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的主要内容,如果未能解决你的问题,请参考以下文章
在 MySQL 中将 UTC 格式的日期时间转换为 GMT+7
在 Swift 中将日期从 GMT+1 转换为 UTC 时的困惑