Skip to content

Commit

Permalink
Update timeline/timespan call to propagate timezone
Browse files Browse the repository at this point in the history
  • Loading branch information
allenporter committed Oct 29, 2023
1 parent 3807b6d commit 2f38ace
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 5 deletions.
7 changes: 4 additions & 3 deletions ical/timeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,10 +118,11 @@ class RecurAdapter:
necessary updated fields to act as a flattened instance of the event.
"""

def __init__(self, event: Event):
def __init__(self, event: Event, tzinfo: datetime.tzinfo | None = None):
"""Initialize the RecurAdapter."""
self._event = event
self._event_duration = event.computed_duration
self._tzinfo = tzinfo

def get(
self, dtstart: datetime.datetime | datetime.date
Expand All @@ -146,7 +147,7 @@ def build() -> Event:
)

return LazySortableItem(
Timespan.of(dtstart, dtstart + self._event_duration), build
Timespan.of(dtstart, dtstart + self._event_duration, self._tzinfo), build
)


Expand All @@ -158,5 +159,5 @@ def calendar_timeline(events: list[Event], tzinfo: datetime.tzinfo) -> Timeline:
for event in events:
if not (recur := event.as_rrule()):
continue
iters.append(RecurIterable(RecurAdapter(event).get, recur))
iters.append(RecurIterable(RecurAdapter(event, tzinfo=tzinfo).get, recur))
return Timeline(MergedIterable(iters))
5 changes: 4 additions & 1 deletion ical/timespan.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,12 @@ def of( # pylint: disable=invalid-name]
cls,
start: datetime.date | datetime.datetime,
end: datetime.date | datetime.datetime,
tzinfo: datetime.tzinfo | None = None,
) -> "Timespan":
"""Create a Timestapn for the specified date range."""
return Timespan(normalize_datetime(start), normalize_datetime(end))
return Timespan(
normalize_datetime(start, tzinfo), normalize_datetime(end, tzinfo)
)

@property
def start(self) -> datetime.datetime:
Expand Down
4 changes: 3 additions & 1 deletion ical/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,5 +46,7 @@ def normalize_datetime(
if not isinstance(value, datetime.datetime):
value = datetime.datetime.combine(value, MIDNIGHT)
if value.tzinfo is None:
value = value.replace(tzinfo=tzinfo if tzinfo else local_timezone())
if tzinfo is None:
tzinfo = local_timezone()
value = value.replace(tzinfo=tzinfo)
return value
35 changes: 35 additions & 0 deletions tests/test_calendar.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from ical.calendar import Calendar
from ical.calendar_stream import IcsCalendarStream
from ical.event import Event
from ical.types.recur import Recur


@pytest.fixture(name="calendar")
Expand Down Expand Up @@ -423,3 +424,37 @@ def start_after(dtstart: datetime.datetime) -> list[str]:

local_after = dt_after.astimezone(local_tz)
assert not start_after(local_after)


@freeze_time(datetime.datetime(2023, 10, 25, 12, 0, 0, tzinfo=datetime.timezone.utc))
def test_floating_time_with_timezone_propagation() -> None:
"""Test iteration of floating time events ensuring timezones are respected."""
cal = Calendar()
cal.events.extend(
[
Event(
summary="Event 1",
start=datetime.datetime(2023, 10, 25, 6, 40),
end=datetime.datetime(2023, 10, 25, 6, 50),
rrule=Recur.from_rrule("FREQ=WEEKLY;BYDAY=WE,MO,TU,TH,FR"),
),
Event(
summary="Event 2",
start=datetime.datetime(2023, 10, 25, 8, 30),
end=datetime.datetime(2023, 10, 25, 8, 40),
rrule=Recur.from_rrule("FREQ=DAILY"),
),
Event(
summary="Event 3",
start=datetime.datetime(2023, 10, 25, 18, 30),
end=datetime.datetime(2023, 10, 25, 18, 40),
rrule=Recur.from_rrule("FREQ=DAILY"),
),
]
)
# Ensure there are no calls to fetch the local timezone, only using the provided
# timezone information.
with patch("ical.util.local_timezone", side_effect=ValueError("do not invoke")):
it = iter(cal.timeline_tz(zoneinfo.ZoneInfo("Europe/Brussels")))
for i in range(0, 30):
next(it)

0 comments on commit 2f38ace

Please sign in to comment.