Laravel 使用Carbon按自然年拆分日期并生成对应月份统计表格
实现方案
核心逻辑
按自然年拆分日期区间可以直接通过遍历涉及年份计算边界,也可以通过日期差值逐月循环累加实现,两种方式都可以用Carbon快速完成,以下是符合你需求的实现代码:
方案1:按年遍历实现(效率更高)
use Carbon\Carbon; // 初始化起止日期 $startDate = Carbon::parse('2018-10-01'); $endDate = Carbon::parse('2020-08-01'); $splitResult = []; // 同一年直接返回单个区间 if ($startDate->year == $endDate->year) { $splitResult[] = [ 'year' => $startDate->year, 'period_start' => $startDate->format('Y/m/d'), 'period_end' => $endDate->format('Y/m/d'), 'months' => $startDate->diffInMonths($endDate) ]; } else { // 遍历所有涉及的自然年 for ($year = $startDate->year; $year <= $endDate->year; $year++) { if ($year == $startDate->year) { // 首年边界处理 $currentStart = $startDate->copy(); $currentEnd = Carbon::create($year, 12, 31); } elseif ($year == $endDate->year) { // 结束年边界处理 $currentStart = Carbon::create($year, 1, 1); $currentEnd = $endDate->copy(); } else { // 中间完整年处理 $currentStart = Carbon::create($year, 1, 1); $currentEnd = Carbon::create($year, 12, 31); } // 计算间隔月份,diffInMonths默认返回完整满月差值,和你示例的计算规则对齐 $months = $currentStart->diffInMonths($currentEnd); $splitResult[] = [ 'year' => $year, 'period_start' => $currentStart->format('Y/m/d'), 'period_end' => $currentEnd->format('Y/m/d'), 'months' => $months ]; } } // 输出结果可直接用于生成统计表格 dd($splitResult);
测试用例输出结果
array:3 [ 0 => array:4 [ "year" => 2018 "period_start" => "2018/10/01" "period_end" => "2018/12/31" "months" => 2 ] 1 => array:4 [ "year" => 2019 "period_start" => "2019/01/01" "period_end" => "2019/12/31" "months" => 12 ] 2 => array:4 [ "year" => 2020 "period_start" => "2020/01/01" "period_end" => "2020/08/01" "months" => 7 ] ]
如果你需要统计包含首尾月的总月份数,将月份计算逻辑改为
$currentStart->diffInMonths($currentEnd->copy()->addDay()) + 1即可。
方案2:日期差值循环实现
如果你要求必须通过循环日期差值的方式实现,可以按月步进累加统计:
use Carbon\Carbon; $startDate = Carbon::parse('2018-10-01'); $endDate = Carbon::parse('2020-08-01'); $splitResult = []; $currentDate = $startDate->copy(); while ($currentDate->lte($endDate)) { $year = $currentDate->year; // 初始化当前年份的区间 if (!isset($splitResult[$year])) { $splitResult[$year] = [ 'year' => $year, 'period_start' => $currentDate->format('Y/m/d'), 'months' => 0 ]; } $splitResult[$year]['months']++; // 计算当前年的区间结束日期 $yearEnd = $year == $endDate->year ? $endDate : Carbon::create($year, 12, 31); $splitResult[$year]['period_end'] = min($currentDate->copy()->endOfMonth(), $yearEnd)->format('Y/m/d'); // 步进1个月循环 $currentDate->addMonth(); } // 重置数组索引 $splitResult = array_values($splitResult); dd($splitResult);
内容的提问来源于stack exchange,提问作者suleiman abdulrazaq
相关产品推荐
相关产品推荐

