在 php 中使用序列化日期从数组中查找间隙日期范围

问题描述 投票:0回答:2

对于酒店管理系统,我有以下 php 数组,其中包含预订酒店房间的日期。新客人无法在这些日期预订客房。

Array([0] => '2017-02-23' 
  [1] => '2017-02-24' 
  [2] => '2017-04-01' 
  [3] => '2017-04-02' 
  [4] => '2017-04-03' 
  [5] => '2017-04-04' 
  [6] => '2017-04-05' 
  [7] => '2017-04-06' 
  [8] => '2017-04-07' 
  [9] => '2017-04-08' 
  [10] => '2017-04-09' 
  [11] => '2017-04-10' 
  [12] => '2017-04-11' 
  [13] => '2017-04-12' 
  [14] => '2017-04-13' 
  [15] => '2017-04-14' 
  [16] => '2017-04-15' 
  [17] => '2017-04-16'      
  [18] => '2017-04-17' 
  [19] => '2017-04-18' 
  [20] => '2017-04-19' 
  [21] => '2017-04-20' 
  [22] => '2017-04-21' 
  [23] => '2017-04-22' 
  [24] => '2017-04-23' 
  [25] => '2017-04-24' 
  [26] => '2017-04-25' 
  [27] => '2017-04-26' 
  [28] => '2017-04-27' 
  [29] => '2017-04-28' 
  [30] => '2017-04-29' 
  [31] => '2017-04-30'
 ) 

这个数组告诉我们房间被预订了 2 个不同的时期:

  1. 2017-02-23
    2017-02-24
  2. 2017-04-01
    2017-04-30

我想在某个宽阔的窗口内找到可用房间的日期范围。

例如,如果有人想从

2017-02-15
2017-05-07
留在房间,那么我希望系统返回以下可用日期范围:

  1. 2017-02-15
    2017-02-22
  2. 2017-02-25
    2017-03-31
  3. 2017-05-01
    2017-05-07

如果有人想从

2017-02-22
2017-03-30
入住房间,那么我希望系统返回以下可用日期范围:

  1. 2017-02-25
    2017-03-30
php arrays date filtering date-range
2个回答
0
投票

谢谢乔治,这是一个多么有趣的小挑战。我推出了我自己的日期范围数组填充函数,我对此感到非常自豪。在几个数组函数和几个 foreach 循环的帮助下,我相信我已经满足了要求。这是演示

代码:

function fillDateRange($a,$b,$x=0,$dates=[]){
  while(end($dates)!=$b && $x=array_push($dates,date("Y-m-d",strtotime("$a +$x day"))));
  return $dates;
}

$booked=array(0=>'2017-02-03',1=>'2017-02-24',2=>'2017-04-01',3=>'2017-04-02',
              4=>'2017-04-03',5=>'2017-04-04',6=>'2017-04-05',7=>'2017-04-06',
              8=>'2017-04-07',9=>'2017-04-08',10=>'2017-04-09',11=>'2017-04-10',
              12=>'2017-04-11',13=>'2017-04-12',14=>'2017-04-13',15=>'2017-04-14',
              16=>'2017-04-15',17=>'2017-04-16',18=>'2017-04-17',19=>'2017-04-18',
              20=>'2017-04-19',21=>'2017-04-20',22=>'2017-04-21',23=>'2017-04-22',
              24=>'2017-04-23',25=>'2017-04-24',26=>'2017-04-25',27=>'2017-04-26',
              28=>'2017-04-27',29=>'2017-04-28',30=>'2017-04-29',31=>'2017-04-30');

$search=fillDateRange('2017-02-15','2017-05-07');  // pre-validated user input

// remove all dates from $search where exist in $booked...
$vacant=array_diff($search,$booked);

// group consecutive days
$date_checker=date("Y-m-d",strtotime("{$vacant[0]} -1 day"));
$x=0;
foreach($vacant as $date){
    if($date!=date("Y-m-d",strtotime("$date_checker +1 day"))){++$x;}
    $grouped[$x][]="$date";
    $date_checker=$date;
}

echo "Array of vacant date ranges:";
foreach($grouped as $group){
    $vacant_ranges[]=current($group)." to ".end($group);
}
echo "<pre>";
    var_export($vacant_ranges);
echo "</pre>";

//echo "Array of arrays containing consecutive days:";
/*foreach($grouped as $group){
    $vacant_arrays[current($group)." to ".end($group)]=$group;
}
echo "<pre>";
    var_export($vacant_arrays);
echo "</pre>";*/

输出:

Array of vacant date ranges:
array (
  0 => '2017-02-15 to 2017-02-23',
  1 => '2017-02-25 to 2017-03-31',
  2 => '2017-05-01 to 2017-05-07',
)

0
投票

我决定重新审视这个问题,目标是将脚本性能放在第一位。我之前的答案可能更容易阅读/维护,但它在生成结果之前执行多个循环并使用臃肿的多维数组。

相反,下面的脚本将迭代用户定义的开始日期和结束日期(含)之间的日期,并另一个循环在黑名单数组中搜索不合格的日期。为了获得最佳性能,黑名单数组将被“消耗”/减少,以最大限度地减少后续搜索所需的周期。也就是说,每一次搜索黑名单都会让黑名单变得越来越小。

输入:

$date = '2017-02-15';  // start date
$end = '2017-05-07';

$bookings = [          // blacklist
    '2017-02-03',
    '2017-02-24',
    '2017-04-01',
    '2017-04-02',
    '2017-04-03',
    '2017-04-04',
    '2017-04-05',
    '2017-04-06',
    '2017-04-07',
    '2017-04-08',
    '2017-04-09',
    '2017-04-10',
    '2017-04-11',
    '2017-04-12',
    '2017-04-13',
    '2017-04-14',
    '2017-04-15',
    '2017-04-16',
    '2017-04-17',
    '2017-04-18',
    '2017-04-19',
    '2017-04-20',
    '2017-04-21',
    '2017-04-22',
    '2017-04-23',
    '2017-04-24',
    '2017-04-25',
    '2017-04-26',
    '2017-04-27',
    '2017-04-28',
    '2017-04-29',
    '2017-04-30',
];

代码:(演示

function isBooked(array &$bookings, string $date): bool
{
    foreach ($bookings as $i => $taken) {
        if ($date > $taken) {
            unset($bookings[$i]);
        } else {
            return $date === $taken;
        }
    }
    return false;
}

$result = [];
$temp = [];
while ($date <= $end) {
    $exclude = isBooked($bookings, $date);
    if ($temp) {
        if ($exclude) {
            $result[] = implode(' to ', $temp);
            $temp = [];
        } elseif ($date != date('Y-m-d', strtotime($temp[1] . ' +1 day'))) {
            $result[] = implode(' to ', $temp);
            $temp = [$date, $date];
        } else {
            $temp[1] = $date;
        }
    } elseif (!$exclude) {
        $temp = [$date, $date];
    }
    $date = date('Y-m-d', strtotime($date . ' +1 day'));
}
if ($temp) {
    $result[] = implode(' to ', $temp);
}
var_export($result);

输出:

array (
  0 => '2017-02-15 to 2017-02-23',
  1 => '2017-02-25 to 2017-03-31',
  2 => '2017-05-01 to 2017-05-07',
)
© www.soinside.com 2019 - 2024. All rights reserved.