
本文介绍一种高效方法:通过统计每个日期在预订区间端点(start/end)中出现的次数,自动将出现两次及以上的日期(即同日既有退房又有入住)标记为不可用。
在酒店、短租或日历类应用中,一个常见业务逻辑是:当某天既是前一订单的退房日(end),又是后一订单的入住日(start)时,该天应视为“不可预约”——因为房间需进行清洁、交接等操作,通常不支持当日无缝续住。 这类“同日双事件”(如 2023-07-05 同时作为上单的 end 和下单的 start)需要被精准识别并置为 available: false。
核心思路并非检查日期重叠区间,而是聚焦于端点日期的重复性:只要某个日期在所有 reserved 对象的 start 或 end 字段中出现 ≥2 次,就说明它承载了“交接”语义,应被锁定。
以下是实现该逻辑的简洁、可读性强的方案:
const dates = [/* 31 天日期数组,available 默认 true */];
const reserved = [
{ start: "2023-07-03", end: "2023-07-05" },
{ start: "2023-07-05", end: "2023-07-08" },
{ start: "2023-07-08", end: "2023-07-10" },
{ start: "2023-07-18", end: "2023-07-20" },
{ start: "2023-07-22", end: "2023-07-24" },
{ start: "2023-07-24", end: "2023-07-26" }
];
// 步骤 1:提取所有端点日期(含重复)
const allEndpoints = reserved.flatMap(item => [item.start, item.end]);
// 步骤 2:遍历原始日期数组,标记重复端点
const updatedDates = dates.map(dateObj => {
const date = dateObj.date;
// indexOf 与 lastIndexOf 不等 → 至少出现 2 次
if (allEndpoints.indexOf(date) !== allEndpoints.lastIndexOf(date)) {
return { ...dateObj, available: false };
}
return dateObj;
});
console.log(updatedDates);
// 输出中:'2023-07-05', '2023-07-08', '2023-07-24' 的 available 均为 false✅ 优势说明:
- 零依赖、纯原生:仅使用 Array.prototype.flatMap()、indexOf() 和 lastIndexOf(),兼容现代浏览器及 Node.js;
- 时间复杂度友好:O(n × m)(n 为 dates 长度,m 为端点总数),对月度日历(~30–31 天)完全无压力;
- 语义清晰:直接对应业务需求——“同日双端点 = 不可用”,避免过度设计区间合并或扫描线算法。
⚠️ 注意事项:
- 此方案不处理跨日重叠(如 start: '2023-07-05', end: '2023-07-10' 与 start: '2023-07-07', end: '2023-07-12'),它只解决“端点碰撞”问题。若需完整占用检测(即整段区间内所有日期均不可用),应另用日期范围匹配逻辑;
- 确保 date 字符串格式统一为 'YYYY-MM-DD'(ISO 8601),否则 indexOf 匹配会失效;
- 如需更高性能(例如万级端点),建议改用 Map 统计频次:
const countMap = new Map(); allEndpoints.forEach(d => countMap.set(d, (countMap.get(d) || 0) + 1)); // 然后用 countMap.get(date) >= 2 判断
总结来说,抓住“端点复用即交接日”这一关键业务特征,用最简逻辑达成精准标记,是此类日历状态管理的最佳实践。










