Beispiel #1
0
    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):
    """`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
Beispiel #3
0
def sample(unit):
    """Random time between between bounds of possible time.

    Returned time is not included in the last segment of
    interval measured in 'unit'.
    """
    return floor(random_datetime_between(MIN, add_delta(MAX, -1, unit)), unit)
    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
Beispiel #5
0
    def forward(self, start):
        """Iterate time intervals starting from 'start'.
        Intervals returned in form of `(start, end)` pair,
        where `start` is a datetime object representing the start
        of the interval and `end` is the non-inclusive end of the interval.

        Parameters
        ----------
        start : datetime.datetime
            A lower bound for the resulting sequence of intervals.

        Yields
        ------
        start : datetime.datetime
            Start of an interval.
        end : datetime.datetime
            End of an interval.
        """
        if self.recurrence is None:
            base = MIN
        else:
            base = floor(start, self.recurrence)

        correction = -1 * BASE[self.unit]

        def addfloor(base, delta):
            """Adds 'delta' to 'base' and than floors it
            by unit of this interval."""
            return floor(add_delta(base, delta, self.unit), self.unit)

        # Handle possible overlap in first interval
        try:
            first = addfloor(base, self.interval.start + correction)
            second = addfloor(base, self.interval.stop + correction + 1)
            if first < start < second:
                yield Interval(start, second)
            elif start <= first:
                yield Interval(first, second)
        except OverflowError:
            return

        if self.recurrence is None:
            return
        while True:  # Handle recurring intervals
            base = add_delta(base, 1, self.recurrence)
            try:
                first = addfloor(base, self.interval.start + correction)
                second = addfloor(base, self.interval.stop + correction + 1)
                if base > first:  # In case if flooring by week resulted
                    first = base  # as a time earlier than 'base'
                yield Interval(first, second)
            except OverflowError:
                return
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
Beispiel #7
0
 def addfloor(base, delta):
     """Adds 'delta' to 'base' and than floors it
     by unit of this interval."""
     return floor(add_delta(base, delta, self.unit), self.unit)
    def forward(self, start, trim=True):
        """Iterate time intervals starting from 'start'.
        Intervals returned in form of `(start, end)` pair,
        where `start` is a datetime object representing the start
        of the interval and `end` is the non-inclusive end of the interval.

        Parameters
        ----------
        start : datetime.datetime
            A lower bound for the resulting sequence of intervals.
        trim : bool
            Whether a first interval should be trimmed by 'start' or
            it should be full, so it's start point may potentially be
            earlier, that 'start'.

        Yields
        ------
        start : datetime.datetime
            Start of an interval.
        end : datetime.datetime
            End of an interval.
        """
        # pylint: disable=too-many-branches
        if self.recurrence is None:
            base = MIN
        else:
            base = floor(start, self.recurrence)

        correction = -1 * BASE[self.unit]

        def addfloor(base, n):
            """Adds 'delta' to 'base' and than floors it
            by unit of this interval."""
            return floor(add_delta(base, n, self.unit), self.unit)

        # Handle possible overlap in first interval
        try:
            first = addfloor(base, self.start + correction)

            if start > first:
                if trim:
                    first = start
                # If 'unit' is week, 'first' could be earlier than
                # start of 'recurrence' time component corresponding to
                # 'start'.
                elif self.recurrence is not None:
                    recurrence_start = floor(start, self.recurrence)
                    if first < recurrence_start:
                        first = recurrence_start

            if self.isgapless():
                yield first, MAX
                return

            second = addfloor(base, self.stop + correction)

            if self.recurrence is not None:
                first, second = self._clamp_by_recurrence(base, first, second)

            yield first, second
        except OverflowError:
            return

        if self.recurrence is None:
            return
        while True:  # Handle recurring intervals
            base = add_delta(base, 1, self.recurrence)
            try:
                first = addfloor(base, self.start + correction)
                second = addfloor(base, self.stop + correction)
                if base > first:  # In case if flooring by week resulted
                    first = base  # as a time earlier than 'base'

                first, second = self._clamp_by_recurrence(base, first, second)
                yield first, second
            except OverflowError:
                return
 def _clamp_by_recurrence(self, base, *dates):
     max_ = floor(add_delta(base, 1, self.recurrence), self.recurrence)
     return [min(d, max_) for d in dates]