Passed
Pull Request — master (#1)
by Guillaume
04:03
created

Difference   F

Complexity

Total Complexity 124

Size/Duplication

Total Lines 1057
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 207
dl 0
loc 1057
rs 2
c 0
b 0
f 0
wmc 124

How to fix   Complexity   

Complex Class

Complex classes like Difference often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Difference, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/**
4
 * This file is part of the Carbon package.
5
 *
6
 * (c) Brian Nesbitt <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
namespace Carbon\Traits;
12
13
use Carbon\Carbon;
14
use Carbon\CarbonImmutable;
15
use Carbon\CarbonInterface;
16
use Carbon\CarbonInterval;
17
use Carbon\CarbonPeriod;
18
use Carbon\Translator;
19
use Closure;
20
use DateInterval;
21
use DateTimeInterface;
22
23
/**
24
 * Trait Difference.
25
 *
26
 * Depends on the following methods:
27
 *
28
 * @method bool lessThan($date)
29
 * @method DateInterval diff(\DateTimeInterface $date, bool $absolute = false)
30
 * @method static copy()
31
 * @method static resolveCarbon($date = null)
32
 * @method static Translator translator()
33
 */
34
trait Difference
35
{
36
    /**
37
     * @codeCoverageIgnore
38
     *
39
     * @param CarbonInterval $diff
40
     */
41
    protected static function fixNegativeMicroseconds(CarbonInterval $diff)
42
    {
43
        if ($diff->s !== 0 || $diff->i !== 0 || $diff->h !== 0 || $diff->d !== 0 || $diff->m !== 0 || $diff->y !== 0) {
44
            $diff->f = (round($diff->f * 1000000) + 1000000) / 1000000;
45
            $diff->s--;
46
47
            if ($diff->s < 0) {
48
                $diff->s += 60;
49
                $diff->i--;
50
51
                if ($diff->i < 0) {
52
                    $diff->i += 60;
53
                    $diff->h--;
54
55
                    if ($diff->h < 0) {
56
                        $diff->h += 24;
57
                        $diff->d--;
58
59
                        if ($diff->d < 0) {
60
                            $diff->d += 30;
61
                            $diff->m--;
62
63
                            if ($diff->m < 0) {
64
                                $diff->m += 12;
65
                                $diff->y--;
66
                            }
67
                        }
68
                    }
69
                }
70
            }
71
72
            return;
73
        }
74
75
        $diff->f *= -1;
76
        $diff->invert();
77
    }
78
79
    /**
80
     * @param DateInterval $diff
81
     * @param bool         $absolute
82
     *
83
     * @return CarbonInterval
84
     */
85
    protected static function fixDiffInterval(DateInterval $diff, $absolute)
86
    {
87
        $diff = CarbonInterval::instance($diff);
88
89
        // Work-around for https://bugs.php.net/bug.php?id=77145
90
        // @codeCoverageIgnoreStart
91
        if ($diff->f > 0 && $diff->y === -1 && $diff->m === 11 && $diff->d >= 27 && $diff->h === 23 && $diff->i === 59 && $diff->s === 59) {
92
            $diff->y = 0;
93
            $diff->m = 0;
94
            $diff->d = 0;
95
            $diff->h = 0;
96
            $diff->i = 0;
97
            $diff->s = 0;
98
            $diff->f = (1000000 - round($diff->f * 1000000)) / 1000000;
99
            $diff->invert();
100
        } elseif ($diff->f < 0) {
101
            static::fixNegativeMicroseconds($diff);
102
        }
103
        // @codeCoverageIgnoreEnd
104
105
        if ($absolute && $diff->invert) {
106
            $diff->invert();
107
        }
108
109
        return $diff;
110
    }
111
112
    /**
113
     * Get the difference as a DateInterval instance.
114
     * Return relative interval (negative if
115
     *
116
     * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date
117
     * @param bool                                                   $absolute Get the absolute of the difference
118
     *
119
     * @return DateInterval
120
     */
121
    public function diff($date = null, $absolute = false)
122
    {
123
        return parent::diff($this->resolveCarbon($date), (bool) $absolute);
124
    }
125
126
    /**
127
     * Get the difference as a CarbonInterval instance.
128
     * Return absolute interval (always positive) unless you pass false to the second argument.
129
     *
130
     * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date
131
     * @param bool                                                   $absolute Get the absolute of the difference
132
     *
133
     * @return CarbonInterval
134
     */
135
    public function diffAsCarbonInterval($date = null, $absolute = true)
136
    {
137
        return static::fixDiffInterval($this->diff($this->resolveCarbon($date), $absolute), $absolute);
138
    }
139
140
    /**
141
     * Get the difference in years
142
     *
143
     * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date
144
     * @param bool                                                   $absolute Get the absolute of the difference
145
     *
146
     * @return int
147
     */
148
    public function diffInYears($date = null, $absolute = true)
149
    {
150
        return (int) $this->diff($this->resolveCarbon($date), $absolute)->format('%r%y');
151
    }
152
153
    /**
154
     * Get the difference in quarters rounded down.
155
     *
156
     * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date
157
     * @param bool                                                   $absolute Get the absolute of the difference
158
     *
159
     * @return int
160
     */
161
    public function diffInQuarters($date = null, $absolute = true)
162
    {
163
        return (int) ($this->diffInMonths($date, $absolute) / static::MONTHS_PER_QUARTER);
164
    }
165
166
    /**
167
     * Get the difference in months rounded down.
168
     *
169
     * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date
170
     * @param bool                                                   $absolute Get the absolute of the difference
171
     *
172
     * @return int
173
     */
174
    public function diffInMonths($date = null, $absolute = true)
175
    {
176
        $date = $this->resolveCarbon($date);
177
178
        return $this->diffInYears($date, $absolute) * static::MONTHS_PER_YEAR + (int) $this->diff($date, $absolute)->format('%r%m');
179
    }
180
181
    /**
182
     * Get the difference in weeks rounded down.
183
     *
184
     * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date
185
     * @param bool                                                   $absolute Get the absolute of the difference
186
     *
187
     * @return int
188
     */
189
    public function diffInWeeks($date = null, $absolute = true)
190
    {
191
        return (int) ($this->diffInDays($date, $absolute) / static::DAYS_PER_WEEK);
192
    }
193
194
    /**
195
     * Get the difference in days rounded down.
196
     *
197
     * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date
198
     * @param bool                                                   $absolute Get the absolute of the difference
199
     *
200
     * @return int
201
     */
202
    public function diffInDays($date = null, $absolute = true)
203
    {
204
        return (int) $this->diff($this->resolveCarbon($date), $absolute)->format('%r%a');
205
    }
206
207
    /**
208
     * Get the difference in days using a filter closure rounded down.
209
     *
210
     * @param Closure                                                $callback
211
     * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date
212
     * @param bool                                                   $absolute Get the absolute of the difference
213
     *
214
     * @return int
215
     */
216
    public function diffInDaysFiltered(Closure $callback, $date = null, $absolute = true)
217
    {
218
        return $this->diffFiltered(CarbonInterval::day(), $callback, $date, $absolute);
219
    }
220
221
    /**
222
     * Get the difference in hours using a filter closure rounded down.
223
     *
224
     * @param Closure                                                $callback
225
     * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date
226
     * @param bool                                                   $absolute Get the absolute of the difference
227
     *
228
     * @return int
229
     */
230
    public function diffInHoursFiltered(Closure $callback, $date = null, $absolute = true)
231
    {
232
        return $this->diffFiltered(CarbonInterval::hour(), $callback, $date, $absolute);
233
    }
234
235
    /**
236
     * Get the difference by the given interval using a filter closure.
237
     *
238
     * @param CarbonInterval                                         $ci       An interval to traverse by
239
     * @param Closure                                                $callback
240
     * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date
241
     * @param bool                                                   $absolute Get the absolute of the difference
242
     *
243
     * @return int
244
     */
245
    public function diffFiltered(CarbonInterval $ci, Closure $callback, $date = null, $absolute = true)
246
    {
247
        $start = $this;
248
        $end = $this->resolveCarbon($date);
249
        $inverse = false;
250
251
        if ($end < $start) {
252
            $start = $end;
253
            $end = $this;
254
            $inverse = true;
255
        }
256
257
        $options = CarbonPeriod::EXCLUDE_END_DATE | ($this->isMutable() ? 0 : CarbonPeriod::IMMUTABLE);
258
        $diff = $ci->toPeriod($start, $end, $options)->filter($callback)->count();
259
260
        return $inverse && !$absolute ? -$diff : $diff;
261
    }
262
263
    /**
264
     * Get the difference in weekdays rounded down.
265
     *
266
     * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date
267
     * @param bool                                                   $absolute Get the absolute of the difference
268
     *
269
     * @return int
270
     */
271
    public function diffInWeekdays($date = null, $absolute = true)
272
    {
273
        return $this->diffInDaysFiltered(function (CarbonInterface $date) {
274
            return $date->isWeekday();
275
        }, $date, $absolute);
276
    }
277
278
    /**
279
     * Get the difference in weekend days using a filter rounded down.
280
     *
281
     * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date
282
     * @param bool                                                   $absolute Get the absolute of the difference
283
     *
284
     * @return int
285
     */
286
    public function diffInWeekendDays($date = null, $absolute = true)
287
    {
288
        return $this->diffInDaysFiltered(function (CarbonInterface $date) {
289
            return $date->isWeekend();
290
        }, $date, $absolute);
291
    }
292
293
    /**
294
     * Get the difference in hours rounded down.
295
     *
296
     * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date
297
     * @param bool                                                   $absolute Get the absolute of the difference
298
     *
299
     * @return int
300
     */
301
    public function diffInHours($date = null, $absolute = true)
302
    {
303
        return (int) ($this->diffInSeconds($date, $absolute) / static::SECONDS_PER_MINUTE / static::MINUTES_PER_HOUR);
304
    }
305
306
    /**
307
     * Get the difference in hours rounded down using timestamps.
308
     *
309
     * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date
310
     * @param bool                                                   $absolute Get the absolute of the difference
311
     *
312
     * @return int
313
     */
314
    public function diffInRealHours($date = null, $absolute = true)
315
    {
316
        return (int) ($this->diffInRealSeconds($date, $absolute) / static::SECONDS_PER_MINUTE / static::MINUTES_PER_HOUR);
317
    }
318
319
    /**
320
     * Get the difference in minutes rounded down.
321
     *
322
     * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date
323
     * @param bool                                                   $absolute Get the absolute of the difference
324
     *
325
     * @return int
326
     */
327
    public function diffInMinutes($date = null, $absolute = true)
328
    {
329
        return (int) ($this->diffInSeconds($date, $absolute) / static::SECONDS_PER_MINUTE);
330
    }
331
332
    /**
333
     * Get the difference in minutes rounded down using timestamps.
334
     *
335
     * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date
336
     * @param bool                                                   $absolute Get the absolute of the difference
337
     *
338
     * @return int
339
     */
340
    public function diffInRealMinutes($date = null, $absolute = true)
341
    {
342
        return (int) ($this->diffInRealSeconds($date, $absolute) / static::SECONDS_PER_MINUTE);
343
    }
344
345
    /**
346
     * Get the difference in seconds rounded down.
347
     *
348
     * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date
349
     * @param bool                                                   $absolute Get the absolute of the difference
350
     *
351
     * @return int
352
     */
353
    public function diffInSeconds($date = null, $absolute = true)
354
    {
355
        $diff = $this->diff($date);
356
357
        if ($diff->days === 0) {
358
            $diff = static::fixDiffInterval($diff, $absolute);
359
        }
360
361
        $value = (((($diff->m || $diff->y ? $diff->days : $diff->d) * static::HOURS_PER_DAY) +
362
            $diff->h) * static::MINUTES_PER_HOUR +
363
            $diff->i) * static::SECONDS_PER_MINUTE +
364
            $diff->s;
365
366
        return $absolute || !$diff->invert ? $value : -$value;
367
    }
368
369
    /**
370
     * Get the difference in microseconds.
371
     *
372
     * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date
373
     * @param bool                                                   $absolute Get the absolute of the difference
374
     *
375
     * @return int
376
     */
377
    public function diffInMicroseconds($date = null, $absolute = true)
378
    {
379
        $diff = $this->diff($date);
380
        $value = (int) round(((((($diff->m || $diff->y ? $diff->days : $diff->d) * static::HOURS_PER_DAY) +
381
            $diff->h) * static::MINUTES_PER_HOUR +
382
            $diff->i) * static::SECONDS_PER_MINUTE +
383
            ($diff->f + $diff->s)) * static::MICROSECONDS_PER_SECOND);
384
385
        return $absolute || !$diff->invert ? $value : -$value;
386
    }
387
388
    /**
389
     * Get the difference in milliseconds rounded down.
390
     *
391
     * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date
392
     * @param bool                                                   $absolute Get the absolute of the difference
393
     *
394
     * @return int
395
     */
396
    public function diffInMilliseconds($date = null, $absolute = true)
397
    {
398
        return (int) ($this->diffInMicroseconds($date, $absolute) / static::MICROSECONDS_PER_MILLISECOND);
399
    }
400
401
    /**
402
     * Get the difference in seconds using timestamps.
403
     *
404
     * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date
405
     * @param bool                                                   $absolute Get the absolute of the difference
406
     *
407
     * @return int
408
     */
409
    public function diffInRealSeconds($date = null, $absolute = true)
410
    {
411
        /** @var CarbonInterface $date */
412
        $date = $this->resolveCarbon($date);
413
        $value = $date->getTimestamp() - $this->getTimestamp();
414
415
        return $absolute ? abs($value) : $value;
416
    }
417
418
    /**
419
     * Get the difference in microseconds using timestamps.
420
     *
421
     * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date
422
     * @param bool                                                   $absolute Get the absolute of the difference
423
     *
424
     * @return int
425
     */
426
    public function diffInRealMicroseconds($date = null, $absolute = true)
427
    {
428
        /** @var CarbonInterface $date */
429
        $date = $this->resolveCarbon($date);
430
        $value = ($date->timestamp - $this->timestamp) * static::MICROSECONDS_PER_SECOND +
431
            $date->micro - $this->micro;
432
433
        return $absolute ? abs($value) : $value;
434
    }
435
436
    /**
437
     * Get the difference in milliseconds rounded down using timestamps.
438
     *
439
     * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date
440
     * @param bool                                                   $absolute Get the absolute of the difference
441
     *
442
     * @return int
443
     */
444
    public function diffInRealMilliseconds($date = null, $absolute = true)
445
    {
446
        return (int) ($this->diffInRealMicroseconds($date, $absolute) / static::MICROSECONDS_PER_MILLISECOND);
447
    }
448
449
    /**
450
     * Get the difference in seconds as float (microsecond-precision).
451
     *
452
     * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date
453
     * @param bool                                                   $absolute Get the absolute of the difference
454
     *
455
     * @return float
456
     */
457
    public function floatDiffInSeconds($date = null, $absolute = true)
458
    {
459
        return $this->diffInMicroseconds($date, $absolute) / static::MICROSECONDS_PER_SECOND;
460
    }
461
462
    /**
463
     * Get the difference in minutes as float (microsecond-precision).
464
     *
465
     * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date
466
     * @param bool                                                   $absolute Get the absolute of the difference
467
     *
468
     * @return float
469
     */
470
    public function floatDiffInMinutes($date = null, $absolute = true)
471
    {
472
        return $this->floatDiffInSeconds($date, $absolute) / static::SECONDS_PER_MINUTE;
473
    }
474
475
    /**
476
     * Get the difference in hours as float (microsecond-precision).
477
     *
478
     * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date
479
     * @param bool                                                   $absolute Get the absolute of the difference
480
     *
481
     * @return float
482
     */
483
    public function floatDiffInHours($date = null, $absolute = true)
484
    {
485
        return $this->floatDiffInMinutes($date, $absolute) / static::MINUTES_PER_HOUR;
486
    }
487
488
    /**
489
     * Get the difference in days as float (microsecond-precision).
490
     *
491
     * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date
492
     * @param bool                                                   $absolute Get the absolute of the difference
493
     *
494
     * @return float
495
     */
496
    public function floatDiffInDays($date = null, $absolute = true)
497
    {
498
        $hoursDiff = $this->floatDiffInHours($date, $absolute);
499
500
        return ($hoursDiff < 0 ? -1 : 1) * $this->diffInDays($date) + fmod($hoursDiff, static::HOURS_PER_DAY) / static::HOURS_PER_DAY;
501
    }
502
503
    /**
504
     * Get the difference in months as float (microsecond-precision).
505
     *
506
     * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date
507
     * @param bool                                                   $absolute Get the absolute of the difference
508
     *
509
     * @return float
510
     */
511
    public function floatDiffInMonths($date = null, $absolute = true)
512
    {
513
        $start = $this;
514
        $end = $this->resolveCarbon($date);
515
        $ascending = ($start <= $end);
516
        $sign = $absolute || $ascending ? 1 : -1;
517
        if (!$ascending) {
518
            [$start, $end] = [$end, $start];
519
        }
520
        $monthsDiff = $start->diffInMonths($end);
521
        /** @var Carbon|CarbonImmutable $floorEnd */
522
        $floorEnd = $start->copy()->addMonths($monthsDiff);
523
524
        if ($floorEnd >= $end) {
525
            return $sign * $monthsDiff;
526
        }
527
528
        /** @var Carbon|CarbonImmutable $startOfMonthAfterFloorEnd */
529
        $startOfMonthAfterFloorEnd = $floorEnd->copy()->addMonth()->startOfMonth();
530
531
        if ($startOfMonthAfterFloorEnd > $end) {
532
            return $sign * ($monthsDiff + $floorEnd->floatDiffInDays($end) / $floorEnd->daysInMonth);
533
        }
534
535
        return $sign * ($monthsDiff + $floorEnd->floatDiffInDays($startOfMonthAfterFloorEnd) / $floorEnd->daysInMonth + $startOfMonthAfterFloorEnd->floatDiffInDays($end) / $end->daysInMonth);
536
    }
537
538
    /**
539
     * Get the difference in year as float (microsecond-precision).
540
     *
541
     * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date
542
     * @param bool                                                   $absolute Get the absolute of the difference
543
     *
544
     * @return float
545
     */
546
    public function floatDiffInYears($date = null, $absolute = true)
547
    {
548
        $start = $this;
549
        $end = $this->resolveCarbon($date);
550
        $ascending = ($start <= $end);
551
        $sign = $absolute || $ascending ? 1 : -1;
552
        if (!$ascending) {
553
            [$start, $end] = [$end, $start];
554
        }
555
        $yearsDiff = $start->diffInYears($end);
556
        /** @var Carbon|CarbonImmutable $floorEnd */
557
        $floorEnd = $start->copy()->addYears($yearsDiff);
558
559
        if ($floorEnd >= $end) {
560
            return $sign * $yearsDiff;
561
        }
562
563
        /** @var Carbon|CarbonImmutable $startOfYearAfterFloorEnd */
564
        $startOfYearAfterFloorEnd = $floorEnd->copy()->addYear()->startOfYear();
565
566
        if ($startOfYearAfterFloorEnd > $end) {
567
            return $sign * ($yearsDiff + $floorEnd->floatDiffInDays($end) / $floorEnd->daysInYear);
568
        }
569
570
        return $sign * ($yearsDiff + $floorEnd->floatDiffInDays($startOfYearAfterFloorEnd) / $floorEnd->daysInYear + $startOfYearAfterFloorEnd->floatDiffInDays($end) / $end->daysInYear);
571
    }
572
573
    /**
574
     * Get the difference in seconds as float (microsecond-precision) using timestamps.
575
     *
576
     * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date
577
     * @param bool                                                   $absolute Get the absolute of the difference
578
     *
579
     * @return float
580
     */
581
    public function floatDiffInRealSeconds($date = null, $absolute = true)
582
    {
583
        return $this->diffInRealMicroseconds($date, $absolute) / static::MICROSECONDS_PER_SECOND;
584
    }
585
586
    /**
587
     * Get the difference in minutes as float (microsecond-precision) using timestamps.
588
     *
589
     * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date
590
     * @param bool                                                   $absolute Get the absolute of the difference
591
     *
592
     * @return float
593
     */
594
    public function floatDiffInRealMinutes($date = null, $absolute = true)
595
    {
596
        return $this->floatDiffInRealSeconds($date, $absolute) / static::SECONDS_PER_MINUTE;
597
    }
598
599
    /**
600
     * Get the difference in hours as float (microsecond-precision) using timestamps.
601
     *
602
     * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date
603
     * @param bool                                                   $absolute Get the absolute of the difference
604
     *
605
     * @return float
606
     */
607
    public function floatDiffInRealHours($date = null, $absolute = true)
608
    {
609
        return $this->floatDiffInRealMinutes($date, $absolute) / static::MINUTES_PER_HOUR;
610
    }
611
612
    /**
613
     * Get the difference in days as float (microsecond-precision).
614
     *
615
     * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date
616
     * @param bool                                                   $absolute Get the absolute of the difference
617
     *
618
     * @return float
619
     */
620
    public function floatDiffInRealDays($date = null, $absolute = true)
621
    {
622
        $hoursDiff = $this->floatDiffInRealHours($date, $absolute);
623
624
        return ($hoursDiff < 0 ? -1 : 1) * $this->diffInDays($date) + fmod($hoursDiff, static::HOURS_PER_DAY) / static::HOURS_PER_DAY;
625
    }
626
627
    /**
628
     * Get the difference in months as float (microsecond-precision) using timestamps.
629
     *
630
     * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date
631
     * @param bool                                                   $absolute Get the absolute of the difference
632
     *
633
     * @return float
634
     */
635
    public function floatDiffInRealMonths($date = null, $absolute = true)
636
    {
637
        $start = $this;
638
        $end = $this->resolveCarbon($date);
639
        $ascending = ($start <= $end);
640
        $sign = $absolute || $ascending ? 1 : -1;
641
        if (!$ascending) {
642
            [$start, $end] = [$end, $start];
643
        }
644
        $monthsDiff = $start->diffInMonths($end);
645
        /** @var Carbon|CarbonImmutable $floorEnd */
646
        $floorEnd = $start->copy()->addMonths($monthsDiff);
647
648
        if ($floorEnd >= $end) {
649
            return $sign * $monthsDiff;
650
        }
651
652
        /** @var Carbon|CarbonImmutable $startOfMonthAfterFloorEnd */
653
        $startOfMonthAfterFloorEnd = $floorEnd->copy()->addMonth()->startOfMonth();
654
655
        if ($startOfMonthAfterFloorEnd > $end) {
656
            return $sign * ($monthsDiff + $floorEnd->floatDiffInRealDays($end) / $floorEnd->daysInMonth);
657
        }
658
659
        return $sign * ($monthsDiff + $floorEnd->floatDiffInRealDays($startOfMonthAfterFloorEnd) / $floorEnd->daysInMonth + $startOfMonthAfterFloorEnd->floatDiffInRealDays($end) / $end->daysInMonth);
660
    }
661
662
    /**
663
     * Get the difference in year as float (microsecond-precision) using timestamps.
664
     *
665
     * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date
666
     * @param bool                                                   $absolute Get the absolute of the difference
667
     *
668
     * @return float
669
     */
670
    public function floatDiffInRealYears($date = null, $absolute = true)
671
    {
672
        $start = $this;
673
        $end = $this->resolveCarbon($date);
674
        $ascending = ($start <= $end);
675
        $sign = $absolute || $ascending ? 1 : -1;
676
        if (!$ascending) {
677
            [$start, $end] = [$end, $start];
678
        }
679
        $yearsDiff = $start->diffInYears($end);
680
        /** @var Carbon|CarbonImmutable $floorEnd */
681
        $floorEnd = $start->copy()->addYears($yearsDiff);
682
683
        if ($floorEnd >= $end) {
684
            return $sign * $yearsDiff;
685
        }
686
687
        /** @var Carbon|CarbonImmutable $startOfYearAfterFloorEnd */
688
        $startOfYearAfterFloorEnd = $floorEnd->copy()->addYear()->startOfYear();
689
690
        if ($startOfYearAfterFloorEnd > $end) {
691
            return $sign * ($yearsDiff + $floorEnd->floatDiffInRealDays($end) / $floorEnd->daysInYear);
692
        }
693
694
        return $sign * ($yearsDiff + $floorEnd->floatDiffInRealDays($startOfYearAfterFloorEnd) / $floorEnd->daysInYear + $startOfYearAfterFloorEnd->floatDiffInRealDays($end) / $end->daysInYear);
695
    }
696
697
    /**
698
     * The number of seconds since midnight.
699
     *
700
     * @return int
701
     */
702
    public function secondsSinceMidnight()
703
    {
704
        return $this->diffInSeconds($this->copy()->startOfDay());
705
    }
706
707
    /**
708
     * The number of seconds until 23:59:59.
709
     *
710
     * @return int
711
     */
712
    public function secondsUntilEndOfDay()
713
    {
714
        return $this->diffInSeconds($this->copy()->endOfDay());
715
    }
716
717
    /**
718
     * Get the difference in a human readable format in the current locale from current instance to an other
719
     * instance given (or now if null given).
720
     *
721
     * @example
722
     * ```
723
     * echo Carbon::tomorrow()->diffForHumans() . "\n";
724
     * echo Carbon::tomorrow()->diffForHumans(['parts' => 2]) . "\n";
725
     * echo Carbon::tomorrow()->diffForHumans(['parts' => 3, 'join' => true]) . "\n";
726
     * echo Carbon::tomorrow()->diffForHumans(Carbon::yesterday()) . "\n";
727
     * echo Carbon::tomorrow()->diffForHumans(Carbon::yesterday(), ['short' => true]) . "\n";
728
     * ```
729
     *
730
     * @param Carbon|\DateTimeInterface|string|array|null $other   if array passed, will be used as parameters array, see $syntax below;
731
     *                                                             if null passed, now will be used as comparison reference;
732
     *                                                             if any other type, it will be converted to date and used as reference.
733
     * @param int|array                                   $syntax  if array passed, parameters will be extracted from it, the array may contains:
734
     *                                                             - 'syntax' entry (see below)
735
     *                                                             - 'short' entry (see below)
736
     *                                                             - 'parts' entry (see below)
737
     *                                                             - 'options' entry (see below)
738
     *                                                             - 'join' entry determines how to join multiple parts of the string
739
     *                                                             `  - if $join is a string, it's used as a joiner glue
740
     *                                                             `  - if $join is a callable/closure, it get the list of string and should return a string
741
     *                                                             `  - if $join is an array, the first item will be the default glue, and the second item
742
     *                                                             `    will be used instead of the glue for the last item
743
     *                                                             `  - if $join is true, it will be guessed from the locale ('list' translation file entry)
744
     *                                                             `  - if $join is missing, a space will be used as glue
745
     *                                                             - 'other' entry (see above)
746
     *                                                             if int passed, it add modifiers:
747
     *                                                             Possible values:
748
     *                                                             - CarbonInterface::DIFF_ABSOLUTE          no modifiers
749
     *                                                             - CarbonInterface::DIFF_RELATIVE_TO_NOW   add ago/from now modifier
750
     *                                                             - CarbonInterface::DIFF_RELATIVE_TO_OTHER add before/after modifier
751
     *                                                             Default value: CarbonInterface::DIFF_ABSOLUTE
752
     * @param bool                                        $short   displays short format of time units
753
     * @param int                                         $parts   maximum number of parts to display (default value: 1: single unit)
754
     * @param int                                         $options human diff options
755
     *
756
     * @return string
757
     */
758
    public function diffForHumans($other = null, $syntax = null, $short = false, $parts = 1, $options = null)
759
    {
760
        /* @var CarbonInterface $this */
761
        if (is_array($other)) {
762
            $other['syntax'] = array_key_exists('syntax', $other) ? $other['syntax'] : $syntax;
763
            $syntax = $other;
764
            $other = $syntax['other'] ?? null;
765
        }
766
767
        $intSyntax = &$syntax;
768
        if (is_array($syntax)) {
769
            $syntax['syntax'] = $syntax['syntax'] ?? null;
770
            $intSyntax = &$syntax['syntax'];
771
        }
772
        $intSyntax = (int) ($intSyntax === null ? static::DIFF_RELATIVE_AUTO : $intSyntax);
773
        $intSyntax = $intSyntax === static::DIFF_RELATIVE_AUTO && $other === null ? static::DIFF_RELATIVE_TO_NOW : $intSyntax;
774
775
        $parts = min(7, max(1, (int) $parts));
776
777
        return $this->diffAsCarbonInterval($other, false)
778
            ->setLocalTranslator($this->getLocalTranslator())
779
            ->forHumans($syntax, (bool) $short, $parts, $options ?? $this->localHumanDiffOptions ?? static::getHumanDiffOptions());
780
    }
781
782
    /**
783
     * @alias diffForHumans
784
     *
785
     * Get the difference in a human readable format in the current locale from current instance to an other
786
     * instance given (or now if null given).
787
     *
788
     * @param Carbon|\DateTimeInterface|string|array|null $other   if array passed, will be used as parameters array, see $syntax below;
789
     *                                                             if null passed, now will be used as comparison reference;
790
     *                                                             if any other type, it will be converted to date and used as reference.
791
     * @param int|array                                   $syntax  if array passed, parameters will be extracted from it, the array may contains:
792
     *                                                             - 'syntax' entry (see below)
793
     *                                                             - 'short' entry (see below)
794
     *                                                             - 'parts' entry (see below)
795
     *                                                             - 'options' entry (see below)
796
     *                                                             - 'join' entry determines how to join multiple parts of the string
797
     *                                                             `  - if $join is a string, it's used as a joiner glue
798
     *                                                             `  - if $join is a callable/closure, it get the list of string and should return a string
799
     *                                                             `  - if $join is an array, the first item will be the default glue, and the second item
800
     *                                                             `    will be used instead of the glue for the last item
801
     *                                                             `  - if $join is true, it will be guessed from the locale ('list' translation file entry)
802
     *                                                             `  - if $join is missing, a space will be used as glue
803
     *                                                             - 'other' entry (see above)
804
     *                                                             if int passed, it add modifiers:
805
     *                                                             Possible values:
806
     *                                                             - CarbonInterface::DIFF_ABSOLUTE          no modifiers
807
     *                                                             - CarbonInterface::DIFF_RELATIVE_TO_NOW   add ago/from now modifier
808
     *                                                             - CarbonInterface::DIFF_RELATIVE_TO_OTHER add before/after modifier
809
     *                                                             Default value: CarbonInterface::DIFF_ABSOLUTE
810
     * @param bool                                        $short   displays short format of time units
811
     * @param int                                         $parts   maximum number of parts to display (default value: 1: single unit)
812
     * @param int                                         $options human diff options
813
     *
814
     * @return string
815
     */
816
    public function from($other = null, $syntax = null, $short = false, $parts = 1, $options = null)
817
    {
818
        return $this->diffForHumans($other, $syntax, $short, $parts, $options);
819
    }
820
821
    /**
822
     * @alias diffForHumans
823
     *
824
     * Get the difference in a human readable format in the current locale from current instance to an other
825
     * instance given (or now if null given).
826
     */
827
    public function since($other = null, $syntax = null, $short = false, $parts = 1, $options = null)
828
    {
829
        return $this->diffForHumans($other, $syntax, $short, $parts, $options);
830
    }
831
832
    /**
833
     * Get the difference in a human readable format in the current locale from an other
834
     * instance given (or now if null given) to current instance.
835
     *
836
     * When comparing a value in the past to default now:
837
     * 1 hour from now
838
     * 5 months from now
839
     *
840
     * When comparing a value in the future to default now:
841
     * 1 hour ago
842
     * 5 months ago
843
     *
844
     * When comparing a value in the past to another value:
845
     * 1 hour after
846
     * 5 months after
847
     *
848
     * When comparing a value in the future to another value:
849
     * 1 hour before
850
     * 5 months before
851
     *
852
     * @param Carbon|\DateTimeInterface|string|array|null $other   if array passed, will be used as parameters array, see $syntax below;
853
     *                                                             if null passed, now will be used as comparison reference;
854
     *                                                             if any other type, it will be converted to date and used as reference.
855
     * @param int|array                                   $syntax  if array passed, parameters will be extracted from it, the array may contains:
856
     *                                                             - 'syntax' entry (see below)
857
     *                                                             - 'short' entry (see below)
858
     *                                                             - 'parts' entry (see below)
859
     *                                                             - 'options' entry (see below)
860
     *                                                             - 'join' entry determines how to join multiple parts of the string
861
     *                                                             `  - if $join is a string, it's used as a joiner glue
862
     *                                                             `  - if $join is a callable/closure, it get the list of string and should return a string
863
     *                                                             `  - if $join is an array, the first item will be the default glue, and the second item
864
     *                                                             `    will be used instead of the glue for the last item
865
     *                                                             `  - if $join is true, it will be guessed from the locale ('list' translation file entry)
866
     *                                                             `  - if $join is missing, a space will be used as glue
867
     *                                                             - 'other' entry (see above)
868
     *                                                             if int passed, it add modifiers:
869
     *                                                             Possible values:
870
     *                                                             - CarbonInterface::DIFF_ABSOLUTE          no modifiers
871
     *                                                             - CarbonInterface::DIFF_RELATIVE_TO_NOW   add ago/from now modifier
872
     *                                                             - CarbonInterface::DIFF_RELATIVE_TO_OTHER add before/after modifier
873
     *                                                             Default value: CarbonInterface::DIFF_ABSOLUTE
874
     * @param bool                                        $short   displays short format of time units
875
     * @param int                                         $parts   maximum number of parts to display (default value: 1: single unit)
876
     * @param int                                         $options human diff options
877
     *
878
     * @return string
879
     */
880
    public function to($other = null, $syntax = null, $short = false, $parts = 1, $options = null)
881
    {
882
        if (!$syntax && !$other) {
883
            $syntax = CarbonInterface::DIFF_RELATIVE_TO_NOW;
884
        }
885
886
        return $this->resolveCarbon($other)->diffForHumans($this, $syntax, $short, $parts, $options);
887
    }
888
889
    /**
890
     * @alias to
891
     *
892
     * Get the difference in a human readable format in the current locale from an other
893
     * instance given (or now if null given) to current instance.
894
     *
895
     * @param Carbon|\DateTimeInterface|string|array|null $other   if array passed, will be used as parameters array, see $syntax below;
896
     *                                                             if null passed, now will be used as comparison reference;
897
     *                                                             if any other type, it will be converted to date and used as reference.
898
     * @param int|array                                   $syntax  if array passed, parameters will be extracted from it, the array may contains:
899
     *                                                             - 'syntax' entry (see below)
900
     *                                                             - 'short' entry (see below)
901
     *                                                             - 'parts' entry (see below)
902
     *                                                             - 'options' entry (see below)
903
     *                                                             - 'join' entry determines how to join multiple parts of the string
904
     *                                                             `  - if $join is a string, it's used as a joiner glue
905
     *                                                             `  - if $join is a callable/closure, it get the list of string and should return a string
906
     *                                                             `  - if $join is an array, the first item will be the default glue, and the second item
907
     *                                                             `    will be used instead of the glue for the last item
908
     *                                                             `  - if $join is true, it will be guessed from the locale ('list' translation file entry)
909
     *                                                             `  - if $join is missing, a space will be used as glue
910
     *                                                             - 'other' entry (see above)
911
     *                                                             if int passed, it add modifiers:
912
     *                                                             Possible values:
913
     *                                                             - CarbonInterface::DIFF_ABSOLUTE          no modifiers
914
     *                                                             - CarbonInterface::DIFF_RELATIVE_TO_NOW   add ago/from now modifier
915
     *                                                             - CarbonInterface::DIFF_RELATIVE_TO_OTHER add before/after modifier
916
     *                                                             Default value: CarbonInterface::DIFF_ABSOLUTE
917
     * @param bool                                        $short   displays short format of time units
918
     * @param int                                         $parts   maximum number of parts to display (default value: 1: single unit)
919
     * @param int                                         $options human diff options
920
     *
921
     * @return string
922
     */
923
    public function until($other = null, $syntax = null, $short = false, $parts = 1, $options = null)
924
    {
925
        return $this->to($other, $syntax, $short, $parts, $options);
926
    }
927
928
    /**
929
     * Get the difference in a human readable format in the current locale from current
930
     * instance to now.
931
     *
932
     * @param int|array $syntax  if array passed, parameters will be extracted from it, the array may contains:
933
     *                           - 'syntax' entry (see below)
934
     *                           - 'short' entry (see below)
935
     *                           - 'parts' entry (see below)
936
     *                           - 'options' entry (see below)
937
     *                           - 'join' entry determines how to join multiple parts of the string
938
     *                           `  - if $join is a string, it's used as a joiner glue
939
     *                           `  - if $join is a callable/closure, it get the list of string and should return a string
940
     *                           `  - if $join is an array, the first item will be the default glue, and the second item
941
     *                           `    will be used instead of the glue for the last item
942
     *                           `  - if $join is true, it will be guessed from the locale ('list' translation file entry)
943
     *                           `  - if $join is missing, a space will be used as glue
944
     *                           if int passed, it add modifiers:
945
     *                           Possible values:
946
     *                           - CarbonInterface::DIFF_ABSOLUTE          no modifiers
947
     *                           - CarbonInterface::DIFF_RELATIVE_TO_NOW   add ago/from now modifier
948
     *                           - CarbonInterface::DIFF_RELATIVE_TO_OTHER add before/after modifier
949
     *                           Default value: CarbonInterface::DIFF_ABSOLUTE
950
     * @param bool      $short   displays short format of time units
951
     * @param int       $parts   maximum number of parts to display (default value: 1: single unit)
952
     * @param int       $options human diff options
953
     *
954
     * @return string
955
     */
956
    public function fromNow($syntax = null, $short = false, $parts = 1, $options = null)
957
    {
958
        $other = null;
959
960
        if ($syntax instanceof DateTimeInterface) {
961
            [$other, $syntax, $short, $parts, $options] = array_pad(func_get_args(), 5, null);
962
        }
963
964
        return $this->from($other, $syntax, $short, $parts, $options);
965
    }
966
967
    /**
968
     * Get the difference in a human readable format in the current locale from an other
969
     * instance given to now
970
     *
971
     * @param int|array $syntax  if array passed, parameters will be extracted from it, the array may contains:
972
     *                           - 'syntax' entry (see below)
973
     *                           - 'short' entry (see below)
974
     *                           - 'parts' entry (see below)
975
     *                           - 'options' entry (see below)
976
     *                           - 'join' entry determines how to join multiple parts of the string
977
     *                           `  - if $join is a string, it's used as a joiner glue
978
     *                           `  - if $join is a callable/closure, it get the list of string and should return a string
979
     *                           `  - if $join is an array, the first item will be the default glue, and the second item
980
     *                           `    will be used instead of the glue for the last item
981
     *                           `  - if $join is true, it will be guessed from the locale ('list' translation file entry)
982
     *                           `  - if $join is missing, a space will be used as glue
983
     *                           if int passed, it add modifiers:
984
     *                           Possible values:
985
     *                           - CarbonInterface::DIFF_ABSOLUTE          no modifiers
986
     *                           - CarbonInterface::DIFF_RELATIVE_TO_NOW   add ago/from now modifier
987
     *                           - CarbonInterface::DIFF_RELATIVE_TO_OTHER add before/after modifier
988
     *                           Default value: CarbonInterface::DIFF_ABSOLUTE
989
     * @param bool      $short   displays short format of time units
990
     * @param int       $parts   maximum number of parts to display (default value: 1: single part)
991
     * @param int       $options human diff options
992
     *
993
     * @return string
994
     */
995
    public function toNow($syntax = null, $short = false, $parts = 1, $options = null)
996
    {
997
        return $this->to(null, $syntax, $short, $parts, $options);
998
    }
999
1000
    /**
1001
     * Get the difference in a human readable format in the current locale from an other
1002
     * instance given to now
1003
     *
1004
     * @param int|array $syntax  if array passed, parameters will be extracted from it, the array may contains:
1005
     *                           - 'syntax' entry (see below)
1006
     *                           - 'short' entry (see below)
1007
     *                           - 'parts' entry (see below)
1008
     *                           - 'options' entry (see below)
1009
     *                           - 'join' entry determines how to join multiple parts of the string
1010
     *                           `  - if $join is a string, it's used as a joiner glue
1011
     *                           `  - if $join is a callable/closure, it get the list of string and should return a string
1012
     *                           `  - if $join is an array, the first item will be the default glue, and the second item
1013
     *                           `    will be used instead of the glue for the last item
1014
     *                           `  - if $join is true, it will be guessed from the locale ('list' translation file entry)
1015
     *                           `  - if $join is missing, a space will be used as glue
1016
     *                           if int passed, it add modifiers:
1017
     *                           Possible values:
1018
     *                           - CarbonInterface::DIFF_ABSOLUTE          no modifiers
1019
     *                           - CarbonInterface::DIFF_RELATIVE_TO_NOW   add ago/from now modifier
1020
     *                           - CarbonInterface::DIFF_RELATIVE_TO_OTHER add before/after modifier
1021
     *                           Default value: CarbonInterface::DIFF_ABSOLUTE
1022
     * @param bool      $short   displays short format of time units
1023
     * @param int       $parts   maximum number of parts to display (default value: 1: single part)
1024
     * @param int       $options human diff options
1025
     *
1026
     * @return string
1027
     */
1028
    public function ago($syntax = null, $short = false, $parts = 1, $options = null)
1029
    {
1030
        $other = null;
1031
1032
        if ($syntax instanceof DateTimeInterface) {
1033
            [$other, $syntax, $short, $parts, $options] = array_pad(func_get_args(), 5, null);
1034
        }
1035
1036
        return $this->from($other, $syntax, $short, $parts, $options);
1037
    }
1038
1039
    /**
1040
     * Get the difference in a human readable format in the current locale from current instance to an other
1041
     * instance given (or now if null given).
1042
     *
1043
     * @return string
1044
     */
1045
    public function timespan($other = null, $timezone = null)
1046
    {
1047
        if (!$other instanceof DateTimeInterface) {
1048
            $other = static::parse($other, $timezone);
1049
        }
1050
1051
        return $this->diffForHumans($other, [
1052
            'join' => ', ',
1053
            'syntax' => CarbonInterface::DIFF_ABSOLUTE,
1054
            'options' => CarbonInterface::NO_ZERO_DIFF,
1055
            'parts' => -1,
1056
        ]);
1057
    }
1058
1059
    /**
1060
     * Returns either the close date "Friday 15h30", or a calendar date "10/09/2017" is farthest than 7 days from now.
1061
     *
1062
     * @param Carbon|\DateTimeInterface|string|null $referenceTime
1063
     * @param array                                 $formats
1064
     *
1065
     * @return string
1066
     */
1067
    public function calendar($referenceTime = null, array $formats = [])
1068
    {
1069
        /** @var CarbonInterface $current */
1070
        $current = $this->copy()->startOfDay();
1071
        /** @var CarbonInterface $other */
1072
        $other = $this->resolveCarbon($referenceTime)->copy()->setTimezone($this->getTimezone())->startOfDay();
1073
        $diff = $other->diffInDays($current, false);
1074
        $format = $diff < -6 ? 'sameElse' : (
1075
            $diff < -1 ? 'lastWeek' : (
1076
                $diff < 0 ? 'lastDay' : (
1077
                    $diff < 1 ? 'sameDay' : (
1078
                        $diff < 2 ? 'nextDay' : (
1079
                            $diff < 7 ? 'nextWeek' : 'sameElse'
1080
                        )
1081
                    )
1082
                )
1083
            )
1084
        );
1085
        $format = array_merge($this->getCalendarFormats(), $formats)[$format];
1086
        if ($format instanceof Closure) {
1087
            $format = $format($current, $other) ?? '';
1088
        }
1089
1090
        return $this->isoFormat(strval($format));
1091
    }
1092
}
1093