1

我目前正在为 RFC 5545 的解释细节而苦苦挣扎。 第 3.3.10 节指出,基本上,所有BYxxx字段都显示出扩展行为,除了BYDAY,它具有特定规则,具体取决于BYxxx实际存在的字段。

但是,我不清楚对于RRULE指定多个{ BYMONTH, BYWEEKNO, BYYEARDAY} 的情况到底应该发生什么。在我看来,第 3.3.10 节中的表格允许解释我必须分别扩展每个规则部分,即构建三个集合的并集

  1. 扩容BYMONTHBYMONTHDAY_
  2. 扩大BYWEEKNO
  3. 扩大BYYEARDAY

一直尊重解释BYDAY行为的注释 2。结果可能有点违反直觉(当然,用户不太可能指定此类规则)。但是至少有一种实现声称可以这样做

对于YEARLY频率,如果指定BYMONTHBYWEEKNO、 和BYYEARDAY规则将彼此分开扩展。

如果存在多个规则部分,则其他实现(例如http://recurrence-expansion-service.appspot.com/或 Google 日历)似乎使用限制策略:

  1. 展开BYMONTH/BYMONTHDAY
  2. 然后限制使用BYWEEKNOBYYEARDAY

有效地创建交叉而不是联合。该方法似乎与第 3.3.10 节规定的规则部分的应用顺序有些一致:

如果指定了多个BYxxx规则部分,则在评估指定FREQINTERVAL规则部分之后,BYxxx规则部分将按以下顺序应用于当前评估的事件集:BYMONTHBYWEEKNOBYYEARDAYBYMONTHDAYBYDAYBYHOURBYMINUTEBYSECOND; BYSETPOS然后COUNTUNTIL被评估。

但是,将其解释为规则部分是限制而不是扩展在我看来与标准第 44 页上显示的扩展/限制表直接矛盾。

因此,我的问题是:

RFC5545 是否实际上明确指定了多个BYMONTH,BYWEEKNO和的同时存在如何BYYEARDAY被解释?如果是这样,它在哪里说明?而如果标准在这方面实际上并不清楚,是否有“事实上的标准”首选方式来处理这种情况?

4

1 回答 1

3

RFC5545 实际上是否明确指定如何解释同时存在的 BYMONTH、BYWEEKNO 和 BYYEARDAY 中的一个以上?

是的,在您在问题中引用的摘录中:它们按顺序应用于当前的评估事件集。

术语当前评估出现的集合是句子的关键部分。例如,让我们采用 BYMONTH 和 BYYEARDAY 的规则。

  1. 首先评估 BYMONTH,生成一组事件(在 Y​​EARLY 频率上扩展,即集合中每年可以出现一次以上)
  2. 只有BYYEARDAY仅应用于那些事件,即匹配 BYMONTH 的事件。不考虑与 BYMONTH 不匹配的每一年的一天,因为根据定义,它不是步骤 1 中计算的当前事件集的一部分。

在这种情况下,扩展/限制表无关紧要。RFC 非常明确地指出:

“下表总结了 BYxxx 规则部分扩展或限制行为对 FREQ 规则部分值的依赖性。

该表没有总结 BYxxx 规则部分对其他 BYxxx 规则部分的行为。

因此,它无疑是一个交叉点。可以这样想:如果结果是一个并集,就没有办法编写诸如“一年中第 5 周的每一天在二月”(FREQ=YEARLY;BYWEEKNO=5;BYMONTH=2)之类的规则。

为了实现联合,RFC 定义了一个重复集,它简单地组合了多个 RRULE、RDATE 和 EXDATE(尽管出于某种原因,RFC 声明 RRULE不应出现多次)。

而如果标准在这方面实际上并不清楚,是否有“事实上的标准”首选方式来处理这种情况?

我是php-rrule的维护者,它是 Python dateutil的一个端口,这就是两个版本处理这种情况的方式。据我记得,Javascript 和 Ruby 库也以这种方式工作。我不知道那里的所有其他库,但无论如何,RFC 都很清楚,正如我希望我在上面所展示的那样。

编辑:回答您对 BYDAY 的评论

表中的注 2 确实很混乱,所以在这里做一点澄清。BYDAY之所以特别,是因为它有 2 种语法:带有日期名称的简单语法(例如MOTU等等),以及带有日期名称集合中位置的“复杂”语法。例如1MO表示“第一个星期一”和-1MO“最后一个星期一”。但是问题是“什么的第一个/最后一个星期一 ”。

  • 当使用 YEARLY 频率时BYDAY=1MO,2MO,它是“一年中的第一个和第二个星期一”,当使用 MONTHLY 时,它是“一个月的第一个和第二个星期一”等等,这非常简单。
  • 但是,当使用 YEARLY 频率时 BYMONTH=2,3例如,规则实际上意味着“每年 2 月和 3 月”,所以问题是:你应该得到 2 月和 3 月的每个第一个和第二个星期一(扩展),还是每年第一个和第二个星期一发生在二月和三月 - 即空集,因为两者都在一月(限制)。答案是通过实际将其视为“每月”频率(即使是每年)来进行“特殊扩展”,因此BYDAY=1MO,2MO更改为“二月的第一个和第二个星期一以及三月的每个第一个和第二个星期一”的含义`。

引用 RFC 的相关部分

FREQ 规则部分设置为 YEARLY 的 BYDAY 规则部分中的数值对应于存在 BYMONTH 规则部分的月份内的偏移量,并且对应于存在 BYWEEKNO 或 BYMONTH 规则部分的年份内的偏移量。

老实说,我不确定为什么 BYDAY 会有这种特殊情况,但无论如何它应该如何表现是很清楚的。

于 2018-01-03T08:37:00.130 回答