【问题标题】:Laravel SQLSTATE[22007]: Invalid datetime format: 1292 Incorrect datetime value: '2019-03-10 02:00:39' for column 'updated_at' (daylight savings?)Laravel SQLSTATE [22007]:无效的日期时间格式:1292 不正确的日期时间值:“updated_at”列的“2019-03-10 02:00:39”(夏令时?)
【发布时间】:2019-07-31 17:16:04
【问题描述】:

我正在使用队列工作者开发一个 Laravel 应用程序,但它刚刚开始失败并向日志中抛出一个恒定的异常流。这是其中之一:

SQLSTATE[22007]: Invalid datetime format: 1292 Incorrect datetime value: '2019-03-10 02:00:39' for column 'updated_at' at row 1 (SQL: update `videos` set `updated_at` = 2019-03-10 02:00:39 where `id` = 30860) 

需要注意的几点:

  • 时间戳似乎格式正确
  • 该列是 MySQL TIMESTAMP 类型(可为空),使用 InnoDB
  • updated_at 字段由 Laravel 默认管理,没有任何自定义日期格式发生
  • 我没有使用任何日期修改器,也没有使用任何会在保存之前更改值的东西
  • 此代码已经运行了数周,没有任何问题
  • 最近没有更改代码
  • 我执行了git checkout .composer install 以确保没有任何库文件已更改或以某种方式损坏(没有更改)
  • 错误首次出现在2019-03-10 02:00:39 (UTC),即当地时间晚上 8 点(中部时间)

明尼苏达州 2019 年夏令时将于凌晨 2:00 开始 3 月 10 日星期日

-- 谷歌

我可以在谷歌上找到的所有内容都与使用明显错误的时间格式的人有关,所以这并没有帮助我弄清楚。

我觉得在夏令时应该在美国中部时间 02:00 开始的同一天 UTC 02:00 开始的错误之间有太多的巧合,但我不知道为什么当时间戳由框架管理并在保存之前转换为 UTC 时会引发此错误(并且 UTC 不会因夏令时而改变)。

MySQL 5.5.45
Laravel 5.7.28
nesbot/碳 1.36.2
PHP 7.2.7

config/database.php:

'mysql' => [
    
    'charset' => 'utf8',
    'collation' => 'utf8_unicode_ci',
    'prefix' => '',
    'strict' => true,
    'engine' => null,
],

什么可能导致日期值被识别为无效?

编辑:我确定这绝对是夏令时错误,因为时钟快进 1 小时,并且 02:00 和 03:00 之间的时间在美国中部时间无效。我不明白为什么设置为 UTC 的应用程序上的 TIMESTAMP 字段会引发错误? UTC 如何受到夏令时的影响,当时间戳由框架(Laravel+Carbon)管理时,我该怎么做才能防止这种情况发生?

【问题讨论】:

  • 您应该编辑您的previous question 而不是发布新的。您在此网站上拥有多个用户名吗?
  • 嗨蒂姆,感谢您抽出宝贵时间回复!但是,我没有发布这个问题。
  • 另外,您的错误消息似乎来自 SQL Server,而不是 MySQL。
  • @TimBiegeleisen 这是来自 Laravel 的 Illuminate\Database\QueryException,我可以向您保证,它是问题中所述的 MySQL 5.5.45。我认为包含完整的堆栈跟踪不会有太大帮助,因为异常是由我显示的数据库错误引发的。
  • 如果 MySQL 有某种严重的 DST 错误现在才出现,那将会非常“有趣”。

标签: mysql laravel


【解决方案1】:

我发现问题是由于我的 MySQL 服务器的 time_zone 设置被设置为 SYSTEM (我的系统是美国中部)。 Laravel 提供的时间戳已经转换为 UTC,但由于time_zone 设置,我的数据库将它们解释为美国中部。时间实际上正在由 MySQL 在内部 再次 转换为“真正的”UTC unix 时间戳表示(这将是不正确的,因为它被时区偏移),即使它们似乎已经在每个查询,因为它们还会再次转换回美国中部进行阅读(我知道是对的)。

因此,在当地时间 20:00:39(晚上 8:00),我的 Laravel UTC 时间戳为 02:00:39。 MySQL 将这些时间解释为美国中部时间,并且因为时间在 02:00 和 03:00 之间(美国中部的时钟向前跳),所以时间无效。

Laravel 应用程序的最佳解决方案是强制每个数据库连接使用 +00:00 时区(或您在 config/app.php 中设置的应用程序时区),这样就不会发生二次转换。这可以在config/database.php 中完成:

'mysql' => [
    // ...

    'timezone'  => '+00:00'
],

这样,如果数据库服务器的配置时区与您的 Laravel 应用程序不同,您就不会受到数据库服务器的摆布。另一种选择是更改数据库的time_zone 设置,但是如果您更改主机或出于任何原因需要重建服务器(并且不要再次正确配置时区)或影响其他服务器上的数据库。

重要说明:由于 MySQL 在内部将所有以前的时间戳从配置的时区偏移到 UTC unix 时间戳(这又是错误的,因为记录已经是 UTC),因此可能需要运行数据迁移更正旧的时间戳。我没有进一步调查,因为对于我的应用程序,旧时间戳是否有几个小时的错误并不重要。

【讨论】:

  • 谢谢你一千遍!
  • 哈。我遇到了同样的问题,但是当我解决问题时已经过了一个小时,我有一整年的时间来解决它。直到一年后,同样的事情再次发生。老实说,这似乎是一个错误,因为不应该发生第二次转换。但是您的解决方案效果很好。我还将服务器时钟设置为 UTC,然后重新启动 MySQL。
  • @Gazzer 这些更改是否真的修复了您的旧时间戳? MySQL 保存的“真实”unix 时间戳将被您的应用程序时区和数据库时区之间的差异所抵消。我认为修复这个问题需要数据迁移来纠正偏移量,但我从来没有费心去检查,因为在我的应用程序中,我只是不在乎旧记录是否在 6 小时内出错。
  • 哇,非常感谢。这解决了我的问题!
  • @Gazzer 我的理解是,对于 TIMESTAMP 类型,MySQL 会将它们从连接时区转换为 UTC,然后在内部将它们保存为 unix 时间戳。由于 Laravel 提供的 values 是 UTC 而 connection 不是,所以 MySQL 认为现在是 UTC 的内部时间戳实际上是错误的。如果您在它们设置的同一时区中读取值,一切都会看起来很好,但是如果您突然更改连接时区,那么 MySQL 为您所做的转换最终会得到错误的值。如果正确性对您的应用很重要,我会三重检查。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-12-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多