对于酒店管理系统,我有以下 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 个不同的时期:
2017-02-23
至 2017-02-24
2017-04-01
至 2017-04-30
我想在某个宽阔的窗口内找到可用房间的日期范围。
例如,如果有人想从
2017-02-15
到2017-05-07
留在房间,那么我希望系统返回以下可用日期范围:
2017-02-15
至 2017-02-22
2017-02-25
至 2017-03-31
2017-05-01
至 2017-05-07
如果有人想从
2017-02-22
到 2017-03-30
入住房间,那么我希望系统返回以下可用日期范围:
2017-02-25
至 2017-03-30
我决定重新审视这个问题,目标是将脚本性能放在第一位。我之前的答案可能更容易阅读/维护,但它在生成结果之前执行多个循环并使用臃肿的多维数组。
相反,下面的脚本将迭代用户定义的开始日期和结束日期(含)之间的日期,并另一个循环在黑名单数组中搜索不合格的日期。为了获得最佳性能,黑名单数组将被“消耗”/减少,以最大限度地减少后续搜索所需的周期。也就是说,每一次搜索黑名单都会让黑名单变得越来越小。
输入:
$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',
)
在几个数组函数和几个 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 = [
'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'
];
$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:\n";
foreach ($grouped as $group) {
$vacant_ranges[] = current($group) . " to " . end($group);
}
var_export($vacant_ranges);
输出:
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',
)