我遇到了一个有趣的案例,与diff()
类的DateTime
方法有关。
如果我尝试计算像月一样的两个日期之间的差异
$datetime1 = new \DateTime('June 2019');
$datetime2 = new \DateTime('July 2019');
$interval = $datetime1->diff($datetime2);
echo $interval->format('%m');
,结果我得到0
。
为什么会这样?
Print_r的:
$ datetime1:
DateTime Object ( [date] => 2019-06-01 00:00:00.000000
[timezone_type] => 3 [timezone] => Europe/Berlin )
$ datetime2:
DateTime Object ( [date] => 2019-07-01 00:00:00.000000
[timezone_type] => 3 [timezone] => Europe/Berlin )
$ interval:
DateInterval Object ( [y] => 0 [m] => 0 [d] => 30 [h] => 0 [i] => 0 [s] => 0 [f] => 0
[weekday] => 0 [weekday_behavior] => 0 [first_last_day_of] => 0
[invert] => 0 [days] => 30 [special_type] => 0 [special_amount] => 0
[have_weekday_relative] => 0 [have_special_relative] => 0 )
答案 0 :(得分:2)
这似乎是一个错误(就日期时间格式被强制为GMT *偏移量according to this comment而言)。
*(但强制执行GMT似乎与下面的代码确定的结果不一致)
将服务器时区值设置为任何时区都不会影响此脚本时区异常。
以下两种情况显示了在不同时区发生的情况:
以下代码将输出每个时区的结果列表:
$tzList = DateTimeZone::listIdentifiers(DateTimeZone::ALL);
print "Current Zone:". print_r(ini_get('date.timezone'),true)."<br>\n<BR>\n";
foreach($tzList as $tzRow) {
$tz = new DateTimeZone($tzRow);
//$tz = null;
$datetime1 = new \DateTime('June 2019', $tz);
$datetime2 = new \DateTime('July 2019', $tz);
$interval = $datetime1->diff($datetime2, false);
echo $interval->format('%a %m') . PHP_EOL. " :: ";
print print_r($datetime1->getTimezone(),true)."<BR>";
}
此列表输出的结果显示0
和其余1
月的高(〜60%)率。
请在此处查看:http://sandbox.onlinephpfunctions.com/code/b18ba13deb94d112b12630a12265363fb6c7670b
在创建对象后设置时区,会得到一致的答案(尽管不正确)
$tzList = DateTimeZone::listIdentifiers(DateTimeZone::ALL);
print "Current Zone:". print_r(ini_get('date.timezone'),true)."<br>\n<BR>\n";
foreach($tzList as $tzRow) {
//$tz = new DateTimeZone($tzRow);
$tz = null;
$datetime1 = new \DateTime('June 2019', $tz);
$datetime2 = new \DateTime('July 2019', $tz);
$datetime1->setTimezone(new DateTimeZone($tzRow));
$datetime2->setTimezone(new DateTimeZone($tzRow));
$interval = $datetime1->diff($datetime2, false);
echo $interval->format('%a %m') . PHP_EOL. " :: ";
print print_r($datetime1->getTimezone(),true)."<BR>";
}
此输出在30天后全部全部生成;但所有相差0个月。
在此处查看代码:http://sandbox.onlinephpfunctions.com/code/7bcc62f4e36f41df71b9cb928de75a53f233d9fd
因此,如果要使用有时正确的结果或普遍不正确的而是一致的结果,这是您的选择,方法是设置时间,以便在DateTime对象中建立时区值。
如果服务器时区正确设置为UTC“正确”时区(自然会在Case 1
中返回“ 1”月,则上述 CASE 2 在指定给DateTime对象。
答案 1 :(得分:1)
您可以通过添加时区来尝试吗?
$timezones = [
'UTC',
'Europe/Berlin',
'America/Belize',
'Asia/Hong_Kong',
];
foreach ($timezones as $timezone) {
$tz = new DateTimeZone($timezone);
$datetime1 = new \DateTime('June 2019', $tz);
$datetime2 = new \DateTime('July 2019', $tz);
$interval = $datetime1->diff($datetime2);
echo str_pad($timezone, 20, ' ').' '.$interval->format('months: %M, day: %D, days: %a') . PHP_EOL;
}
结果:
UTC months: 01, day: 00, days: 30
Europe/Berlin months: 00, day: 30, days: 30
America/Belize months: 01, day: 00, days: 30
Asia/Hong_Kong months: 00, day: 30, days: 30
答案 2 :(得分:1)
问题出在您所在的时区。
有一篇关于here的说明。
请参见以下示例:
<?php
echo "----- Europe/Berlin -----\n";
date_default_timezone_set('Europe/Berlin');
$datetime1 = new \DateTime('June 2019');
$datetime2 = new \DateTime('July 2019');
print_r($datetime1);
print_r($datetime2);
$interval = $datetime1->diff($datetime2);
print_r($interval);
echo "%m = " . $interval->format('%m') . PHP_EOL;
echo "%a = " . $interval->format('%a') . PHP_EOL;
echo "%s = " . $interval->format('%s') . PHP_EOL;
echo "\n\n\n----- America/Sao_Paulo -----\n";
date_default_timezone_set('America/Sao_Paulo');
$datetime1 = new \DateTime('June 2019');
$datetime2 = new \DateTime('July 2019');
print_r($datetime1);
print_r($datetime2);
$interval = $datetime1->diff($datetime2);
print_r($interval);
echo "%m = " . $interval->format('%m') . PHP_EOL;
echo "%a = " . $interval->format('%a') . PHP_EOL;
echo "%s = " . $interval->format('%s') . PHP_EOL;
输出:
$ php date_diff.php
----- Europe/Berlin -----
DateTime Object
(
[date] => 2019-06-01 00:00:00.000000
[timezone_type] => 3
[timezone] => Europe/Berlin
)
DateTime Object
(
[date] => 2019-07-01 00:00:00.000000
[timezone_type] => 3
[timezone] => Europe/Berlin
)
DateInterval Object
(
[y] => 0
[m] => 0
[d] => 30
[h] => 0
[i] => 0
[s] => 0
[f] => 0
[weekday] => 0
[weekday_behavior] => 0
[first_last_day_of] => 0
[invert] => 0
[days] => 30
[special_type] => 0
[special_amount] => 0
[have_weekday_relative] => 0
[have_special_relative] => 0
)
%m = 0
%a = 30
%s = 0
----- America/Sao_Paulo -----
DateTime Object
(
[date] => 2019-06-01 00:00:00.000000
[timezone_type] => 3
[timezone] => America/Sao_Paulo
)
DateTime Object
(
[date] => 2019-07-01 00:00:00.000000
[timezone_type] => 3
[timezone] => America/Sao_Paulo
)
DateInterval Object
(
[y] => 0
[m] => 1
[d] => 0
[h] => 0
[i] => 0
[s] => 0
[f] => 0
[weekday] => 0
[weekday_behavior] => 0
[first_last_day_of] => 0
[invert] => 0
[days] => 30
[special_type] => 0
[special_amount] => 0
[have_weekday_relative] => 0
[have_special_relative] => 0
)
%m = 1
%a = 30
%s = 0
在我的时区$interval->format('%m');
中是1。
您可以在日期上设置时区,以计算它们之间的时差。
$datetime1 = new \DateTime('June 2019', new DateTimeZone('UTC'));
$datetime2 = new \DateTime('July 2019', new DateTimeZone('UTC'));
$interval = $datetime1->diff($datetime2);
print_r($interval);
echo "%m = " . $interval->format('%m') . PHP_EOL;
$ php date_diff.php
DateInterval Object
(
[y] => 0
[m] => 1
[d] => 0
[h] => 0
[i] => 0
[s] => 0
[f] => 0
[weekday] => 0
[weekday_behavior] => 0
[first_last_day_of] => 0
[invert] => 0
[days] => 30
[special_type] => 0
[special_amount] => 0
[have_weekday_relative] => 0
[have_special_relative] => 0
)
%m = 1