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.