rrule-go
rrule-go copied to clipboard
`UNTIL` is always interpreted as UTC
teambition/rrule-go version: v1.8.2
According to RFC5545, a DATE-TIME
value can specify either a local time or UTC:
FORM #1: DATE WITH LOCAL TIME
The date with local time form is simply a DATE-TIME value that
does not contain the UTC designator nor does it reference a time
zone. For example, the following represents January 18, 1998, at
11 PM:
19980118T230000
DATE-TIME values of this type are said to be "floating" and are
not bound to any time zone in particular. They are used to
represent the same hour, minute, and second value regardless of
which time zone is currently being observed.
and
FORM #2: DATE WITH UTC TIME
The date with UTC time, or absolute time, is identified by a LATIN
CAPITAL LETTER Z suffix character, the UTC designator, appended to
the time value. For example, the following represents January 19,
1998, at 0700 UTC:
19980119T070000Z
The "TZID" property parameter MUST NOT be applied to DATE-TIME
properties whose time values are specified in UTC.
An example is given for DTSTART
:
FORM #3: DATE WITH LOCAL TIME AND TIME ZONE REFERENCE
The date and local time with reference to time zone information is
identified by the use the "TZID" property parameter to reference
the appropriate time zone definition. "TZID" is discussed in
detail in [Section 3.2.19](https://datatracker.ietf.org/doc/html/rfc5545#section-3.2.19). For example, the following represents
2:00 A.M. in New York on January 19, 1998:
TZID=America/New_York:19980119T020000
NOTE: The time specified in DTSTART
is interpreted correctly by the library.
RFC5545 specifies UNTIL
as:
The UNTIL rule part defines a DATE or DATE-TIME value that bounds
the recurrence rule in an inclusive manner. If the value
specified by UNTIL is synchronized with the specified recurrence,
this DATE or DATE-TIME becomes the last instance of the
recurrence. The value of the UNTIL rule part MUST have the same
value type as the "DTSTART" property. Furthermore, if the
"DTSTART" property is specified as a date with local time, then
the UNTIL rule part MUST also be specified as a date with local
time. If the "DTSTART" property is specified as a date with UTC
time or a date with local time and time zone reference, then the
UNTIL rule part MUST be specified as a date with UTC time.
Note this part:
Furthermore, if the "DTSTART" property is specified as a date with local time, then the UNTIL rule part MUST also be specified as a date with local time.
Unfortunately, this is not handled correctly. All date-time values in this field are interpreted as UTC.
To Reproduce
Code to reproduce the behavior:
func TestLocalTime(t *testing.T) {
localTimeRRULE := "DTSTART;TZID=Australia/Sydney:19980101T090000\nRRULE:FREQ=WEEKLY;UNTIL=20201230T220000"
r, err := StrToRRule(localTimeRRULE)
if err != nil {
t.Errorf("Error parsing rrule: %v", err)
}
localTimeRRULE2 := r.String()
if localTimeRRULE != localTimeRRULE2 {
t.Errorf("Expected:\n%v\ngot\n%v\n", localTimeRRULE, localTimeRRULE2)
}
}
The test above shows that the UNTIL
value is interpreted as UTC:
str_test.go:27: Expected:
DTSTART;TZID=Australia/Sydney:19980101T090000
RRULE:FREQ=WEEKLY;UNTIL=20201230T220000
got
DTSTART;TZID=Australia/Sydney:19980101T090000
RRULE:FREQ=WEEKLY;UNTIL=20201230T220000Z
We can confirm this in another test:
func TestLocalTime2(t *testing.T) {
sydney, _ := time.LoadLocation("Australia/Sydney")
localTimeRRULE := "DTSTART;TZID=Australia/Sydney:19980101T090000\nRRULE:FREQ=WEEKLY;UNTIL=20201230T220000"
r, err := StrToRRule(localTimeRRULE)
if err != nil {
t.Errorf("Error parsing rrule: %v", err)
}
until := r.GetUntil()
if until.Location() != sydney {
t.Errorf("Expected:\n%v\ngot\n%v\n", sydney.String(), until.Location().String())
}
}
which outputs:
str_test.go:40: Expected:
Australia/Sydney
got
UTC
Expected behavior
- If the value specified in
UNTIL
does not end in aZ
, it should be interpreted as local to the timezone specified inDTSTART
as per the spec. Bonus points: - If the date-time format given in
UNTIL
is not the same as that given inDTSTART
, it should error. - If the date-time format given in
DTSTART
is inUTC
butTZID
is also given, it should error.