如何比较 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' =&gt; 'Europe/Paris', 是个坏主意。当您想在用户的特定上下文中格式化或处理日期时,请参阅medium.com/@kylekatarnls/… Europe/Paris。否则使用 UTC 以不可知的方式处理时间。 在数据库中记录 DST 时区日期时间的主要问题是:当字符串 25 oct 2020 02h30(对于巴黎时区)时,您不知道是冬季时间还是夏季时间 2h30 .所以你应该为你的数据库和你的 Laravel 配置设置 UTC (GMT) 时区,以便它对齐,然后如果你需要在巴黎时间显示日期,很容易在 Carbon 实例上-&gt;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 更改时的日期的主要内容,如果未能解决你的问题,请参考以下文章

如何将字符串密码与 laravel 加密密码进行比较

laravel 单元测试设置模拟时间

laravel 单元测试设置模拟时间

opencv - 如何返回与比较矩阵相同类型的比较矩阵

R:如何在 ggplot 条形图中的右轴上添加标签?

c++中strcmp函数如何使用??