You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用PHP CarbonPeriod计算多段可能重叠日期的非重叠总天数?

在PHP中使用CarbonPeriod计算多段重叠日期范围的非重叠总天数

需求:计算2段及以上可能存在重叠的日期范围的非重叠总天数,例如以下示例中的3个日期范围,最终需得到非重叠总天数20天。询问Carbon/CarbonPeriod是否提供内置方法实现该需求?

示例代码:

$startDate_1 = '2022-12-01';
$endDate_1 = '2022-12-10';

$startDate_2 = '2022-12-06';
$endDate_2 = '2022-12-15';

$startDate_3 = '2022-12-21';
$endDate_3 = '2022-12-25';

$dateRange_1 = CarbonPeriod::create($startDate_1, $endDate_1);
$dateRange_2 = CarbonPeriod::create($startDate_2, $endDate_2);
$dateRange_3 = CarbonPeriod::create($startDate_3, $endDate_3);

解答

CarbonPeriod本身没有直接计算多段非重叠日期范围总天数的内置方法,但可以通过合并重叠/相邻区间的方式手动实现,步骤如下:

  1. 将所有日期范围转换为包含Carbon实例的数组,方便后续处理
  2. 按区间的开始日期从小到大排序
  3. 遍历数组,合并重叠或相邻的区间
  4. 计算每个合并后区间的天数并求和

具体实现代码

use Carbon\Carbon;
use Carbon\CarbonPeriod;

// 整理所有日期范围为包含Carbon对象的数组
$ranges = [
    ['start' => Carbon::parse($startDate_1), 'end' => Carbon::parse($endDate_1)],
    ['start' => Carbon::parse($startDate_2), 'end' => Carbon::parse($endDate_2)],
    ['start' => Carbon::parse($startDate_3), 'end' => Carbon::parse($endDate_3)],
];

// 按开始日期排序
usort($ranges, function($a, $b) {
    return $a['start']->compare($b['start']);
});

// 合并重叠/相邻区间
$mergedRanges = [];
foreach ($ranges as $range) {
    if (empty($mergedRanges)) {
        $mergedRanges[] = $range;
        continue;
    }

    $last = &$mergedRanges[count($mergedRanges) - 1];
    // 当前区间的开始日期小于等于最后一个合并区间的结束日期,说明有重叠/相邻,合并
    if ($range['start']->lte($last['end'])) {
        // 更新合并区间的结束日期为两者中较大的那个
        if ($range['end']->gt($last['end'])) {
            $last['end'] = $range['end'];
        }
    } else {
        $mergedRanges[] = $range;
    }
}

// 计算总天数
$totalDays = 0;
foreach ($mergedRanges as $range) {
    // diffInDays返回的是两个日期之间的天数差(不包含结束日),所以需要+1
    $totalDays += $range['start']->diffInDays($range['end']) + 1;
}

echo $totalDays; // 输出:20

代码说明

  • 排序确保我们从最早的区间开始处理,避免遗漏重叠情况
  • 合并逻辑:如果当前区间的开始日期在最后一个合并区间的范围内(或等于结束日),则合并两个区间,取最大的结束日期作为新的结束日
  • 计算天数时,diffInDays()方法返回的是两个日期之间的间隔天数(例如2022-12-01到2022-12-10返回9),因此需要加1来包含区间的首尾日期,得到正确的天数

内容的提问来源于stack exchange,提问作者Dmitry Chasovnikov

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 21:15:44