如何写日程冲突检测脚本

wen 实用脚本 27

本文目录导读:

如何写日程冲突检测脚本

  1. Python 版本
  2. JavaScript 版本
  3. 高级功能版本
  4. 使用建议

我来帮你写一个日程冲突检测脚本,这里提供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()  # 运行高级版

使用建议

  1. 基础使用:直接用 main() 函数测试基本的冲突检测
  2. 高级功能:使用 AdvancedScheduleManager 进行更复杂的日程管理
  3. 自定义修改:可以根据需要修改:
    • 冲突判断逻辑(如允许一定时间重叠)
    • 时间格式
    • 批量导入/导出功能

这个脚本可以用于日历应用、会议预订系统等场景。

抱歉,评论功能暂时关闭!