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.34k stars 513 forks source link

Incorrect dates when local timezone moves to winter time in Europe/Chisinau #295

Open vbarbarosh opened 6 years ago

vbarbarosh commented 6 years ago

The problem happens when local timezone moves to winter time (DST).

Steps to reproduce

$ echo {} > package.json
$ npm install --save rrule@2.5.6

$ cat > index.js
const RRule = require('rrule').RRule;
const expr = 'DTSTART;TZID=Australia/Eucla:20181027T000000\nRRULE:FREQ=DAILY;COUNT=5';
console.log(RRule.fromString(expr).all().map(v => v.toJSON()).join('\n'));

$ TZ=Europe/Chisinau node index.js

Actual Results

2018-10-26T18:15:00.000Z
2018-10-27T17:15:00.000Z
2018-10-28T17:15:00.000Z
2018-10-29T17:15:00.000Z
2018-10-30T17:15:00.000Z

Expected Results

2018-10-26T18:15:00.000Z
2018-10-27T18:15:00.000Z
2018-10-28T17:15:00.000Z
2018-10-29T17:15:00.000Z
2018-10-30T17:15:00.000Z

Additional info

$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 18.04.1 LTS
Release:    18.04
Codename:   bionic

$ date
Sun Oct 28 01:14:16 EEST 2018

$ node --version
v10.8.0
davidgoli commented 6 years ago

This is an interesting fluke, investigating. It appears that the timezone offset is correctly applied for the nearly identical timezone Europe/Kiev, can you confirm?

vbarbarosh commented 6 years ago

I found 4 timezones with the same issue:

TZ=Asia/Jerusalem     DST at 2018-10-28T01:00
TZ=Asia/Tel_Aviv      DST at 2018-10-28T01:00
TZ=Europe/Chisinau    DST at 2018-10-28T02:00
TZ=Europe/Tiraspol    DST at 2018-10-28T02:00
Jerhyn commented 5 years ago

Hi,

we have the same issue :

import moment from "moment";
import { RRule } from "rrule";

const rule = new RRule({
  freq: RRule.MONTHLY,
  count: 30,
  interval: 1,
  tzid: "Europe/Paris",
  until: moment("2020-06-10").toDate()
});

rule.all().forEach(date => {
  console.log(moment(date).format("DD/MM/YYYY HH:mm"));
});

and the result is :

07/02/2019 15:56 
07/03/2019 15:56 
07/04/2019 16:56 
07/05/2019 16:56 
07/06/2019 16:56 
07/07/2019 16:56 
07/08/2019 16:56 
07/09/2019 16:56 
07/10/2019 16:56 
07/11/2019 15:56 <----------- hour is updated !
07/12/2019 15:56
07/01/2020 15:56 
07/02/2020 15:56 
07/03/2020 15:56 
07/04/2020 16:56 
07/05/2020 16:56 
07/06/2020 16:56 

We don’t want the hour to be updated.

What is the solution ?

Is there an error in DateTime (see source code below) ? https://github.com/jakubroztocil/rrule/blob/master/src/datetime.ts

Because when you add N months, we do it without updating the hour. So in UTC, the hour is the same, and now in summer time, we have a shift of 1 hour.

djbeaumont commented 5 years ago

I think we're having a similar issue. An rrulestring of:

DTSTART;TZID=Europe/London:20190330T000000 RRULE:FREQ=DAILY;UNTIL=20190331T235900;COUNT=30;INTERVAL=1;WKST=MO;BYHOUR=8;BYMINUTE=0;BYSECOND=0

results in:

1 | Sat, | 30 | Mar | 2019 | 08:00:00 | GMT
2 | Sun, | 31 | Mar | 2019 | 08:00:00 | GMT

However, Europe/London will move to +01:00 at 2019-03-31T01:00:00Z so the second occurrence should actually be at 07:00:00 GMT to maintain a Europe/London time of 08:00:00. Have I misunderstood how this should work?

harvzor commented 4 years ago

This is very confusing.

In the documentation, it notes this: https://github.com/jakubroztocil/rrule#important-use-utc-dates

The bottom line is the returned "UTC" dates are always meant to be interpreted as dates in your local timezone. This may mean you have to do additional conversion to get the "correct" local time with offset applied.

It doesn't make much sense to me that it's in UTC and in your local timezone. These are normally mutually exclusive..?

There's a comment in the code:

Even though the given offset is Z (UTC), these are local times, not UTC times. Each of these this is the correct local Pacific time of each recurrence in America/Los_Angeles when it is 19:00 in America/Denver, including the DST shift.

arturohu commented 4 years ago

I have the same problem, I want to represent the appearances of a rule that goes through different DST schedules. What I expect is to receive the same time with different offsets. I also think that the UTC time changes from one DST to another.

I'm using RRule version 2.6.4, and UTC+2 (DST) now.

let rule = RRule.fromString('DTSTART:20201001T110000Z\nRRULE:FREQ=DAILY')
console.log(rule.between(new Date(Date.UTC(2020, 9, 23)), new Date(Date.UTC(2020, 9, 27))));

Expected, what I need:

0: Fri Oct 23 2020 13:00:00 GMT+0200 (hora de verano de Europa central) {} -> UTC 11:00 1: Sat Oct 24 2020 13:00:00 GMT+0200 (hora de verano de Europa central) {} -> UTC 11:00 2: Sun Oct 25 2020 13:00:00 GMT+0100 (hora estándar de Europa central) {} -> UTC 12:00 3: Mon Oct 26 2020 13:00:00 GMT+0100 (hora estándar de Europa central) {} -> UTC 12:00

Received:

0: Fri Oct 23 2020 13:00:00 GMT+0200 (hora de verano de Europa central) {} -> UTC 11:00 1: Sat Oct 24 2020 13:00:00 GMT+0200 (hora de verano de Europa central) {} -> UTC 11:00 2: Sun Oct 25 2020 12:00:00 GMT+0100 (hora estándar de Europa central) {} <- Different hour -> UTC 11:00 3: Mon Oct 26 2020 12:00:00 GMT+0100 (hora estándar de Europa central) {} <- Different hour -> UTC 11:00

Maybe I'm making a mistake. Thank you!