-
-
Notifications
You must be signed in to change notification settings - Fork 519
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
UTC-but-not-UTC confusion #336
Comments
I'm also terribly confused. |
Ok I got it, there was this key paragraph in the readme: You have to use these two helper fucntions for the local timezone. You would have to modify offset to get the offset for the X timezone if you want to modify this to support tzid.
Then your code would change to:
|
I suspect there's not going to be a good way around this in this library, built as it is on JS' confusing and irregular |
Thanks @davidgoli your work is so super appreciated!!! I think we need someone that understands to write an article to help others understand the irregular date implementation. I honestly still don't get it, I just tweaked things till it worked. |
It would be because the returned date that you're printing to the console is a JavaScript date that is being converted into a string, and JavaScript automatically prints Dates to console in UTC (See the 'Z' at the end of your timestamps that denotes zero offset). Since the next occurrences in each of your four cases are happening at the exact same time (although in different time zones), it's printing the exact same timestamp four times. |
Also note that the JavaScript |
You might want to check out rSchedule's source. All iteration is done with a special For example: this date import { DateTime as LuxonDateTime } from 'luxon';
const date = LuxonDateTime.fromObject({
year: 2019,
month: 1,
day: 1,
zone: 'America/Los_Angeles'
}) would be converted to this UTC date and the timezone would be saved const fakeDate = Date.UTC(2019, 0, 1)
const fakeDateZone = 'America/Los_Angeles' Note that this UTC date look similar to the Luxon date (they both look like This being said, iterating with this special "UTC" date lets us iterate without worrying about daylight savings time. After the correct date is found, we can convert is back to a luxon date. For example: LuxonDateTime.fromObject({
year: fakeDate.year,
month: fakeDate.month,
day: fakeDate.day,
zone: fakeDateZone,
}) This keeps the iteration logic nice an UTC friendly while still supporting arbitrary timezones. |
@thefliik I got the primitives down; it's weeks that are the real headache here. Though I see rschedule has also punted (so far) on byweekno & bysetpos support... |
Ah ya. |
any news? |
I think it's easy to conflate issues with the JavaScript Date objectI don't agree that the JS As @hlee5zebra mentioned, dates created with the The implementation also correctly follows the convention of doing all processing in UTC and only converting to local time on display to the user. It just so happens that we, the developers, are the user; but then we have our own user in mind which muddies the water. When developing our apps, we must make sure to follow the convention and save dates as UTC in our backend (JS already processes dates in UTC so we're good there). If you store dates as UTC in your data store, they should arrive at the client as ISO strings, be parsed correctly by the This write up has helped me understand the RRULECalculating occurrences for an For example, if our user wants recurrence that occurs every Tuesday, they're going to expect all occurrences to fall on a Tuesday in their local time. However, all calculations are done in UTC, so an
would return occurrences on Tuesdays in UTC, but for any user located significantly west of the prime meridian, occurrences would appear on Mondays in local time, which is obviously not the result anyone is hoping for. Getting it rightAll that said, what the developer must do to solve for this is force JavaScript to think that the local date is actually a UTC date, give that "fake" date to import { RRule } from 'rrule'
const dtstart = new Date('2019-10-29T00:02:26Z') // same as: `new Date(Date.UTC(2019, 9, 29, 0, 2, 26))`
console.log(dtstart.toISOString()) // 2019-10-29T00:02:26.000Z
console.log(dtstart) // Mon Oct 28 2019 17:02:26 GMT-0700 (Pacific Daylight Time)
const fakeDateStart = setPartsToUTCDate(dtstart)
console.log(fakeDateStart.toISOString()) // 2019-10-28T17:02:26.000Z
console.log(fakeDateStart) // Mon Oct 28 2019 10:02:26 GMT-0700 (Pacific Daylight Time)
const rule = new RRule({
freq: RRule.WEEKLY,
byweekday: [RRule.TU],
count: 2,
dtstart: fakeDateStart
})
const localUTCOccurrences = rule.all()
console.log(localUTCOccurrences.map(toISOString)) // ["2019-10-29T17:02:26.000Z", "2019-11-05T17:02:26.000Z"]
console.log(localUTCOccurrences) // [Tue Oct 29 2019 10:02:26 GMT-0700 (Pacific Daylight Time), Tue Nov 05 2019 09:02:26 GMT-0800 (Pacific Standard Time)]
const occurrences = localUTCOccurrences.map(setUTCPartsToDate)
console.log(occurrences.map(toISOString)) // ["2019-10-30T00:02:26.000Z", "2019-11-06T01:02:26.000Z"]
console.log(occurrences) // [Tue Oct 29 2019 17:02:26 GMT-0700 (Pacific Daylight Time), Tue Nov 05 2019 17:02:26 GMT-0800 (Pacific Standard Time)]
function setPartsToUTCDate(d) {
return new Date(
Date.UTC(
d.getFullYear(),
d.getMonth(),
d.getDate(),
d.getHours(),
d.getMinutes(),
d.getSeconds()
)
)
}
function setUTCPartsToDate(d) {
return new Date(
d.getUTCFullYear(),
d.getUTCMonth(),
d.getUTCDate(),
d.getUTCHours(),
d.getUTCMinutes(),
d.getUTCSeconds()
)
}
function toISOString(d) {
return d.toISOString()
} https://codesandbox.io/s/rrule-localutc-conversion-zxlki Or in short: import { RRule } from 'rrule'
const date = new Date('2019-10-29T00:02:26Z')
const rule = new RRule({
freq: RRule.WEEKLY,
byweekday: [RRule.TU],
count: 2,
dtstart: setPartsToUTCDate(date)
})
const occurrences = rule.all().map(setUTCPartsToDate) https://codesandbox.io/s/rrule-localutc-conversion-in-short-ez7g0 As far as I can see, Chrome, Firefox, and Safari all display dates as strings in local time when logging to the console, and Node.js as ISO strings in UTC. |
@tim-phillips I am also suffering for this right now and looking for some sort of monkey patch to get around it. I have a recurring event at 8 PM EST that works fine, but 9 PM EST is pushing it back to the day before it should be. Looking forward to see if you can find an answer to this. |
@tim-phillips that is an excellent breakdown. I'm still going through it, but it looks like it will help me finally understand, thank you! |
@tim-phillips Thank you for your analysis. However, can you explain the following? It seems your solution still can return Wednesday depending on your computer's local timezone. |
@tonylau don't look at the stringified output in your console, which will always be converted into your local timezone. You should use the |
I set my timezone to UTC+14 (Kiritimati Island/Line Islands Time) and got the following, even when I'm using getUTCDay(). The day is still returned as Wednesday when it should be Tuesday? Sandbox: https://codesandbox.io/s/rrule-localutc-conversion-in-short-0uzt1 |
Potentially relevant to this discussion: https://github.com/tc39/proposal-temporal |
@tim-phillips thank you!!!!!!!!!! that was so helpful!!!!!!! Do you happen to know how to make the ics with the rrule? I am having the day issue again when I use the ics package in node and when I receive the calendar invites, they are a day off. (But I'm able to put everything in my db correctly because of your code!! thank you so much. ) |
@tim-phillips you absolute legend |
I suspect this isn't an issue with rrule, but with my understanding of it and/or its timezone support. I've already read related sections in the documentation for rrule and luxon.
Code sample
Actual output
Expected output
I would think the specification of
tzid
would have some effect on the output, but the same output is generated for each timezone.I also can't see what the correlation is between the times provided in the rules and the output for the next event instance. I'd expect that the next instance would roughly correspond to one of the two hours represented by the supplied rules depending on how the specified
dtstart
andtzid
values are interpreted or applied.rrule version
2.6.0
Operating system
OS X 10.14.2, Node 8.11.4
Local timezone
The text was updated successfully, but these errors were encountered: