【问题标题】:Carbon timezone issues碳时区问题
【发布时间】:2017-08-30 15:11:55
【问题描述】:

date_default_timezone_set() 设置的时区与 Carbon 使用的时区不同时,我遇到了 Carbon 和时区问题。

在下面的示例中,我有一个 while 循环,它添加一个月并恢复到该月的开始,直到 $end_date 大于 $current_date

date_default_timezone_set('Australia/Brisbane');

$tz = new DateTimeZone('Australia/Brisbane');

$start_date = \Carbon\Carbon::instance(new DateTime('2019-03-01 00:00:00', $tz));
$end_date = \Carbon\Carbon::instance(new DateTime('2021-03-21 23:59:00', $tz));

$current_date = $start_date->copy();

while ($end_date->gte($current_date)) {
   echo $current_date->toDateTimeString() . "\n";
   $current_date->addMonth()->startOfMonth();
}

如您所见,输出是正确的。

2019-03-01 00:00:00
2019-04-01 00:00:00
2019-05-01 00:00:00
2019-06-01 00:00:00
2019-07-01 00:00:00
2019-08-01 00:00:00
2019-09-01 00:00:00
2019-10-01 00:00:00
2019-11-01 00:00:00
2019-12-01 00:00:00
2020-01-01 00:00:00

一旦我将默认时区更改为UTC,我就会得到一个无限循环。为了这个例子,我将代码调整为在 10 次循环后停止:

date_default_timezone_set('UTC'); // <---- Changed to UTC

$tz = new DateTimeZone('Australia/Brisbane');

$start_date = \Carbon\Carbon::instance(new DateTime('2019-03-01 00:00:00', $tz));
$end_date = \Carbon\Carbon::instance(new DateTime('2021-03-21 23:59:00', $tz));

$current_date = $start_date->copy();

$x = 0;
while ($end_date->gte($current_date)) {
   echo $current_date->toDateTimeString() . "\n";
   $current_date->addMonth()->startOfMonth();
   $x++;
   if ($x === 10)
       break;
}

这是输出。

2019-03-01 00:00:00
2019-03-01 00:00:00
2019-03-01 00:00:00
2019-03-01 00:00:00
2019-03-01 00:00:00
2019-03-01 00:00:00
2019-03-01 00:00:00
2019-03-01 00:00:00
2019-03-01 00:00:00
2019-03-01 00:00:00

我的期望是,因为我将Australia/Brisbane 作为$start_date$end_date 的时区传递,所以这里应该没有任何问题。

最后,如果我重建我的代码以使用 DateTime 而不是 Carbon,我没有问题。

date_default_timezone_set('UTC');

$tz = new DateTimeZone('Australia/Brisbane');

$start_date = new DateTime('2019-03-01 00:00:00', $tz);
$end_date = new DateTime('2020-03-21 23:59:00', $tz);

$current_date = clone $start_date;

while ($current_date->getTimestamp() < $end_date->getTimestamp()) {
    echo $current_date->format('Y-m-d H:i:s') . "\n";
    $current_date->add(new DateInterval('P1M'));
    $current_date->modify('first day of this month');
}

我是否遗漏了一些对 Carbon 处理时区至关重要的东西?

【问题讨论】:

    标签: php datetime timezone php-carbon


    【解决方案1】:

    如果要保留Carbon结构,可以直接使用add函数,如下:

    $x = 0;
    while ($end_date->gte($current_date)) {
       echo $current_date->toDateTimeString() . "\n";
       $current_date->add(new \DateTimeinterval('P1M'))->startOfMonth();
       $x++;
       if ($x === 10)
           break;
    }
    

    更新

    以下方法是addMonth 方法用于将当前日期增加一个月的方法

    /**
     * Consider the timezone when modifying the instance.
     *
     * @param string $modify
     *
     * @return static
     */
    public function modify($modify)
    {
        if ($this->local) {
            return parent::modify($modify);
        }
    
        $timezone = $this->getTimezone();
        $this->setTimezone('UTC');
        $instance = parent::modify($modify);
        $this->setTimezone($timezone);
    
        return $instance;
    }
    

    如您所见,这个函数 reset 可以说是 UTC 在修改您的日期然后修改之前的时区,最后将其转换为给定的时区 -在这种情况下它是一个 Australia/Brisbane -

    实际上,Carbon 作者在该函数中将时区重置为UTC 的原因还不够清楚,但这是您的问题的原因。

    【讨论】:

    • 谢谢!你救了我几个小时!我可能会在他们的 repo 上打开一个问题,看看他们怎么说。
    猜你喜欢
    • 1970-01-01
    • 2017-11-28
    • 1970-01-01
    • 2020-08-20
    • 2019-01-25
    • 2015-04-20
    • 1970-01-01
    • 2016-11-08
    • 1970-01-01
    相关资源
    最近更新 更多