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