tplaner / when
日期/日历递归库。
v3.1.5
2021-09-24 14:09 UTC
Requires
- php: >=7.1.3
Requires (Dev)
- phpunit/phpunit: ^7.0
README
PHP 7.1+ 的日期/日历递归库
作者: Tom Planer
安装
composer require tplaner/When
当前功能
When 完全支持 RFC5455 重复规则 功能(以及一些附加功能)。请查看 单元测试 了解如何使用它的信息和示例。
以下是一些基本示例。
// friday the 13th for the next 5 occurrences $r = new When(); $r->startDate(new DateTime("19980213T090000")) ->freq("monthly") ->count(5) ->byday("fr") ->bymonthday(13) ->generateOccurrences(); print_r($r->occurrences);
// friday the 13th for the next 5 occurrences rrule $r = new When(); $r->startDate(new DateTime("19980213T090000")) ->rrule("FREQ=MONTHLY;BYDAY=FR;BYMONTHDAY=13;COUNT=5") ->generateOccurrences(); print_r($r->occurrences);
// friday the 13th for the next 5 occurrences, skipping known friday the 13ths $r = new When(); $r->startDate(new DateTime("19980213T090000")) ->freq("monthly") ->count(5) ->byday("fr") ->bymonthday(13) ->exclusions('19990813T090000,20001013T090000') ->generateOccurrences(); print_r($r->occurrences);
// friday the 13th forever; see which ones occur in 2018 $r = new When(); $r->startDate(new DateTime("19980213T090000")) ->rrule("FREQ=MONTHLY;BYDAY=FR;BYMONTHDAY=13"); $occurrences = $r->getOccurrencesBetween(new DateTime('2018-01-01 09:00:00'), new DateTime('2019-01-01 09:00:00')); print_r($occurrences);
InvalidStartDate 异常:开始日期必须是第一次发生
根据 规范,开始日期应该是第一次重复日期。这通常很麻烦,尤其是如果你是从用户输入生成重复日期,因为它会抛出异常。你可以轻松禁用此功能
$r = new When(); $r->RFC5545_COMPLIANT = When::IGNORE; // get the last Friday of the month for the next 5 occurrences $r->startDate(new DateTime()) ->rrule("FREQ=MONTHLY;BYDAY=-1FR;COUNT=5") ->generateOccurrences(); print_r($r->occurrences);
其他示例
$r = new When(); $r->RFC5545_COMPLIANT = When::IGNORE; // second to last day of the month $r->startDate(new DateTime()) ->rrule("FREQ=MONTHLY;BYMONTHDAY=-2;COUNT=5") ->generateOccurrences(); print_r($r->occurrences);
$r = new When(); $r->RFC5545_COMPLIANT = When::IGNORE; // every other week $r->startDate(new DateTime()) ->rrule("FREQ=WEEKLY;INTERVAL=2;COUNT=10") ->generateOccurrences(); print_r($r->occurrences);
$r1 = new When(); $r2 = new When(); $r1->RFC5545_COMPLIANT = When::IGNORE; $r2->RFC5545_COMPLIANT = When::IGNORE; // complex example of a payment schedule // borrowed from: https://www.mikeyroy.com/2019/10/25/google-calendar-recurring-event-for-twice-monthly-payroll-only-on-weekdays/ // // you're paid on the 15th, (or closest to it, but only on a weekday) $r1->startDate(new DateTime()) ->rrule("FREQ=MONTHLY;INTERVAL=1;BYSETPOS=-1;BYDAY=MO,TU,WE,TH,FR;BYMONTHDAY=13,14,15;COUNT=12") ->generateOccurrences(); // you're also paid on the last weekday of the month $r2->startDate(new DateTime()) ->rrule("FREQ=MONTHLY;INTERVAL=1;BYSETPOS=-1;BYDAY=MO,TU,WE,TH,FR;BYMONTHDAY=26,27,28,29,30,31;COUNT=12") ->generateOccurrences(); $totalPaydays = count($r1->occurrences); for ($i = 0; $i < $totalPaydays; $i++) { echo "You'll be paid on: " . $r1->occurrences[$i]->format('F d, Y') . "\n"; echo "You'll be paid on: " . $r2->occurrences[$i]->format('F d, Y') . "\n"; }
性能
When 非常快,不会无限循环。这是因为格里高利历实际上每400年完全重复一次。因此,这是 When 施加的上限,它不会生成超过400年的发生时间,如果它在接下来的400年内找不到匹配项,则模式根本不存在。
默认情况下,我们不会生成超过200次发生,尽管可以通过指定更高的 COUNT
或在调用 generateOccurrences()
之前修改 $rangeLimit
来简单地配置。
$r = new When(); $r->RFC5545_COMPLIANT = When::IGNORE; $r->startDate(new DateTime()) ->rrule("FREQ=MONTHLY;BYDAY=FR;BYMONTHDAY=13") ->generateOccurrences(); // will generate an array of 200 print_r($r->occurrences);
以下是一个相当复杂的基准测试,最后一次发生是在2254年。在我的机器上,这大约需要 0.28s
。
$r = new When(); $r->RFC5545_COMPLIANT = When::IGNORE; $r->startDate(new DateTime(20210101)) ->rrule("FREQ=MONTHLY;BYDAY=FR;BYMONTHDAY=13;COUNT=400") ->generateOccurrences(); // will generate an array of 400 print_r($r->occurrences);
使用 COUNT
和 UNTIL
,从2021年到2025年只有5个13号星期五。
$r = new When(); $r->RFC5545_COMPLIANT = When::IGNORE; $r->startDate(new DateTime(20210101)) ->rrule("FREQ=MONTHLY;BYDAY=FR;BYMONTHDAY=13;COUNT=400;UNTIL=20250101") ->generateOccurrences(); // will generate until 2023-01-01 or 400 print_r($r->occurrences);
通过 $rangeLimit
限制
$r = new When(); $r->RFC5545_COMPLIANT = When::IGNORE; $r->rangeLimit = 400; $r->startDate(new DateTime()) ->rrule("FREQ=MONTHLY;BYDAY=-1FR") ->generateOccurrences(); // 400 occurrences, limited by the rangeLimit print_r($r->occurrences);