本文目录导读:

我来帮你写一个日程冲突检测脚本,这里提供Python和JavaScript两个版本的实现。
Python 版本
from datetime import datetime, timedelta
from typing import List, Tuple, Optional
class Schedule:
"""日程类"""
def __init__(self, title: str, start_time: datetime, end_time: datetime):
self.title = title
self.start_time = start_time
self.end_time = end_time
def __repr__(self):
return f"{self.title}: {self.start_time.strftime('%H:%M')}-{self.end_time.strftime('%H:%M')}"
def detect_conflicts(schedules: List[Schedule]) -> List[Tuple[Schedule, Schedule]]:
"""
检测日程冲突
返回冲突的日程对列表
"""
# 按开始时间排序
sorted_schedules = sorted(schedules, key=lambda s: s.start_time)
conflicts = []
for i in range(len(sorted_schedules)):
for j in range(i + 1, len(sorted_schedules)):
# 如果日程i的结束时间大于日程j的开始时间,则冲突
if sorted_schedules[i].end_time > sorted_schedules[j].start_time:
conflicts.append((sorted_schedules[i], sorted_schedules[j]))
else:
# 因为已排序,后面的日程开始时间更晚,不会冲突
break
return conflicts
def find_available_slots(schedules: List[Schedule],
day_start: datetime,
day_end: datetime,
min_duration: timedelta = timedelta(minutes=30)) -> List[Tuple[datetime, datetime]]:
"""
查找空闲时间段
"""
sorted_schedules = sorted(schedules, key=lambda s: s.start_time)
available_slots = []
current_time = day_start
for schedule in sorted_schedules:
# 如果当前时间早于日程开始时间,中间有空闲
if current_time < schedule.start_time:
slot_duration = schedule.start_time - current_time
if slot_duration >= min_duration:
available_slots.append((current_time, schedule.start_time))
# 更新当前时间为日程结束时间和当前时间的较晚者
current_time = max(current_time, schedule.end_time)
# 检查最后一个日程到下班时间的空闲
if current_time < day_end:
slot_duration = day_end - current_time
if slot_duration >= min_duration:
available_slots.append((current_time, day_end))
return available_slots
# 使用示例
def main():
# 创建示例日程
schedules = [
Schedule("会议A", datetime(2024, 1, 1, 9, 0), datetime(2024, 1, 1, 10, 0)),
Schedule("会议B", datetime(2024, 1, 1, 9, 30), datetime(2024, 1, 1, 10, 30)),
Schedule("访谈C", datetime(2024, 1, 1, 11, 0), datetime(2024, 1, 1, 12, 0)),
Schedule("午餐D", datetime(2024, 1, 1, 12, 0), datetime(2024, 1, 1, 13, 0)),
Schedule("培训E", datetime(2024, 1, 1, 14, 0), datetime(2024, 1, 1, 15, 30)),
Schedule("汇报F", datetime(2024, 1, 1, 15, 0), datetime(2024, 1, 1, 16, 0)),
]
# 检测冲突
conflicts = detect_conflicts(schedules)
if conflicts:
print("检测到日程冲突:")
for s1, s2 in conflicts:
print(f" - {s1} 与 {s2} 冲突")
else:
print("没有检测到日程冲突")
# 查找空闲时间段
day_start = datetime(2024, 1, 1, 8, 0) # 上班时间
day_end = datetime(2024, 1, 1, 18, 0) # 下班时间
min_duration = timedelta(minutes=30) # 最少空闲30分钟
available_slots = find_available_slots(schedules, day_start, day_end, min_duration)
print(f"\n空闲时间段(最少{min_duration.seconds//60}分钟):")
for start, end in available_slots:
print(f" {start.strftime('%H:%M')} - {end.strftime('%H:%M')}")
if __name__ == "__main__":
main()
JavaScript 版本
class Schedule {
constructor(title, startTime, endTime) {
this.title = title;
this.startTime = new Date(startTime);
this.endTime = new Date(endTime);
}
toString() {
const formatTime = (date) => {
return date.toLocaleTimeString('zh-CN', { hour: '2-digit', minute: '2-digit' });
};
return `${this.title}: ${formatTime(this.startTime)}-${formatTime(this.endTime)}`;
}
}
function detectConflicts(schedules) {
// 按开始时间排序
const sorted = [...schedules].sort((a, b) => a.startTime - b.startTime);
const conflicts = [];
for (let i = 0; i < sorted.length; i++) {
for (let j = i + 1; j < sorted.length; j++) {
if (sorted[i].endTime > sorted[j].startTime) {
conflicts.push([sorted[i], sorted[j]]);
} else {
break; // 后面不会冲突
}
}
}
return conflicts;
}
function findAvailableSlots(schedules, dayStart, dayEnd, minDurationMinutes = 30) {
const sorted = [...schedules].sort((a, b) => a.startTime - b.startTime);
const availableSlots = [];
let currentTime = new Date(dayStart);
for (const schedule of sorted) {
if (currentTime < schedule.startTime) {
const duration = (schedule.startTime - currentTime) / (1000 * 60);
if (duration >= minDurationMinutes) {
availableSlots.push({
start: new Date(currentTime),
end: new Date(schedule.startTime)
});
}
}
currentTime = new Date(Math.max(currentTime, schedule.endTime));
}
// 最后一个日程到结束时间
if (currentTime < dayEnd) {
const duration = (dayEnd - currentTime) / (1000 * 60);
if (duration >= minDurationMinutes) {
availableSlots.push({
start: new Date(currentTime),
end: new Date(dayEnd)
});
}
}
return availableSlots;
}
// 批量检测
function batchConflictCheck(schedules) {
const conflicts = detectConflicts(schedules);
if (conflicts.length > 0) {
console.log('检测到日程冲突:');
conflicts.forEach(([s1, s2]) => {
console.log(` - ${s1.toString()} 与 ${s2.toString()} 冲突`);
});
} else {
console.log('没有检测到日程冲突');
}
return conflicts;
}
// 使用示例
function main() {
const schedules = [
new Schedule('会议A', '2024-01-01T09:00', '2024-01-01T10:00'),
new Schedule('会议B', '2024-01-01T09:30', '2024-01-01T10:30'),
new Schedule('访谈C', '2024-01-01T11:00', '2024-01-01T12:00'),
new Schedule('午餐D', '2024-01-01T12:00', '2024-01-01T13:00'),
new Schedule('培训E', '2024-01-01T14:00', '2024-01-01T15:30'),
new Schedule('汇报F', '2024-01-01T15:00', '2024-01-01T16:00')
];
// 检测冲突
batchConflictCheck(schedules);
// 查找空闲时间
const dayStart = new Date('2024-01-01T08:00');
const dayEnd = new Date('2024-01-01T18:00');
const slots = findAvailableSlots(schedules, dayStart, dayEnd, 30);
if (slots.length > 0) {
console.log('\n空闲时间段(最少30分钟):');
slots.forEach(slot => {
console.log(` ${slot.start.toLocaleTimeString('zh-CN', { hour: '2-digit', minute: '2-digit' })} - ${slot.end.toLocaleTimeString('zh-CN', { hour: '2-digit', minute: '2-digit' })}`);
});
}
}
main();
高级功能版本
如果需要更复杂的检测功能,这里提供包含更多特性的版本:
from datetime import datetime, timedelta
from typing import List, Dict, Any
import json
class AdvancedScheduleManager:
"""高级日程管理器"""
def __init__(self):
self.schedules = []
def add_schedule(self, title: str, start: str, end: str,
priority: int = 0, attendees: List[str] = None):
"""添加日程"""
schedule = {
'title': title,
'start': datetime.fromisoformat(start),
'end': datetime.fromisoformat(end),
'priority': priority,
'attendees': attendees or [],
'duration': (datetime.fromisoformat(end) -
datetime.fromisoformat(start)).total_seconds() / 60
}
self.schedules.append(schedule)
def check_all_conflicts(self) -> Dict[str, Any]:
"""全面的冲突检测"""
conflicts = []
warnings = []
for i, s1 in enumerate(self.schedules):
for j, s2 in enumerate(self.schedules[i+1:], i+1):
# 时间冲突
if s1['start'] < s2['end'] and s2['start'] < s1['end']:
conflict_info = {
'type': '时间冲突',
'schedule1': s1,
'schedule2': s2,
'overlap_minutes': self._calc_overlap(s1, s2)
}
conflicts.append(conflict_info)
# 参会者冲突
common_attendees = set(s1['attendees']) & set(s2['attendees'])
if common_attendees and not self._is_time_conflict(s1, s2):
warnings.append({
'type': '参会者冲突',
'schedule1': s1,
'schedule2': s2,
'common_attendees': list(common_attendees)
})
return {
'total_schedules': len(self.schedules),
'conflicts': conflicts,
'warnings': warnings,
'has_conflicts': len(conflicts) > 0
}
def suggest_resolution(self) -> List[Dict[str, Any]]:
"""建议冲突解决方案"""
result = self.check_all_conflicts()
suggestions = []
for conflict in result['conflicts']:
s1, s2 = conflict['schedule1'], conflict['schedule2']
# 根据优先级建议
if s1['priority'] > s2['priority']:
suggestions.append({
'keep': s1['title'],
'reschedule': s2['title'],
'reason': f"{s1['title']} 优先级更高",
'current_overlap': f"{conflict['overlap_minutes']}分钟"
})
elif s2['priority'] > s1['priority']:
suggestions.append({
'keep': s2['title'],
'reschedule': s1['title'],
'reason': f"{s2['title']} 优先级更高",
'current_overlap': f"{conflict['overlap_minutes']}分钟"
})
else:
suggestions.append({
'type': '需要协商',
'schedule1': s1['title'],
'schedule2': s2['title'],
'reason': '两个日程优先级相同',
'overlap_minutes': conflict['overlap_minutes']
})
return suggestions
def _calc_overlap(self, s1: Dict, s2: Dict) -> float:
"""计算重叠分钟数"""
overlap_start = max(s1['start'], s2['start'])
overlap_end = min(s1['end'], s2['end'])
return max(0, (overlap_end - overlap_start).total_seconds() / 60)
def _is_time_conflict(self, s1: Dict, s2: Dict) -> bool:
"""检查是否有时间冲突"""
return s1['start'] < s2['end'] and s2['start'] < s1['end']
def export_json(self, filepath: str):
"""导出为JSON"""
data = []
for s in self.schedules:
data.append({
'title': s['title'],
'start': s['start'].isoformat(),
'end': s['end'].isoformat(),
'priority': s['priority'],
'attendees': s['attendees']
})
with open(filepath, 'w', encoding='utf-8') as f:
json.dump(data, f, ensure_ascii=False, indent=2)
# 使用示例
def advanced_demo():
manager = AdvancedScheduleManager()
# 添加日程
manager.add_schedule("重要客户会议", "2024-01-01T09:00", "2024-01-01T10:30",
priority=3, attendees=["张三", "李四", "王五"])
manager.add_schedule("团队周会", "2024-01-01T10:00", "2024-01-01T11:00",
priority=2, attendees=["张三", "李四"])
manager.add_schedule("项目评审", "2024-01-01T11:00", "2024-01-01T12:00",
priority=1, attendees=["王五"])
# 检测冲突
result = manager.check_all_conflicts()
print(f"总计 {result['total_schedules']} 个日程")
print(f"发现 {len(result['conflicts'])} 个时间冲突")
print(f"发现 {len(result['warnings'])} 个警告")
# 获取建议
suggestions = manager.suggest_resolution()
if suggestions:
print("\n解决建议:")
for s in suggestions:
print(f" - {s}")
# 运行示例
if __name__ == "__main__":
main() # 运行基础版
advanced_demo() # 运行高级版
使用建议
- 基础使用:直接用
main()函数测试基本的冲突检测 - 高级功能:使用
AdvancedScheduleManager进行更复杂的日程管理 - 自定义修改:可以根据需要修改:
- 冲突判断逻辑(如允许一定时间重叠)
- 时间格式
- 批量导入/导出功能
这个脚本可以用于日历应用、会议预订系统等场景。