Skip to content
Open
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
49 changes: 49 additions & 0 deletions test_files/recurrence-mixed-with-and-without-tz.ics
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Mozilla.org/NONSGML Mozilla Calendar V1.1//EN

BEGIN:VTIMEZONE
TZID:Europe/Berlin
BEGIN:STANDARD
DTSTART:19701025T030000
RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
TZNAME:CET
TZOFFSETFROM:+0200
TZOFFSETTO:+0100
END:STANDARD
BEGIN:DAYLIGHT
DTSTART:19700329T020000
RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=3
TZNAME:CEST
TZOFFSETFROM:+0100
TZOFFSETTO:+0200
END:DAYLIGHT
END:VTIMEZONE

BEGIN:VEVENT
UID:24151946-f737-44b2-eeee-a85f560944b0
DTSTAMP:19910520T070708Z
DTSTART;VALUE=DATE:19910520
DTEND;VALUE=DATE:19910521
CREATED:20101031T171909Z
DESCRIPTION:
EXDATE;VALUE=DATE-TIME:19920520T000000Z
RRULE:FREQ=YEARLY;WKST=MO;UNTIL=19940519T235959Z;BYMONTH=5;BYMONTHDAY=20
SUMMARY:Test
END:VEVENT

BEGIN:VEVENT
DTSTAMP:20171023T070708Z
CREATED:20171023T070428Z
UID:24151946-f737-44b2-9db5-a85f560944b0
SEQUENCE:2
LAST-MODIFIED:20171023T070708Z
SUMMARY:EES Praktikum
RRULE:FREQ=WEEKLY;UNTIL=20171115T120000Z;BYDAY=WE
EXDATE;VALUE=DATE:20171101
DTSTART;TZID=Europe/Berlin:20171025T140000
DTEND;TZID=Europe/Berlin:20171025T183000
TRANSP:OPAQUE
END:VEVENT

END:VCALENDAR
18 changes: 18 additions & 0 deletions tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -828,6 +828,24 @@ def test_recurrence_offset_naive(self):
self.assertEqual(dates[1], datetime.datetime(2013, 1, 24, 0, 0))
self.assertEqual(dates[-1], datetime.datetime(2013, 3, 28, 0, 0))

def test_recurrence_mixed_with_and_without_tz(self):
"""
Ensure recurring vevent with DTSTART and EXDATE not both have or
not have timezone information is parsing.
"""
test_file = get_test_file("recurrence-mixed-with-and-without-tz.ics")
vcalendar = base.readOne(test_file, validate=True)
expected = None
for vobj in vcalendar.getChildren():
if vobj.name == 'VTIMEZONE':
expected = iter([
[datetime.datetime(1991, 5, 20, 0, 0, 0),
datetime.datetime(1993, 5, 20, 0, 0, 0)],
[datetime.datetime(2017, 10, 25, 14, 0, 0, tzinfo=vobj.gettzinfo()),
datetime.datetime(2017, 11, 8, 14, 0, 0, tzinfo=vobj.gettzinfo())]]);
elif vobj.name == 'VEVENT':
dates = list(vobj.getrruleset(addRDate=True))
self.assertEqual(dates, next(expected))

class TestChangeTZ(unittest.TestCase):
"""
Expand Down
15 changes: 13 additions & 2 deletions vobject/icalendar.py
Original file line number Diff line number Diff line change
Expand Up @@ -430,12 +430,23 @@ def getrruleset(self, addRDate=False):
logging.error('failed to find DUE at all.')
return None

if isinstance(dtstart, datetime.datetime):
dtstart_tzinfo = dtstart.tzinfo
else:
dtstart_tzinfo = None
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please move this into the if name in DATENAMES: clause since it is only used in that case.

if name in DATENAMES:
if type(line.value[0]) == datetime.datetime:
list(map(addfunc, line.value))
for dt in line.value:
if dtstart_tzinfo is None:
addfunc(dt.replace(tzinfo=None))
else:
addfunc(dt)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please move the test outside the loop. This makes the code more efficient.

Same below.

elif type(line.value[0]) == datetime.date:
for dt in line.value:
addfunc(datetime.datetime(dt.year, dt.month, dt.day))
if isinstance(dtstart, datetime.datetime):
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this test different from the one for datetime (line 440)?

addfunc(dtstart.replace(dt.year, dt.month, dt.day))
else:
addfunc(datetime.datetime(dt.year, dt.month, dt.day, tzinfo=dtstart_tzinfo))
else:
# ignore RDATEs with PERIOD values for now
pass
Expand Down