duankang5882 2017-04-05 06:50
浏览 50
已采纳

碳时区问题

I am having issues with Carbon and timezones when the timezone set by date_default_timezone_set() differs from the timezone Carbon is using.

In the example below, I have a while loop that adds a month and reverts to the start of that month until the $end_date is greater than $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() . "
";
   $current_date->addMonth()->startOfMonth();
}

As you can see the output is correct.

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

As soon as I change the default timezone to UTC I get an infinite loop. For the sake of this example, I've adjusted the code to stop after 10 loops:

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() . "
";
   $current_date->addMonth()->startOfMonth();
   $x++;
   if ($x === 10)
       break;
}

And here is the output.

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

My expectation is that because I am passing Australia/Brisbane as the timezone for $start_date and $end_date there shouldn't be any issue here.

Finally, if I rebuild my code to use DateTime instead of Carbon, I have no problem.

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') . "
";
    $current_date->add(new DateInterval('P1M'));
    $current_date->modify('first day of this month');
}

Have I missed something vital to how Carbon handles timezones?

  • 写回答

1条回答 默认 最新

  • douju5062 2017-04-05 11:27
    关注

    if you want to keep Carbon structure , you may use add function directly as follows :

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

    Update

    The following method is the method that's addMonth method uses to increments the current date by one month

    /**
     * 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;
    }
    

    As you can see, this function reset so to speak the timezone to UTC before modifying your date then modify , and finally convert it into the given timezone -in this context it is a Australia/Brisbane-

    Actually It's not clear enough why Carbon authors resets the timezone to UTC in that function but this is the cause of your issue.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥20 软件测试决策法疑问求解答
  • ¥15 win11 23H2删除推荐的项目,支持注册表等
  • ¥15 matlab 用yalmip搭建模型,cplex求解,线性化处理的方法
  • ¥15 qt6.6.3 基于百度云的语音识别 不会改
  • ¥15 关于#目标检测#的问题:大概就是类似后台自动检测某下架商品的库存,在他监测到该商品上架并且可以购买的瞬间点击立即购买下单
  • ¥15 神经网络怎么把隐含层变量融合到损失函数中?
  • ¥15 lingo18勾选global solver求解使用的算法
  • ¥15 全部备份安卓app数据包括密码,可以复制到另一手机上运行
  • ¥20 测距传感器数据手册i2c
  • ¥15 RPA正常跑,cmd输入cookies跑不出来