PHP中如何将带IsBlocked标记的日期数组转为可用区间数组?
合并可用日期为连续区间需求
我有一个覆盖2023年11月1日至11月30日的日期数组,其中11月3日至6日、11月15日至20日的日期标记为已锁定(IsBlocked=true)。需要将其中可用日期(IsBlocked=false)合并为连续的日期区间,输出包含start_date和end_date的目标数组。
原日期数组
Array ( [0] => Array ( [date] => 2023-11-01 [IsBlocked] => false ) [1] => Array ( [date] => 2023-11-02 [IsBlocked] => false ) [2] => Array ( [date] => 2023-11-03 [IsBlocked] => true ) [3] => Array ( [date] => 2023-11-04 [IsBlocked] => true ) [4] => Array ( [date] => 2023-11-05 [IsBlocked] => true ) [5] => Array ( [date] => 2023-11-06 [IsBlocked] => true ) [6] => Array ( [date] => 2023-11-07 [IsBlocked] => false ) [7] => Array ( [date] => 2023-11-08 [IsBlocked] => false ) [8] => Array ( [date] => 2023-11-09 [IsBlocked] => false ) [9] => Array ( [date] => 2023-11-10 [IsBlocked] => false ) [10] => Array ( [date] => 2023-11-11 [IsBlocked] => false ) [11] => Array ( [date] => 2023-11-12 [IsBlocked] => false ) [12] => Array ( [date] => 2023-11-13 [IsBlocked] => false ) [13] => Array ( [date] => 2023-11-14 [IsBlocked] => false ) [14] => Array ( [date] => 2023-11-15 [IsBlocked] => true ) [15] => Array ( [date] => 2023-11-16 [IsBlocked] => true ) [16] => Array ( [date] => 2023-11-17 [IsBlocked] => true ) [17] => Array ( [date] => 2023-11-18 [IsBlocked] => true ) [18] => Array ( [date] => 2023-11-19 [IsBlocked] => true ) [19] => Array ( [date] => 2023-11-20 [IsBlocked] => true ) [20] => Array ( [date] => 2023-11-21 [IsBlocked] => false ) [21] => Array ( [date] => 2023-11-22 [IsBlocked] => false ) [22] => Array ( [date] => 2023-11-23 [IsBlocked] => false ) [23] => Array ( [date] => 2023-11-24 [IsBlocked] => false ) [24] => Array ( [date] => 2023-11-25 [IsBlocked] => false ) [25] => Array ( [date] => 2023-11-26 [IsBlocked] => false ) [26] => Array ( [date] => 2023-11-27 [IsBlocked] => false ) [27] => Array ( [date] => 2023-11-28 [IsBlocked] => false ) [28] => Array ( [date] => 2023-11-29 [IsBlocked] => false ) [29] => Array ( [date] => 2023-11-30 [IsBlocked] => false ) )
期望输出数组
Array ( [0] => Array ( [start_date] => 2023-11-01 [end_date] => 2023-11-02 ) [1] => Array ( [start_date] => 2023-11-07 [end_date] => 2023-11-14 ) [2] => Array ( [start_date] => 2023-11-21 [end_date] => 2023-11-30 ) )
尝试过的代码(未实现需求)
foreach($dates as $calDay) { if($calDay['IsBlocked'] == "true") { $closeDates[] = $calDay['date']; } else { $openDates[] = $calDay['date']; } }
解决方案
核心思路是遍历日期数组时,维护一个临时的连续区间,当遇到不可用日期或日期不连续时,将当前区间存入结果并开启新的区间。
实现代码
$dates = [ // 此处放入你的原日期数组内容 ]; $result = []; $currentInterval = null; foreach ($dates as $day) { // 跳过锁定的日期 if ($day['IsBlocked'] === true) { // 如果当前有未完成的区间,先存入结果 if ($currentInterval !== null) { $result[] = $currentInterval; $currentInterval = null; } continue; } $currentDate = new DateTime($day['date']); if ($currentInterval === null) { // 初始化新的区间 $currentInterval = [ 'start_date' => $day['date'], 'end_date' => $day['date'] ]; } else { // 检查当前日期是否是区间结束日期的下一天 $nextDay = (new DateTime($currentInterval['end_date']))->modify('+1 day'); if ($currentDate->format('Y-m-d') === $nextDay->format('Y-m-d')) { // 更新区间结束日期 $currentInterval['end_date'] = $day['date']; } else { // 日期不连续,存入当前区间并开启新的 $result[] = $currentInterval; $currentInterval = [ 'start_date' => $day['date'], 'end_date' => $day['date'] ]; } } } // 遍历结束后,把最后一个未存入的区间加入结果 if ($currentInterval !== null) { $result[] = $currentInterval; } // 输出结果 print_r($result);
代码说明
- 初始化
$result存储最终区间数组,$currentInterval存储当前正在构建的连续区间 - 遍历每个日期,遇到锁定日期时,若当前有未完成的区间则存入结果,然后跳过
- 对于可用日期:
- 如果当前没有正在构建的区间,初始化新的区间
- 如果有,检查当前日期是否是区间结束日期的下一天,是则更新结束日期;否则存入当前区间并开启新的
- 遍历结束后,确保最后一个区间被存入结果
内容的提问来源于stack exchange,提问作者Hola
相关产品推荐
相关产品推荐

