Laravel Carbon不考虑时区的夏令时

6
根据我的 UsersTableSeeder.php 类,我正在使用循环种植假数据来填充我的数据库:
$numberOfUsers = 150;

DB::table('users')->delete();

$faker = Faker::create();

for ($i = 1; $i <= $numberOfUsers; $i++) {
    DB::table('users')->insert([
        'id' => $i,
        'firstName' => $faker->firstName,
        'lastName' => $faker->lastName,
        'email' => $faker->email,
        'password' => bcrypt("123"),
        'created_at' => Carbon::now()->addDays((-5 * $i) - 2)->format('Y-m-d H:i:s'),
        'updated_at' => Carbon::now()->addDays(-5 * $i)->format('Y-m-d H:i:s'),
    ]);
}

问题在于,当我的日期时间值生成时,有可能会落在夏令时区域,比如在 2017-03-12 02:00:00 和 2017-03-12 02:59:59 之间(这确实会发生),这将导致以下错误:

[PDOException]
SQLSTATE[22007]: Invalid datetime format: 1292 Incorrect datetime value: '2016-03-13 02:08:11' for column 'created_at' at row 1

现在我明白了,我的数据库不能存储这样的值,因为我的数据库足够聪明,知道这个时间区间并不存在。但是有没有办法让Carbon变得聪明起来,考虑到夏令时?我不想使用类似以下的方式手动检查:

if ($my_date > 2017-03-12 02:00:00 && $my_date < 2017-03-12 02:59:59)

你尝试过使用 Carbon::now('Asia/Tokyo')->addDays((-5 * $i) - 2)->format('Y-m-d H:i:s') 吗? - linktoahref
为什么需要格式化日期字符串,只需传递 Carbon 对象即可,它将使用设置中的时区。 - Jorge Y. C. Rodriguez
2个回答

4
事实上,Carbon可以处理夏令时区域。
$date = '2017-03-26 02:01:01';
$date = \Carbon\Carbon::parse($date, 'Europe/Berlin');
dd((string)$date);

结果在

// an extra hour was added automatically
"2017-03-26 03:01:01"

默认情况下,Laravel在所有日期和时间操作(包括Carbon)中使用“UTC”。可以在app/config.php中设置该值。

如果您希望数据库中实际上将日期时间视为“UTC”,则可以采用类似以下方式的不可靠解决方法:

编辑:

// calculate current offset to UTC:
$offset = \Carbon\Carbon::now('America/Montreal')->offsetHours;

'created_at' => Carbon::now('America/Montreal')->addHours(-4 + $i)->addDays((-1 * $i) - 2)->tz('UTC')->addHours($offset)->format('Y-m-d H:i:s')

1
因为默认时区是UTC,而UTC不知道夏令时。生成的时间在UTC中完全有效,但可能是其他时区无效的时间。 - shock_gone_wild
你是否使用自己的时区而不是'Europe/Berlin'? - shock_gone_wild
是的,我用了Carbon::now('America/Montreal')->tz('UTC')->addHours(-4 + $i)->addDays((-1 * $i) - 2)->format('Y-m-d H:i:s') - Antoine
2
抱歉,我的逻辑出错了...你还需要添加UTC偏移量。请看我的编辑答案。我已经测试过它,对我有效。 - shock_gone_wild
抱歉,当我使用'created_at' => Carbon::now('America/Montreal')->addHours($hours * $i)->addDays(($days * $i) - 2)->tz('UTC')->addHours($offset)->format('Y-m-d H:i:s')来填充我的数据库时,仍然出现错误。 - Antoine
显示剩余3条评论

2
您可以使用Carbon生成您的时间戳,并提供时区。只需尝试以下内容:
Carbon::now()->format('c')

好的建议,谢谢。但是我会因为2017-04-14T02:36:34+00:00不是我的数据库所期望的格式,并且它是在UTC而不是我的本地时间,所以我会出现错误。 - Antoine

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接