1 | <?php |
||
2 | |||
3 | namespace Gearbox\DateTime; |
||
4 | |||
5 | use DateTime as PhpDateTime; |
||
6 | use Exception as PhpException; |
||
7 | |||
8 | /** |
||
9 | * Represents a specific moment in time and cannot be changed. |
||
10 | */ |
||
11 | class DateTimeImmutable implements DateTimeInterface |
||
12 | { |
||
13 | const DATETIME_FOR_FILE_NAME = 'Y-m-d_H-i-s'; |
||
14 | const GERMAN_DATETIME = 'd.m.Y H:i:s'; |
||
15 | const GERMAN_DATE = 'd.m.Y'; |
||
16 | const MYSQL_DATETIME = 'Y-m-d H:i:s'; |
||
17 | const MYSQL_DATE = 'Y-m-d'; |
||
18 | |||
19 | /** @var \DateTime */ |
||
20 | protected $phpDateTime = null; |
||
21 | |||
22 | |||
23 | |||
24 | /** |
||
25 | * May be called with any date string the php version of DateTime accepts |
||
26 | * and additionally with a unix timestamp also. |
||
27 | * |
||
28 | * @param string $dateString Defaults to 'now'. |
||
29 | */ |
||
30 | public function __construct($dateString = 'now') |
||
31 | { |
||
32 | try { |
||
33 | $this->phpDateTime = new PhpDateTime($dateString); |
||
34 | } |
||
35 | catch (PhpException $exception) { |
||
36 | // Suspect it is a unixtime that could not be parsed. |
||
37 | $this->phpDateTime = new PhpDateTime(); |
||
38 | $this->phpDateTime->setTimestamp($dateString); |
||
39 | } |
||
40 | } |
||
41 | |||
42 | |||
43 | |||
44 | public function __clone() |
||
45 | { |
||
46 | // Force a clone of phpDateTime, otherwise the cloned DateTime object |
||
47 | // would point to the same phpDateTime instance. |
||
48 | $this->phpDateTime = clone $this->phpDateTime; |
||
49 | } |
||
50 | |||
51 | |||
52 | |||
53 | /** |
||
54 | * Returns numeric representation of a day, without leading zeros. |
||
55 | * |
||
56 | * @return integer |
||
57 | */ |
||
58 | public function getDayAsNumber() |
||
59 | { |
||
60 | $day = $this->phpDateTime->format('j'); |
||
61 | |||
62 | return $day; |
||
63 | } |
||
64 | |||
65 | |||
66 | |||
67 | /** |
||
68 | * Returns instance of MonthImmutable |
||
69 | * |
||
70 | * @return \Gearbox\DateTime\MonthImmutable |
||
71 | */ |
||
72 | public function getMonth() |
||
73 | { |
||
74 | $month = new MonthImmutable($this->phpDateTime->format('Y-m')); |
||
75 | |||
76 | return $month; |
||
77 | } |
||
78 | |||
79 | |||
80 | |||
81 | /** |
||
82 | * Returns numeric representation of a month, without leading zeros. |
||
83 | * |
||
84 | * @return integer |
||
85 | */ |
||
86 | public function getMonthAsNumber() |
||
87 | { |
||
88 | $month = $this->phpDateTime->format('n'); |
||
89 | |||
90 | return $month; |
||
91 | } |
||
92 | |||
93 | |||
94 | |||
95 | /** |
||
96 | * Returns year with four digits |
||
97 | * |
||
98 | * @return integer |
||
99 | */ |
||
100 | public function getYearAsNumber() |
||
101 | { |
||
102 | $year = $this->phpDateTime->format('Y'); |
||
103 | |||
104 | return $year; |
||
105 | } |
||
106 | |||
107 | |||
108 | |||
109 | /** |
||
110 | * @param integer $hours |
||
111 | * @param integer $minutes |
||
112 | * @param integer $seconds |
||
113 | * @return \Gearbox\DateTime\DateTimeImmutable |
||
114 | */ |
||
115 | public function setTime($hours, $minutes, $seconds = 0) |
||
116 | { |
||
117 | $phpDateTime = clone $this->phpDateTime; |
||
118 | $phpDateTime->setTime($hours, $minutes, $seconds); |
||
119 | $newDateTime = $this->createInstance($phpDateTime); |
||
120 | |||
121 | return $newDateTime; |
||
122 | } |
||
123 | |||
124 | |||
125 | |||
126 | /** |
||
127 | * Returns true if the DateTime object and the date to compare with represent the same date. |
||
128 | * |
||
129 | * @param \Gearbox\DateTime\DateTimeInterface $dateToCompareWith |
||
130 | * @return boolean |
||
131 | */ |
||
132 | public function equals(DateTimeInterface $dateToCompareWith) |
||
133 | { |
||
134 | $equals = $this->asUnixTimestamp() == $dateToCompareWith->asUnixTimestamp(); |
||
135 | |||
136 | return $equals; |
||
137 | } |
||
138 | |||
139 | |||
140 | |||
141 | /** |
||
142 | * Returns true if the DateTime object is earlier than the date to compare with. |
||
143 | * |
||
144 | * @param \Gearbox\DateTime\DateTimeInterface $dateToCompareWith |
||
145 | * @return boolean |
||
146 | */ |
||
147 | public function isEarlier(DateTimeInterface $dateToCompareWith) |
||
148 | { |
||
149 | $isEarlier = $this->asUnixTimestamp() < $dateToCompareWith->asUnixTimestamp(); |
||
150 | |||
151 | return $isEarlier; |
||
152 | } |
||
153 | |||
154 | |||
155 | |||
156 | /** |
||
157 | * Returns true if the DateTime object is later than the date to compare with. |
||
158 | * |
||
159 | * @param \Gearbox\DateTime\DateTimeInterface $dateToCompareWith |
||
160 | * @return boolean |
||
161 | */ |
||
162 | public function isLater(DateTimeInterface $dateToCompareWith) |
||
163 | { |
||
164 | $isLater = $this->asUnixTimestamp() > $dateToCompareWith->asUnixTimestamp(); |
||
165 | |||
166 | return $isLater; |
||
167 | } |
||
168 | |||
169 | |||
170 | |||
171 | /** |
||
172 | * @param \Gearbox\DateTime\DateTimeInterface $dateToCompareWith |
||
173 | * @return boolean |
||
174 | */ |
||
175 | public function isLaterOrEquals(DateTimeInterface $dateToCompareWith) |
||
176 | { |
||
177 | $equals = ($this->isLater($dateToCompareWith) || $this->equals($dateToCompareWith)); |
||
178 | |||
179 | return $equals; |
||
180 | } |
||
181 | |||
182 | |||
183 | |||
184 | /** |
||
185 | * @param \Gearbox\DateTime\DateTimeInterface $dateToCompareWith |
||
186 | * @return boolean |
||
187 | */ |
||
188 | public function isEarlierOrEquals(DateTimeInterface $dateToCompareWith) |
||
189 | { |
||
190 | $equals = ($this->isEarlier($dateToCompareWith) || $this->equals($dateToCompareWith)); |
||
191 | |||
192 | return $equals; |
||
193 | } |
||
194 | |||
195 | |||
196 | |||
197 | /** |
||
198 | * @param \Gearbox\DateTime\DateTimeInterface $dateTimeToCompareWith |
||
199 | * @return boolean |
||
200 | */ |
||
201 | public function isSameMonth(DateTimeInterface $dateTimeToCompareWith) |
||
202 | { |
||
203 | $sameMonth = $this->getMonthAsNumber() == $dateTimeToCompareWith->getMonthAsNumber() && $this->getYearAsNumber() == $dateTimeToCompareWith->getYearAsNumber(); |
||
204 | |||
205 | return $sameMonth; |
||
206 | } |
||
207 | |||
208 | |||
209 | |||
210 | /** |
||
211 | * @return boolean |
||
212 | */ |
||
213 | public function isInThePast() |
||
214 | { |
||
215 | $isInThePast = $this->asUnixTimestamp() < time(); |
||
216 | |||
217 | return $isInThePast; |
||
218 | } |
||
219 | |||
220 | |||
221 | |||
222 | /** |
||
223 | * @return boolean |
||
224 | */ |
||
225 | public function isInTheFuture() |
||
226 | { |
||
227 | $isInTheFuture = $this->asUnixTimestamp() > time(); |
||
228 | |||
229 | return $isInTheFuture; |
||
230 | } |
||
231 | |||
232 | |||
233 | |||
234 | /** |
||
235 | * @param \Gearbox\DateTime\DateIntervalInterface $interval |
||
236 | * @return \Gearbox\DateTime\DateTimeImmutable |
||
237 | */ |
||
238 | public function add(DateIntervalInterface $interval) |
||
239 | { |
||
240 | $phpDateTime = clone $this->phpDateTime; |
||
241 | $phpDateTime->add($interval->getAsPhpDateInterval()); |
||
242 | $newDateTime = $this->createInstance($phpDateTime); |
||
243 | |||
244 | return $newDateTime; |
||
245 | } |
||
246 | |||
247 | |||
248 | |||
249 | /** |
||
250 | * @param integer $numberOfDays |
||
251 | * @return \Gearbox\DateTime\DateTimeImmutable |
||
252 | */ |
||
253 | public function addDays($numberOfDays) |
||
254 | { |
||
255 | $daysInterval = new DateInterval($numberOfDays . ' days'); |
||
256 | $newDateTime = $this->add($daysInterval); |
||
257 | |||
258 | return $newDateTime; |
||
259 | } |
||
260 | |||
261 | |||
262 | |||
263 | /** |
||
264 | * @param integer $numberOfMonths |
||
265 | * @return \Gearbox\DateTime\DateTimeImmutable |
||
266 | */ |
||
267 | public function addMonths($numberOfMonths) |
||
268 | { |
||
269 | $monthsInterval = new DateInterval($numberOfMonths . ' months'); |
||
270 | $newDateTime = $this->add($monthsInterval); |
||
271 | |||
272 | return $newDateTime; |
||
273 | } |
||
274 | |||
275 | |||
276 | |||
277 | /** |
||
278 | * @param \Gearbox\DateTime\DateTimeInterface $dateTime |
||
279 | * @return \Gearbox\DateTime\DateIntervalInterface |
||
280 | */ |
||
281 | public function diff(DateTimeInterface $dateTime) |
||
282 | { |
||
283 | $phpDateInterval = $this->phpDateTime->diff($dateTime->phpDateTime); |
||
284 | $dateIntervalAsString = $phpDateInterval->format(DateIntervalInterface::FORMAT_ISO_8601); |
||
285 | $interval = new DateInterval($dateIntervalAsString); |
||
286 | |||
287 | return $interval; |
||
288 | } |
||
289 | |||
290 | |||
291 | |||
292 | |||
293 | /** |
||
294 | * @param \Gearbox\DateTime\DateTimeInterface $dateTime |
||
295 | * @return integer |
||
296 | */ |
||
297 | public function diffInDays(DateTimeInterface $dateTime) |
||
298 | { |
||
299 | $phpDateInterval = $this->phpDateTime->diff($dateTime->phpDateTime); |
||
300 | $dateIntervalInDays = $phpDateInterval->days; |
||
0 ignored issues
–
show
|
|||
301 | |||
302 | return $dateIntervalInDays; |
||
303 | } |
||
304 | |||
305 | |||
306 | |||
307 | /** |
||
308 | * @param \Gearbox\DateTime\DateIntervalInterface $interval |
||
309 | * @return \Gearbox\DateTime\DateTimeImmutable |
||
310 | */ |
||
311 | public function sub(DateIntervalInterface $interval) |
||
312 | { |
||
313 | $phpDateTime = clone $this->phpDateTime; |
||
314 | $phpDateTime->sub($interval->getAsPhpDateInterval()); |
||
315 | $newDateTime = $this->createInstance($phpDateTime); |
||
316 | |||
317 | return $newDateTime; |
||
318 | } |
||
319 | |||
320 | |||
321 | |||
322 | /** |
||
323 | * @param string $formatString |
||
324 | * @return string |
||
325 | */ |
||
326 | public function format($formatString) |
||
327 | { |
||
328 | return $this->phpDateTime->format($formatString); |
||
329 | } |
||
330 | |||
331 | |||
332 | |||
333 | /** |
||
334 | * @return string 'Y-m-d H:i:s' |
||
335 | */ |
||
336 | public function asMySqlDateTime() |
||
337 | { |
||
338 | return $this->phpDateTime->format(self::MYSQL_DATETIME); |
||
339 | } |
||
340 | |||
341 | |||
342 | |||
343 | /** |
||
344 | * @return string 'Y-m-d' |
||
345 | */ |
||
346 | public function asMySqlDate() |
||
347 | { |
||
348 | return $this->phpDateTime->format(self::MYSQL_DATE); |
||
349 | } |
||
350 | |||
351 | |||
352 | |||
353 | /** |
||
354 | * @return string |
||
355 | */ |
||
356 | public function asUnixTimestamp() |
||
357 | { |
||
358 | return $this->phpDateTime->format('U'); |
||
359 | } |
||
360 | |||
361 | |||
362 | |||
363 | /** |
||
364 | * @return string 'd.m.Y' |
||
365 | */ |
||
366 | public function asGermanDate() |
||
367 | { |
||
368 | return $this->phpDateTime->format(self::GERMAN_DATE); |
||
369 | } |
||
370 | |||
371 | |||
372 | |||
373 | /** |
||
374 | * @return string 'd.m.Y H:i:s' |
||
375 | */ |
||
376 | public function asGermanDateTime() |
||
377 | { |
||
378 | return $this->phpDateTime->format(self::GERMAN_DATETIME); |
||
379 | } |
||
380 | |||
381 | |||
382 | |||
383 | /** |
||
384 | * @return string 'Y-m-d_H-i-s' |
||
385 | */ |
||
386 | public function asDateTimeForFilename() |
||
387 | { |
||
388 | return $this->phpDateTime->format(self::DATETIME_FOR_FILE_NAME); |
||
389 | } |
||
390 | |||
391 | |||
392 | |||
393 | /** |
||
394 | * @return string |
||
395 | */ |
||
396 | public function __toString() |
||
397 | { |
||
398 | return $this->phpDateTime->format(self::GERMAN_DATETIME); |
||
399 | } |
||
400 | |||
401 | |||
402 | |||
403 | /** |
||
404 | * @param $phpDateTime |
||
405 | * @return \Gearbox\DateTime\DateTimeImmutable |
||
406 | */ |
||
407 | private function createInstance($phpDateTime) |
||
408 | { |
||
409 | $newDateTime = new self($phpDateTime->format('Y-m-d H:i:s')); |
||
410 | |||
411 | return $newDateTime; |
||
412 | } |
||
413 | } |
||
414 |
Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.
For example, imagine you have a variable
$accountId
that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to theid
property of an instance of theAccount
class. This class holds a proper account, so the id value must no longer be false.Either this assignment is in error or a type check should be added for that assignment.