jkbrzt / rrule

JavaScript library for working with recurrence rules for calendar dates as defined in the iCalendar RFC and more.

Home Page:https://jkbrzt.github.io/rrule

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

returned date incorrect caused by TZ rollover

sdetweil opened this issue · comments

Reporting an issue

Thank you for taking an interest in rrule! Please include the following in
your report:

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

os info

uname -a
Linux sams 5.15.0-88-generic #98-Ubuntu SMP Mon Oct 2 15:18:56 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux

lsb_release -a
No LSB modules are available.
Distributor ID:	Ubuntu
Description:	Ubuntu 22.04.3 LTS
Release:	22.04
Codename:	jammy

local tz, America/Denver
Wed Dec 13 01:40:55 PM MST 2023

sample code

const RRule=require("rrule").RRule
const datetime= require("rrule").datetime;
const Log=console

	let rule = new RRule({
		  freq: RRule.WEEKLY,
  	           interval: 1,
                  byweekday: [RRule.WE],
		  dtstart: 	datetime(2023, 12, 14, 00, 15, 00),  //20231206T171500
		  count: 5,
		  tzid: 'America/Denver',
		})

	let results=rule.all()
	console.log("all dates="+JSON.stringify(results,null,2))

results

all dates=[
                                                    // because of the wrong date, todays event is clipped off 2023:12:13T17:15:00 MST
  "2023-12-20T00:15:00.000Z",  // this is tuesday 2023-12-11T17:15:00 in local tz, not wednesday 
  "2023-12-27T00:15:00.000Z",
  "2024-01-03T00:15:00.000Z",
  "2024-01-10T00:15:00.000Z",
  "2024-01-17T00:15:00.000Z"
]

from package,json

{
  "name": "rrule",
  "version": "2.8.1",

remove tzid no change

Basically this library is full of footguns because it tries to rely on bare Date object and stores everything in utc. If it use moment or analog it would be like 4x smaller and cleaner. So this is it. Number of issues says it all.

@Reeywhaar general criticism is not helpful. you are welcome to show your talent and provide a better solution. I don't have time or the inclination

our app uses an ICS parser that uses this library. and I support the calendar component, so I'm sorta stuck.

In my case what I've done is stopped using tzid parameter in rrule completely. What I do now is I receive dtstart, assign it local timezone (in case of moment library this is moment(dtstart).local(true)) so 05:00 in some dtstart timezone becomes 05:00 in whatever local time it is. Then I find occurences and reassign original timezone to received results: results.map((d: Date) => moment(d).tzid(dtstartTimezone, true) ).

So basically I don't use anything tz related in rrule because this is unreliable as hell. All incoming parameters in rrule are in local timezone.
Local timezone is treated by rrule as timezone without offset, i.e literal time. So 09:00 remains 09:00 no matter what dst mark it passes.

Also in case of finding occurences you have to convert incoming parameters (after and before). First to timezone of dtstart, and then assign local timezone.

here is my fix :

`
from dateutil.rrule import rrulestr
from datetime import datetime
import sys

inputtime = sys.argv[1]
rules = sys.argv[2].split("RRULE:")[1] #

start = datetime.fromtimestamp(float(inputtime)/1000)

ruleObj = rrulestr(rules, dtstart=start)
next = ruleObj.after(datetime.now())
print(next.isoformat())

const response = spawnSync(python, [join(__dirname, "rrule.py"), ${+date}, rule], { encoding: "utf8" })
return new Date(response.stdout.trim())
`
works liek a charm 🤣 (sry i just spent half a day on this )

I'm sure this library can do a lot of things. Creating date recurrences that respect timezones and daylight saving times unfortunately isn't one of them. If you want to do this, you've picked the wrong tool.

Anyone who ends up here, might want to check out rschedule. It comes with adapters for many popular date libraries, such as moment.js and Luxon, as well as vanilla JS Date. It doesn't see much activity and documentation isn't exactly exhaustive, but from the few usage examples and the codesandbox one will quickly figure out how to use it. It sports a modular approach and pluggable features, such as JSON and iCal support.

Hope this helps.