import pandas as pd from datetime import datetime, timedelta import bisect JOUR_OFFSET = { 'Monday': 0, 'Tuesday': 1, 'Wednesday': 2, 'Thursday': 3, 'Friday': 4, 'Saturday': 5, 'Sunday': 6 } BASE_DATE = datetime(2025, 1, 6) def parse_slot(slot_str): jour, horaire = slot_str.split() horaire = horaire.replace(';', ':') h, m = map(int, horaire.split(':')) date = BASE_DATE + timedelta(days=JOUR_OFFSET[jour]) return datetime(date.year, date.month, date.day, h, m) def format_slot(dt): return f"{dt.strftime('%A')} {dt.strftime('%H:%M')}" def add_request(df_fixed, new_slot_str): new_dt = parse_slot(new_slot_str) desired_dt = new_dt - timedelta(minutes=5) # on récupère les adjusted existants triés slots_dt = sorted(parse_slot(s) for s in df_fixed['adjusted_time']) # on commence par placer final_dt = desired_dt, puis on recule au besoin final_dt = desired_dt # boucle tant que final_dt viole au moins une contrainte d'espacement while True: conflict = False # 1) avec le schedule_time if new_dt - final_dt < timedelta(minutes=5): # on recule pour avoir exactement 7mi d'avance final_dt = new_dt - timedelta(minutes=5) conflict = True # 2) avec chaque adjusted existant for slot in slots_dt: if abs((slot - final_dt).total_seconds()) < 5*60: # on recule de 7min par rapport à cet adjusted # si slot > final, on repousse final à slot -7min # sinon (slot < final), on recule encore de 7min if slot > final_dt: final_dt = slot - timedelta(minutes=5) else: final_dt = slot - timedelta(minutes=5) conflict = True break if not conflict: break # on a trouvé un créneau valide final_str = format_slot(final_dt) df_fixed = pd.concat([ df_fixed, pd.DataFrame([{ 'schedule_time': new_slot_str, 'adjusted_time': final_str }]) ], ignore_index=True) return df_fixed.sort_values('adjusted_time').reset_index(drop=True),final_str