如何统计日历列的事件数并判断hour_start、hour_end对应事件是否相交
问题1:计算日历某一列上的事件总数量
首先明确日历列的划分逻辑,常规日历列一般按「日期」「资源ID(如人员、会议室)」两类维度划分,对应统计方式如下:
前端场景(直接操作日历组件数据)
以常用的FullCalendar组件为例,逻辑如下:
- 确定目标列的唯一标识,如日期列的标识为
YYYY-MM-DD格式的日期值,资源列的标识为resourceId - 遍历所有日历事件,匹配对应标识后计数
示例代码:
// FullCalendar 场景示例 const targetColumnId = '2024-05-20' // 目标列ID const allEvents = calendar.getEvents() const columnEventCount = allEvents.filter(event => event.startStr.split('T')[0] === targetColumnId ).length
后端场景(从数据库统计)
- 过滤条件匹配目标列的关联字段,直接执行count统计即可
示例SQL:
-- 按日期列统计 SELECT COUNT(*) FROM calendar_events WHERE event_date = '2024-05-20'; -- 按资源列统计 SELECT COUNT(*) FROM calendar_events WHERE resource_id = 1001;
注意:如果存在跨列事件(如跨天事件),需要先将跨列事件按覆盖的列拆分后再统计,避免漏算
问题2:找出存在时间交集的事件
核心判断逻辑
两个事件A、B存在时间交集的充要条件是:A.hour_start < B.hour_end AND B.hour_start < A.hour_end
如果需要把「A结束时间等于B开始时间」的相邻场景也判定为交集,将小于号替换为小于等于即可。
小数据集实现(x<10000,时间复杂度O(n²))
直接两两配对判断即可,逻辑简单不易出错:
from datetime import datetime def find_overlapping_pairs(events: list) -> list: overlapping_pairs = [] event_count = len(events) # 统一转时间戳避免格式问题 for event in events: event["start_ts"] = datetime.fromisoformat(event["hour_start"]).timestamp() event["end_ts"] = datetime.fromisoformat(event["hour_end"]).timestamp() # 两两比较不重复计算 for i in range(event_count): a = events[i] for j in range(i + 1, event_count): b = events[j] if a["start_ts"] < b["end_ts"] and b["start_ts"] < a["end_ts"]: overlapping_pairs.append((a["id"], b["id"])) return overlapping_pairs
大数据集实现(x≥10000,时间复杂度O(nlogn))
用扫描线算法优化,避免暴力两两比较:
- 将所有事件拆分为「开始时间点(标记为+1,绑定事件ID)」和「结束时间点(标记为-1,绑定事件ID)」
- 所有时间点按时间升序排序,时间相同时结束点排在开始点前面(避免相邻事件判定为交集)
- 遍历排序后的时间点,维护当前活跃事件集合:遇到开始点时,当前事件与活跃集合内所有事件都有交集,记录配对后将当前事件加入活跃集合;遇到结束点时将对应事件移出活跃集合
示例代码片段:
def find_overlapping_events_optimized(events: list) -> list: points = [] for e in events: start_ts = datetime.fromisoformat(e["hour_start"]).timestamp() end_ts = datetime.fromisoformat(e["hour_end"]).timestamp() points.append((start_ts, 1, e["id"])) points.append((end_ts, -1, e["id"])) # 排序规则:先按时间,再按类型(结束点-1排在开始点1前面) points.sort(key=lambda x: (x[0], x[1])) active_events = set() overlaps = [] for ts, typ, event_id in points: if typ == 1: # 所有活跃事件和当前事件有交集 for active_id in active_events: overlaps.append((active_id, event_id)) active_events.add(event_id) else: active_events.discard(event_id) return overlaps
注意:所有时间需要统一时区,避免跨时区事件的交集判断错误
内容的提问来源于stack exchange,提问作者Adrian Simionescu
相关产品推荐
相关产品推荐

