Skip to content

Commit 8977917

Browse files
authored
Add intersects method for date range (#10)
1 parent c3f2618 commit 8977917

6 files changed

Lines changed: 590 additions & 3 deletions

File tree

README.md

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,11 +74,12 @@ $dateTimeZone2 = $dateTimeHelper->createDateTimeZone('Europe/Kiev'); // Or with
7474
$dateTimeZone3 = $dateTimeHelper->createDateTimeZoneUtc(); // Another method to get UTC timezone
7575
```
7676

77-
### Immutable ValueObject `DateRange`
77+
### Immutable `DateRange` ValueObject
7878

79-
You often need to manipulate with since/till dates, so-called date ranges.
79+
You often needed to manipulate with since/till dates, so-called date ranges.
8080
By its nature, date range is a `ValueObject`, it can be reused many times for different purposes.
81-
This library provides a `DateRange` immutable class, which is not able to be changed after its creation.
81+
This library provides a `DateRange` immutable class, which is not able to be changed after its creation.
82+
`DateRange` operates only with dates and ignore time.
8283

8384
```php
8485
use Fresh\DateTime\DateRange;
@@ -90,6 +91,32 @@ $dateRange2 = new DateRange(new \DateTime('yesterday'), new \DateTime('tomorrow'
9091
$dateRange1->isEqual($dateRange2); // Returns FALSE, because date ranges have different timezones
9192
```
9293

94+
### Immutable `DateTimeRange` ValueObject
95+
96+
This library provides also immutable class `DateTimeRange`, instead of `DateRange` it checks date and time.
97+
98+
```php
99+
use Fresh\DateTime\DateTimeRange;
100+
101+
$dateTimeRange1 = new DateTimeRange(new \DateTime('2000-01-01 19:00:00'), new \DateTime('2000-01-01 21:00:00'));
102+
$dateTimeRange2 = new DateTimeRange(new \DateTime('2000-01-01 19:00:00'), new \DateTime('2000-01-01 21:00:00', new \DateTimeZone('Europe/Kiev')));
103+
$dateTimeRange3 = new DateTimeRange(new \DateTime('2000-01-01 20:00:00'), new \DateTime('2000-01-01 22:00:00'));
104+
105+
// There is also the `isEqual` method to compare two DateTimeRange objects.
106+
$dateTimeRange1->isEqual($dateTimeRange2); // Returns FALSE, because datetime ranges have different timezones
107+
108+
// There is also the `intersects` method to check if datetime range intersected each other.
109+
$dateTimeRange1->intersects($dateTimeRange3); // Returns TRUE, because datetime ranges are intersected
110+
```
111+
112+
#### Examples of date ranges with intersection
113+
114+
![Example of intersection](docs/images/intersect.png "Example of intersection")
115+
116+
#### Examples of date ranges without intersection
117+
118+
![Example of no intersection](docs/images/does_not_intersect.png "Example of no intersection")
119+
93120
### Getting array of objects/strings of all dates in date range
94121

95122
```php

docs/images/does_not_intersect.png

21.5 KB
Loading

docs/images/intersect.png

24.5 KB
Loading

src/DateTimeRange.php

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
<?php
2+
/*
3+
* This file is part of the DateTime library.
4+
*
5+
* (c) Artem Henvald <genvaldartem@gmail.com>
6+
*
7+
* For the full copyright and license information, please view the LICENSE
8+
* file that was distributed with this source code.
9+
*/
10+
11+
declare(strict_types=1);
12+
13+
namespace Fresh\DateTime;
14+
15+
use Fresh\DateTime\Exception\LogicException;
16+
17+
/**
18+
* DateTimeRange.
19+
*
20+
* @author Artem Henvald <genvaldartem@gmail.com>
21+
*/
22+
final class DateTimeRange implements DateTimeRangeInterface
23+
{
24+
/** @var \DateTimeImmutable */
25+
private $since;
26+
27+
/** @var \DateTimeImmutable */
28+
private $till;
29+
30+
/**
31+
* @param \DateTimeInterface $since
32+
* @param \DateTimeInterface $till
33+
*/
34+
public function __construct(\DateTimeInterface $since, \DateTimeInterface $till)
35+
{
36+
$this->assertSameTimezones($since, $till);
37+
38+
$this->since = DateTimeCloner::cloneIntoDateTimeImmutable($since);
39+
$this->till = DateTimeCloner::cloneIntoDateTimeImmutable($till);
40+
}
41+
42+
/**
43+
* {@inheritdoc}
44+
*/
45+
public function getTimezone(): \DateTimeZone
46+
{
47+
return $this->since->getTimezone(); // Since and till timezones are equal
48+
}
49+
50+
/**
51+
* {@inheritdoc}
52+
*/
53+
public function getTimezoneName(): string
54+
{
55+
return $this->since->getTimezone()->getName(); // Since and till timezones are equal
56+
}
57+
58+
/**
59+
* {@inheritdoc}
60+
*/
61+
public function getSince(): \DateTimeImmutable
62+
{
63+
return $this->since;
64+
}
65+
66+
/**
67+
* {@inheritdoc}
68+
*/
69+
public function getTill(): \DateTimeImmutable
70+
{
71+
return $this->till;
72+
}
73+
74+
/**
75+
* {@inheritdoc}
76+
*/
77+
public function isEqual(DateTimeRangeInterface $dateTimeRange): bool
78+
{
79+
$dateRangeSince = $dateTimeRange->getSince();
80+
$dateRangeTill = $dateTimeRange->getTill();
81+
82+
return $this->since->getTimestamp() === $dateRangeSince->getTimestamp()
83+
&& $this->till->getTimestamp() === $dateRangeTill->getTimestamp()
84+
&& $this->since->getTimezone()->getName() === $dateRangeSince->getTimezone()->getName()
85+
&& $this->till->getTimezone()->getName() === $dateRangeTill->getTimezone()->getName();
86+
}
87+
88+
/**
89+
* {@inheritdoc}
90+
*/
91+
public function intersects(DateTimeRangeInterface $dateTimeRange): bool
92+
{
93+
if ($this->getTimezoneName() !== $dateTimeRange->getTimezoneName()) {
94+
throw new LogicException('Timezones of datetime ranges are different');
95+
}
96+
97+
$givenDateRangeSince = $dateTimeRange->getSince();
98+
$givenDateRangeTill = $dateTimeRange->getTill();
99+
100+
switch (true) {
101+
case $this->since === $givenDateRangeSince && $this->till === $givenDateRangeTill: // Current date range is equal to the given date range
102+
case $givenDateRangeSince < $this->since && $this->till < $givenDateRangeTill: // Current date range is fully inside the given date range
103+
case $this->since < $givenDateRangeSince && $givenDateRangeTill < $this->till: // Given date range is fully inside the current date range
104+
case $givenDateRangeSince <= $this->since && $this->since < $givenDateRangeTill: // Current date range beginning is inside the given date range
105+
case $givenDateRangeSince < $this->till && $this->till <= $givenDateRangeTill: // Current date range ending is inside the given date range
106+
return true;
107+
default:
108+
return false;
109+
}
110+
}
111+
112+
/**
113+
* @param \DateTimeInterface $since
114+
* @param \DateTimeInterface $till
115+
*
116+
* @throws LogicException
117+
*/
118+
private function assertSameTimezones(\DateTimeInterface $since, \DateTimeInterface $till): void
119+
{
120+
if ($since->getTimezone()->getName() !== $till->getTimezone()->getName()) {
121+
throw new LogicException('Datetimes have different timezones');
122+
}
123+
}
124+
}

src/DateTimeRangeInterface.php

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<?php
2+
/*
3+
* This file is part of the DateTime library.
4+
*
5+
* (c) Artem Henvald <genvaldartem@gmail.com>
6+
*
7+
* For the full copyright and license information, please view the LICENSE
8+
* file that was distributed with this source code.
9+
*/
10+
11+
declare(strict_types=1);
12+
13+
namespace Fresh\DateTime;
14+
15+
/**
16+
* DateTimeRangeInterface.
17+
*
18+
* @author Artem Henvald <genvaldartem@gmail.com>
19+
*/
20+
interface DateTimeRangeInterface
21+
{
22+
/**
23+
* @return \DateTimeZone
24+
*/
25+
public function getTimezone(): \DateTimeZone;
26+
27+
/**
28+
* @return string
29+
*/
30+
public function getTimezoneName(): string;
31+
32+
/**
33+
* @return \DateTimeImmutable
34+
*/
35+
public function getSince(): \DateTimeImmutable;
36+
37+
/**
38+
* @return \DateTimeImmutable
39+
*/
40+
public function getTill(): \DateTimeImmutable;
41+
42+
/**
43+
* @param DateTimeRangeInterface $dateTimeRange
44+
*
45+
* @return bool
46+
*/
47+
public function isEqual(self $dateTimeRange): bool;
48+
49+
/**
50+
* @param DateTimeRangeInterface $dateTimeRange
51+
*
52+
* @return bool
53+
*/
54+
public function intersects(self $dateTimeRange): bool;
55+
}

0 commit comments

Comments
 (0)