mangstadt / biweekly

biweekly is an iCalendar library written in Java.
BSD 2-Clause "Simplified" License
323 stars 44 forks source link

Windows timezone not parsed correctly #115

Closed slowcar closed 2 years ago

slowcar commented 2 years ago

I have an issue parsing ical files in my test cases, which occurs when my timezone switches from summer (DST) to winter time. There are two ics files, both from 08:00-08:30, one on 29.10.2022, a day before the switch, one on 31.10.2022, the day after.

E1: DTSTART;TZID="W. Europe Standard Time":20221029T080000 E2: DTSTART;TZID="W. Europe Standard Time":20221031T080000

When i log the timestamps of the VEvent, the first (E1) is 1667023200000, which is correct GMT: Saturday, 29. October 2022 06:00:00 Your time zone: Samstag, 29. Oktober 2022 08:00:00 [GMT+02:00] DST

the second event (E2) has the timestamp 1667196000000, which is not correct GMT: Monday, 31. October 2022 06:00:00 Your time zone: Montag, 31. Oktober 2022 07:00:00 [GMT+01:00]

Importing the ical files with Outlook shows them correct, and the timestamps on Exchange are also correct for both events. (i created the files with Outlook)

When i set my test device to a date outside dst (e.g. to november), both timestamps are parsed correctly.

I have attached the ics files for both events: ics.zip

slowcar commented 2 years ago

Looks like it was my mistake, i assumed that vEvent.getDateEnd().getValue() returned a Date with an UTC timestamp, but on further inspection i saw that there are other components in the extended class ICalDate. Using vEvent.getDateStart().getValue().getRawComponents().toDate(TimeZone.getDefault()) i can get the timestamp

slowcar commented 2 years ago

On further inspection, i think i found the issue. The timezone in the ics is "W. Europe Standard Time", which is parsed by biweekly to a timezone with the id "W. Europe Standard Time" and the displayname "GMT+01:00", which is not the same as the Microsoft timezone with the id "W. Europe Standard Time" which would be the olson id "Europe/Amsterdam".

The parsed timezone "GMT+01:00" has an offset of 7200000 (2h) while the "Europe/Amsterdam" timezone has an offset of 3600000 (1h) for the timestamp in question (start of the ics on November 23, 1669190400000 )

The source of the mapping i use is https://github.com/unicode-org/cldr/blob/main/common/supplemental/windowsZones.xml with code similar to this old snippet https://gist.github.com/scottmac/655675e9b4d4913c539c or this code https://github.com/LinkedInAttic/RookBoom/blob/master/ews/src/main/java/com/microsoft/exchange/utils/WindowsZonesMapping.java

I built a workaround by using the id of the biweekly timezone as an Exchange identifier and look up the matching olson timezone.

mangstadt commented 2 years ago

Not sure if this helps, but:

In order to parse the "W. Europe Standard Time" timestamps in your examples, biweekly uses the timezone definition data located between the BEGIN:VTIMEZONE and END:VTIMEZONE lines.

If the "TZID" parameter value begins with a /, then biweekly will treat the timezone as an Olsen ID and will use Java's embedded timezone definition to parse the timestamp. For example: DTSTART;TZID="/Europe/Amsterdam":20221029T080000

slowcar commented 2 years ago

The timezone in the ics switches from +0200 to +0100 at the last sunday of october (BYDAY=-1SU;BYMONTH=10), but the parsed timezone does not.

Microsoft does not use Olson ids, which should not matter if biweekly parses the timezone information.

mangstadt commented 2 years ago

Could you write a unit test that demonstrates this?