MySQL 夏令时信息似乎不正确。如何确保它在 Windows 中是最新的?
MySQL daylight savings info seems to be incorrect. How can I ensure it is up to date in Windows?
我发现我程序中的一个错误是由 MySQL 的 UNIX_TIMESTAMP() 函数在给定相同值时向 PHP 的 strtotime() 返回不同的值引起的输入。
然后我发现错误发生的日期恰好是我所在时区夏令时生效的日期。
所以我需要知道为什么 PHP 知道夏令时开始日,但 MySQL 不知道。 PHP 和 MySQL 不应该都从操作系统中获取时区和夏令时信息吗?
操作系统是Windows7,根据Windows更新程序,它是最新的补丁。
这是我的代码:
// Checking timezones in MySQL and PHP.
echo "<pre>\n";
echo "date_default_timezone_get(): " . date_default_timezone_get() . "\n";
echo "date('P'): " . date('P') . "\n";
echo "MySQL timezone: " . $sqlObj->fetchField('SELECT IF(@@session.time_zone="SYSTEM", @@system_time_zone, @@session.time_zone)') . "\n";
// Testing MySQL and PHP conversion to unix timestamp for specific datetime values.
for ($hour = 0; $hour < 5; ++$hour)
{
$timeString = '2018-10-07 ' . (($hour < 10)? '0': '') . "$hour:00:00";
$timestampFromMySql = $sqlObj->fetchField('SELECT UNIX_TIMESTAMP(?)', array($timeString));
$timestampFromPhp = strtotime($timeString);
echo " * timestring : $timeString\n";
echo " timestampFromMySql: $timestampFromMySql\n";
echo " timestampFromPhp : $timestampFromPhp\n";
// Checking daylight savings status for the date in question in PHP.
echo " date('I', $timestampFromMySql): " . date('I', $timestampFromMySql) . "\n";
echo " date('I', $timestampFromPhp ): " . date('I', $timestampFromPhp ) . "\n";
echo " difference: " . ($timestampFromMySql - $timestampFromPhp) . "\n";
}
echo "</pre>\n";
这是输出。请注意,PHP 和 MySQL 在凌晨 3 点报告的 unix 时间出现 3600 秒或一小时的差异。
date_default_timezone_get(): Australia/Melbourne
date('P'): +10:00
MySQL timezone: +10:00
* timestring : 2018-10-07 00:00:00
timestampFromMySql: 1538834400
timestampFromPhp : 1538834400
date('I', $timestampFromMySql): 0
date('I', $timestampFromPhp ): 0
difference: 0
* timestring : 2018-10-07 01:00:00
timestampFromMySql: 1538838000
timestampFromPhp : 1538838000
date('I', $timestampFromMySql): 0
date('I', $timestampFromPhp ): 0
difference: 0
* timestring : 2018-10-07 02:00:00
timestampFromMySql: 1538841600
timestampFromPhp : 1538841600
date('I', $timestampFromMySql): 1
date('I', $timestampFromPhp ): 1
difference: 0
* timestring : 2018-10-07 03:00:00
timestampFromMySql: 1538845200
timestampFromPhp : 1538841600
date('I', $timestampFromMySql): 1
date('I', $timestampFromPhp ): 1
difference: 3600
* timestring : 2018-10-07 04:00:00
timestampFromMySql: 1538848800
timestampFromPhp : 1538845200
date('I', $timestampFromMySql): 1
date('I', $timestampFromPhp ): 1
difference: 3600
Google 告诉我 2018 年墨尔本的夏令时将从 10 月 7 日星期日 2:00 am 开始,时钟将拨快一小时。所以 2018 年 10 月 7 日凌晨 2 点实际上与 2018 年 10 月 7 日凌晨 3 点是同一时间,因此我在上面的脚本输出中从 PHP 观察到的行为是预期的。 MySQL 的行为似乎不正确。
谁能告诉我如何确保 MySQL 拥有与夏令时相关的最新信息?
我还发现 mysql.time_zone 表都是空的。这是否意味着 MySQL 没有时区信息,或者是否意味着 MySQL 的时区信息来自操作系统?
已知 "feature" 的 UNIX_TIMESTAMP 函数在 MySQL
https://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html
Note: If you use UNIX_TIMESTAMP() and FROM_UNIXTIME() to convert
between TIMESTAMP values and Unix timestamp values, the conversion is
lossy because the mapping is not one-to-one in both directions. For
example, due to conventions for local time zone changes, it is
possible for two UNIX_TIMESTAMP() to map two TIMESTAMP values to the
same Unix timestamp value. FROM_UNIXTIME() will map that value back to
only one of the original TIMESTAMP values. Here is an example, using
TIMESTAMP values in the CET time zone:
解决方案 - 仅在 PHP 中使用时间函数,MySQL 仅用于存储(日期时间格式)
相关文档在这里:
https://dev.mysql.com/doc/refman/5.5/en/time-zone-upgrades.html
关键句子是:
"The operating system time affects the value that the MySQL server uses for times if its time zone is set to SYSTEM"
和
"If you use named time zones with MySQL, make sure that the time zone tables in the mysql database are up to date."
后面的文档指出,如果 mysql.time_zone_name table 为空,则没有人可以使用命名时区,并且您不需要更新 tables .
因此,要强制 MySQL 使用时区和夏令时的操作系统信息,请将时区设置为 'SYSTEM'。
此外,如果时区设置为 'SYSTEM',则无需填写 mysql.time_zone tables。
通过 运行 'SET time_zone="SYSTEM"' 将 MySQL 时区设置为 'SYSTEM' 后,我重新 运行 问题中的脚本并得到以下内容输出,显示 PHP 和 MySQL 的行为与预期相同。
date_default_timezone_get(): Australia/Melbourne
date('P'): +10:00
MySQL timezone: AUS Eastern Standard Time
* timestring : 2018-10-07 00:00:00
timestampFromMySql: 1538834400
timestampFromPhp : 1538834400
date('I', $timestampFromMySql): 0
date('I', $timestampFromPhp ): 0
difference: 0
* timestring : 2018-10-07 01:00:00
timestampFromMySql: 1538838000
timestampFromPhp : 1538838000
date('I', $timestampFromMySql): 0
date('I', $timestampFromPhp ): 0
difference: 0
* timestring : 2018-10-07 02:00:00
timestampFromMySql: 1538841600
timestampFromPhp : 1538841600
date('I', $timestampFromMySql): 1
date('I', $timestampFromPhp ): 1
difference: 0
* timestring : 2018-10-07 03:00:00
timestampFromMySql: 1538841600
timestampFromPhp : 1538841600
date('I', $timestampFromMySql): 1
date('I', $timestampFromPhp ): 1
difference: 0
* timestring : 2018-10-07 04:00:00
timestampFromMySql: 1538845200
timestampFromPhp : 1538845200
date('I', $timestampFromMySql): 1
date('I', $timestampFromPhp ): 1
difference: 0
我发现我程序中的一个错误是由 MySQL 的 UNIX_TIMESTAMP() 函数在给定相同值时向 PHP 的 strtotime() 返回不同的值引起的输入。
然后我发现错误发生的日期恰好是我所在时区夏令时生效的日期。
所以我需要知道为什么 PHP 知道夏令时开始日,但 MySQL 不知道。 PHP 和 MySQL 不应该都从操作系统中获取时区和夏令时信息吗?
操作系统是Windows7,根据Windows更新程序,它是最新的补丁。
这是我的代码:
// Checking timezones in MySQL and PHP.
echo "<pre>\n";
echo "date_default_timezone_get(): " . date_default_timezone_get() . "\n";
echo "date('P'): " . date('P') . "\n";
echo "MySQL timezone: " . $sqlObj->fetchField('SELECT IF(@@session.time_zone="SYSTEM", @@system_time_zone, @@session.time_zone)') . "\n";
// Testing MySQL and PHP conversion to unix timestamp for specific datetime values.
for ($hour = 0; $hour < 5; ++$hour)
{
$timeString = '2018-10-07 ' . (($hour < 10)? '0': '') . "$hour:00:00";
$timestampFromMySql = $sqlObj->fetchField('SELECT UNIX_TIMESTAMP(?)', array($timeString));
$timestampFromPhp = strtotime($timeString);
echo " * timestring : $timeString\n";
echo " timestampFromMySql: $timestampFromMySql\n";
echo " timestampFromPhp : $timestampFromPhp\n";
// Checking daylight savings status for the date in question in PHP.
echo " date('I', $timestampFromMySql): " . date('I', $timestampFromMySql) . "\n";
echo " date('I', $timestampFromPhp ): " . date('I', $timestampFromPhp ) . "\n";
echo " difference: " . ($timestampFromMySql - $timestampFromPhp) . "\n";
}
echo "</pre>\n";
这是输出。请注意,PHP 和 MySQL 在凌晨 3 点报告的 unix 时间出现 3600 秒或一小时的差异。
date_default_timezone_get(): Australia/Melbourne
date('P'): +10:00
MySQL timezone: +10:00
* timestring : 2018-10-07 00:00:00
timestampFromMySql: 1538834400
timestampFromPhp : 1538834400
date('I', $timestampFromMySql): 0
date('I', $timestampFromPhp ): 0
difference: 0
* timestring : 2018-10-07 01:00:00
timestampFromMySql: 1538838000
timestampFromPhp : 1538838000
date('I', $timestampFromMySql): 0
date('I', $timestampFromPhp ): 0
difference: 0
* timestring : 2018-10-07 02:00:00
timestampFromMySql: 1538841600
timestampFromPhp : 1538841600
date('I', $timestampFromMySql): 1
date('I', $timestampFromPhp ): 1
difference: 0
* timestring : 2018-10-07 03:00:00
timestampFromMySql: 1538845200
timestampFromPhp : 1538841600
date('I', $timestampFromMySql): 1
date('I', $timestampFromPhp ): 1
difference: 3600
* timestring : 2018-10-07 04:00:00
timestampFromMySql: 1538848800
timestampFromPhp : 1538845200
date('I', $timestampFromMySql): 1
date('I', $timestampFromPhp ): 1
difference: 3600
Google 告诉我 2018 年墨尔本的夏令时将从 10 月 7 日星期日 2:00 am 开始,时钟将拨快一小时。所以 2018 年 10 月 7 日凌晨 2 点实际上与 2018 年 10 月 7 日凌晨 3 点是同一时间,因此我在上面的脚本输出中从 PHP 观察到的行为是预期的。 MySQL 的行为似乎不正确。
谁能告诉我如何确保 MySQL 拥有与夏令时相关的最新信息?
我还发现 mysql.time_zone 表都是空的。这是否意味着 MySQL 没有时区信息,或者是否意味着 MySQL 的时区信息来自操作系统?
已知 "feature" 的 UNIX_TIMESTAMP 函数在 MySQL
https://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html
Note: If you use UNIX_TIMESTAMP() and FROM_UNIXTIME() to convert between TIMESTAMP values and Unix timestamp values, the conversion is lossy because the mapping is not one-to-one in both directions. For example, due to conventions for local time zone changes, it is possible for two UNIX_TIMESTAMP() to map two TIMESTAMP values to the same Unix timestamp value. FROM_UNIXTIME() will map that value back to only one of the original TIMESTAMP values. Here is an example, using TIMESTAMP values in the CET time zone:
解决方案 - 仅在 PHP 中使用时间函数,MySQL 仅用于存储(日期时间格式)
相关文档在这里: https://dev.mysql.com/doc/refman/5.5/en/time-zone-upgrades.html
关键句子是:
"The operating system time affects the value that the MySQL server uses for times if its time zone is set to SYSTEM"
和
"If you use named time zones with MySQL, make sure that the time zone tables in the mysql database are up to date."
后面的文档指出,如果 mysql.time_zone_name table 为空,则没有人可以使用命名时区,并且您不需要更新 tables .
因此,要强制 MySQL 使用时区和夏令时的操作系统信息,请将时区设置为 'SYSTEM'。
此外,如果时区设置为 'SYSTEM',则无需填写 mysql.time_zone tables。
通过 运行 'SET time_zone="SYSTEM"' 将 MySQL 时区设置为 'SYSTEM' 后,我重新 运行 问题中的脚本并得到以下内容输出,显示 PHP 和 MySQL 的行为与预期相同。
date_default_timezone_get(): Australia/Melbourne
date('P'): +10:00
MySQL timezone: AUS Eastern Standard Time
* timestring : 2018-10-07 00:00:00
timestampFromMySql: 1538834400
timestampFromPhp : 1538834400
date('I', $timestampFromMySql): 0
date('I', $timestampFromPhp ): 0
difference: 0
* timestring : 2018-10-07 01:00:00
timestampFromMySql: 1538838000
timestampFromPhp : 1538838000
date('I', $timestampFromMySql): 0
date('I', $timestampFromPhp ): 0
difference: 0
* timestring : 2018-10-07 02:00:00
timestampFromMySql: 1538841600
timestampFromPhp : 1538841600
date('I', $timestampFromMySql): 1
date('I', $timestampFromPhp ): 1
difference: 0
* timestring : 2018-10-07 03:00:00
timestampFromMySql: 1538841600
timestampFromPhp : 1538841600
date('I', $timestampFromMySql): 1
date('I', $timestampFromPhp ): 1
difference: 0
* timestring : 2018-10-07 04:00:00
timestampFromMySql: 1538845200
timestampFromPhp : 1538845200
date('I', $timestampFromMySql): 1
date('I', $timestampFromPhp ): 1
difference: 0