diff --git a/parse.go b/parse.go index 21e9d63..8e6a9a8 100644 --- a/parse.go +++ b/parse.go @@ -518,9 +518,16 @@ func (p *Parser) parseTimeField(fieldName string, eventData string) (time.Time, return t, tzID } tzID = result[2] + dt := result[4] if !strings.Contains(dt, "Z") { - dt = fmt.Sprintf("%sZ", dt) + loc, err := time.LoadLocation(strings.TrimSpace(tzID)) + if err != nil { + dt = fmt.Sprintf("%sZ", strings.TrimSpace(dt)) + } else { + t, err = time.ParseInLocation(IcsFormatWithoutTZ, strings.TrimSpace(dt), loc) + return t, tzID + } } t, _ = time.Parse(IcsFormat, dt) } diff --git a/parse_test.go b/parse_test.go index 0b9d30b..2af7ef1 100644 --- a/parse_test.go +++ b/parse_test.go @@ -382,8 +382,8 @@ func TestCalendarEvents(t *testing.T) { } // event must have - start, _ := time.Parse(IcsFormat, "20140714T100000Z") - end, _ := time.Parse(IcsFormat, "20140714T110000Z") + start := time.Date(2014, 7, 14, 10, 0, 0, 0, time.FixedZone("EEST", 3*60*00)) + end := time.Date(2014, 7, 14, 11, 0, 0, 0, time.FixedZone("EEST", 3*60*00)) created, _ := time.Parse(IcsFormat, "20140515T075711Z") modified, _ := time.Parse(IcsFormat, "20141125T074253Z") location := "In The Office" @@ -399,11 +399,11 @@ func TestCalendarEvents(t *testing.T) { org.SetName("r.chupetlovska@gmail.com") org.SetEmail("r.chupetlovska@gmail.com") - if event.GetStart() != start { + if event.GetStart().Equal(start) { t.Errorf("Expected start %s, found %s", start, event.GetStart()) } - if event.GetEnd() != end { + if event.GetEnd().Equal(end) { t.Errorf("Expected end %s, found %s", end, event.GetEnd()) } @@ -723,3 +723,46 @@ func TestPagerDutyCalendarEventTimes(t *testing.T) { t.Fatalf("End should be %s, but was %s", expectedEnd, end) } } + +func TestAppleCalendar(t *testing.T) { + parser := New() + input := parser.GetInputChan() + input <- "testCalendars/apple.ics" + parser.Wait() + + parseErrors, err := parser.GetErrors() + if err != nil { + t.Errorf("Failed to wait the parse of the calendars ( %s )", err) + } + if len(parseErrors) != 0 { + t.Errorf("Expected 0 error, found %d in :\n %#v", len(parseErrors), parseErrors) + } + + calendars, errCal := parser.GetCalendars() + if errCal != nil { + t.Errorf("Failed to get calendars ( %s )", errCal) + } + + if len(calendars) != 1 { + t.Errorf("Expected 1 calendar, found %d calendars", len(calendars)) + return + } + + calendar := calendars[0] + if len(calendar.events) != 1 { + t.Errorf("Expected no 1 event, got %d", len(calendar.events)) + } + + event := calendar.events[0] + + st := time.Date(2013, 2, 26, 19, 0, 0, 0, time.FixedZone("CET", -1*60*60)) + if event.start.Equal(st) { + t.Errorf("Expected no start time to be %q, got %q", st, event.start) + } + + // Test exact start day + et := time.Date(2013, 2, 26, 20, 0, 0, 0, time.FixedZone("CET", -1*60*60)) + if event.end.Equal(et) { + t.Errorf("Expected no start time to be %q, got %q", et, event.end) + } +} diff --git a/testCalendars/apple.ics b/testCalendars/apple.ics new file mode 100644 index 0000000..d8ff910 --- /dev/null +++ b/testCalendars/apple.ics @@ -0,0 +1,62 @@ +BEGIN:VCALENDAR +METHOD:PUBLISH +VERSION:2.0 +X-WR-CALNAME:Private +PRODID:-//Apple Inc.//Mac OS X 10.13.6//EN +X-APPLE-CALENDAR-COLOR:#AF26AE +X-WR-TIMEZONE:Europe/Berlin +CALSCALE:GREGORIAN +BEGIN:VTIMEZONE +TZID:Europe/Berlin +BEGIN:DAYLIGHT +TZOFFSETFROM:+0100 +RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU +DTSTART:19810329T020000 +TZNAME:MESZ +TZOFFSETTO:+0200 +END:DAYLIGHT +BEGIN:STANDARD +TZOFFSETFROM:+0200 +RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU +DTSTART:19961027T030000 +TZNAME:MEZ +TZOFFSETTO:+0100 +END:STANDARD +END:VTIMEZONE +BEGIN:VTIMEZONE +TZID:America/Los_Angeles +BEGIN:STANDARD +TZOFFSETFROM:-0700 +RRULE:FREQ=YEARLY;UNTIL=20061029T090000Z;BYMONTH=10;BYDAY=-1SU +DTSTART:19621028T020000 +TZNAME:GMT-8 +TZOFFSETTO:-0800 +END:STANDARD +BEGIN:DAYLIGHT +TZOFFSETFROM:-0800 +RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU +DTSTART:20070311T020000 +TZNAME:GMT-7 +TZOFFSETTO:-0700 +END:DAYLIGHT +BEGIN:STANDARD +TZOFFSETFROM:-0700 +RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU +DTSTART:20071104T020000 +TZNAME:GMT-8 +TZOFFSETTO:-0800 +END:STANDARD +END:VTIMEZONE +BEGIN:VEVENT +CREATED:20130222T144647Z +UID:1311CE22-DB37-11EA-A969-00155DC69F13 +DTEND;TZID=Europe/Berlin:20130226T200000 +TRANSP:OPAQUE +X-APPLE-TRAVEL-ADVISORY-BEHAVIOR:AUTOMATIC +SUMMARY:Some Event +DTSTART;TZID=Europe/Berlin:20130226T190000 +DTSTAMP:20200203T171541Z +LAST-MODIFIED:20130222T144647Z +SEQUENCE:0 +END:VEVENT +END:VCALENDAR diff --git a/utils.go b/utils.go index 2d25b47..4115b39 100644 --- a/utils.go +++ b/utils.go @@ -32,8 +32,11 @@ var MaxRepeats int // unixtimestamp const uts = "1136239445" +//ics date time format without timezone +const IcsFormatWithoutTZ = "20060102T150405" + //ics date time format -const IcsFormat = "20060102T150405Z" +const IcsFormat = IcsFormatWithoutTZ + "Z" // Y-m-d H:i:S time format const YmdHis = "2006-01-02 15:04:05"