|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
declare(strict_types = 1); |
|
4
|
|
|
|
|
5
|
|
|
namespace Arbor\Moment; |
|
6
|
|
|
|
|
7
|
|
|
use Arbor\Moment\Comparator\DateTimeComparator; |
|
8
|
|
|
use Arbor\Moment\Exception\InvalidArgumentException; |
|
9
|
|
|
use Arbor\Moment\Formatter\DateRangeFormatter; |
|
10
|
|
|
use Arbor\Moment\Formatter\FormatterInterface; |
|
11
|
|
|
|
|
12
|
|
|
/** |
|
13
|
|
|
* Class DateRange |
|
14
|
|
|
* |
|
15
|
|
|
* @package Arbor\Moment |
|
16
|
|
|
* @author Igor Vuckovic <[email protected]> |
|
17
|
|
|
*/ |
|
18
|
|
|
class DateRange |
|
19
|
|
|
{ |
|
20
|
|
|
/** @var DateTime */ |
|
21
|
|
|
private $startDate; |
|
22
|
|
|
|
|
23
|
|
|
/** @var DateTime */ |
|
24
|
|
|
private $endDate; |
|
25
|
|
|
|
|
26
|
|
|
/** @var FormatterInterface */ |
|
27
|
|
|
private $formatter; |
|
28
|
|
|
|
|
29
|
|
|
/** |
|
30
|
|
|
* @param DateTime|null $startDate |
|
31
|
|
|
* @param DateTime|null $endDate |
|
32
|
|
|
* @throws \InvalidArgumentException |
|
33
|
|
|
*/ |
|
34
|
18 |
|
public function __construct(DateTime $startDate = null, DateTime $endDate = null) |
|
35
|
|
|
{ |
|
36
|
18 |
|
$this->startDate = $startDate ? clone $startDate : null; |
|
37
|
18 |
|
$this->endDate = $endDate ? clone $endDate : null; |
|
38
|
|
|
|
|
39
|
18 |
|
if ($startDate && $endDate && $endDate < $startDate) { |
|
40
|
1 |
|
throw InvalidArgumentException::startDateNotBeforeEndDate($startDate, $endDate); |
|
41
|
|
|
} |
|
42
|
|
|
|
|
43
|
17 |
|
$this->formatter = new DateRangeFormatter($this); |
|
44
|
17 |
|
} |
|
45
|
|
|
|
|
46
|
|
|
/** |
|
47
|
|
|
* @return DateTime|null |
|
48
|
|
|
*/ |
|
49
|
26 |
|
public function getStartDate() |
|
50
|
|
|
{ |
|
51
|
26 |
|
return $this->startDate; |
|
52
|
|
|
} |
|
53
|
|
|
|
|
54
|
|
|
/** |
|
55
|
|
|
* @return DateTime|null |
|
56
|
|
|
*/ |
|
57
|
22 |
|
public function getEndDate() |
|
58
|
|
|
{ |
|
59
|
22 |
|
return $this->endDate; |
|
60
|
|
|
} |
|
61
|
|
|
|
|
62
|
|
|
/** |
|
63
|
|
|
* @param DateTime $date |
|
64
|
|
|
* @return bool |
|
65
|
|
|
*/ |
|
66
|
8 |
|
public function containsDate(DateTime $date) : bool |
|
67
|
|
|
{ |
|
68
|
8 |
|
if ($this->startDate === null) { |
|
69
|
3 |
|
return $this->endDate === null || $this->endDate >= $date; |
|
70
|
5 |
|
} elseif ($this->endDate === null) { |
|
71
|
2 |
|
return $this->startDate <= $date; |
|
72
|
|
|
} |
|
73
|
|
|
|
|
74
|
3 |
|
return $this->startDate <= $date && $this->endDate >= $date; |
|
75
|
|
|
} |
|
76
|
|
|
|
|
77
|
|
|
/** |
|
78
|
|
|
* @param DateRange $dateRange |
|
79
|
|
|
* @return bool |
|
80
|
|
|
*/ |
|
81
|
10 |
|
public function containsDateRange(DateRange $dateRange) : bool |
|
82
|
|
|
{ |
|
83
|
10 |
|
if ($this->startDate === null && $this->endDate === null) { |
|
84
|
4 |
|
return true; |
|
85
|
|
|
} |
|
86
|
|
|
|
|
87
|
6 |
|
return $this->startDate <= $dateRange->getStartDate() |
|
88
|
6 |
|
&& $dateRange->getEndDate() !== null |
|
89
|
6 |
|
&& $this->endDate >= $dateRange->getEndDate(); |
|
90
|
|
|
} |
|
91
|
|
|
|
|
92
|
|
|
/** |
|
93
|
|
|
* @param DateRange $dateRange |
|
94
|
|
|
* @return bool |
|
95
|
|
|
*/ |
|
96
|
6 |
|
public function overlapsDateRange(DateRange $dateRange) : bool |
|
97
|
|
|
{ |
|
98
|
6 |
|
return $this->intersect($dateRange) !== null; |
|
99
|
|
|
} |
|
100
|
|
|
|
|
101
|
|
|
/** |
|
102
|
|
|
* @param DateTime $date |
|
103
|
|
|
* @return bool |
|
104
|
|
|
*/ |
|
105
|
5 |
|
public function isBefore(DateTime $date) : bool |
|
106
|
|
|
{ |
|
107
|
5 |
|
if ($this->endDate === null) { |
|
108
|
1 |
|
return false; |
|
109
|
|
|
} |
|
110
|
|
|
|
|
111
|
4 |
|
return $this->endDate <= $date; |
|
112
|
|
|
} |
|
113
|
|
|
|
|
114
|
|
|
/** |
|
115
|
|
|
* @return bool |
|
116
|
|
|
*/ |
|
117
|
1 |
|
public function isNow() : bool |
|
118
|
|
|
{ |
|
119
|
1 |
|
return $this->containsDate(new DateTime()); |
|
120
|
|
|
} |
|
121
|
|
|
|
|
122
|
|
|
/** |
|
123
|
|
|
* @param DateTime $date |
|
124
|
|
|
* @return bool |
|
125
|
|
|
*/ |
|
126
|
5 |
|
public function isAfter(DateTime $date) : bool |
|
127
|
|
|
{ |
|
128
|
5 |
|
if ($this->startDate === null) { |
|
129
|
1 |
|
return false; |
|
130
|
|
|
} |
|
131
|
|
|
|
|
132
|
4 |
|
return $this->startDate >= $date; |
|
133
|
|
|
} |
|
134
|
|
|
|
|
135
|
|
|
/** |
|
136
|
|
|
* @param DateRange $dateRange |
|
137
|
|
|
* @return DateRange|null |
|
138
|
|
|
*/ |
|
139
|
9 |
|
public function intersect(DateRange $dateRange) |
|
140
|
|
|
{ |
|
141
|
9 |
|
$latestStartDate = DateTimeComparator::getLatestDate($this->startDate, $dateRange->startDate); |
|
142
|
9 |
|
$earliestEndDate = DateTimeComparator::getEarliestDate($this->endDate, $dateRange->endDate); |
|
143
|
|
|
|
|
144
|
9 |
|
if ($latestStartDate && $earliestEndDate && ($latestStartDate >= $earliestEndDate)) { |
|
145
|
2 |
|
return null; |
|
146
|
|
|
} |
|
147
|
|
|
|
|
148
|
7 |
|
return new DateRange($latestStartDate, $earliestEndDate); |
|
149
|
|
|
} |
|
150
|
|
|
|
|
151
|
|
|
/** |
|
152
|
|
|
* @param string $nullPlaceholder |
|
153
|
|
|
* @return string |
|
154
|
|
|
*/ |
|
155
|
10 |
|
public function getShort(string $nullPlaceholder = 'Ongoing') : string |
|
156
|
|
|
{ |
|
157
|
10 |
|
return $this->formatter->getShort($nullPlaceholder); |
|
|
|
|
|
|
158
|
|
|
} |
|
159
|
|
|
|
|
160
|
|
|
/** |
|
161
|
|
|
* @param string $nullPlaceholder |
|
162
|
|
|
* @return string |
|
163
|
|
|
*/ |
|
164
|
21 |
|
public function getLong(string $nullPlaceholder = 'Ongoing') : string |
|
165
|
|
|
{ |
|
166
|
21 |
|
return $this->formatter->getLong($nullPlaceholder); |
|
|
|
|
|
|
167
|
|
|
} |
|
168
|
|
|
|
|
169
|
|
|
/** |
|
170
|
|
|
* @return DateTime[] |
|
171
|
|
|
* @throws InvalidArgumentException |
|
172
|
|
|
*/ |
|
173
|
4 |
|
public function getAllDates() : array |
|
174
|
|
|
{ |
|
175
|
4 |
|
if ($this->getStartDate() === null || $this->getEndDate() === null) { |
|
176
|
3 |
|
throw InvalidArgumentException::dateRangeWithoutBoundaries(); |
|
177
|
|
|
} |
|
178
|
|
|
|
|
179
|
1 |
|
$startDate = $this->startDate; |
|
180
|
1 |
|
$endDate = $this->endDate; |
|
181
|
1 |
|
$referenceDate = clone $startDate; |
|
182
|
1 |
|
$referenceDate->setDateType(DateTime::TYPE_DATE); |
|
183
|
|
|
|
|
184
|
1 |
|
$dates = []; |
|
185
|
1 |
|
while ($referenceDate <= $endDate) { |
|
186
|
1 |
|
$dates[$referenceDate->getUnixTimestamp()] = clone $referenceDate; |
|
187
|
1 |
|
$referenceDate->add(new \DateInterval('P1D')); |
|
188
|
|
|
} |
|
189
|
|
|
|
|
190
|
1 |
|
return array_values($dates); |
|
191
|
|
|
} |
|
192
|
|
|
|
|
193
|
|
|
/** |
|
194
|
|
|
* @return Time|null |
|
195
|
|
|
*/ |
|
196
|
4 |
|
public function getDuration() |
|
197
|
|
|
{ |
|
198
|
4 |
|
if ($this->startDate && $this->endDate) { |
|
199
|
1 |
|
return Time::fromSeconds($this->endDate->getTimestamp() - $this->startDate->getTimestamp()); |
|
200
|
|
|
} |
|
201
|
|
|
|
|
202
|
3 |
|
return null; |
|
203
|
|
|
} |
|
204
|
|
|
|
|
205
|
|
|
/** |
|
206
|
|
|
* @return string |
|
207
|
|
|
*/ |
|
208
|
7 |
|
public function __toString() : string |
|
209
|
|
|
{ |
|
210
|
7 |
|
return $this->getLong(); |
|
211
|
|
|
} |
|
212
|
|
|
|
|
213
|
|
|
/** |
|
214
|
|
|
* |
|
215
|
|
|
*/ |
|
216
|
1 |
|
public function __clone() |
|
217
|
|
|
{ |
|
218
|
1 |
|
$this->startDate = ($this->startDate ? clone $this->startDate : null); |
|
219
|
1 |
|
$this->endDate = ($this->endDate ? clone $this->endDate : null); |
|
220
|
1 |
|
} |
|
221
|
|
|
} |
|
222
|
|
|
|
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.
If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.
In this case you can add the
@ignorePhpDoc annotation to the duplicate definition and it will be ignored.