以下示例展示了日期/时间运算在 DST 转换和月份天数不同方面的一些陷阱。
示例 #1 DateTimeImmutable::add/sub 添加包含已过时间的间隔
在 DST 转换期间添加 PT24H 将显示为添加 23/25 小时(对于大多数时区)。
<?php
$dt = new DateTimeImmutable("2015-11-01 00:00:00", new DateTimeZone("America/New_York"));
echo "开始: ", $dt->format("Y-m-d H:i:s P"), PHP_EOL;
$dt = $dt->add(new DateInterval("PT3H"));
echo "结束: ", $dt->format("Y-m-d H:i:s P"), PHP_EOL;
?>
上面的示例将输出
Start: 2015-11-01 00:00:00 -04:00 End: 2015-11-01 02:00:00 -05:00
示例 #2 DateTimeImmutable::modify 和 strtotime 增加或减少单个组件值
在 DST 转换期间添加 +24 小时将添加正好 24 小时,如日期/时间字符串所示(除非开始或结束时间处于转换点)。
<?php
$dt = new DateTimeImmutable("2015-11-01 00:00:00", new DateTimeZone("America/New_York"));
echo "开始: ", $dt->format("Y-m-d H:i:s P"), PHP_EOL;
$dt = $dt->modify("+24 hours");
echo "结束: ", $dt->format("Y-m-d H:i:s P"), PHP_EOL;
?>
上面的示例将输出
Start: 2015-11-01 00:00:00 -04:00 End: 2015-11-02 00:00:00 -05:00
示例 #3 添加或减去时间可能会导致日期溢出或不足
例如,1 月 31 日 + 1 个月 将导致 3 月 2 日(闰年)或 3 月 3 日(平年)。
<?php
echo "平年:\n"; // 二月有 28 天
$dt = new DateTimeImmutable("2015-01-31 00:00:00", new DateTimeZone("America/New_York"));
echo "开始: ", $dt->format("Y-m-d H:i:s P"), PHP_EOL;
$dt = $dt->modify("+1 month");
echo "结束: ", $dt->format("Y-m-d H:i:s P"), PHP_EOL;
echo "闰年:\n"; // 二月有 29 天
$dt = new DateTimeImmutable("2016-01-31 00:00:00", new DateTimeZone("America/New_York"));
echo "开始: ", $dt->format("Y-m-d H:i:s P"), PHP_EOL;
$dt = $dt->modify("+1 month");
echo "结束: ", $dt->format("Y-m-d H:i:s P"), PHP_EOL;
?>
上面的示例将输出
Normal year: Start: 2015-01-31 00:00:00 -05:00 End: 2015-03-03 00:00:00 -05:00 Leap year: Start: 2016-01-31 00:00:00 -05:00 End: 2016-03-02 00:00:00 -05:00
要获取下一个月的最后一天(即防止溢出),可以使用 last day of
格式。
<?php
echo "平年:\n"; // 二月有 28 天
$dt = new DateTimeImmutable("2015-01-31 00:00:00", new DateTimeZone("America/New_York"));
echo "开始: ", $dt->format("Y-m-d H:i:s P"), PHP_EOL;
$dt = $dt->modify("last day of next month");
echo "结束: ", $dt->format("Y-m-d H:i:s P"), PHP_EOL;
echo "闰年:\n"; // 二月有 29 天
$dt = new DateTimeImmutable("2016-01-31 00:00:00", new DateTimeZone("America/New_York"));
echo "开始: ", $dt->format("Y-m-d H:i:s P"), PHP_EOL;
$dt = $dt->modify("last day of next month");
echo "结束: ", $dt->format("Y-m-d H:i:s P"), PHP_EOL;
?>
上面的示例将输出
Normal year: Start: 2015-01-31 00:00:00 -05:00 End: 2015-02-28 00:00:00 -05:00 Leap year: Start: 2016-01-31 00:00:00 -05:00 End: 2016-02-29 00:00:00 -05:00