def get_free_time(total_range, schedule): schedule.sort(key=lambda x: x.lower_bound) free_timeslots = [ Timeslot(total_range.lower_bound, schedule[0].lower_bound) ] for i in range(len(schedule[:-1])): free_timeslots.append( Timeslot(schedule[i].upper_bound, schedule[i + 1].lower_bound)) free_timeslots.append( Timeslot(schedule[-1].upper_bound, total_range.upper_bound)) return [ timeslot for timeslot in free_timeslots if validate_timeslot(timeslot) ]
def union_no_overlap(events1: List[Event], events2: List[Event]) -> List[Event]: """Merges two eventlists and removes overlap, the first eventlist will have precedence Example: events1 | xxx xx xxx | events1 | ---- ------ -- | result | xxx-- xx ----xxx -- | """ events1 = deepcopy(events1) events2 = deepcopy(events2) # I looked a lot at aw_transform.union when I wrote this events_union = [] e1_i = 0 e2_i = 0 while e1_i < len(events1) and e2_i < len(events2): e1 = events1[e1_i] e2 = events2[e2_i] e1_p = Timeslot(e1.timestamp, e1.timestamp + e1.duration) e2_p = Timeslot(e2.timestamp, e2.timestamp + e2.duration) if e1_p.intersects(e2_p): if e1.timestamp <= e2.timestamp: events_union.append(e1) e1_i += 1 # If e2 continues after e1, we need to split up the event so we only get the part that comes after _, e2_next = _split_event(e2, e1.timestamp + e1.duration) if e2_next: events2[e2_i] = e2_next else: e2_i += 1 else: e2_next, e2_next2 = _split_event(e2, e1.timestamp) events_union.append(e2_next) e2_i += 1 if e2_next2: events2.insert(e2_i, e2_next2) else: if e1.timestamp <= e2.timestamp: events_union.append(e1) e1_i += 1 else: events_union.append(e2) e2_i += 1 events_union += events1[e1_i:] events_union += events2[e2_i:] return events_union
def test_course_can_take(self): ts1 = Timeslot('FA12', { 'M': ['09:00', '11:00'], 'R': ['09:00', '11:00'] }) ts2 = Timeslot('FA13', { 'M': ['09:00', '11:00'], 'R': ['09:00', '11:00'] }) ts3 = Timeslot('FA14', { 'M': ['09:00', '11:00'], 'R': ['09:00', '11:00'] }) c1 = Course("CS101", ts1) c2 = Course("CS201", ts2, ["CS101"]) c3 = Course("CS101", ts3) self.assertFalse(c2.can_take([])) self.assertTrue(c2.can_take([c1])) self.assertFalse(c2.can_take([c3]))
def parse_time(days, start_time, end_time): # Convert times from 12 hr to 24 hr start_time = convert_time(start_time) end_time = convert_time(end_time) # Read in the times for the course d = {} if 'M' in days: d['M'] = [start_time, end_time] if 'T' in days: d['T'] = [start_time, end_time] if 'W' in days: d['W'] = [start_time, end_time] if 'R' in days: d['R'] = [start_time, end_time] if 'F' in days: d['F'] = [start_time, end_time] # Create timeslot for the course # Hard-code semester (should be read in somehow) return Timeslot("FA14", d)
def test_contains(): now = datetime.now() tp1 = Timeslot(now - timedelta(hours=1), now + timedelta(hours=1)) tp2 = Timeslot(now, now + timedelta(hours=1)) assert tp1.contains(tp2) assert not tp2.contains(tp1) # if datetime is contained in period assert now in tp1 assert now in tp2 # __contains__ operator overloading assert tp2 in tp1 assert tp1 not in tp2 with pytest.raises(TypeError): assert 0 in tp1
def parse_input_range(input_range): return Timeslot(input_range.split(".")[0], input_range.split(".")[1])
def parse_input_array(input_array): return [Timeslot(x, y) for x, y in [val.split(".") for val in input_array.split(",")]]
def test_union(): now = datetime.now() # adjacent but not overlapping tp1 = Timeslot(now - timedelta(hours=1), now) tp2 = Timeslot(now, now + timedelta(hours=1)) tp_union = tp1.union(tp2) assert tp1 in tp_union assert tp2 in tp_union # union with self tp_union = tp1.union(tp1) assert tp1 == tp_union # overlapping tp1 = Timeslot(now - timedelta(hours=1), now + timedelta(minutes=30)) tp2 = Timeslot(now, now + timedelta(hours=1)) tp_union = tp1.union(tp2) assert tp1 in tp_union assert tp2 in tp_union # tp2 contained in tp1 tp1 = Timeslot(now - timedelta(minutes=30), now + timedelta(minutes=30)) tp2 = Timeslot(now, now + timedelta(minutes=10)) tp_union = tp1.union(tp2) assert tp1 in tp_union assert tp2 in tp_union assert tp1 == tp_union
def test_adjacent(): now = datetime.now() tp1 = Timeslot(now - timedelta(hours=1), now) tp2 = Timeslot(now, now + timedelta(hours=1)) assert tp1.adjacent(tp2) assert tp2.adjacent(tp1)
def test_intersection_start(): now = datetime.now() tp1 = Timeslot(now, now + timedelta(hours=1)) tp2 = Timeslot(now - timedelta(minutes=10), now + timedelta(minutes=50)) assert tp1.intersection(tp2).duration == timedelta(minutes=50) assert tp2.intersection(tp1).duration == timedelta(minutes=50)
def test_overlaps(): now = datetime.now() # If periods are just "touching", they should not count as overlap tp1 = Timeslot(now - timedelta(hours=1), now) tp2 = Timeslot(now, now + timedelta(hours=1)) assert not tp1.overlaps(tp2) assert not tp2.overlaps(tp1) # If outer contains inner, or vice versa, they overlap tp1 = Timeslot(now, now + timedelta(hours=1)) tp2 = Timeslot(now - timedelta(hours=1), now + timedelta(hours=2)) assert tp1.overlaps(tp2) assert tp2.overlaps(tp1) # If start/end is contained in the other event, they overlap tp1 = Timeslot(now, now + timedelta(hours=2)) tp2 = Timeslot(now - timedelta(hours=1), now + timedelta(hours=1)) assert tp1.overlaps(tp2) assert tp2.overlaps(tp1)
def test_intersection_none(): now = datetime.now() tp1 = Timeslot(now, now + timedelta(hours=1)) tp2 = Timeslot(now - timedelta(hours=1), now) assert tp1.intersection(tp2) is None assert tp2.intersection(tp1) is None
def _get_event_period(event: Event) -> Timeslot: start = event.timestamp end = start + event.duration return Timeslot(start, end)
def create_timeslots(self): return [ Timeslot(timeslot_id=slot) for slot in range(self.no_timeslots) ]