碳时区问题
Carbon timezone issues
当 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 如何处理时区的重要信息?
如果你想保留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
然后修改,最后将其转换成给定的时区-in这个上下文是 Australia/Brisbane
-
实际上,Carbon
作者在该函数中将时区重置为 UTC
的原因还不够清楚,但这就是问题的原因。
当 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 如何处理时区的重要信息?
如果你想保留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
然后修改,最后将其转换成给定的时区-in这个上下文是 Australia/Brisbane
-
实际上,Carbon
作者在该函数中将时区重置为 UTC
的原因还不够清楚,但这就是问题的原因。