Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Timedelta #168

Merged
merged 2 commits into from
Aug 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,8 @@ The resulting ``events`` are a list of `icalendar events <https://icalendar.read

``between(start, end)`` returns all events happening between a start and an end time. Both arguments can be `datetime.datetime`_, `datetime.date`_, tuples of numbers passed as arguments to `datetime.datetime`_ or strings in the form of
``%Y%m%d`` (``yyyymmdd``) and ``%Y%m%dT%H%M%SZ`` (``yyyymmddThhmmssZ``).
For examples, see ``at(a_date)`` above.
Additionally, the ``end`` argument can be a ``datetime.timedelta`` to express that the end is relative to the ``start``.
For examples of arguments, see ``at(a_date)`` above.

.. code:: Python

Expand Down Expand Up @@ -394,6 +395,10 @@ These **Occurrences** are used internally and convert to **Components** for furt
Changelog
---------

- v3.2.0

- Allow ``datetime.timedelta`` as second argument to ``between(absolute_time, datetime.timedelta())``

- v3.1.1

- Fix: Remove duplication of modification with same sequence number, see `Issue 164 <https://github.com/niccokunzmann/python-recurring-ical-events/issues/164>`_
Expand Down
15 changes: 12 additions & 3 deletions recurring_ical_events.py
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down Expand Up @@ -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."""

Expand Down Expand Up @@ -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]
Expand Down
7 changes: 4 additions & 3 deletions test/test_issue_164_duplicated_event.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
assert len(events) == 2
27 changes: 27 additions & 0 deletions test/test_timedelta_for_between.py
Original file line number Diff line number Diff line change
@@ -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