blob: f742a676c7eeaae5580ee468b5493567739f1cac [file] [log] [blame]
package calendar
import (
"fmt"
"time"
ics "github.com/arran4/golang-ical"
)
// EventTime is a timestamp for calendar events. It either represents a real
// point-in time or a calender day, if it's a whole-day event.
type EventTime struct {
// Time is a timestamp in the timezone originally defined for this event if
// WholeDay is true. Otherwise, it's a UTC time from which a year, month
// and day can be extracted and treated as the indication of a 'calendar
// day' in an unknown timezone.
Time time.Time
// WholeDay is true if this EventTime represents an entire calendar day.
WholeDay bool
}
func (e *EventTime) String() string {
if e.WholeDay {
return fmt.Sprintf("%s (whole day)", e.Time.Format("2006/01/02"))
} else {
return e.Time.String()
}
}
// parseICSTime attempts to parse a given ICS DT{START,END} object into an
// EventTime, trying to figure out if the given object represents a timestamp
// or a whole-day event.
func parseICSTime(p *ics.IANAProperty) (*EventTime, error) {
// If this is has a VALUE of DATE, then this is a whole-day time.
// Otherwise, it's an actual timestamp.
valueList, ok := p.ICalParameters[string(ics.ParameterValue)]
if ok {
if len(valueList) != 1 || valueList[0] != "DATE" {
return nil, fmt.Errorf("unsupported time type: %v", valueList)
}
ts, err := time.Parse("20060102", p.Value)
if err != nil {
return nil, fmt.Errorf("could not parse date %q: %w", p.Value, err)
}
return &EventTime{
Time: ts,
WholeDay: true,
}, nil
}
// You would expect that nextcloud would emit VALUE == DATE-TIME for
// timestamps, but that just doesn't seem to be the case. Maye I should
// read the ICS standard...
tzidList, ok := p.ICalParameters[string(ics.ParameterTzid)]
if !ok || len(tzidList) != 1 {
return nil, fmt.Errorf("TZID missing")
}
tzid := tzidList[0]
location, err := time.LoadLocation(tzid)
if err != nil {
return nil, fmt.Errorf("could not parse TZID %q: %w", tzid, err)
}
ts, err := time.ParseInLocation("20060102T150405", p.Value, location)
if err != nil {
return nil, fmt.Errorf("could not parse time %q: %w", p.Value, err)
}
return &EventTime{
Time: ts,
WholeDay: false,
}, nil
}