2

我正在尝试解析 RRULE 并显示重复事件在该月的哪些周有效。我查看了 RFC2445 文档(http://www.ietf.org/rfc/rfc2445.txt)并不清楚。

我知道例如规则:

RRULE FREQ=MONTHLY;INTERVAL=1;BYDAY=TH,FR,WE;BYSETPOS=10,11,12,7,8,9,1,2,3,4,5,6

适用于每月第 1、2、3 和 4 周的周三、周四、周五。

或者

RRULE FREQ=MONTHLY;INTERVAL=1;BYDAY=TU,MO;BYSETPOS=3,4,5,6;

适用于每月第 2 周和第 3 周的周一和周二。

或者

RRULE FREQ=MONTHLY;INTERVAL=1;BYDAY=TH,WE;BYSETPOS=-1,-2

适用于本月最后一周的周三和周四。

我通过另一个程序生成了这些,但不确定它实际上是如何生成它们的。

因此,我遇到的问题是了解 BYSETPOS 如何描述一个月的重复发生周数。最终目标是能够解析上述 RRULE 并显示如下:

为了: RRULE FREQ=MONTHLY;INTERVAL=1;BYDAY=TH,FR,WE;BYSETPOS=10,11,12,7,8,9,1,2,3,4,5,6

节目:Thur,Friday,Wed on week:1,2,3,4

为了: RRULE FREQ=MONTHLY;INTERVAL=1;BYDAY=TU,MO;BYSETPOS=3,4,5,6;

节目:Tues, Monday on week:2,3

为了: RRULE FREQ=MONTHLY;INTERVAL=1;BYDAY=TH,WE;BYSETPOS=-1,-2

节目:Whu,Wed on last week

最好的解决方案是objective-c中的字符串,但我可以弄清楚它是否是另一种类似C的语言。即使只是解释 BYSETPOS 和 BYDAY 的工作原理也会很棒。

4

2 回答 2

8

因此,我遇到的问题是了解 BYSETPOS 如何描述一个月的重复发生周数。

BYSETPOS 不代表周,而只是计算与规则剩余部分对应的实例后的第 n 个实例。例如,FREQ=MONTHLY;INTERVAL=1;BYDAY=TU,MO对应于每月的每个星期一和星期二。因此,对于每个月,您首先计算一个集合(例如,如果您选择 2014 年 7 月,则为 9 个条目)。然后 BYSETPOS 为您提供您应该保留的集合中的“索引”,-1,-2 表示集合中的最后 2 个条目。

继续 2014 年 7 月的示例,基本规则将返回以下集合:(7 月 1 日、7 日、8 日、14 日、15 日、21 日、22 日、28 日、29 日)。给定 BYSETPOS=1,2,-1,-2,我们将保留 7 月 1 日、7 日、28 日、29 日。

您想查看https://www.rfc-editor.org/rfc/rfc5545,它已经过时 RFC2245 并且对重复规则有更详细的描述。

于 2014-07-25T08:08:32.303 回答
0

很好的解释阿诺。帮助我了解它。

因为这对于我自己和其他人来说是一个不寻常的概念,所以我复制了我为自己创建的一个 wiki 页面以及我创建的一个简短的 php 脚本,以便通过演示清楚地了解它是如何工作的。

BYSETPOS不是规则,而是限制现有规则的东西

例如,假设您有一个 RRULE 用于每月在周一和周二发生两次的事件,如下所示:

频率=每月;间隔=1;BYDAY=MO,TU

现在让我们以 Arnaud 上面提供的示例为例,仅关注 7 月份。

7 月 1 日是第一个星期三 7 月 7 日是下一个星期二,8 日是下一个星期三,依此类推。我们上面的 RRULE 将让事件发生在 7 月 1 日、7 日、8 日、14 日、15 日、21 日、22 日、28 日和 29 日 现在让我们附加一个 BYSETPOS 限制器。

频率=每月;间隔=1;BYDAY=MO,TU;BYSETPOS=1,2,-1,-2

这到底是在说什么?

意思是好的,我们知道您的规则将在 7 月 1 日、7 日、8 日、14 日、15 日、21 日、22 日、28 日和 29 日举行活动。但是,我们只想显示事件的第一个、第二个实例 (1,2) 以及最后一个 (-1) 和第二个到最后一个 (-2)。

BYSETPOS 说只显示 BYSETPOS 限制器中的那些实例。

因此,如果您获取天数数组 $moDays Array(1,7,8,14,15,21,22,28,29) 并使用 BYSETPOS 限制器 $bspLimiter=Array(1,2,-1,- 2) 如下所示:

<?php
// 9 event days - limiting the events displayed based on the BYSETPOS limiter

$moDays = array(1,7,8,14,15,21,22,28,29);
$bspLimiter = array(1,2,-1,-2);
$keepers = [];
for($b=0;$b<count($bspLimiter);$b++){
    if($bspLimiter[$b] < 0){
        echo '$bspLimiter[$b] is negative value ('.$bspLimiter[$b].') so getting from back of array<br>';
        $limiter=count($moDays)+$bspLimiter[$b];
        $keeper=$moDays[$limiter];
        $keepers[]=$keeper;
    } else {
        # accounting for index
        $limiter = $bspLimiter[$b]-1;
        $keeper=$moDays[$limiter];
        $keepers[]=$keeper;
    }

    echo '<b>keeping '.$keeper."</b><Br>";

}
echo "<hr>";
asort($keepers);
echo $keepers=str_replace("'","",implode("', '", $keepers));
?>
于 2020-01-19T21:29:29.677 回答