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

Recurring Events using byweekday shift by one day #391

Closed
7 tasks done
spurreiter opened this issue Mar 22, 2020 · 5 comments
Closed
7 tasks done

Recurring Events using byweekday shift by one day #391

spurreiter opened this issue Mar 22, 2020 · 5 comments

Comments

@spurreiter
Copy link

  • Verify that you've looked through existing issues for duplicates before
    creating a new one
  • Code sample reproducing the issue. Be sure to include all input values you
    are using such as the exact RRule string and dates.
  • Expected output
  • Actual output
  • The version of rrule you are using
    • 2.6.4
  • Your operating system
    • Linux
  • Your local timezone (run $ date from the command line of the machine showing the bug)
    • Europe/Paris but timezones are shifted. See below

I'm trying to get the next Tuesdays after a given date (1st Feb 2020 in Europe/Paris).
Nonetheless the events start at Wednesday if still being in that timezone.
Calculating the events for timezone America/New_York the events are as expected.

Please check the below snippet. My findings are:

// problem: events should be on Tuesday but are shifted by one day:
// Tue Feb 04 2020 00:00:00 GMT+0100 (Central European Standard Time) ...
$ TZ=Europe/Paris node zone.js Europe/Paris
rule:
DTSTART;TZID=Europe/Paris:20200131T230000
RRULE:FREQ=WEEKLY;BYDAY=TU;COUNT=2
events:
Wed Feb 05 2020 00:00:00 GMT+0100 (Central European Standard Time)
Wed Feb 12 2020 00:00:00 GMT+0100 (Central European Standard Time)
luxon:
Sat Feb 01 2020 00:00:00 GMT+0100 (Central European Standard Time)

// timezone America/New_York shows correct result
$ TZ=America/New_York node zone.js America/New_York
rule:
DTSTART;TZID=America/New_York:20200201T050000
RRULE:FREQ=WEEKLY;BYDAY=TU;COUNT=2
events:
Tue Feb 04 2020 00:00:00 GMT-0500 (Eastern Standard Time)
Tue Feb 11 2020 00:00:00 GMT-0500 (Eastern Standard Time)
luxon:
Sat Feb 01 2020 00:00:00 GMT-0500 (Eastern Standard Time)

// crossing timezones show correct result
$ TZ=America/New_York node zone.js Europe/Paris
rule:
DTSTART;TZID=Europe/Paris:20200201T050000
RRULE:FREQ=WEEKLY;BYDAY=TU;COUNT=2
events:
Mon Feb 03 2020 18:00:00 GMT-0500 (Eastern Standard Time)
Mon Feb 10 2020 18:00:00 GMT-0500 (Eastern Standard Time)
luxon:
Sat Feb 01 2020 00:00:00 GMT-0500 (Eastern Standard Time)

// UTC shows correct result
$ TZ=UTC node zone.js UTC
rule:
DTSTART:20200201T000000Z
RRULE:FREQ=WEEKLY;BYDAY=TU;COUNT=2
events:
Tue Feb 04 2020 00:00:00 GMT+0000 (Coordinated Universal Time)
Tue Feb 11 2020 00:00:00 GMT+0000 (Coordinated Universal Time)
luxon:
Sat Feb 01 2020 00:00:00 GMT+0000 (Coordinated Universal Time)
const { DateTime } = require('luxon')
const { RRule } = require('rrule/dist/es5/rrule-tz.js')

const dtstart = new Date(2020, 1, 1, 0)
const tzid = process.argv[2] || 'Europe/Paris'

const rule = new RRule({
  freq: RRule.WEEKLY,
  dtstart,
  tzid,
  byweekday: [RRule.TU],
  count: 2
})

console.log('rule:\n' + rule.toString())
console.log('events:\n' + rule.all().map(d => d.toString()).join('\n'))

const datetime = DateTime.fromJSDate(dtstart).setZone(tzid)
console.log('luxon:\n' + datetime.toJSDate().toString())
@proficiat
Copy link

Hello, the same issue here
For recurrence: "FREQ=WEEKLY;INTERVAL=1;BYDAY=MO,TU,WE,TH,FR;UNTIL=20200430T040000Z"

rule.all() shows TU,WE,TH,FR,SA

@cmditch
Copy link

