Laravel SQLSTATE[22007]:无效的日期时间格式:1292 不正确的日期时间值:'2019-03-10 02:00:39'列'updated_at'(夏令时?)

Tra*_*itz 7 mysql laravel

我正在使用队列工作器处理 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) 
Run Code Online (Sandbox Code Playgroud)

需要注意的几点:

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

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

- 谷歌

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

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

MySQL 5.5.45
Laravel 5.7.28
nesbot/carbon 1.36.2
PHP 7.2.7

配置/数据库.php:

'mysql' => [
    
    'charset' => 'utf8',
    'collation' => 'utf8_unicode_ci',
    'prefix' => '',
    'strict' => true,
    'engine' => null,
],
Run Code Online (Sandbox Code Playgroud)

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

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

Tra*_*itz 12

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

因此,在当地时间 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'
],
Run Code Online (Sandbox Code Playgroud)

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

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