如何比较 DST 与 Laravel / Carbon 更改时的日期
Posted
技术标签:
【中文标题】如何比较 DST 与 Laravel / Carbon 更改时的日期【英文标题】:How to compare dates when DST is changing with Laravel / Carbon 【发布时间】:2020-12-14 04:44:06 【问题描述】:我有一个字段时间为 30 分钟的对象集合:
我正在扫描我的列表中的数据漏洞,这意味着在此列表中,它应该返回:
dataHoleStart: 2020-03-29 04:30
dataHoleEnd : 2020-03-29 08:30
今年 29 日我遇到了一个问题,因为那是我们更改 DST 的日子。
There is no hole:2020-03-29 01:00
There is no hole:2020-03-29 01:30
There is no hole:2020-03-29 03:00
There is no hole:2020-03-29 03:30
New hole: 2020-03-29 03:00
Existing hole: 2020-03-29 03:30
Existing hole: 2020-03-29 04:00
Existing hole: 2020-03-29 04:30
Existing hole: 2020-03-29 05:00
但是查看我的 Postgres 数据库,我可以看到数据很规律,没有漏洞。
这是我的代码:
foreach ($measures as $key => $measure)
if ($key == 0) continue;
$nextTS = (clone $ts_cursor)->addMinutes(30);
if ($measure->time->eq($nextTS))
$ts_cursor = $nextTS;
echo "There is no hole:". $measure->time->format('yy-m-d H:i'). "<br/>";
continue;
// Here we have a hole.
if ($missingDataIni != null)
// We are in an existing hole
$ts_cursor = $nextTS;
echo('Existing hole: ' .$measure->time->format('yy-m-d H:i'). "<br/>");
else
// We create a new hole
$missingDataIni = $nextTS;
$ts_cursor = $nextTS;
echo 'New hole: '.$measure->time->format('yy-m-d H:i'). "<br/>";
我尝试将 Carbon 字段转换为时间戳,但我仍然遇到同样的问题。
另外,在config/app.php
中,我的时区定义为:
'timezone' => 'Europe/Paris',
我应该如何处理日期比较,包括与Carbon
的夏令时?
【问题讨论】:
事实上在你的config/app.php
中使用'timezone' => 'Europe/Paris',
是个坏主意。当您想在用户的特定上下文中格式化或处理日期时,请参阅medium.com/@kylekatarnls/… Europe/Paris。否则使用 UTC 以不可知的方式处理时间。
在数据库中记录 DST 时区日期时间的主要问题是:当字符串 25 oct 2020 02h30(对于巴黎时区)时,您不知道是冬季时间还是夏季时间 2h30 .所以你应该为你的数据库和你的 Laravel 配置设置 UTC (GMT) 时区,以便它对齐,然后如果你需要在巴黎时间显示日期,很容易在 Carbon 实例上->tz('Europe/Paris')
。
我同意你关于不在 UTC 工作的观点。作为记录,我所有的数据库日期都是 UTC。但是要管理 DST,我必须使用时区,否则,我无法获得依赖于时区的转换
哦,你是对的,我最终将时区更改为 UTC
【参考方案1】:
我使用getTransitions
解决它
代码如下:
// We get the transition at timezone.
$transitions = collect($tz->getTransitions($start->format('U'), $end->format('U')))
->map(function ($transition) use ($tz)
return (new Carbon($transition['time']))->timezone($tz)->toAtomString();
)->toArray();
foreach ($measures as $key => $measure)
if ($key == 0) continue;
$nextTS = (clone $ts_cursor)->addMinutes(30);
if ($measure->time->timezone($tz)->eq($nextTS))
$ts_cursor = $nextTS;
echo "There is no hole:" . $measure->time->timezone($tz)->toAtomString() . "<br/>";
continue;
if (in_array($measure->time->timezone($tz)->toAtomString(), $transitions))
echo "Transition setting ts_cursor:".$ts_cursor->timezone($tz)->toAtomString(). "<br/>";
$ts_cursor = $ts_cursor->addMinutes(-30);
continue;
// Here we have a hole.
if ($missingDataIni != null)
// We are in an existing hole
echo('Existing hole: ' . $measure->time->timezone($tz)->toAtomString() . "<br/>");
$ts_cursor = $nextTS;
else
// We create a new hole
$ts_cursor = $nextTS;
$missingDataIni = $ts_cursor;
echo 'New hole: ' . $ts_cursor->timezone($tz)->toAtomString() . "<br/>";
【讨论】:
以上是关于如何比较 DST 与 Laravel / Carbon 更改时的日期的主要内容,如果未能解决你的问题,请参考以下文章