我希望有人能帮上忙,我想问题可能是我在第二个for循环中覆盖了DateTime值,因为它没有输出正确的值,但不完全确定。
<?php
$begin_from = new DateTime( "2023-01-01" );
$end_from = new DateTime( "2023-12-31" );
$begin_to = new DateTime( "2023-01-31" );
$end_to = new DateTime( "2023-12-31" );
for($i = $begin_from; $i <= $end_from; $i->modify('+1 month')){
for($k = $begin_to; $k <= $end_to; $k->modify('first day of')->modify('+1 month')->modify('last day of')){
echo $i->format("Y-m-d"),'..',$k->format("Y-m-d");
echo "\n";
}
}
从上面的代码中输出:
2023-01-01..2023-01-31
2023-01-01..2023-02-28
2023-01-01..2023-03-31
2023-01-01..2023-04-30
2023-01-01..2023-05-31
2023-01-01..2023-06-30
2023-01-01..2023-07-31
2023-01-01..2023-08-31
2023-01-01..2023-09-30
2023-01-01..2023-10-31
2023-01-01..2023-11-30
2023-01-01..2023-12-31
但是,如果您单独运行这些for循环,您将得到如下所示的正确值。
2023-01-01..2023-01-31
2023-02-01..2023-02-28
2023-03-01..2023-03-31
2023-04-01..2023-04-30
2023-05-01..2023-05-31
2023-06-01..2023-06-30
2023-07-01..2023-07-31
2023-08-01..2023-08-31
2023-09-01..2023-09-30
2023-10-01..2023-10-31
2023-11-01..2023-11-30
2023-12-01..2023-12-31
有谁知道我哪里做错了吗?
4条答案
按热度按时间jq6vz3qz1#
我不知道为什么你的代码会产生这样的输出,但是可以使用
while
循环来简化它,你只需要在每个循环中手动修改一个日期,以及一个目标日期(对于不想改变的日期时间,建议使用DateTimeImmutable
)以上代码在PHP v7+中将生成以下内容:
PHP v5.6.40要求您在创建
DateTime
之前设置时区或默认时区(如date_default_timezone_set('UTC');
),但您会得到与上面相同的输出。Run it live here.
qmb5sa222#
要在@ArleighHix的答案这样的循环中使用datetime对象,我只需修改开始日期,并结合
01
和t
使用min()
和max()
的调用,以确保不超出日期边界。max()
和min()
在这种情况下是安全的,因为Y-m-d
是一种“big-endian”日期格式--这意味着可以将字符串作为简单字符串进行计算。代码:(Demo)
如果您的实际项目要求是每个月都有非完整的日期范围,那么重构方法将是必要的。如果这是一个真实的的问题/可能性,请编辑您的问题,提供一个更具挑战性的示例。
3z6pesqy3#
如果您的主要目标是输出给定日期范围内每个月的开始和结束日期(包括结束月份),则可以将此简化为:
如果您需要遵守
$from
和$to
日期,即;如果您需要第一个日期范围从$from
开始,最后一个日期范围从$to
结束,您可以使用max()
和min()
函数稍微调整上面的代码:dohp0rv54#
可变对象真的很难推理,特别是,你需要知道
$bar = $foo
使$bar
指向与$foo
相同的对象,而不是指向具有相同值的新对象。记住这一点,让我们“展开”循环(never write code like this!):
特别是,查看内部循环的开始和结束:
$k = $begin_to;
将使$k
指向与$begin_to
相同的对象$k->modify(...)
将修改该对象,这意味着$k
* 和 *$begin_to
都向前移动了一个月$k <= $end_to
,得到预期的结果$k = $begin_to;
,期望它 * 重置值 *;但是$k
和$begin_to
已经指向同一对象,该对象已经被修改;该赋值语句不执行任何操作$k <= $end_to
时,它已经是false了:我们根本就不会进入这个循环要实际复制对象的 value,可以使用
clone
keyword,例如$k = clone $begin_to;
但是,这种特殊情况就是创建the
DateTimeImmutable
class的原因。使用DateTimeImmutable
,您永远不会更改现有对象的值,而是始终将结果赋给某个位置。简而言之,将$i->modify(...)
替换为$i = $i->modify(...)
,将$k->modify(...)
替换为$k = $k->modify(...)
:这修复了for循环......但没有给予你想要的结果,因为如果你有两个嵌套循环,每个循环迭代12次,结果将是144次迭代--想象一下用12列12行填充一个网格。
实际上,我们需要的是一个 single 循环,它控制开始和结束日期,有几种方法可以编写它,但与现有代码最相似的可能是保留
$i
的循环,然后在此基础上定义$k
: