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

Summer-wintertime-change is not regarded in Component.calculateRecurrenceSet #688

Open
catschl opened this issue Apr 26, 2024 · 0 comments
Labels

Comments

@catschl
Copy link

catschl commented Apr 26, 2024

A want to check if a timespec specified in an ical-string is valid at a moment. Therefore I use FreeBusy in following method:

boolean isValidAt(String calendarString, Clock clock) {
        StringReader sin = new StringReader( calendarString);
        CalendarBuilder builder = new CalendarBuilder();
        Calendar calendar = null;
        try {
            calendar = builder.build(sin);
        } catch (IOException | ParserException e) {

        }
        List<CalendarComponent> componentList = calendar.getComponents(Component.VEVENT);

        // range to check
        VFreeBusy request = new VFreeBusy(Instant.now(clock), Instant.now(clock).plusNanos(1));
        VFreeBusy reply = new VFreeBusy(request, componentList);
        List<Property> p = reply.getProperties("FREEBUSY");

        return !p.isEmpty();
    }

But this does not work if the ical String has a RRULE with freq=daily and the start and end includes a timechange.

To Reproduce
Steps to reproduce the behavior:
1.

@Test
 void test () {

     String myCalendarString =
             "BEGIN:VCALENDAR\n" +
                     "PRODID:-//github.com/rianjs/ical.net//NONSGML ical.net 4.0//EN\n" +
                     "VERSION:2.0\n" +
                     "BEGIN:VEVENT\n" +
                     "DTEND;TZID=Europe/Berlin:20220310T060000\n" +
                     "DTSTAMP:20240403T074328Z\n" +
                     "DTSTART;TZID=Europe/Berlin:20220309T220000\n" +
                     "SUMMARY:\nTZID:Europe/Berlin\n" +
                     "UID:b9dbac1f-03f7-47ad-9f23-36bd605dd1ff\n" +
                     "RRULE:FREQ=DAILY\n" +
                     "SEQUENCE:0\n" +
                     "END:VEVENT\n" +
                     "BEGIN:VTIMEZONE\n" +
                     "TZID:Europe/Berlin\n" +
                     "TZURL:http://tzurl.org/zoneinfo-outlook/Europe/Berlin\n" +
                     "X-LIC-LOCATION:Europe/Berlin\n" +
                     "BEGIN:DAYLIGHT\n" +
                     "TZOFFSETFROM:+0100\n" +
                     "TZOFFSETTO:+0200\n" +
                     "TZNAME:CEST\n" +
                     "DTSTART:19700329T020000\n" +
                     "RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU\n" +
                     "END:DAYLIGHT\n" +
                     "BEGIN:STANDARD\n" +
                     "TZOFFSETFROM:+0200\n" +
                     "TZOFFSETTO:+0100\n" +
                     "TZNAME:CET\n" +
                     "DTSTART:19701025T030000\n" +
                     "RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU\n" +
                     "END:STANDARD\n" +
                     "END:VTIMEZONE\n" +
                     "END:VCALENDAR\n";

     MockClock mockClock = MockClock.at(2024, 3, 30, 21, 59, 0, ZoneId.of("Europe/Berlin"));

     mockClock = MockClock.at(2024, 3, 30, 21, 59, 0, ZoneId.of("Europe/Berlin"));
     assertFalse(isValidAt(myCalendarString, mockClock));

     mockClock = MockClock.at(2024, 3, 30, 22, 0, 0, ZoneId.of("Europe/Berlin"));
     assertTrue(isValidAt(myCalendarString, mockClock));

     mockClock = MockClock.at(2024, 3, 31, 5, 0, 0, ZoneId.of("Europe/Berlin"));
     assertTrue(isValidAt(myCalendarString, mockClock));

     mockClock = MockClock.at(2024, 3, 31, 5, 59, 0, ZoneId.of("Europe/Berlin"));
     assertTrue(isValidAt(myCalendarString, mockClock));

     mockClock = MockClock.at(2024, 3, 31, 6, 0, 0, ZoneId.of("Europe/Berlin"));
     assertFalse(isValidAt(myCalendarString, mockClock));


     mockClock = MockClock.at(2023, 10, 28, 21, 59, 0, ZoneId.of("Europe/Berlin"));
     assertFalse(CalendarUtils.isTimespecValidAt(myCalendarString, Instant.now(mockClock), null));

     mockClock = MockClock.at(2023, 10, 28, 22, 0, 0, ZoneId.of("Europe/Berlin"));
     assertTrue(CalendarUtils.isTimespecValidAt(myCalendarString, Instant.now(mockClock), null));

     mockClock = MockClock.at(2023, 10, 29, 4, 59, 0, ZoneId.of("Europe/Berlin"));
     assertTrue(CalendarUtils.isTimespecValidAt(myCalendarString, Instant.now(mockClock), null));

     mockClock = MockClock.at(2023, 10, 29, 5, 0, 0, ZoneId.of("Europe/Berlin"));
     assertTrue(CalendarUtils.isTimespecValidAt(myCalendarString, Instant.now(mockClock), null));

     mockClock = MockClock.at(2023, 10, 29, 5, 59, 0, ZoneId.of("Europe/Berlin"));
     assertTrue(CalendarUtils.isTimespecValidAt(myCalendarString, Instant.now(mockClock), null));

     mockClock = MockClock.at(2023, 10, 29, 6, 0, 0, ZoneId.of("Europe/Berlin"));
     assertFalse(CalendarUtils.isTimespecValidAt(myCalendarString, Instant.now(mockClock), null));
 }

With timezone "Berlin" on my system it fails on 29.10.2023 5:00.

Expected behavior
At both timechanges (summer -> winter, winter -> summer) there should be a FREEBUSY property until 6 o clock, but not from 6 o clock.
I think the problem is in method calculateRecurrenceSet in Component.java: you cannot add a fix duration in this case. Normally the timeslot lasts 8 hours. but when wintertime changes to summertime it lasts only 7 hours. When summertime changes to wintertime the slot lasts 9 hours.
image

Environment (please complete the following information):

  • iCal4j 4.0.0 rc5
@benfortuna benfortuna added the bug label Apr 27, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants