forked from hswaw/hscloud
74 lines
2.2 KiB
Go
74 lines
2.2 KiB
Go
|
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
|
||
|
}
|