Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UNTIL is always interpreted as UTC #67

Open
leaanthony-sc opened this issue Aug 14, 2024 · 0 comments · May be fixed by #68
Open

UNTIL is always interpreted as UTC #67

leaanthony-sc opened this issue Aug 14, 2024 · 0 comments · May be fixed by #68

Comments

@leaanthony-sc
Copy link

leaanthony-sc commented Aug 14, 2024

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 a Z, it should be interpreted as local to the timezone specified in DTSTART as per the spec.
    Bonus points:
  • If the date-time format given in UNTIL is not the same as that given in DTSTART, it should error.
  • If the date-time format given in DTSTART is in UTC but TZID is also given, it should error.
@leaanthony-sc leaanthony-sc linked a pull request Aug 15, 2024 that will close this issue
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant