spatie/period

复杂的周期比较

2.4.0 2023-02-20 14:31 UTC

README

复杂的周期比较

Latest Version on Packagist Quality Score Total Downloads

此包支持比较多个日期。您可以计算n个周期之间的重叠和差异,以及两个周期之间的一些更基本的比较。

周期可以从任何类型的DateTime实现构建,这使得此包与自定义DateTime实现(如Carbon)兼容(请参阅cmixin/enhanced-period以直接从和到CarbonPeriod进行转换)。

周期始终是不可变的,您永远不用担心输入日期被更改。

支持我们

我们投入了大量资源来创建一流的开放式软件包。您可以通过购买我们的付费产品之一来支持我们。

我们非常感谢您从您的家乡给我们寄来明信片,说明您正在使用我们的哪些包。您可以在我们的联系页面上找到我们的地址。我们将在我们的虚拟明信片墙上发布收到的所有明信片。

安装

您可以通过composer安装此包

composer require spatie/period

使用方法

创建周期

鼓励您使用它们的静态构造函数创建周期

$period = Period::make('2021-01-01', '2021-01-31');

您可以手动构建一个周期,但您需要手动提供其精度边界。使用Period::make,使用默认精度(Precision::DAY())和默认边界(Boundaries::EXCLUDE_NONE())。

在讨论此包提供的API之前,了解精度和边界如何使用非常重要。

精度

如果想要可靠地比较两个周期,日期精度至关重要。以下是一个例子

给定两个周期:[2021-01-01, 2021-01-15][2021-01-15, 2021-01-31];它们重叠吗?

乍一看答案是“是的”:它们在2021-01-15上重叠。但如果我们假设第一个周期在2021-01-15 10:00:00结束,而第二个周期在2021-01-15 15:00:00开始,现在它们不重叠了!

这就是为什么此包要求您为每个周期指定一个精度。只有精度相同的周期才能进行比较。

关于为什么精度如此重要,可以在这里找到更深入的说明。在构建周期时可以指定周期的精度

Period::make('2021-01-01', '2021-02-01', Precision::DAY());

默认精度设置为天。以下是可以用的精度选项

Precision::YEAR()
Precision::MONTH()
Precision::DAY()
Precision::HOUR()
Precision::MINUTE()
Precision::SECOND()

边界

默认情况下,周期比较使用包含边界。这意味着这两个周期重叠

$a = Period::make('2021-01-01', '2021-02-01');
$b = Period::make('2021-02-01', '2021-02-28');

$a->overlapsWith($b); // true

周期的长度也将包括两个边界

$a = Period::make('2021-01-01', '2021-01-31');

$a->length(); // 31

可以覆盖边界行为

$a = Period::make('2021-01-01', '2021-02-01', boundaries: Boundaries::EXCLUDE_END());
$b = Period::make('2021-02-01', '2021-02-28', boundaries: Boundaries::EXCLUDE_END());

$a->overlapsWith($b); // false

有四种类型的边界排除

Boundaries::EXCLUDE_NONE();
Boundaries::EXCLUDE_START();
Boundaries::EXCLUDE_END();
Boundaries::EXCLUDE_ALL();

参考

Period类提供了一个丰富的API,用于与其他周期和周期集合交互和比较。请注意,只有精度相同的周期才能进行比较

  • startsBefore(DateTimeInterface $date): bool:判断一个时间段是否在指定日期之前开始。
  • startsBeforeOrAt(DateTimeInterface $date): bool:判断一个时间段是否在指定日期之前或当天开始。
  • startsAfter(DateTimeInterface $date): bool:判断一个时间段是否在指定日期之后开始。
  • startsAfterOrAt(DateTimeInterface $date): bool:判断一个时间段是否在指定日期之后或当天开始。
  • startsAt(DateTimeInterface $date): bool:判断一个时间段是否在指定日期开始。
  • endsBefore(DateTimeInterface $date): bool:判断一个时间段是否在指定日期之前结束。
  • endsBeforeOrAt(DateTimeInterface $date): bool:判断一个时间段是否在指定日期之前或当天结束。
  • endsAfter(DateTimeInterface $date): bool:判断一个时间段是否在指定日期之后结束。
  • endsAfterOrAt(DateTimeInterface $date): bool:判断一个时间段是否在指定日期之后或当天结束。
  • endsAt(DateTimeInterface $date): bool:判断一个时间段是否在指定日期结束。
  • overlapsWith(Period $period): bool:判断一个时间段是否与另一个时间段重叠。
  • touchesWith(Period $other): bool:判断一个时间段是否与另一个时间段接触。
  • contains(DateTimeInterface|Period $other): bool:判断一个时间段是否包含另一个时间段或单个日期。
  • equals(Period $period): bool:判断一个时间段是否与另一个时间段相等。

除了比较之外,Period 类还提供了一系列操作

overlap(Period ...$others): ?static

