【问题标题】:Find dates between 2 dates with custom interval and without overflow查找具有自定义间隔且没有溢出的 2 个日期之间的日期
【发布时间】:2020-11-08 05:09:33
【问题描述】:

我有一个可自定义的 DateInterval 对象,以及一个可自定义的开始和结束日期。我想使用间隔查找开始和结束之间的日期。我正在使用 Carbon 来帮助解决这个问题。

问题来了: 我的间隔是???月,但开始日期 > 28 我无法使用 CarbonPeriod 控制溢出。

这是我正在测试的代码:

$di = CarbonInterval::create('P1M');
$start = Carbon::parse('31 january 2020')->startOfDay();
$end = Carbon::parse('01 april 2020')->startOfDay();

$period = CarbonPeriod::create($start, $di, $end);

$items = [];
foreach ($period as $item) {
    $items[] = $item;
}

我希望以上结果

2020-01-31
2020-02-29
2020-03-30

但我明白了

2020-01-31
2020-03-02
2020-04-02

请记住,DateInterval 是可自定义的(或者我只会使用 Carbon::addMonthNoOverflow())。

任何人都可以帮助我实现上述目标吗?

【问题讨论】:

    标签: php symfony datetime php-carbon dateinterval


    【解决方案1】:

    tl;dr:它不适用于 Carbon。

    日期算术很难传达,也更难正确。因此,例如,当开始日期例如在 2 月时,您甚至无法表达您想要“一个月的最后一天”的间隔:

    start: 2020-02-29
    P1M -> 2020-03-29 (not end of month, obviously)
    

    单独一个区间无法表达你想要的月末语义。

    而且这个问题会延续即使你会找到一种方法让溢出工作,这样你就不会在下个月的开始结束。 (我尝试了一些方法都失败了)

    您(对用户)所能提供的只是将额外的函数应用于日期数组以实现您的目标,例如$item->endOfMonth()。但是您仍然需要注意,开始的月份的第几天

    具有讽刺意味的是,你可以在所有 Carbon、CarbonInterval 和 CarbonPeriod 上调用 ->settings(['monthOverflow'=>false, 'yearOverflow'=>false]),它没有效果(除非你在它上面调用 addMonth(),这是相当令人失望的,它不会' t 应用于$start->add($di))。这归结为这样一个事实,即 Carbon 最终只是标准 DateTime 对象的包装器,它也不支持溢出。

    长话短说,Carbon(当前版本)没有优雅和/或简单的解决方案。 ;o/

    【讨论】:

    • 一个彻底的答案,谢谢。可惜这不是我希望读到的。看来我要写一些丑陋的自定义代码了
    • @Wildcard27 我也很失望;o/ 也许在 carbon 开票可能会在未来改变这一点。
    • 创建了一个问题github.com/briannesbitt/Carbon/issues/2133,但我不会屏住呼吸
    【解决方案2】:

    经过大量挖掘,并意识到@Jakumi 是正确的,我在问了同样的问题here 后,刚刚提出了一个使用Carbon 的解决方案。

    DatePeriod() 不起作用的原因是它总是依赖于循环中的前一个日期。这就是为什么你会在 2 月的 29/28 卡住,然后在整个循环的其余部分重复。

    这是我的解决方案:

    $endDate = CarbonImmutable::parse('10 april 2020')->startOfDay();
    $startDate = CarbonImmutable::parse('31 january 2020')->startOfDay();
    $interval = CarbonInterval::create('P1M'); // only works for number of months, not composite intervals
    
    
    $workingDate = $startDate->copy();
    
    for ($i = 1; $workingDate <= $endDate; $i = $i + $interval->m) {
        echo = $workingDate->format('Y-m-d') . "\n";
        $workingDate = $startDate->addMonthsNoOverflow($i);
    }
    

    我与 Carbon 代码库的贡献者进行了一些代码关闭。如果他找到更好的解决方案,那么我将更新我的答案。目前,这行得通。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-10-07
      • 2020-07-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多