def get_availability(self: ConcreteEntity, range_begin: date, range_end: date) -> IntervalSet: available = IntervalSet([]) unavailable = IntervalSet([]) # Determine availability and unavailability according to entity's settings: for pos_tp in self.timepattern_set.filter( disposition=TimePattern.DISPOSITION_AVAILABLE).all(): available += pos_tp.as_interval_set(range_begin, range_end) if available.empty(): # If no positive timepatterns have been specified then we'll say that the pos part is infinite. # This makes it easy to specify things like "always available" and "always available except Fridays." # For the purpose of this method, "infite" translates to range_begin to range_end. make_ts = lambda d: dt2ts( pytz.utc.localize(datetime(d.year, d.month, d.day))) range_begin_ts = make_ts(range_begin) # type: TimeStamp range_end_ts = make_ts(range_end) # type: TimeStamp available.add(closed(range_begin_ts, range_end_ts)) for neg_tp in self.timepattern_set.filter( disposition=TimePattern.DISPOSITION_UNAVAILABLE).all(): unavailable += neg_tp.as_interval_set(range_begin, range_end) # Determine additional unavailability due to entity being involved in a scheduled class: for involvement in self.scheduled_class_involvements: # type: EntityInScheduledClass if involvement.entitys_status == EntityInScheduledClass.STATUS_G2G: pass # TODO return available - unavailable
def as_interval_set(self, start: date, finish: date) -> IntervalSet: """ Return an interval set representation of the TimePattern between two bounds. The intervals are closed and expressed using Unix timestamps (the number of seconds since 1970-01-01 UTC, not counting leap seconds). Since TimePattern defines an infinite sequence of intervals across all time, this function takes a starting date and ending date. Only those intervals with start times that fall between the starting and ending date are returned in the interval set result. """ dow_dict = { "Mo": 0, "Tu": 1, "We": 2, "Th": 3, "Fr": 4, "Sa": 5, "Su": 6 } # REVIEW: Is there a more efficient implementation that uses dateutil.rrule? tz = timezone.get_current_timezone() iset = IntervalSet([]) # type: IntervalSet d = start - timedelta(days=1) # type: date while d <= finish: d = d + timedelta(days=1) if dow_dict[self.dow] != d.weekday(): continue if self.wom == self.WOM_LAST: if not is_last_xxxday_of_month(d): continue if self.wom not in [self.WOM_LAST, self.WOM_EVERY]: nth = int(self.wom) if not is_nth_xxxday_of_month(d, nth): continue am_pm_adjust = 0 if self.morning else 12 inter_start_dt = tz.localize( datetime(d.year, d.month, d.day, self.hour + am_pm_adjust, self.minute)) inter_start = dt2ts(inter_start_dt) inter_end = int(inter_start + self.duration * 3600) iset.add(closed(inter_start, inter_end)) return iset
def test_add_already_contained_has_no_effect(): expected = IntervalSet((i.open(1, 7),)) result = IntervalSet((i.open(1, 7),)) result.add(i.open(2, 4)) assert result == expected
def test_add_non_overlapping_unions(): expected = IntervalSet((i.open(1, 7), i.open(10, 20))) result = IntervalSet((i.open(1, 7),)) result.add(i.open(10, 20)) assert result == expected
def test_add_overlapping_with_multiple(): expected = IntervalSet((i.open(1, 20), i.open(30, 40))) result = IntervalSet((i.open(1, 7), i.open(10, 20), i.open(30, 40))) result.add(i.open(2, 15)) assert result == expected
def test_add_to_empty(): expected = IntervalSet((i.open(1, 7),)) result = IntervalSet() result.add(i.open(1, 7)) assert result == expected
def test_add_already_contained_has_no_effect(): expected = IntervalSet((i.open(1, 7), )) result = IntervalSet((i.open(1, 7), )) result.add(i.open(2, 4)) assert result == expected
def test_add_non_overlapping_unions(): expected = IntervalSet((i.open(1, 7), i.open(10, 20))) result = IntervalSet((i.open(1, 7), )) result.add(i.open(10, 20)) assert result == expected
def test_add_overlapping_with_multiple(): expected = IntervalSet((i.open(1, 20), i.open(30, 40))) result = IntervalSet((i.open(1, 7), i.open(10, 20), i.open(30, 40))) result.add(i.open(2, 15)) assert result == expected
def test_add_to_empty(): expected = IntervalSet((i.open(1, 7), )) result = IntervalSet() result.add(i.open(1, 7)) assert result == expected