rruleJS:考虑每周案例的时区

rruleJS: Consideration of timezone for weekly case

我正在使用 rruleJS (https://github.com/jkbrzt/rrule) 并且开始日期如下:

开始日期和时间:2015-09-15 23:45 每三周 工作日:周一、周三、周日

我保存并得到这个规则:

FREQ=WEEKLY;INTERVAL=3;DTSTART=20150915T234500Z;BYDAY=MO,WE,SU

我现在希望我的重复开始时间是 23:45,

Wed Sep 16 2015 23:45:00 GMT+0200 (CEST), 
Sun Sep 20 2015 23:45:00 GMT+0200 (CEST), 
Mon Oct 05 2015 23:45:00 GMT+0200 (CEST), 
Wed Oct 07 2015 23:45:00 GMT+0200 (CEST), 

...

但是我得到了这些重复:

Wed Sep 16 2015 01:45:00 GMT+0200 (CEST), 
Sun Sep 20 2015 01:45:00 GMT+0200 (CEST), 
Mon Oct 05 2015 01:45:00 GMT+0200 (CEST), 
Wed Oct 07 2015 01:45:00 GMT+0200 (CEST), 
Sun Oct 11 2015 01:45:00 GMT+0200 (CEST), 
....

这是因为转换为本地时间(CEST-> +2 小时 -> 23:45 变为 01:45)。我可以减去时区偏移量,但这会切换到另一个工作日。例如,如果我从 Wed Sep 16 2015 01:45:00 GMT+0200 (CEST) 减去 2 小时,我将得到 Tue Sep 15 2015 23:45:00 GMT+0200 (CEST)。

但这不是我想要的:时间应该是正确的,但不是工作日。我不希望它在周二重复出现,而是在周一、周三或周日重复出现。

如何在考虑时区的情况下仍保留起始工作日?

首先,你的RRULE真的像​​吗

FREQ=WEEKLY;INTERVAL=3;DTSTART=20150915T234500Z;BYDAY=MO,WE,SU

?

DTSTART 是 属性,不是 RRULE 的参数。

那么对于您的 DTSTART,您要使用的是带有时区参考的当地时间(来自 https://www.rfc-editor.org/rfc/rfc5545#section-3.3.5 的表格 #3)

所以你想要这样的东西:

DTSTART;TZID=Europe/Berlin:20150915T234500
RRULE:FREQ=WEEKLY;INTERVAL=3;BYDAY=MO,WE,SU

我们遇到了类似的问题,因为我们在服务器端以 UTC 格式存储我们的重复规则,但在客户端使用 RRule.js 编写规则。我们仍然希望能够在客户端生成日期供用户预览。

我们的解决方案是创建 RRule 对象的副本,其中 dtstartuntil 时间偏移到本地时区。我们使用此副本生成预览日期。

我们必须在几个地方执行此操作,因此很容易在 RRule 上编写扩展方法:

RRule.prototype.toOffsetRRule = function () {
    var localRule;
    var offset;

    localRule = RRule.fromString(this.toString());

    var dtstart = localRule.origOptions.dtstart;
    if (dtstart) {
        offset = dtstart.getTimezoneOffset();
        localRule.origOptions.dtstart = new Date(dtstart.getTime() + offset * 60000);
    }

    var until = localRule.origOptions.until;
    if (until) {
        offset = until.getTimezoneOffset();
        localRule.origOptions.until = new Date(until.getTime() + offset * 60000);
    }

    localRule = new RRule(localRule.origOptions);
    return localRule;
}

然后,每当我们需要在客户端生成日期时,我们调用此方法并根据 RRule 的本地时区副本生成日期:

var localRule= myRule.toOffsetRRule();
var dates = localRule.all();

当我们将我们的循环规则保存到服务器时,我们实际上存储的是myRule.toString().

生成的字符串