1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* File was created 11.03.2015 14:51 |
4
|
|
|
* |
5
|
|
|
* @author Karsten J. Gerber <[email protected]> |
6
|
|
|
*/ |
7
|
|
|
|
8
|
|
|
namespace PeekAndPoke\Types; |
9
|
|
|
|
10
|
|
|
/** |
11
|
|
|
* LocalDate is an enhanced date that forces construction with a timezone like Europe/Berlin |
12
|
|
|
* |
13
|
|
|
* The LocalDate is immutable. All modifying methods return a new instance. |
14
|
|
|
* |
15
|
|
|
* It also integrates with Slumber to serialize to json like |
16
|
|
|
* |
17
|
|
|
* { date : "2017-10-10T11:11:11+02:00", tz : "Europe/Berlin" } |
18
|
|
|
* |
19
|
|
|
* So the receiver (e.g. the browser) can reconstruct the date with the correct timezone |
20
|
|
|
* |
21
|
|
|
* @api |
22
|
|
|
* |
23
|
|
|
* @author Karsten J. Gerber <[email protected]> |
24
|
|
|
*/ |
25
|
|
|
class LocalDate |
26
|
|
|
{ |
27
|
|
|
/** @var \DateTime */ |
28
|
|
|
private $date; |
29
|
|
|
/** @var \DateTimeZone */ |
30
|
|
|
private $timezone; |
31
|
|
|
|
32
|
|
|
/** |
33
|
|
|
* @param int $timestamp The unix timestamp |
34
|
|
|
* @param \DateTimeZone|string $timezone The timezone or a string the DateTimeZone c'tor can understand |
35
|
|
|
* |
36
|
|
|
* @return LocalDate |
37
|
|
|
*/ |
38
|
109 |
|
public static function fromTimestamp($timestamp, $timezone) |
39
|
|
|
{ |
40
|
109 |
|
return new LocalDate($timestamp, $timezone); |
41
|
|
|
} |
42
|
|
|
|
43
|
|
|
/** |
44
|
|
|
* @return LocalDate |
45
|
|
|
*/ |
46
|
2 |
|
public static function now() |
47
|
|
|
{ |
48
|
2 |
|
return self::raw(new \DateTime()); |
49
|
|
|
} |
50
|
|
|
|
51
|
|
|
/** |
52
|
|
|
* @param \DateTime $dateTime |
53
|
|
|
* |
54
|
|
|
* @return LocalDate |
55
|
|
|
*/ |
56
|
18 |
|
public static function raw(\DateTime $dateTime) |
57
|
|
|
{ |
58
|
18 |
|
$tz = $dateTime->getTimezone(); |
59
|
|
|
|
60
|
|
|
// normalize input coming from Javascript or Java etc... |
61
|
18 |
|
if ($tz->getName() === 'Z') { |
62
|
8 |
|
$tz = new \DateTimeZone('Etc/UTC'); |
63
|
|
|
} |
64
|
|
|
|
65
|
18 |
|
return new LocalDate($dateTime, $tz); |
66
|
|
|
} |
67
|
|
|
|
68
|
|
|
/** |
69
|
|
|
* @param \DateTime|string|float|int $input The date or a string the DateTime c'tor can understand or a timestamp |
70
|
|
|
* @param \DateTimeZone|string $timezone The timezone or a string the DateTimeZone c'tor can understand |
71
|
|
|
*/ |
72
|
226 |
|
public function __construct($input, $timezone) |
73
|
|
|
{ |
74
|
226 |
|
if (! $timezone instanceof \DateTimeZone) { |
75
|
198 |
|
$timezone = new \DateTimeZone((string) $timezone); |
76
|
|
|
} |
77
|
|
|
|
78
|
|
|
///// |
79
|
|
|
// We have to trick PHP a bit here, but why? |
80
|
|
|
// |
81
|
|
|
// Apparently things behave different, when setting a timezone like |
82
|
|
|
// a) 'Europe/Berlin' |
83
|
|
|
// b) '+02:00' |
84
|
|
|
// |
85
|
|
|
// When the date already has a timezone set then |
86
|
|
|
// a) will only set the timezone |
87
|
|
|
// b) will set the timezone and will also change the timestamp by 2 hours |
88
|
|
|
// |
89
|
|
|
// Therefore we create a fresh date, that does not have a timezone yet, set the timestamp, and then apply the |
90
|
|
|
// timezone |
91
|
|
|
// |
92
|
|
|
// See the unit tests for more as well |
93
|
|
|
//// |
94
|
226 |
|
if ($input instanceof \DateTime) { |
95
|
|
|
|
96
|
62 |
|
$date = (clone $input)->setTimezone($timezone); |
97
|
|
|
|
98
|
188 |
|
} elseif (is_numeric($input)) { |
99
|
|
|
// Handle numeric input. Special case is floats with micro second precision |
100
|
139 |
|
if (\is_float($input)) { |
101
|
20 |
|
$date = \DateTime::createFromFormat('U.u', sprintf('%.6f', $input)); |
102
|
20 |
|
$date->setTimezone($timezone); |
103
|
|
|
} else { |
104
|
|
|
// otherwise we handle things as integer timestamps |
105
|
139 |
|
$date = (new \DateTime())->setTimestamp((int) $input)->setTimezone($timezone); |
106
|
|
|
} |
107
|
|
|
|
108
|
|
|
} else { |
109
|
|
|
// When we have string input, we immediately use the timezone |
110
|
|
|
// We reconstruct the date time again in order to set the timezone on the inner one |
111
|
136 |
|
$date = (new \DateTime($input, $timezone))->setTimezone($timezone); |
112
|
|
|
} |
113
|
|
|
|
114
|
226 |
|
$this->date = $date; |
115
|
226 |
|
$this->timezone = $timezone; |
116
|
226 |
|
} |
117
|
|
|
|
118
|
|
|
/** |
119
|
|
|
* @return string |
120
|
|
|
*/ |
121
|
1 |
|
public function __toString() |
122
|
|
|
{ |
123
|
1 |
|
return $this->format(); |
124
|
|
|
} |
125
|
|
|
|
126
|
|
|
/** |
127
|
|
|
* @return \DateTime |
128
|
|
|
*/ |
129
|
85 |
|
public function getDate() |
130
|
|
|
{ |
131
|
85 |
|
return clone $this->date; |
132
|
|
|
} |
133
|
|
|
|
134
|
|
|
/** |
135
|
|
|
* @return int |
136
|
|
|
*/ |
137
|
125 |
|
public function getTimestamp() |
138
|
|
|
{ |
139
|
125 |
|
return $this->date->getTimestamp(); |
140
|
|
|
} |
141
|
|
|
|
142
|
|
|
/** |
143
|
|
|
* @return \DateTimeZone |
144
|
|
|
*/ |
145
|
174 |
|
public function getTimezone() |
146
|
|
|
{ |
147
|
174 |
|
return clone $this->timezone; |
148
|
|
|
} |
149
|
|
|
|
150
|
|
|
/** |
151
|
|
|
* @return int |
152
|
|
|
*/ |
153
|
4 |
|
public function getOffset() |
154
|
|
|
{ |
155
|
4 |
|
return $this->date->getOffset(); |
156
|
|
|
} |
157
|
|
|
|
158
|
|
|
/** |
159
|
|
|
* @return float |
160
|
|
|
*/ |
161
|
1 |
|
public function getOffsetInMinutes() |
162
|
|
|
{ |
163
|
1 |
|
$offset = $this->getTimezone()->getOffset($this->getDate()); |
164
|
|
|
|
165
|
1 |
|
return $offset / 60; |
166
|
|
|
} |
167
|
|
|
|
168
|
|
|
/** |
169
|
|
|
* @return float |
170
|
|
|
*/ |
171
|
1 |
|
public function getOffsetInHours() |
172
|
|
|
{ |
173
|
1 |
|
$offset = $this->getTimezone()->getOffset($this->getDate()); |
174
|
|
|
|
175
|
1 |
|
return $offset / 3600; |
176
|
|
|
} |
177
|
|
|
|
178
|
|
|
/** |
179
|
|
|
* @param string $format |
180
|
|
|
* |
181
|
|
|
* @return string |
182
|
|
|
*/ |
183
|
210 |
|
public function format($format = 'c') |
184
|
|
|
{ |
185
|
210 |
|
return $this->date->format($format); |
186
|
|
|
} |
187
|
|
|
|
188
|
|
|
/** |
189
|
|
|
* @return LocalDate |
190
|
|
|
*/ |
191
|
1 |
|
public function getClone() |
192
|
|
|
{ |
193
|
1 |
|
return new LocalDate($this->date, $this->timezone); |
194
|
|
|
} |
195
|
|
|
|
196
|
|
|
/** |
197
|
|
|
* Get the time saving shift on this date in seconds |
198
|
|
|
* |
199
|
|
|
* @return int |
200
|
|
|
*/ |
201
|
1 |
|
public function getDaylightSavingShift() |
202
|
|
|
{ |
203
|
1 |
|
$previousNoon = $this->getStartOfPreviousDay()->modifyByHours(12); |
204
|
|
|
|
205
|
1 |
|
return $this->getOffset() - $previousNoon->getOffset(); |
206
|
|
|
} |
207
|
|
|
|
208
|
|
|
//// Daylight saving time shift aware methods ////////////////////////////////////////////////////////////////////// |
209
|
|
|
|
210
|
|
|
/** |
211
|
|
|
* Add hours to start of day while also respecting Daylight-saving-time shift |
212
|
|
|
* |
213
|
|
|
* E.g. on 2016-03-27T10:00:00 in Berlin is only 9 hours after the start of the day. |
214
|
|
|
* |
215
|
|
|
* @param $hours |
216
|
|
|
* |
217
|
|
|
* @return LocalDate |
218
|
|
|
*/ |
219
|
2 |
|
public function getDstStartOfDayPlusHours($hours) |
220
|
|
|
{ |
221
|
2 |
|
$startOfDay = $this->getStartOfDay(); |
222
|
2 |
|
$startOfDayOffset = $startOfDay->getOffset(); |
223
|
|
|
|
224
|
2 |
|
$result = $startOfDay->modifyByHours($hours); |
225
|
2 |
|
$resultOffset = $result->getOffset(); |
226
|
|
|
|
227
|
2 |
|
return $result->modifyBySeconds($startOfDayOffset)->modifyBySeconds(0 - $resultOffset); |
228
|
|
|
} |
229
|
|
|
|
230
|
|
|
//// Modification methods ////////////////////////////////////////////////////////////////////////////////////////// |
231
|
|
|
|
232
|
|
|
/** |
233
|
|
|
* @return LocalDate |
234
|
|
|
*/ |
235
|
10 |
|
public function getStartOfDay() |
236
|
|
|
{ |
237
|
10 |
|
return $this->modifyTime(0, 0, 0); |
238
|
|
|
} |
239
|
|
|
|
240
|
|
|
/** |
241
|
|
|
* Get the nearest start of a day, either the current or the next day depending on the time in the day |
242
|
|
|
* |
243
|
|
|
* @return LocalDate |
244
|
|
|
*/ |
245
|
1 |
|
public function getNearestStartOfDay() |
246
|
|
|
{ |
247
|
1 |
|
if ($this->getHours() < 12) { |
248
|
1 |
|
return $this->getStartOfDay(); |
249
|
|
|
} |
250
|
|
|
|
251
|
1 |
|
return $this->getStartOfNextDay(); |
252
|
|
|
} |
253
|
|
|
|
254
|
|
|
/** |
255
|
|
|
* @return LocalDate |
256
|
|
|
*/ |
257
|
2 |
View Code Duplication |
public function getStartOfPreviousDay() |
|
|
|
|
258
|
|
|
{ |
259
|
2 |
|
$dateCloned = clone $this->getDate(); |
260
|
|
|
|
261
|
|
|
// take switches between summer and winter time into account |
262
|
2 |
|
if ($dateCloned->format('H') > 21) { |
263
|
1 |
|
$dateCloned->modify('-27 hours'); |
264
|
|
|
} else { |
265
|
2 |
|
$dateCloned->modify('-24 hours'); |
266
|
|
|
} |
267
|
|
|
|
268
|
2 |
|
$temp = new LocalDate($dateCloned, $this->timezone); |
269
|
|
|
|
270
|
2 |
|
return $temp->getStartOfDay(); |
271
|
|
|
} |
272
|
|
|
|
273
|
|
|
/** |
274
|
|
|
* @return LocalDate |
275
|
|
|
*/ |
276
|
2 |
View Code Duplication |
public function getStartOfNextDay() |
|
|
|
|
277
|
|
|
{ |
278
|
2 |
|
$dateCloned = clone $this->getDate(); |
279
|
|
|
|
280
|
|
|
// take switches between summer and winter time into account |
281
|
2 |
|
if ($dateCloned->format('H') < 3) { |
282
|
1 |
|
$dateCloned->modify('+27 hours'); |
283
|
|
|
} else { |
284
|
2 |
|
$dateCloned->modify('+24 hours'); |
285
|
|
|
} |
286
|
|
|
|
287
|
2 |
|
$temp = new LocalDate($dateCloned, $this->timezone); |
288
|
|
|
|
289
|
2 |
|
return $temp->getStartOfDay(); |
290
|
|
|
} |
291
|
|
|
|
292
|
|
|
/** |
293
|
|
|
* @return LocalDate |
294
|
|
|
*/ |
295
|
1 |
|
public function getEndOfDay() |
296
|
|
|
{ |
297
|
1 |
|
return $this->getStartOfDay()->modifyByDays(1); |
298
|
|
|
} |
299
|
|
|
|
300
|
|
|
/** |
301
|
|
|
* @param int $hour |
302
|
|
|
* @param int $minute |
303
|
|
|
* @param int $second |
304
|
|
|
* |
305
|
|
|
* @return LocalDate |
306
|
|
|
*/ |
307
|
10 |
|
public function modifyTime($hour, $minute, $second) |
308
|
|
|
{ |
309
|
10 |
|
$hour = (int) $hour; |
310
|
10 |
|
$minute = (int) $minute; |
311
|
10 |
|
$second = (int) $second; |
312
|
|
|
|
313
|
10 |
|
$clonedDate = clone $this->date; |
314
|
|
|
|
315
|
10 |
|
$clonedDate->setTime((int) $hour, (int) $minute, (int) $second); |
316
|
|
|
|
317
|
10 |
|
return new LocalDate($clonedDate, $this->timezone); |
318
|
|
|
} |
319
|
|
|
|
320
|
|
|
/** |
321
|
|
|
* @param int $numSeconds |
322
|
|
|
* |
323
|
|
|
* @return LocalDate |
324
|
|
|
*/ |
325
|
94 |
|
public function modifyBySeconds($numSeconds) |
326
|
|
|
{ |
327
|
94 |
|
return self::fromTimestamp( |
328
|
94 |
|
$this->getTimestamp() + (int) $numSeconds, |
329
|
94 |
|
$this->getTimezone() |
330
|
|
|
); |
331
|
|
|
} |
332
|
|
|
|
333
|
|
|
/** |
334
|
|
|
* @param float $numMinutes |
335
|
|
|
* |
336
|
|
|
* @return LocalDate |
337
|
|
|
*/ |
338
|
19 |
|
public function modifyByMinutes($numMinutes) |
339
|
|
|
{ |
340
|
19 |
|
return $this->modifyBySeconds(((double) $numMinutes) * 60); |
341
|
|
|
} |
342
|
|
|
|
343
|
|
|
/** |
344
|
|
|
* @param float $numHours |
345
|
|
|
* |
346
|
|
|
* @return LocalDate |
347
|
|
|
*/ |
348
|
24 |
|
public function modifyByHours($numHours) |
349
|
|
|
{ |
350
|
24 |
|
return $this->modifyBySeconds(((double) $numHours) * 3600); |
351
|
|
|
} |
352
|
|
|
|
353
|
|
|
/** |
354
|
|
|
* @param float $numDays |
355
|
|
|
* |
356
|
|
|
* @return LocalDate |
357
|
|
|
*/ |
358
|
32 |
|
public function modifyByDays($numDays) |
359
|
|
|
{ |
360
|
32 |
|
return $this->modifyBySeconds(((double) $numDays) * 86400); |
361
|
|
|
} |
362
|
|
|
|
363
|
|
|
/** |
364
|
|
|
* @param int $numDays |
365
|
|
|
* |
366
|
|
|
* @return LocalDate |
367
|
|
|
*/ |
368
|
3 |
|
public function modifyByDaysDaylightSavingAware($numDays) |
369
|
|
|
{ |
370
|
3 |
|
$numDays = (int) $numDays; |
371
|
3 |
|
$timestamp = $this->getTimestamp() + (86400 * $numDays); |
372
|
|
|
|
373
|
3 |
|
$newDate = self::fromTimestamp($timestamp, $this->timezone); |
374
|
|
|
|
375
|
|
|
// calculate the datetime savings offsets |
376
|
3 |
|
$timezoneInitialDateOffset = $this->timezone->getOffset($this->date); |
377
|
3 |
|
$timezoneNewDateOffset = $this->timezone->getOffset($newDate->date); |
378
|
|
|
|
379
|
|
|
// fix the new date if it's needed |
380
|
3 |
|
if ($timezoneInitialDateOffset !== $timezoneNewDateOffset) { |
381
|
3 |
|
$newDate = self::fromTimestamp($timestamp + ($timezoneInitialDateOffset - $timezoneNewDateOffset), $this->timezone); |
382
|
|
|
} |
383
|
|
|
|
384
|
3 |
|
return $newDate; |
385
|
|
|
} |
386
|
|
|
|
387
|
|
|
/** |
388
|
|
|
* @param \DateInterval|string $interval |
389
|
|
|
* |
390
|
|
|
* @deprecated use addInterval or subInterval |
391
|
|
|
* |
392
|
|
|
* @return LocalDate |
393
|
|
|
* |
394
|
|
|
* @throws \Exception When the given param is not a valid date interval |
395
|
|
|
*/ |
396
|
|
|
public function modifyByInterval($interval) |
397
|
|
|
{ |
398
|
|
|
return $this->addInterval($interval); |
399
|
|
|
} |
400
|
|
|
|
401
|
|
|
/** |
402
|
|
|
* @param \DateInterval|string $interval |
403
|
|
|
* |
404
|
|
|
* @return LocalDate |
405
|
|
|
* |
406
|
|
|
* @throws \Exception When the given param is not a valid date interval |
407
|
|
|
*/ |
408
|
10 |
View Code Duplication |
public function addInterval($interval) |
|
|
|
|
409
|
|
|
{ |
410
|
10 |
|
if (! $interval instanceof \DateInterval) { |
411
|
10 |
|
$interval = new \DateInterval($interval); |
412
|
|
|
} |
413
|
|
|
|
414
|
10 |
|
$dateCloned = clone $this->date; |
415
|
10 |
|
$dateCloned->add($interval); |
416
|
|
|
|
417
|
10 |
|
return new LocalDate($dateCloned, $this->timezone); |
418
|
|
|
} |
419
|
|
|
|
420
|
|
|
/** |
421
|
|
|
* @param \DateInterval|string $interval |
422
|
|
|
* |
423
|
|
|
* @return LocalDate |
424
|
|
|
* |
425
|
|
|
* @throws \Exception When the given param is not a valid date interval |
426
|
|
|
*/ |
427
|
10 |
View Code Duplication |
public function subInterval($interval) |
|
|
|
|
428
|
|
|
{ |
429
|
10 |
|
if (! $interval instanceof \DateInterval) { |
430
|
10 |
|
$interval = new \DateInterval($interval); |
431
|
|
|
} |
432
|
|
|
|
433
|
10 |
|
$dateCloned = clone $this->date; |
434
|
10 |
|
$dateCloned->sub($interval); |
435
|
|
|
|
436
|
10 |
|
return new LocalDate($dateCloned, $this->timezone); |
437
|
|
|
} |
438
|
|
|
|
439
|
|
|
/** |
440
|
|
|
* @param $minutesInterval |
441
|
|
|
* |
442
|
|
|
* @return LocalDate |
443
|
|
|
*/ |
444
|
1 |
|
public function alignToMinutesInterval($minutesInterval) |
445
|
|
|
{ |
446
|
1 |
|
if ($minutesInterval <= 0) { |
447
|
1 |
|
return $this; |
448
|
|
|
} |
449
|
|
|
|
450
|
|
|
// This is a work-around for the day-light-saving shift days |
451
|
|
|
// If we would use minutesIntoDay and then add those to startOfDay, we loose one hour. |
452
|
|
|
// Example would be '2015-03-29 11:20' with tz 'Europe/Berlin' would result in '2015-03-29 10:00' |
453
|
1 |
|
$minutesIntoDay = ((int) $this->date->format('H') * 60) + ((int) $this->date->format('i')); |
454
|
|
|
// cut off partial intervals |
455
|
1 |
|
$corrected = ((int) ($minutesIntoDay / $minutesInterval)) * $minutesInterval; |
456
|
|
|
|
457
|
1 |
|
return $this->getStartOfDay()->modifyByMinutes($corrected); |
458
|
|
|
} |
459
|
|
|
|
460
|
|
|
/** |
461
|
|
|
* @return int |
462
|
|
|
*/ |
463
|
1 |
|
public function getMinutesIntoDay() |
464
|
|
|
{ |
465
|
1 |
|
$day = $this->getStartOfDay(); |
466
|
1 |
|
$diff = $this->getTimestamp() - $day->getTimestamp(); |
467
|
|
|
|
468
|
1 |
|
return (int) ($diff / 60); |
469
|
|
|
} |
470
|
|
|
|
471
|
|
|
/** |
472
|
|
|
* Get the hours portion of the current time |
473
|
|
|
* |
474
|
|
|
* @return int |
475
|
|
|
*/ |
476
|
1 |
|
public function getHours() |
477
|
|
|
{ |
478
|
1 |
|
return (int) $this->format('H'); |
479
|
|
|
} |
480
|
|
|
|
481
|
|
|
/** |
482
|
|
|
* Get the weekday with Sun = 0, Mon = 1, ... Sat = 6 |
483
|
|
|
* |
484
|
|
|
* @return int |
485
|
|
|
*/ |
486
|
1 |
|
public function getWeekday() |
487
|
|
|
{ |
488
|
1 |
|
$day = (int) $this->format('N'); |
489
|
|
|
|
490
|
1 |
|
if ($day === 7) { |
491
|
1 |
|
return 0; |
492
|
|
|
} |
493
|
|
|
|
494
|
1 |
|
return $day; |
495
|
|
|
} |
496
|
|
|
|
497
|
|
|
//// COMPARISON METHODS ////////////////////////////////////////////////////////////////////////////////////////// |
498
|
|
|
|
499
|
|
|
/** |
500
|
|
|
* Returns the data that is earlier, either the current or the other |
501
|
|
|
* |
502
|
|
|
* @param LocalDate|\DateTime $other |
503
|
|
|
* |
504
|
|
|
* @return LocalDate |
505
|
|
|
*/ |
506
|
1 |
|
public function min($other) |
507
|
|
|
{ |
508
|
1 |
|
$other = $this->ensure($other); |
509
|
|
|
|
510
|
1 |
|
return $this->isBefore($other) ? $this : $other; |
511
|
|
|
} |
512
|
|
|
|
513
|
|
|
/** |
514
|
|
|
* Returns the data that is later, either the current or the other |
515
|
|
|
* |
516
|
|
|
* @param LocalDate|\DateTime $other |
517
|
|
|
* |
518
|
|
|
* @return LocalDate |
519
|
|
|
*/ |
520
|
1 |
|
public function max($other) |
521
|
|
|
{ |
522
|
1 |
|
$other = $this->ensure($other); |
523
|
|
|
|
524
|
1 |
|
return $this->isAfter($other) ? $this : $other; |
525
|
|
|
} |
526
|
|
|
|
527
|
|
|
/** |
528
|
|
|
* Get the number of seconds between this and the other. |
529
|
|
|
* |
530
|
|
|
* The result will be negative when this is after the other |
531
|
|
|
* |
532
|
|
|
* @param LocalDate|\DateTime $other |
533
|
|
|
* |
534
|
|
|
* @return float |
535
|
|
|
*/ |
536
|
82 |
|
public function diffInSeconds($other) |
537
|
|
|
{ |
538
|
82 |
|
$other = $this->ensure($other); |
539
|
|
|
|
540
|
82 |
|
return ($other->getTimestamp() - $this->getTimestamp()); |
541
|
|
|
} |
542
|
|
|
|
543
|
|
|
/** |
544
|
|
|
* Get the number of minutes between this and the other. |
545
|
|
|
* |
546
|
|
|
* The result will be negative when this is after the other |
547
|
|
|
* |
548
|
|
|
* @param LocalDate|\DateTime $other |
549
|
|
|
* |
550
|
|
|
* @return float |
551
|
|
|
*/ |
552
|
18 |
|
public function diffInMinutes($other) |
553
|
|
|
{ |
554
|
18 |
|
$other = $this->ensure($other); |
555
|
|
|
|
556
|
18 |
|
return $this->diffInSeconds($other) / 60; |
557
|
|
|
} |
558
|
|
|
|
559
|
|
|
/** |
560
|
|
|
* Get the number of minutes between this and the other. |
561
|
|
|
* |
562
|
|
|
* The result will be negative when this is after the other |
563
|
|
|
* |
564
|
|
|
* @param LocalDate|\DateTime $other |
565
|
|
|
* |
566
|
|
|
* @return float |
567
|
|
|
*/ |
568
|
18 |
|
public function diffInHours($other) |
569
|
|
|
{ |
570
|
18 |
|
$other = $this->ensure($other); |
571
|
|
|
|
572
|
18 |
|
return $this->diffInSeconds($other) / 3600; |
573
|
|
|
} |
574
|
|
|
|
575
|
|
|
/** |
576
|
|
|
* Get the number of minutes between this and the other. |
577
|
|
|
* |
578
|
|
|
* The result will be negative when this is after the other |
579
|
|
|
* |
580
|
|
|
* @param LocalDate|\DateTime $other |
581
|
|
|
* |
582
|
|
|
* @return float |
583
|
|
|
*/ |
584
|
28 |
|
public function diffInDays($other) |
585
|
|
|
{ |
586
|
28 |
|
$other = $this->ensure($other); |
587
|
|
|
|
588
|
28 |
|
return $this->diffInSeconds($other) / 86400; |
589
|
|
|
} |
590
|
|
|
|
591
|
|
|
/** |
592
|
|
|
* @param LocalDate|\DateTime $other |
593
|
|
|
* |
594
|
|
|
* @return bool |
595
|
|
|
*/ |
596
|
6 |
|
public function isBefore($other) |
597
|
|
|
{ |
598
|
6 |
|
$other = $this->ensure($other); |
599
|
|
|
|
600
|
6 |
|
return $this->date < $other->date; |
601
|
|
|
} |
602
|
|
|
|
603
|
|
|
/** |
604
|
|
|
* @param LocalDate|\DateTime $other |
605
|
|
|
* |
606
|
|
|
* @return bool |
607
|
|
|
*/ |
608
|
1 |
|
public function isBeforeOrEqual($other) |
609
|
|
|
{ |
610
|
1 |
|
$other = $this->ensure($other); |
611
|
|
|
|
612
|
1 |
|
return $this->date <= $other->date; |
613
|
|
|
} |
614
|
|
|
|
615
|
|
|
/** |
616
|
|
|
* @param LocalDate|\DateTime $other |
617
|
|
|
* |
618
|
|
|
* @return bool |
619
|
|
|
*/ |
620
|
7 |
|
public function isEqual($other) |
621
|
|
|
{ |
622
|
7 |
|
$other = $this->ensure($other); |
623
|
|
|
|
624
|
7 |
|
return $this->date->getTimestamp() === $other->date->getTimestamp(); |
625
|
|
|
} |
626
|
|
|
|
627
|
|
|
/** |
628
|
|
|
* @param LocalDate|\DateTime $other |
629
|
|
|
* |
630
|
|
|
* @return bool |
631
|
|
|
*/ |
632
|
1 |
|
public function isAfter($other) |
633
|
|
|
{ |
634
|
1 |
|
$other = $this->ensure($other); |
635
|
|
|
|
636
|
1 |
|
return $this->date > $other->date; |
637
|
|
|
} |
638
|
|
|
|
639
|
|
|
/** |
640
|
|
|
* @param LocalDate|\DateTime $other |
641
|
|
|
* |
642
|
|
|
* @return bool |
643
|
|
|
*/ |
644
|
1 |
|
public function isAfterOrEqual($other) |
645
|
|
|
{ |
646
|
1 |
|
$other = $this->ensure($other); |
647
|
|
|
|
648
|
1 |
|
return $this->date >= $other->date; |
649
|
|
|
} |
650
|
|
|
|
651
|
|
|
//// PRIVATE HELPER ////////////////////////////////////////////////////////////////////////////////////////////// |
652
|
|
|
|
653
|
|
|
/** |
654
|
|
|
* @param mixed $input |
655
|
|
|
* |
656
|
|
|
* @return LocalDate |
657
|
|
|
*/ |
658
|
98 |
|
private function ensure($input) |
659
|
|
|
{ |
660
|
98 |
|
if ($input instanceof self) { |
661
|
97 |
|
return $input; |
662
|
|
|
} |
663
|
|
|
|
664
|
3 |
|
if ($input instanceof \DateTime) { |
665
|
2 |
|
return new LocalDate($input, $this->timezone); |
666
|
|
|
} |
667
|
|
|
|
668
|
1 |
|
return new LocalDate($input, $this->timezone); |
669
|
|
|
} |
670
|
|
|
} |
671
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.