Skip to content

Commit 8f4bd7b

Browse files
authored
Merge pull request #11 from spatie/boundaries
Boundary and precision support
2 parents fbb30b1 + b724b37 commit 8f4bd7b

File tree

11 files changed

+729
-98
lines changed

11 files changed

+729
-98
lines changed

README.md

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,108 @@ composer require spatie/period
2727

2828
## Usage
2929

30+
### Quick reference
31+
32+
#### Creating a period
33+
34+
```php
35+
$period = new Period(
36+
DateTimeImmutable $start
37+
, DateTimeImmutable $end
38+
[, ?int $precisionMask = Precision::DAY]
39+
[, ?int $boundaryExclusionMask = Boundaries::EXCLUDE_NONE]
40+
)
41+
```
42+
43+
The static `::make` constructor can also take strings and other implementations of `DateTimeInterface`,
44+
as well as an extra format string, in case the textual dates passed aren't of the format `Y-m-d` or `Y-m-d H:i:s`.
45+
46+
```php
47+
$period = Period::make(
48+
string|DateTimeInterface $start
49+
, string|DateTimeInterface $end
50+
[, ?int Precision::DAY]
51+
[, ?int Boundaries::EXCLUDE_NONE]
52+
[, string $format]
53+
)
54+
```
55+
56+
#### Length and boundaries
57+
58+
```php
59+
$period->length(): int
60+
```
61+
62+
```php
63+
$period->startIncluded(): bool
64+
$period->startExcluded(): bool
65+
$period->endIncluded(): bool
66+
$period->endExcluded(): bool
67+
```
68+
69+
```php
70+
$period->getStart(): DateTimeImmutable
71+
$period->getStartIncluded(): DateTimeImmutable
72+
$period->getEnd(): DateTimeImmutable
73+
$period->getEndIncluded(): DateTimeImmutable
74+
```
75+
76+
#### Comparisons
77+
78+
```php
79+
$period->contains(DateTimeInterface $date): bool
80+
$period->equals(Period $period): bool
81+
82+
$period->overlapsWith(Period $period): bool
83+
$period->touchesWith(Period $period): bool
84+
```
85+
86+
```php
87+
$period->startsAt(DateTimeInterface $date): bool
88+
$period->startsBefore(DateTimeInterface $date): bool
89+
$period->startsBeforeOrAt(DateTimeInterface $date): bool
90+
$period->startsAfter(DateTimeInterface $date): bool
91+
$period->startsAfterOrAt(DateTimeInterface $date): bool
92+
```
93+
94+
```php
95+
$period->endsAt(DateTimeInterface $date): bool
96+
$period->endsBefore(DateTimeInterface $date): bool
97+
$period->endsBeforeOrAt(DateTimeInterface $date): bool
98+
$period->endsAfter(DateTimeInterface $date): bool
99+
$period->endsAfterOrAt(DateTimeInterface $date): bool
100+
```
101+
102+
```php
103+
$period->gap(Period $period): ?Period
104+
```
105+
106+
```php
107+
$period->overlapSingle(Period $period): ?Period
108+
$period->overlap(Period ...$periods): PeriodCollection
109+
$period->overlapAll(Period ...$periods): Period
110+
```
111+
112+
```php
113+
$period->diffSingle(Period $period): PeriodCollection
114+
$period->diff(Period ...$periods): PeriodCollection
115+
```
116+
117+
```php
118+
$periodCollection->overlap(PeriodCollection ...$periodCollections): PeriodCollection
119+
$periodCollection->overlapSingle(PeriodCollection $periodCollection): PeriodCollection
120+
```
121+
122+
```php
123+
$periodCollection->boundaries(): ?Period
124+
```
125+
126+
```php
127+
$periodCollection->gaps(): PeriodCollection
128+
```
129+
130+
### Comparing periods
131+
30132
**Overlaps with any other period**:
31133
this method returns a `PeriodCollection` multiple `Period` objects representing the overlaps.
32134

@@ -239,6 +341,76 @@ And finally construct one collection from another:
239341
$newCollection = new PeriodCollection(...$otherCollection);
240342
```
241343

344+
### Precision
345+
346+
Date precision is of utmost importance if you want to reliably compare two periods.
347+
The the following example:
348+
349+
> Given two periods: `[2018-01-01, 2018-01-15]` and `[2018-01-15, 2018-01-31]`; do they overlap?
350+
351+
At first glance the answer is "yes": they overlap on `2018-01-15`.
352+
But what if the first period ends at `2018-01-15 10:00:00`,
353+
while the second starts at `2018-01-15 15:00:00`?
354+
Now they don't anymore!
355+
356+
This is why this package requires you to specify a precision with each period.
357+
Only periods with the same precision can be compared.
358+
359+
A period's precision can be specified when constructing that period:
360+
361+
```php
362+
Period::make('2018-01-01', '2018-02-01', Precision::DAY);
363+
```
364+
365+
The default precision is set on days. These are the available precision options:
366+
367+
```php
368+
Precision::YEAR
369+
Precision::MONTH
370+
Precision::DAY
371+
Precision::HOUR
372+
Precision::MINUTE
373+
Precision::SECOND
374+
```
375+
376+
### Boundaries
377+
378+
By default, period comparisons are done with included boundaries.
379+
This means that these two periods overlap:
380+
381+
```php
382+
$a = Period::make('2018-01-01', '2018-02-01');
383+
$b = Period::make('2018-02-01', '2018-02-28');
384+
385+
$a->overlapsWith($b); // true
386+
```
387+
388+
The length of a period will also include both boundaries:
389+
390+
```php
391+
$a = Period::make('2018-01-01', '2018-01-31');
392+
393+
$a->length(); // 31
394+
```
395+
396+
It's possible to override the boundary behaviour:
397+
398+
```php
399+
$a = Period::make('2018-01-01', '2018-02-01', null, Boundaries::EXCLUDE_END);
400+
$b = Period::make('2018-02-01', '2018-02-28', null, Boundaries::EXCLUDE_END);
401+
402+
$a->overlapsWith($b); // false
403+
```
404+
405+
There are four types of boundary exclusion:
406+
407+
```php
408+
Boundaries::EXCLUDE_NONE;
409+
Boundaries::EXCLUDE_START;
410+
Boundaries::EXCLUDE_END;
411+
Boundaries::EXCLUDE_ALL;
412+
```
413+
242414
### Compatibility
243415

244416
You can construct a `Period` from any type of `DateTime` object such as Carbon:

src/Boundaries.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php
2+
3+
namespace Spatie\Period;
4+
5+
interface Boundaries
6+
{
7+
const EXCLUDE_NONE = 0;
8+
const EXCLUDE_START = 2;
9+
const EXCLUDE_END = 4;
10+
const EXCLUDE_ALL = 6;
11+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
namespace Spatie\Period\Exceptions;
4+
5+
use Exception;
6+
7+
class CannotComparePeriods extends Exception
8+
{
9+
public static function precisionDoesNotMatch(): CannotComparePeriods
10+
{
11+
return new self("Cannot compare two periods whose precision doesn't match.");
12+
}
13+
}

0 commit comments

Comments
 (0)