mysql数据库中不同的时间戳和新的DateTime()函数



当用户采取一些操作时,我正在处理examplep,然后在数据库中插入一条记录

$creation_datetime = new DateTime($row0['creation_date_time']);

上面语句的输出,其中creation_date_time是数据库中的timestamp类型,并且在插入记录时会自动填充。

DateTime Object ( [date] => 2020-07-25 15:31:46.000000 [timezone_type] => 3 [timezone] => Europe/Berlin )

我看到数据库中显示的时间实际上与我所在国家的时间相匹配,所以看起来是当地时间,但服务器时区不同。

print_r(new DateTime());

上述报表的输出

DateTime Object ( [date] => 2020-07-25 12:40:33.451120 [timezone_type] => 3 [timezone] => Europe/Berlin )

在这两种情况下,记录都来自数据库和日期函数,时区是欧洲/柏林,但DateTime函数显示基于服务器时间的正确日期。

(这些输出是在创建记录后记录的,时间几乎没有任何时间差)

为什么会发生这种情况?我想根据创建的时间和新的DateTime(即当前时间)来计算过期时间。

我应该不使用时间戳并插入基于新DateTime()的创建日期吗;函数,该函数似乎根据服务器输出正确的日期时间。

做这件事最可靠的方法是什么?

如果列creation_date_time是TIMESTAMP,则该值在内部存储为协调世界时(UTC),但当检索到该值时,它将被转换为当前会话时区,这将是服务器的默认时区,除非您已将会话时区设置为不同的时区。当您在没有明确设置时区的情况下将此值$row0['creation_date_time']分配给PHPDateTime时,它将使用UTC。

因此,为了保持一致并假设您想要使用特定的时区,您应该为MySql连接显式设置会话时区。因此,纽约人可能会做以下事情:

set session time_zone = 'America/New_York'; /* MySql */

在PHP中:

$date = new DateTime($row0['creation_date_time'], new DateTimeZone('America/New_York'));

或者,如果您不想使用UTC以外的任何内容创建DateTime,那么在检索TIMESTAMP之前,您至少应该将MySql会话时区设置为UTC。然后,您将拥有一致的时区,但不一定是您想要的可显示值。

例如,如果一个事件发生在2020年7月1日纽约凌晨5点,并且时间戳保存在timestamp列中,则内部会将其存储为"2020-07-01 01:00:00",因为有4小时的差异假设NOW()CURRENT_TIMESTAMP()的值用于存储时间戳,则这将独立于事件发生时有效的当前会话时区(但是,如果您将文字存储到timestamp列中,则在转换为UTC之前,它将在当前会话的时区中进行解释)。然而,当我检索该值时,我希望它反映";本地";时间因此,如果我希望检索到的值为"2020-07-01 05:00:00",我需要在获取列之前将会话时区设置为America/New_York。如果我在没有设置适当时区的情况下将其分配给PHP DateTime,它将显示为凌晨5点,但带有UTC时区,这是不正确的。

我不确定以上所有内容是否真的回答了你的问题,所以让我告诉你,在不了解或不了解你的实际情况的情况下,我通常会采取的方法:

我不会尝试使用PHP初始化的变量显式更新时间戳,而是允许MySql根据您的要求在创建和/或更新时进行初始化:

UPDATE my_table set creation_date_time = now(), etc.

问题是,当您用文字值设置TIMESTAMP列时,它将在当前会话时区中进行解释,如果不明确设置,这将变得不确定,除非您可以控制系统时区(应用程序也会迁移到不同的ISP,从而迁移到时区,至少在我的国家是这样)。即使按照我的建议,将显式设置会话时区,但让MySql进行初始化要简单得多。

然后我会确保连接后的第一件事就是设置本地会话时区:

set session_time_zone = 'Europe/Berlin';

然后你的PHP代码是:

$date1 = new DateTime($row0['creation_date_time'], new DateTimeZone('Europe/Berlin'));
$date1 = $date1->modify("+1 month");
$date2 = new DateTime("now", new DateTimeZone('Europe/Berlin'));
if ($date1 <= date2) {
// expired
}

更新

如果当前MySql服务器时间是"欧洲/柏林",那么当您执行SELECT TIMEDIFF(NOW(), UTC_TIMESTAMP)查询时,我希望得到的结果是"02:00",而不是"05:30",如下所示:

mysql> set session time_zone = 'Europe/Berlin';
Query OK, 0 rows affected (0.19 sec)
mysql> SELECT TIMEDIFF(NOW(), UTC_TIMESTAMP);
+--------------------------------+
| TIMEDIFF(NOW(), UTC_TIMESTAMP) |
+--------------------------------+
| 02:00:00                       |
+--------------------------------+
1 row in set (0.00 sec)

因此,无论MySql服务器的时间是什么,似乎都是柏林以东03:30。现在,您正在比较的时间戳是:

来自MySql:

DateTime Object ( [date] => 2020-07-25 15:31:46.000000 [timezone_type] => 3 [timezone] => Europe/Berlin )

来自PHP:

DateTime Object ( [date] => 2020-07-25 12:40:33.451120 [timezone_type] => 3 [timezone] => Europe/Berlin )

现在要准确地比较这两者有点困难。如果您同时创建了PHP时间戳和MySql时间戳,并且MySql时间戳是使用MySql函数(如NOW())创建的(在这种情况下,timestamp在内部是正确的),那么我希望MySql时间戳记比PHP时间戳晚03:30(因为timestamp从UTC转换回时时区有效)。但是,如果你真的在大约40分钟后创建了PHP时间戳,那么你所显示的或多或少就是我所期望的你告诉我40分钟是否更接近这两个事件之间的经过时间假设是这样,那么这也告诉我,您已经使用NOW()或其等效CURRENT_TIMESTAMP初始化了TIMESTAMP列,这将是一件非常好的事情,因为在内部时间戳是正确的,而您唯一的问题是当您检索它时,会将其转换到错误的时区。但这可以通过在连接后立即设置会话时区来弥补:

set session time_zone = 'Europe/Berlin'

更新2

如果您无法设置上述时区,则MySql安装中缺少时区,需要加载它们(您在PHP大小上看到该时区的原因是PHP有时区,并且您正在显式地将其加载到DateTime对象中)。

URLhttps://dev.mysql.com/downloads/timezones.html具有时区的文件。选择适合MySql版本的POSIX版本,并将其下载到您的PC上。

URLhttps://dev.mysql.com/doc/refman/8.0/en/time-zone-support.html具有加载此文件的说明。阅读这篇文章,确保你明白自己在做什么(必须有人承担责任)。简而言之,您将执行:

mysql_tzinfo_to_sql path-to-downloaded-timezones-file | mysql -u admin-user-id -p admin-password

在所有这些之后,如果你仍然想做一些轻松的阅读,请参阅DATE、TIME、DATETIME和TIMESTAMP类型之间的区别,特别是我给出的答案(Booboo)。

最新更新