ckuran / period
Requires
- php: ^7.1
Requires (Dev)
- larapack/dd: ^1.0
- nesbot/carbon: ^2.6
- phpunit/phpunit: ^7.0
README
此包添加了对比较多个日期相互支持。您可以计算n个时间段之间的重叠和差异,以及两个时间段之间的一些更基本的比较。
时间段可以由任何类型的 DateTime
实现构建,这使得此包与自定义的 DateTime
实现(如 Carbon)兼容(请参阅 cmixin/enhanced-period 以直接从CarbonPeriod转换过来)。
时间段始终是不可变的,您永远不用担心输入的日期会被更改。
此包仍在开发中。
安装
您可以通过composer安装此包
composer require spatie/period
用法
快速参考
创建一个时间段
$period = new Period( DateTimeImmutable $start , DateTimeImmutable $end [, ?int $precisionMask = Precision::DAY] [, ?int $boundaryExclusionMask = Boundaries::EXCLUDE_NONE] )
静态构造函数 ::make
也可以接受字符串和其他 DateTimeInterface
实现以及额外的格式字符串,以防传递的文本日期不是 Y-m-d
或 Y-m-d H:i:s
格式。
$period = Period::make( string|DateTimeInterface $start , string|DateTimeInterface $end [, ?int Precision::DAY] [, ?int Boundaries::EXCLUDE_NONE] [, string $format] )
长度和边界
$period->length(): int
$period->startIncluded(): bool $period->startExcluded(): bool $period->endIncluded(): bool $period->endExcluded(): bool
$period->getStart(): DateTimeImmutable $period->getStartIncluded(): DateTimeImmutable $period->getEnd(): DateTimeImmutable $period->getEndIncluded(): DateTimeImmutable
比较
$period->contains(DateTimeInterface $date): bool $period->equals(Period $period): bool $period->overlapsWith(Period $period): bool $period->touchesWith(Period $period): bool
$period->startsAt(DateTimeInterface $date): bool $period->startsBefore(DateTimeInterface $date): bool $period->startsBeforeOrAt(DateTimeInterface $date): bool $period->startsAfter(DateTimeInterface $date): bool $period->startsAfterOrAt(DateTimeInterface $date): bool
$period->endsAt(DateTimeInterface $date): bool $period->endsBefore(DateTimeInterface $date): bool $period->endsBeforeOrAt(DateTimeInterface $date): bool $period->endsAfter(DateTimeInterface $date): bool $period->endsAfterOrAt(DateTimeInterface $date): bool
$period->gap(Period $period): ?Period
$period->overlapSingle(Period $period): ?Period $period->overlap(Period ...$periods): PeriodCollection $period->overlapAll(Period ...$periods): Period
$period->diffSingle(Period $period): PeriodCollection $period->diff(Period ...$periods): PeriodCollection
$periodCollection->overlap(PeriodCollection ...$periodCollections): PeriodCollection $periodCollection->overlapSingle(PeriodCollection $periodCollection): PeriodCollection $periodCollection->map(Closure<Period> $closure): PeriodCollection $periodCollection->reduce(Closure<mixed, Period> $closure): mixed
$periodCollection->boundaries(): ?Period
$periodCollection->gaps(): PeriodCollection
比较时间段
与其他任何时间段的重叠:此方法返回一个包含多个重叠 Period
对象的 PeriodCollection
。
/* * A [========] * B [==] * C [=====] * CURRENT [===============] * * OVERLAP [=] [==] [=] */ $a = Period::make('2018-01-01', '2018-01-31'); $b = Period::make('2018-02-10', '2018-02-20'); $c = Period::make('2018-03-01', '2018-03-31'); $current = Period::make('2018-01-20', '2018-03-10'); $overlaps = $current->overlap($a, $b, $c);
与所有时间段的重叠:此方法只返回一个所有时间段都重叠的时间段。
/* * A [============] * B [==] * C [=======] * * OVERLAP [==] */ $a = Period::make('2018-01-01', '2018-01-31'); $b = Period::make('2018-01-10', '2018-01-15'); $c = Period::make('2018-01-10', '2018-01-31'); $overlap = $a->overlapAll($b, $c);
多个时间段之间的差异:此方法返回一个包含多个时间段和单个时间段之间的差异的 PeriodCollection
。
/* * A [====] * B [========] * C [=====] * CURRENT [========================] * * DIFF [=] [====] */ $a = Period::make('2018-01-05', '2018-01-10'); $b = Period::make('2018-01-15', '2018-03-01'); $c = Period::make('2017-01-01', '2018-01-02'); $current = Period::make('2018-01-01', '2018-01-31'); $diff = $current->diff($a, $b, $c);
与重叠:此方法返回一个布尔值,指示两个时间段是否重叠。
/* * A [============] * B [===========] */ $a = Period::make('2018-01-01', '2018-01-31'); $b = Period::make('2018-01-10', '2018-02-15'); $overlap = $a->overlapsWith($b); // true
接触:此方法确定两个时间段是否相互接触。
/* * A [========] * B [===========] */ $a = Period::make('2018-01-01', '2018-01-31'); $b = Period::make('2018-02-01', '2018-02-15'); $overlap = $a->touchesWith($b); // true
间隔:返回两个时间段之间的间隔。如果不存在间隔,则返回 null
。
/* * A [========] * B [===========] */ $a = Period::make('2018-01-01', '2018-01-31'); $b = Period::make('2018-02-05', '2018-02-15'); $overlap = $a->gap($b); // Period('2018-02-01', '2018-02-04')
集合的边界:获取表示集合边界的单个时间段。
/* * A [====] * B [========] * C [=====] * D [====] * * BOUNDARIES [======================================] */ $collection = new PeriodCollection( Period::make('2018-01-01', '2018-01-05'), Period::make('2018-01-10', '2018-01-15'), Period::make('2018-01-20', '2018-01-25'), Period::make('2018-01-30', '2018-01-31') ); $boundaries = $collection->boundaries();
集合的间隔:获取集合的所有间隔。
/* * A [====] * B [========] * C [=====] * D [====] * * GAPS [=] [====] [==] */ $collection = new PeriodCollection( Period::make('2018-01-01', '2018-01-05'), Period::make('2018-01-10', '2018-01-15'), Period::make('2018-01-20', '2018-01-25'), Period::make('2018-01-30', '2018-01-31') ); $gaps = $collection->gaps();
重叠多个集合:返回集合之间的重叠。这意味着在集合之间进行AND操作,并在同一集合内进行OR操作。
/* * A [=====] [===========] * B [=================] * C [====================] * * OVERLAP [=] [====] */ $a = new PeriodCollection( Period::make('2018-01-01', '2018-01-07'), Period::make('2018-01-15', '2018-01-25') ); $b = new PeriodCollection( Period::make('2018-01-01', '2018-01-20') ); $c = new PeriodCollection( Period::make('2018-01-06', '2018-01-25') ); $overlap = $a->overlap($b, $c);
使用 PeriodCollection
时间段集合是由多个时间段构建的
$collection = new PeriodCollection( Period::make('2018-01-01', '2018-01-02'), // … );
可以直接遍历它们,并且您的IDE将识别其内容
$collection = new PeriodCollection(/* … */); foreach ($collection as $period) { $period->… }
您可以对它们进行解构
[$firstPeriod, $secondPeriod, $thirdPeriod] = $collection;
最后,从另一个集合中构建一个集合
$newCollection = new PeriodCollection(...$otherCollection);
精度
如果您想可靠地比较两个时间段,日期精度至关重要。以下示例
给定两个时间段:
[2018-01-01, 2018-01-15]
和[2018-01-15, 2018-01-31]
;它们是否重叠?
乍一看答案是“是”:它们在 2018-01-15
上重叠。但是,如果第一个时间段在 2018-01-15 10:00:00
结束,而第二个时间段在 2018-01-15 15:00:00
开始,情况又如何?现在它们不再重叠了!
这就是为什么此包要求您为每个时间段指定一个精度。只有具有相同精度的时期才能进行比较。
有关精度为什么如此重要的更深入的解释,请参阅 此处。在构建时间段时可以指定时间段精度
Period::make('2018-01-01', '2018-02-01', Precision::DAY);
默认精度设置为天。以下是可用的精度选项
Precision::YEAR Precision::MONTH Precision::DAY Precision::HOUR Precision::MINUTE Precision::SECOND
边界
默认情况下,时间段比较使用包含边界。这意味着这两个时间段重叠
$a = Period::make('2018-01-01', '2018-02-01'); $b = Period::make('2018-02-01', '2018-02-28'); $a->overlapsWith($b); // true
时间段的长度也将包括两个边界
$a = Period::make('2018-01-01', '2018-01-31'); $a->length(); // 31
您可以覆盖边界行为
$a = Period::make('2018-01-01', '2018-02-01', null, Boundaries::EXCLUDE_END); $b = Period::make('2018-02-01', '2018-02-28', null, Boundaries::EXCLUDE_END); $a->overlapsWith($b); // false
边界排除有四种类型
Boundaries::EXCLUDE_NONE; Boundaries::EXCLUDE_START; Boundaries::EXCLUDE_END; Boundaries::EXCLUDE_ALL;
兼容性
您可以从任何类型的 DateTime
对象(如 Carbon)构建一个 Period
Period::make(Carbon::make('2018-01-01'), Carbon::make('2018-01-02'));
请注意,一旦构建了时间段,对其的所有进一步操作都是不可变的。永远不会有改变输入日期的风险。
您可以使用指定的精度迭代 Period
,就像迭代常规的 DatePeriod
一样
$datePeriod = Period::make(Carbon::make('2018-01-01'), Carbon::make('2018-01-31')); foreach ($datePeriod as $date) { /** @var DateTimeImmutable $date */ // 2018-01-01 // 2018-01-02 // ... // (31 iterations) } $timePeriod = Period::make(Carbon::make('2018-01-01 00:00:00'), Carbon::make('2018-01-01 23:59:59'), Precision::HOUR); foreach ($timePeriod as $time) { /** @var DateTimeImmutable $time */ // 2018-01-01 00:00:00 // 2018-01-01 01:00:00 // ... // (24 iterations) }
可视化时间段
您还可以将一个或多个 Period
对象以及 PeriodCollection
对象可视化,以查看它们之间的关系
$visualizer = new Visualizer(["width" => 27]); $visualizer->visualize([ "A" => Period::make('2018-01-01', '2018-01-31'), "B" => Period::make('2018-02-10', '2018-02-20'), "C" => Period::make('2018-03-01', '2018-03-31'), "D" => Period::make('2018-01-20', '2018-03-10'), "OVERLAP" => new PeriodCollection( Period::make('2018-01-20', '2018-01-31'), Period::make('2018-02-10', '2018-02-20'), Period::make('2018-03-01', '2018-03-10') ), ]);
可视化将返回以下字符串
A [========]
B [==]
C [========]
D [==============]
OVERLAP [===] [==] [==]
可视化器在创建时有一个可配置的宽度,这将控制显示的时段时间范围
$visualizer = new Visualizer(["width" => 10]);
测试
composer test
变更日志
有关最近更改的更多信息,请参阅变更日志
贡献
有关详细信息,请参阅贡献指南
安全
如果您发现任何与安全相关的问题,请通过电子邮件freek@spatie.be联系,而不是使用问题跟踪器。
明信片软件
您可以使用这个包,但如果它进入了您的生产环境,我们非常感谢您从您的家乡寄给我们一张明信片,注明您正在使用我们的哪个(些)包。
我们的地址是:Spatie,Samberstraat 69D,2060 安特卫普,比利时。
我们将发布所有收到的明信片在我们的公司网站上。
鸣谢
支持我们
Spatie 是一家位于比利时的安特卫普网站设计公司。您可以在我们的网站上找到我们所有开源项目的概述在这里。
您的业务是否依赖于我们的贡献?联系并支持我们在 Patreon。所有承诺都将用于分配人力进行维护和新奇事物的开发。
许可证
MIT 许可证(MIT)。有关更多信息,请参阅许可证文件。