def __contains__(self, item): """Test given datetime 'item' for containment in the time interval. Parameters ---------- item : datetime.datetime A 'datetime' object to test. Returns ------- bool Result of containment test. Notes ----- The algorithm here consists of following steps: If recurrence is set: 1. Given datetime floored to unit of 'recurrence' and stored. 2. Then given datetime floored to unit of 'unit' and stored. 3. Delta between resulting datetime objects is calculated and expressed in units of 'unit'. For example if delta is "2 days" and 'unit' is minutes, delta will be "2*24*60 minutes". If recurrence is not set: 1. Delta between date of "the beginning of time" and given date is calculated and expressed in units of 'unit'. 4. Resulting delta tested for containment in the interval. """ if isinstance(item, dt.datetime): item = (item,) elif isinstance(item, (tuple, list)): assert len(item) == 2 elif isinstance(item, Interval): item = (item.start, item.stop) elif isinstance(item, EmptyInterval): return True else: raise AssertionError if self.recurrence is None: time_in_unit = [delta(MIN, e, self.unit) for e in item] else: time_in_unit = [delta(floor(e, self.recurrence), floor(e, self.unit), self.unit) for e in item] # Because we need to count not only time # that already happened, but also time, expressed in 'unit' # that "happening" time_in_unit = [n + 1 for n in time_in_unit] if len(item) == 1: return time_in_unit[0] in self.interval elif len(item) == 2: return Interval(*time_in_unit) <= self.interval
def test_forward_recurrent_random(unit, recurrence, overlap, trim): """`forward()` method of recurrent time intervals with and without overlapping `start` date.""" correction = BASE[unit] max_ = add_delta(MAX, -1 * N, recurrence) unit_maximum = delta(MIN, add_delta(MIN, 1, recurrence), unit) from_, to = sorted(randuniq(2, correction, unit_maximum)) expected = [] initial = start = floor( add_delta(MIN, rnd.randrange(delta(MIN, max_, unit)), unit), recurrence ) if overlap: initial = start = add_delta( initial, rnd.randrange( int(from_), int(to) ) - correction, unit ) for i in range(N): recurrence_start = floor(start, recurrence) recurrence_stop = floor(add_delta(recurrence_start, 1, recurrence), recurrence) first = floor(add_delta(recurrence_start, from_ - correction, unit), unit) second = floor(add_delta(recurrence_start, to - correction, unit), unit) first = max(recurrence_start, min(first, recurrence_stop)) second = min(recurrence_stop, second) assert first <= second assert start <= second if start > first and trim: first = start expected.append((first, second)) start = floor(add_delta(recurrence_start, 1, recurrence), recurrence) recurrentevent = RecurrentEvent(from_, to, unit, recurrence) actual = list(islice(recurrentevent.forward(initial, trim), None, N)) assert actual == expected
def test_forward_recurrent_random(unit, recurrence, overlap): """`forward()` method of recurrent time intervals with and without overlapping `start` date.""" correction = BASE[unit] max_ = add_delta(MAX, -1 * N, recurrence) unit_maximum = delta(MIN, add_delta(MIN, 1, recurrence), unit) interval = Interval(*sorted(randuniq(2, correction, unit_maximum))) expected = [] initial = start = floor( add_delta(MIN, rnd.randrange(delta(MIN, max_, unit)), unit), recurrence ) if overlap: initial = start = add_delta( initial, rnd.randrange( int(interval.start), int(interval.stop) ) - correction, unit ) for i in range(N): recurrence_start = floor(start, recurrence) first = floor(add_delta(recurrence_start, interval.start - correction, unit), unit) second = add_delta(floor(add_delta(recurrence_start, interval.stop - correction, unit), unit), 1, unit) assert first < second assert start < second if start > first: first = start expected.append(Interval(first, second)) start = floor(add_delta(recurrence_start, 1, recurrence), recurrence) timeinterval = TimeInterval(interval, unit, recurrence) actual = list(islice(timeinterval.forward(initial), None, N)) assert actual == expected
def test_forward_non_recurrent_random(unit, overlap, trim): """`forward()` method of non-recurrent time intervals with and without overlapping `start` date.""" correction = BASE[unit] max_ = add_delta(MAX, -1 * N, unit) unit_maximum = delta(MIN, max_, unit) interval = sorted(randuniq(2, correction, unit_maximum)) if overlap: start = add_delta( MIN, rnd.randrange(int(interval[0]), int(interval[1])) - correction, unit ) else: start = add_delta(MIN, int(interval[0]) - correction, unit) if trim: expected_start = start else: expected_start = add_delta(MIN, int(interval[0]) - correction, unit) stop = add_delta(MIN, int(interval[1]) - correction, unit) expected = [(expected_start, stop)] recurrentevent = RecurrentEvent(interval[0], interval[1], unit, None) actual = list(islice(recurrentevent.forward(start, trim), None, N)) assert actual == expected
def unit_span(unit, recurrence=None, sample=None): """How much 'unit''s in 'recurrence'.""" lower = BASE[unit] assert ((recurrence is None and sample is None) or (recurrence is not None and sample is not None)) if recurrence is not None: upper = delta(sample, add_delta(sample, 1, recurrence), unit) else: upper = delta(MIN, add_delta(MAX, -1, unit), unit) assert lower != upper and lower < upper return lower, upper
def test_forward_non_recurrent_random(unit, overlap): """`forward()` method of non-recurrent time intervals with and without overlapping `start` date.""" correction = BASE[unit] max_ = add_delta(MAX, -1 * N, unit) unit_maximum = delta(MIN, max_, unit) interval = Interval(*sorted(randuniq(2, correction, unit_maximum))) if overlap: start = add_delta( MIN, rnd.randrange( int(interval.start), int(interval.stop) ) - correction, unit ) else: start = add_delta(MIN, int(interval.start) - correction, unit) stop = add_delta(MIN, int(interval.stop) - correction + 1, unit) expected = [Interval(start, stop)] timeinterval = TimeInterval(interval, unit, None) actual = list(islice(timeinterval.forward(start), None, N)) assert actual == expected
def __contains__(self, item): """Test given datetime 'item' for containment in the recurrent event. Parameters ---------- item : datetime.datetime A 'datetime' object to test. Returns ------- bool Result of containment test. Notes ----- The algorithm here consists of following steps: If recurrence is set: 1. Given datetime floored to unit of 'recurrence' and stored. 2. Then given datetime floored to unit of 'unit' and stored. 3. Delta between resulting datetime objects is calculated and expressed in units of 'unit'. For example if delta is "2 days" and 'unit' is minutes, delta will be "2*24*60 minutes". If recurrence is not set: 1. Delta between date of "the beginning of time" and given date is calculated and expressed in units of 'unit'. 4. Resulting delta tested for containment in the interval. """ correction = BASE[self.unit] if self.recurrence is None: time_in_unit = delta(MIN, item, self.unit) else: time_in_unit = delta(floor(item, self.recurrence), floor(item, self.unit), self.unit) time_in_unit += correction return self.start <= time_in_unit < self.stop