diff --git a/README.rst b/README.rst index 0066e90..d2ab226 100644 --- a/README.rst +++ b/README.rst @@ -166,7 +166,8 @@ The resulting ``events`` are a list of `icalendar events `_ diff --git a/recurring_ical_events.py b/recurring_ical_events.py index 525da66..cdce7f9 100644 --- a/recurring_ical_events.py +++ b/recurring_ical_events.py @@ -327,7 +327,9 @@ def __init__(self, components: Sequence[ComponentAdapter]): ) else: core = with_highest_sequence(core, component) - self.modifications: set[ComponentAdapter] = set(self.recurrence_id_to_modification.values()) + self.modifications: set[ComponentAdapter] = set( + self.recurrence_id_to_modification.values() + ) del component if core is None: raise InvalidCalendar( @@ -718,6 +720,7 @@ def is_in_span(self, span_start: Time, span_stop: Time) -> bool: """Return whether the component is in the span.""" return time_span_contains_event(span_start, span_stop, self.start, self.end) + class EventAdapter(ComponentAdapter): """An icalendar event adapter.""" @@ -1031,9 +1034,15 @@ def at(self, date: DateArgument): dt = self.to_datetime(date) return self._between(dt, dt + self._DELTAS[len(date) - 3]) - def between(self, start: DateArgument, stop: DateArgument): + def between(self, start: DateArgument, stop: DateArgument | datetime.timedelta): """Return events at a time between start (inclusive) and end (inclusive)""" - return self._between(self.to_datetime(start), self.to_datetime(stop)) + start = self.to_datetime(start) + stop = ( + start + stop + if isinstance(stop, datetime.timedelta) + else self.to_datetime(stop) + ) + return self._between(start, stop) def _occurrences_to_components( self, occurrences: list[Occurrence] diff --git a/test/test_issue_164_duplicated_event.py b/test/test_issue_164_duplicated_event.py index 93920d5..a63d302 100644 --- a/test/test_issue_164_duplicated_event.py +++ b/test/test_issue_164_duplicated_event.py @@ -3,12 +3,13 @@ See https://github.com/niccokunzmann/python-recurring-ical-events/issues/164 """ + def test_event_is_only_returned_once(calendars): """We should not see the same event twice!""" - events = calendars.issue_164_duplicated_event.at([2024,8]) + events = calendars.issue_164_duplicated_event.at([2024, 8]) for event in events: start = event["DTSTART"].dt duration = event["DTEND"].dt - event["DTSTART"].dt - print("start {} duration {}".format(start, duration)) + print(f"start {start} duration {duration}") print(event.to_ical().decode()) - assert len(events) == 2 \ No newline at end of file + assert len(events) == 2 diff --git a/test/test_timedelta_for_between.py b/test/test_timedelta_for_between.py new file mode 100644 index 0000000..264417d --- /dev/null +++ b/test/test_timedelta_for_between.py @@ -0,0 +1,27 @@ +"""This tests that a timedelta can be used as the second argument to between. + +This is useful when you do not want to calculate this yourself. +""" + +from datetime import timedelta + +import pytest + + +@pytest.mark.parametrize( + ("start", "delta", "count"), + [ + ("20190301", timedelta(days=3), 0), + ("20190301", timedelta(days=5), 1), + ("20190301", timedelta(days=3, hours=8), 0), + ("20190301", timedelta(days=3, hours=9), 1), + ("20190301", timedelta(days=3, hours=8, seconds=1), 1), + ("20190304", timedelta(days=1), 1), + ("20190304", timedelta(hours=8), 0), + ("20190304", timedelta(hours=9), 1), + ], +) +def test_event_with_between_and_timedelta(calendars, start, delta, count): + """The event starts at 20190304T080000 and ends at 20190304T080000""" + events = calendars.one_event.between(start, delta) + assert len(events) == count