cmditch commented Apr 23, 2020

Update: I think this was purely my confusion around rrule.js's default behavior regarding UTC inputs as well as JS Date objects.

As gleaned from other comments, this confusion seems quite common:
(1) Working with TZID
(2) Inputting DTSTART in the correct format (local to the timezone, rather than UTC or local to the computer)
(3) Inputting the right dates into rrule.between(). If declaring a TZID, much like you have to massage the dates when they come out - using DateTime.fromJSDate(date).toUTC().setZone('local', { keepLocalTime: true }), you have to massage the dates going in to between() (likely after/before as well) using DateTime.fromMillis(posixTime).setZone('utc', { keepLocalTime: true }).

Despite my troubles with the documentation, and frustrations around undocumented behavior, I'm very grateful this library exists. Thank you to the creator and all the maintainers and contributors. Much like luxon grew out of lessons learned from moment, I think the next iteration of an rrule library will build on the shoulders of rrule.js.

Original posted "issue", disregard what I've said below.
Also experiencing what appears to be this issue as well.

import { rrulestr } from 'rrule';

const twoWeeks = 1209600000;
const myrrule = ["DTSTART:20200104T000000Z", "RRULE:FREQ=WEEKLY;BYDAY=FR"]
rrulestr(myrrule.join('\n'))
    .between(new Date(Date.now() - twoWeeks), new Date(Date.now() + twoWeeks))

This returns a list of dates that occur on Thursday.
I've made sure that the DTSTART is UTC.

The event in question occurs on Friday at 18:00-0600 (mountain time), which is the same as Saturday 00:00-UTC, but rrule.between() oddly returns times @ Thursday 18:00-0600.

I'll gladly attempt to dissect the code to see where/how the issue is occurring. If anyone more familiar with the codebase has some tips to point me in the right direction, let me know, thanks!

@jessicaelee
Copy link

@davidgoli Hey David! I've been working with rrule, for the past 5 days and cannot figure out how to work with timezones. If I put the time in at 9pm my time, it gets converted to 4am UTC time. This causes an issue when I want to set recurring events on certain days, lets say Fridays. So then it repeats Friday 4am, and when it gets translated back to my timezone, then it is Thursday 9pm when I wanted it on Friday. Do you have any suggestions for this? I tried with tzid but I cannot get that to work either. Not sure how I'm supposed to incorporate Luxon? I have downloaded the package.

spurreiter added a commit to spurreiter/rrule that referenced this issue Jun 10, 2020
rrule time base is UTC whereas Luxon requires dates in local format to
calculate the correct time offset.

New tests where introduced to prove correct behaviour in different
system timezones. Run those with `npm run test:tz`
aomi added a commit to VikeLabs/rrule that referenced this issue Sep 6, 2021
egarkavy added a commit to egarkavy/rrule that referenced this issue Oct 31, 2021
@davidgoli
Copy link
Collaborator

davidgoli commented Oct 31, 2021

I think this issue arises from a misunderstanding of how this library is using UTC: not to represent dates in UTC, but rather as a sort of a hack to get around JavaScript's broken Date math. @cmditch's comment here is correct.

The times you get back from RRule are not in UTC (unless you explicitly say they should be, by using Z at the end of ISO strings or providing tzid: 'utc'), but rather in your local time but then shifted into UTC. If you want a "proper" Date in your local time, you'll have to do:

const date = rule.all()[0] // for whatever rule you have

// this is probably what you expect
const local new Date(
        date.getUTCFullYear(),
        date.getUTCMonth(),
        date.getUTCDate(),
        date.getUTCHours(),
        date.getUTCMinutes(),
        date.getUTCSeconds(),
        date.valueOf() % 1000
      )

I apologize for leaving this library in a state of neglect for the past couple of years. I moved on to other projects, and the code in this codebase is so tortured and convoluted that it's not really worth attempting to add new features to. I plan to rewrite this library from the ground up soon, stay tuned!

@egarkavy
Copy link

egarkavy commented Nov 1, 2021

@davidgoli Thank you for the reply. Could you help me to understand. Is what @spurreiter proposed in PR change a valid fix for the library?
Why then you propose doing it in other way? First generate an occurrences and only do that UTC hack afterwards?

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

No branches or pull requests

6 participants