jkbrzt / rrule

JavaScript library for working with recurrence rules for calendar dates as defined in the iCalendar RFC and more.
https://jkbrzt.github.io/rrule
Other
3.29k stars 514 forks source link

toText() returns the wrong "until" date (one day early) #486

Open schemar opened 2 years ago

schemar commented 2 years ago

When converting an RRule toText(), the end of the recurrence is one day early. See screenshot from the demo page below:

image

Thank you for rrule and your support!

Zeshan-Sh commented 2 years ago

I am also facing same issue whenever using new RRule({values}).toText().

Zeshan-Sh commented 2 years ago

@schemar I have manged to fix it by passing a new Date(), formatted like 2021-12-31 to until property inside RRule. But the bug is still showing on the mentioned rrule demo page.

CovetingEpiphany2152 commented 1 year ago

The issue seems to be a problem on RRule.fromText(). specifying until via new RRule(options) works fine, and the until date is also included in the recurring instances. However, if you use RRule.fromText(), the until date is excluded from the recurring instances, and doing .toText() shows that there is an off-by-one error, the until in .toText() is one day earlier than what is passed into .fromText()

CovetingEpiphany2152 commented 1 year ago

I have found the root cause of this behavior. It should only occur for people who are living in timezones before UTC. https://github.com/jakubroztocil/rrule/blob/d352fb3c235fa91f9ee108851f49a4b76e2b8ee4/src/nlp/parsetext.ts#L426

It parses date as local time instead of UTC time. For example, you are at UTC+8, and run the following:

const d = Date.parse('dec 29 2022');
const d2 = new Date(d);
console.log(d2);

You'd get Date: "2022-12-28T16:00:00.000Z", which is 2022-12-29T00:00:00 for UTC +8.

However, if you pass in 'dec 29 2022 UTC' instead, you would get the expected "2022-12-29T00:00:00.000Z" for d2.

I'm starting to think that this is not an actual issue. It's because we are passing in date and time without specifying the timezone, and naturally, it is assumed to be our local timezone.

As documented, RRule will work on datetime in UTC, and return them in UTC. So it is up to the user to specify if the input timezone, or convert the output to their timezone.

TobTobXX commented 1 year ago

There's an issue with this though: If you parse "every day until March 27, 2023 UTC" and then toText() it, you get "every day until March 27, 2023", meaning when you parse it again, it gets interpreted in local time this time around.

I think it would be most sensible to use UTC to parse that, since when a user writes a date, I don't think they mean exactly at the moment of midnight, but rather only that date.