tplaner/when

日期/日历递归库。

v3.1.5 2021-09-24 14:09 UTC

This package is auto-updated.

Last update: 2024-08-24 20:24:59 UTC


README

PHP 7.1+ 的日期/日历递归库

Build Status Total Downloads Latest Stable Version License

作者: 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);

使用 COUNTUNTIL,从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);