【问题标题】:MySQL daylight savings info seems to be incorrect. How can I ensure it is up to date in Windows?MySQL 夏令时信息似乎不正确。如何确保它在 Windows 中是最新的?
【发布时间】:2019-03-07 07:21:23
【问题描述】:

我发现我的程序中的一个错误是由 MySQL 的 UNIX_TIMESTAMP() 函数在给定相同的输入时向 PHP 的 strtotime() 返回不同的值引起的。

然后我发现错误发生的日期恰好是我所在时区夏令时生效的日期。

所以我需要知道为什么 PHP 知道夏令时开始日,而 MySQL 不知道。 PHP 和 MySQL 不都应该从操作系统获取它们的时区和夏令时信息吗?

操作系统是Windows 7,根据Windows Update程序,它是最新的补丁。

这是我的代码:

// 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 开始,时钟将提前一小时。因此,2018 年 10 月 7 日凌晨 2 点实际上与 2018 年 10 月 7 日凌晨 3 点相同,因此我在上面的脚本输出中从 PHP 观察到的行为是预期的。 MySQL 的行为似乎不正确。

谁能告诉我如何确保 MySQL 拥有与夏令时相关的最新信息?

我还发现 mysql.time_zone 表都是空的。这是说MySQL没有时区信息,还是说MySQL的时区信息来自操作系统?

【问题讨论】:

  • 通常建议使用公共时区将所有时间戳存储在数据库中,例如世界标准时间。这消除了数据库必须跟踪特定时区的负担。
  • 未来的好建议。在设计下一个数据库时,我会考虑采用这种方式。

标签: php mysql dst


【解决方案1】:

这是已知的 MySQL 中 UNIX_TIMESTAMP 函数的“特性”

https://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html

注意:如果你使用 UNIX_TIMESTAMP() 和 FROM_UNIXTIME() 来转换 在 TIMESTAMP 值和 Unix 时间戳值之间,转换为 有损,因为映射在两个方向上不是一对一的。为了 例如,由于本地时区更改的约定,它是 两个 UNIX_TIMESTAMP() 可以将两个 TIMESTAMP 值映射到 相同的 Unix 时间戳值。 FROM_UNIXTIME() 将该值映射回 只有原始 TIMESTAMP 值之一。这是一个例子,使用 CET 时区的 TIMESTAMP 值:

Walkaround - 仅在 PHP 中使用时间函数,MySQL 仅用于存储(日期时间格式)

【讨论】:

  • 我对该段的解释是,由于夏令时的变化,两个时间字符串实际上可能指的是同一时间。我们在上面的脚本输出中看到了 PHP 的这种行为。凌晨 2 点和凌晨 3 点的 unix 时间戳实际上是相同的,因为在凌晨 3 点,由于夏令时,时钟会向后移动一小时。我的问题是 MySQL 没有这样做,因为它似乎不知道夏令时从 2018 年 10 月 10 日凌晨 3 点开始。
【解决方案2】:

相关文档在这里: https://dev.mysql.com/doc/refman/5.5/en/time-zone-upgrades.html

关键句是:

"如果 MySQL 服务器的时区设置为 SYSTEM,操作系统时间会影响 MySQL 服务器使用的时间值"

“如果您在 MySQL 中使用命名时区,请确保 mysql 数据库中的时区表是最新的。”

随后的文档指出,如果 mysql.time_zone_name 表为空,则没有人可以使用命名时区,并且您不需要更新表。


因此,要强制 MySQL 将操作系统信息用于时区和夏令时,请将时区设置为“SYSTEM”。

此外,如果时区设置为“SYSTEM”,则无需填写 mysql.time_zone 表。


通过运行 '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

【讨论】:

猜你喜欢
  • 2011-09-30
  • 2019-03-26
  • 1970-01-01
  • 2017-09-25
  • 2019-08-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-03
相关资源
最近更新 更多