重叠两个或更多时间段。结果时间段将是所有其他时间段组合的并集。

overlapAny(Period ...$others): PeriodCollection

重叠两个或更多时间段。每当两个或更多时间段重叠时,该重叠时间段将被添加到一个集合中,作为最终结果返回。

subtract(Period ...$others): PeriodCollection

从主时间段中减去一个或多个时间段。这是重叠操作的逆操作。

gap(Period $period): ?static

获取两个时间段之间的间隔,如果时间段重叠则为0。

diffSymmetric(Period $other): PeriodCollection

执行两个时间段的对称差分

renew(): static

更新当前时间段,创建一个与当前时间段长度相同且发生在当前时间段之后的新的时间段。

接下来,Period 类还有一些获取器

  • isStartIncluded(): bool
  • isStartExcluded(): bool
  • isEndIncluded(): bool
  • isEndExcluded(): bool
  • start(): DateTimeImmutable
  • includedStart(): DateTimeImmutable
  • end(): DateTimeImmutable
  • includedEnd(): DateTimeImmutable
  • ceilingEnd(Precision::SECOND): DateTimeImmutable
  • length(): int
  • duration(): PeriodDuration
  • precision(): Precision
  • boundaries(): Boundaries

PeriodCollection 类代表一组时间段,并具有一些自己有用的方法

overlapAll(PeriodCollection ...$others): PeriodCollection

重叠所有集合时间段。

subtract(PeriodCollection|Period ...$others): PeriodCollection

从时间段集合中减去一个时间段或一组时间段。

boundaries(): ?Period

创建一个表示集合外部边界的新的时间段。

gaps(): static

给出此集合中所有时间段的间隔。

intersect(Period $intersection): static

将给定时间段与集合中的每个时间段相交。结果是给定时间段与集合中的每个时间段之间的重叠时间段的新集合。如果没有重叠,则丢弃原始时间段。

union(): static

合并集合中具有重叠范围的全部时间段。

最后,PeriodCollection 上也有几个实用方法

  • add(Period ...$periods): static
  • map(Closure $closure): static:
  • reduce(Closure $closure, $initial = null): mixed:
  • filter(Closure $closure): 静态:
  • isEmpty(): 布尔型:

兼容性

您可以从任何类型的 DateTime 对象(如 Carbon)构造一个 Period

Period::make(Carbon::make('2021-01-01'), Carbon::make('2021-01-02'));

请注意,一旦构造了周期,对该周期的所有后续操作都是不可变的。永远不会存在改变输入日期的风险。

您可以使用创建时指定的精度像常规的 DatePeriod 一样迭代 Period

$datePeriod = Period::make(Carbon::make('2021-01-01'), Carbon::make('2021-01-31'));

foreach ($datePeriod as $date) {
    /** @var DateTimeImmutable $date */
    // 2021-01-01
    // 2021-01-02
    // ...
    // (31 iterations)
}

$timePeriod = Period::make(Carbon::make('2021-01-01 00:00:00'), Carbon::make('2021-01-01 23:59:59'), Precision::HOUR());

foreach ($timePeriod as $time) {
    /** @var DateTimeImmutable $time */
    // 2021-01-01 00:00:00
    // 2021-01-01 01:00:00
    // ...
    // (24 iterations)
}

可视化周期

您还可以将一个或多个 Period 对象以及 PeriodCollection 对象可视化,以查看它们之间的关系

$visualizer = new Visualizer(["width" => 27]);

$visualizer->visualize([
    "A" => Period::make('2021-01-01', '2021-01-31'),
    "B" => Period::make('2021-02-10', '2021-02-20'),
    "C" => Period::make('2021-03-01', '2021-03-31'),
    "D" => Period::make('2021-01-20', '2021-03-10'),
    "OVERLAP" => new PeriodCollection(
        Period::make('2021-01-20', '2021-01-31'),
        Period::make('2021-02-10', '2021-02-20'),
        Period::make('2021-03-01', '2021-03-10')
    ),
]);

可视化将返回以下字符串

A          [========]
B                      [==]
C                           [========]
D               [==============]
OVERLAP         [===]  [==] [==]

可视化器在创建时提供了一个可配置的宽度,这将控制显示周期的界限

$visualizer = new Visualizer(["width" => 10]);

测试

composer test

变更日志

请参阅 变更日志 了解最近更改的详细信息。

贡献

请参阅 贡献指南 了解详细信息。

安全

如果您发现有关安全性的错误,请通过电子邮件 [email protected] 而不是使用问题跟踪器。

卡片软件

您可以自由使用此包,但如果它进入了您的生产环境,我们非常感激您从您家乡寄给我们一张明信片,并提及您正在使用我们的哪个包。

我们的地址是:Spatie, Kruikstraat 22, 2021 安特卫普,比利时。

我们将所有收到的明信片 发布在我们的公司网站上

鸣谢

许可证

MIT 许可证 (MIT)。请参阅 许可证文件 了解更多信息。