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

bug: RRULE Timezone must be in UTC format - ends in Z #28

Closed
4 tasks done
a-nicholls opened this issue May 26, 2020 · 17 comments
Closed
4 tasks done

bug: RRULE Timezone must be in UTC format - ends in Z #28

a-nicholls opened this issue May 26, 2020 · 17 comments
Labels
bug Something isn't working

Comments

@a-nicholls
Copy link

a-nicholls commented May 26, 2020

Describe the bug

I've shared a calendar from Office 365 that shares out the ics link (downloaded file below)
but running with test code reports RRULE UNTIL values must be specified in UTC when DTSTART is timezone-aware

From what I've read the UTC time format can include a trailing Z to indicate UTC time?

If I remove the Z from the RRULE UTIL value it shows the dates but with incorrect changes - I'm guessing this is because the date is not in same time zone UTC +1?)

**start 2020-05-28 duration 1 day, 0:00:00** (shouldn't be there)
start 2020-06-11 duration 1 day, 0:00:00
start 2020-06-25 duration 1 day, 0:00:00
start 2020-07-09 duration 1 day, 0:00:00
start 2020-07-23 duration 1 day, 0:00:00
start 2020-08-06 duration 1 day, 0:00:00
start 2020-08-20 duration 1 day, 0:00:00
**start 2020-09-03 duration 1 day, 0:00:00**(shouldn't be there)
start 2020-06-04 duration 1 day, 0:00:00
start 2020-06-18 duration 1 day, 0:00:00
start 2020-07-02 duration 1 day, 0:00:00
start 2020-07-16 duration 1 day, 0:00:00
start 2020-07-30 duration 1 day, 0:00:00
start 2020-08-13 duration 1 day, 0:00:00
start 2020-08-27 duration 1 day, 0:00:00
start 2020-05-29 duration 1 day, 0:00:00
start 2020-09-04 duration 1 day, 0:00:00

To Reproduce

import icalendar
import recurring_ical_events
import urllib.request

start_date = (2020, 5, 25)
end_date =   (2020, 9, 5)

file = open("test.ics", "rb") 
ical_string = file.read() 
calendar = icalendar.Calendar.from_ical(ical_string)
events = recurring_ical_events.of(calendar).between(start_date, end_date)
for event in events:
    start = event["DTSTART"].dt
    duration = event["DTEND"].dt - event["DTSTART"].dt
    print("start {} duration {}".format(start, duration))

ICS file

test.ics.txt

Expected behavior

I expect it to not show two of the dates (2020-05-28 and 2020-09-03)

Console output

Traceback (most recent call last):
  File "/icstesting/ENV/lib/python3.8/site-packages/recurring_ical_events.py", line 173, in create_rule_with_start
    return rrulestr(rule_string, dtstart=start)
  File "/icstesting/ENV/lib/python3.8/site-packages/dateutil/rrule.py", line 1730, in __call__
    return self._parse_rfc(s, **kwargs)
  File "/icstesting/ENV/lib/python3.8/site-packages/dateutil/rrule.py", line 1650, in _parse_rfc
    return self._parse_rfc_rrule(lines[0], cache=cache,
  File "/icstesting/ENV/lib/python3.8/site-packages/dateutil/rrule.py", line 1559, in _parse_rfc_rrule
    return rrule(dtstart=dtstart, cache=cache, **rrkwargs)
  File "/icstesting/ENV/lib/python3.8/site-packages/dateutil/rrule.py", line 468, in __init__
    raise ValueError(
ValueError: RRULE UNTIL values must be specified in UTC when DTSTART is timezone-aware

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "test.py", line 15, in <module>
    events = recurring_ical_events.of(calendar).between(start_date, end_date)
  File "/icstesting/ENV/lib/python3.8/site-packages/recurring_ical_events.py", line 334, in between
    repetitions = self.RepeatedEvent(event, span_start)
  File "/icstesting/ENV/lib/python3.8/site-packages/recurring_ical_events.py", line 155, in __init__
    rule.rrule(self.create_rule_with_start(_rule.to_ical().decode(), self.start))
  File "/icstesting/ENV/lib/python3.8/site-packages/recurring_ical_events.py", line 178, in create_rule_with_start
    assert self.start.tzinfo is not None, "we assume the start is timezone aware but the until value is not" # see the comment above
AssertionError: we assume the start is timezone aware but the until value is not

Version:

Additional context

I'm new to python and pull requests - but happy to have a go at putting in a test

Suggested implementation


We're using Polar.sh so you can upvote and help fund this issue. We receive the funding once the issue is completed & confirmed by you. Thank you in advance for helping prioritize & fund our work. Fund with Polar
@a-nicholls a-nicholls added the bug Something isn't working label May 26, 2020
@a-nicholls
Copy link
Author

on my limited testing - I think this maybe a potential issue with the python-dateutil module 2.8.1
dateutil/dateutil#1006

@niccokunzmann
Copy link
Owner

niccokunzmann commented May 31, 2020 via email

@a-nicholls
Copy link
Author

not sure what you mean - new to this (as actually just user not developer of someone elses component that called this module!) , but are you referring that the requirements.txt should have a reference to python-dateutil to be at least 2.8.1 to test?

I tried to write a test script but can't figure out what I'm supposed to do in the event that another module raises the error other than it marking as an expected failure - but that would be until potentially it gets fixed in which case the test would need to be updated to remove the expected failure?

I tried something like this with the associated ics file which tests that it should have 15 not 17 events (the exceptions) which I can test if I manually remove the Z's and will correctly fail and hopefully mark it as skipping if it raises any ValueError?

import pytest

@pytest.mark.xfail(raises=ValueError)

def test_expectedamountofevents(calendars):
    events = calendars.issue_28_rrule_with_UTC_endinginZ.between((2020, 5, 25),(2020, 9, 5))
    assert len(events) == 15

@niccokunzmann
Copy link
Owner

@a-nicholls Thanks for providing so much information. I added your file and the test. Let's see how this can be fixed.
834c441

@niccokunzmann
Copy link
Owner

niccokunzmann commented Jun 12, 2020

When I update the dateutil module to version 2.2, I get another error.

$ pip install --upgrade py-dateutil
Collecting py-dateutil
  Downloading py-dateutil-2.2.tar.gz (64 kB)
     |████████████████████████████████| 64 kB 75 kB/s 
Requirement already satisfied, skipping upgrade: six in ./ENV/lib/python3.8/site-packages (from py-dateutil) (1.14.0)
Building wheels for collected packages: py-dateutil
  Building wheel for py-dateutil (setup.py) ... done
  Created wheel for py-dateutil: filename=py_dateutil-2.2-py3-none-any.whl size=34707 sha256=1c14e086dc827e207ceebcfb107de22087caab430264b9f9e3295d30ca9025a1
  Stored in directory: /home/sabin/.cache/pip/wheels/68/10/a2/7c4fddcbdb77c09622a08eef4a6a93168dab9341edd48f7819
Successfully built py-dateutil
Installing collected packages: py-dateutil
Successfully installed py-dateutil-2.2
$ pytest
TypeError: can't compare offset-naive and offset-aware datetimes

This error occurs in your test and in the test of Issue 4.
So, I wonder, how to approach it.

@niccokunzmann
Copy link
Owner

niccokunzmann commented Jun 12, 2020

@a-nicholls I added code and now the test fails in the number of expected events.

test/test_issue_28_timezone_with_z.py FF                                                                                       [100%]

============================================================== FAILURES ==============================================================
_____________________________________________ test_expected_amount_of_events[Calendars] ______________________________________________

calendars = <conftest.Calendars object at 0x7f15167d6310>

    def test_expected_amount_of_events(calendars):
        events = calendars.issue_28_rrule_with_UTC_endinginZ.between((2020, 5, 25),(2020, 9, 5))
>       assert len(events) == 15
E       AssertionError: assert 17 == 15
E        +  where 17 = len([VEVENT({'DESCRIPTION': vText('b'\\n''), 'UID': vText('b'040000008200E00074C5B7101A82E00800000000017E1BADC42ED60100000...b'1''), 'X-MICROSOFT-DONOTFORWARDMEETING': vText('b'FALSE''), 'X-MICROSOFT-DISALLOW-COUNTER': vText('b'FALSE'')}), ...])

test/test_issue_28_timezone_with_z.py:9: AssertionError
_________________________________________ test_expected_amount_of_events[ReversedCalendars] __________________________________________

calendars = <conftest.ReversedCalendars object at 0x7f151680e9a0>

    def test_expected_amount_of_events(calendars):
        events = calendars.issue_28_rrule_with_UTC_endinginZ.between((2020, 5, 25),(2020, 9, 5))
>       assert len(events) == 15
E       AssertionError: assert 17 == 15
E        +  where 17 = len([VEVENT({'DESCRIPTION': vText('b'\\n''), 'UID': vText('b'040000008200E00074C5B7101A82E00800000000017E1BADC42ED60100000...b'1''), 'X-MICROSOFT-DONOTFORWARDMEETING': vText('b'FALSE''), 'X-MICROSOFT-DISALLOW-COUNTER': vText('b'FALSE'')}), ...])

test/test_issue_28_timezone_with_z.py:9: AssertionError
====================================================== 2 failed in 0.09 seconds ======================================================

What do you think how we should proceed?

@a-nicholls
Copy link
Author

Yeah looks similar to the datetime module, the problem with local time being required to be in UTC and the exceptions are saved in UTC+1 (which I believe is correct) so there should be 17 items not 19.

The comparisons in my mind should be all converted to the same time to local time to figure out which exceptions have to be removed

@niccokunzmann
Copy link
Owner

This fix is released in Version v0.1.17

@a-nicholls
Copy link
Author

a-nicholls commented Jun 15, 2020

Hi!

The test the I wrote was correct in that there are only 15 events not 17 as noted in original post, if you check the ics file,

The recurring event SUMMARY:Refuse black bin with UID

040000008200E00074C5B7101A82E00800000000017E1BADC42ED601000000000000000
 010000000FBF1FBAE2E9FBC4D81F16854E2F4D51B

There's two RECURRENCE-IDs referencing the same UID - haven't changed the SUMMARY so that's the same, but it says that in effect, 20200528T000000 (28th May) change that to DTSTART;VALUE=DATE:20200529 (29th May) and
RECURRENCE-ID;TZID=GMT Standard Time:20200903T000000 (3rd September)
change that to (keeping same SUMMARY)
DTSTART;VALUE=DATE:20200904 (4th September)

I've shown how the client shows May 2020 (note no 28th May, but there is something on 29th May)
image

@niccokunzmann
Copy link
Owner

Should we re-open this issue or open a new one since the test is wrong?

@a-nicholls
Copy link
Author

actually the test written did do a test against 15 not 17, so the test file will need to be changed back and it makes sense as problem was mentioned also in issue to reopen this issue if that's ok?

@niccokunzmann niccokunzmann reopened this Jun 22, 2020
niccokunzmann added a commit that referenced this issue Jun 22, 2020
niccokunzmann added a commit that referenced this issue Jun 30, 2020
when the recurrence/id differs in format from the date, this solves some problems
refers to #28 (comment)
@niccokunzmann
Copy link
Owner

@a-nicholls Thanks again for reporting... I could fix the tests and opened an issue for the broader problem of matching recurrence-ids. #36

@niccokunzmann
Copy link
Owner

Again, let me know if you have input!

@niccokunzmann
Copy link
Owner

This fix is included in v0.1.18b.

@a-nicholls
Copy link
Author

looks like that did it! with the test program above, should the calling of recurring_ical_events.of(calendar).between(start_date, end_date) be returning it ordered in date order or is it the calling program that should sort it if it needs to?

@niccokunzmann
Copy link
Owner

niccokunzmann commented Jul 4, 2020 via email

@a-nicholls
Copy link
Author

ah ok - apparently the module that uses this great library is doing the sort :) no problems :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants