更改了laravel应用程序时区,从db获取的时间未更改

更改了laravel应用程序时区,从db获取的时间未更改,laravel,timezone,php-carbon,Laravel,Timezone,Php Carbon,假设有一个名为Request的雄辩模型,列next_check autocasted为date(protected$dates=['next_check'];) APP_时区为初始欧洲/赫尔辛基(+02:00) 看起来一切都很好,假设我们在赫尔辛基,我们节省了14:17:04的时间 现在将时区更改为欧洲/柏林(+01:00),我假设返回13:17:04 >>> Request::find(1)->next_check; => Illuminate\Support\C

假设有一个名为Request的雄辩模型,列next_check autocasted为date(protected$dates=['next_check'];)

APP_时区为初始欧洲/赫尔辛基(+02:00)

看起来一切都很好,假设我们在赫尔辛基,我们节省了14:17:04的时间

现在将时区更改为欧洲/柏林(+01:00),我假设返回13:17:04

>>> Request::find(1)->next_check;
=> Illuminate\Support\Carbon @1603977424 {#2900
     date: 2020-10-29 14:17:04.0 Europe/Berlin (+01:00),
   }
时区已更改,但仍有返回的时间,该时间最初保存在欧洲/赫尔辛基时间

这是一种预期的行为吗?我如何获得预期的行为,即改变应用程序时区将导致转换时间


p、 美国:在laravel中配置的db时区仍然是默认的“+00:00”

如果您想本地化时间,以便它们在用户时区中显示给用户,则需要转换现有日期时间:

$users_timezone = 'Europe/Berlin';
$datetime->setTimezone($users_timezone);

这实际上会根据应用程序的时区与转换为的时区之间的差异来更改时间。

为了获得我的预期行为,我现在找到了一个解决方案。如果其他任何人想要完全相同的行为,这可能是解决方案:

在AppServiceProvider的引导方法中添加以下调用:

$this->setUTCOffsetInDBConnection();
setUTCOffsetInDBConnection方法的代码如下所示:

// according to https://www.sitepoint.com/synchronize-php-mysql-timezone-configuration/
private function setUTCOffsetInDBConnection() {

    $now = new \DateTime();
    $mins = $now->getOffset() / 60;

    $sgn = ($mins < 0 ? -1 : 1);
    $mins = abs($mins);
    $hrs = floor($mins / 60);
    $mins -= $hrs * 60;

    $offset = sprintf('%+d:%02d', $hrs*$sgn, $mins);

    DB::statement("SET time_zone='".$offset."';");
}
//根据https://www.sitepoint.com/synchronize-php-mysql-timezone-configuration/
私有函数setUTCOffsetInDBConnection(){
$now=new\DateTime();
$mins=$now->getOffset()/60;
$sgn=($mins<0?-1:1);
$mins=绝对值($mins);
$hrs=楼层(分钟/60美元);
$mins-=$hrs*60;
$offset=sprintf('%+d:%02d',$hrs*$sgn,$min);
语句(“设置时区=”。$offset.“;”;
}
这将始终根据应用程序的时区同步时区,并将时间戳保存为数据库中的UTC

当您现在在.env中使用app_TIMEZONE=Europe/Berlin从应用程序中保存时间戳2020-10-29 15:28:00时,它将在数据库中保存为UTC(2020-10-29 15:28:00)。 当您现在将应用程序_时区更改为欧洲/赫尔辛基时,您将返回2020-10-29 16:28:00

>>> Request::find(1)->next_check;
=> Illuminate\Support\Carbon @1603977424 {#2900
     date: 2020-10-29 14:17:04.0 Europe/Berlin (+01:00),
   }
请注意,您的phpMyAdmin可能仍然不会在数据库中显示保存的UTC时间,因为phpMyAdmin在打开连接时也会设置服务器时区。因此,如果运行phpMyAdmin的服务器也在欧洲/柏林,您将看到2020-10-29 15:28:00,而不是数据库中保存的UTC日期。

对“这是预期行为”的回答是

要用日期数据“保存”时区,还必须将其另存为一个额外的列

因此,在DB中同时使用“2020-10-29 14:17:04.0”和“欧洲/赫尔辛基”将允许您记住保存此日期所使用的时区,因此如果更改了,您可以转换

<>但是首先你应该考虑不改变你的应用程序和数据库时区,都应该保持UTC。< /P> 看


因此,您可以轻松地将其转换为任何时区,并根据用户时区正确显示,同时保留标准的众所周知的DB格式。

谢谢您的回复。是的,我的意思是我改变了配置中的时区。我不需要知道,记录保存在哪个时区。据我所知,时间将保存为mysql时间戳数据类型中的UTC时间戳。因此,当我更改配置时区时,我会假设访问该字段的时间会更改。所以在我的例子13:17+01:00而不是14:17+02:00啊,是的,我明白了。这是因为时间本身并没有改变-你只是把它放在一个不同的时区,所以唯一改变的是。。。是时区。你需要实现什么?你想根据用户当前的时区向他们显示不同的日期/时间吗?事实上,我问了这个问题是为了更好地理解Laravel中的时区处理,并且相信时间,我明白了。当我的应用程序处于+02:00时,我将时间戳保存到数据库中,它应在内部保存为UTC时间戳。我在phpMyAdmin中看到的另一个时间是由于时区配置。但是现在,当我使用应用程序时区+01:00获取时间时,它不应该从数据库UTC时间戳转换为我的应用程序时区吗?事实上,它只是添加了一个时区而没有转换时间,这让我对该数据没有信心,我正在考虑是否应该切换到datetime字段?也许laravel不认为时间戳总是在UTC中,而是在应用程序时区中?因此,在更改应用程序时区时,我需要始终更改数据库时区?您不能使用现有日期更改数据库时区。请考虑在后端使用UTC,这就是方法。赫尔辛基/柏林时区应该为用户设置格式。不要使用时区偏移,它将在其他DST季节的日期中被打破。