1
<?php
2

3
/**
4
 * This file is part of the Carbon package.
5
 *
6
 * (c) Brian Nesbitt <brian@nesbot.com>
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 static copy()
30
 * @method static resolveCarbon($date = null)
31
 * @method static Translator translator()
32
 */
33
trait Difference
34
{
35
    /**
36
     * @codeCoverageIgnore
37
     *
38
     * @param CarbonInterval $diff
39
     */
40
    protected static function fixNegativeMicroseconds(CarbonInterval $diff)
41
    {
42
        if ($diff->s !== 0 || $diff->i !== 0 || $diff->h !== 0 || $diff->d !== 0 || $diff->m !== 0 || $diff->y !== 0) {
43
            $diff->f = (round($diff->f * 1000000) + 1000000) / 1000000;
44
            $diff->s--;
45

46
            if ($diff->s < 0) {
47
                $diff->s += 60;
48
                $diff->i--;
49

50
                if ($diff->i < 0) {
51
                    $diff->i += 60;
52
                    $diff->h--;
53

54
                    if ($diff->h < 0) {
55
                        $diff->h += 24;
56
                        $diff->d--;
57

58
                        if ($diff->d < 0) {
59
                            $diff->d += 30;
60
                            $diff->m--;
61

62
                            if ($diff->m < 0) {
63
                                $diff->m += 12;
64
                                $diff->y--;
65
                            }
66
                        }
67
                    }
68
                }
69
            }
70

71
            return;
72
        }
73

74
        $diff->f *= -1;
75
        $diff->invert();
76
    }
77

78
    /**
79
     * @param DateInterval $diff
80
     * @param bool         $absolute
81
     *
82
     * @return CarbonInterval
83
     */
84 1
    protected static function fixDiffInterval(DateInterval $diff, $absolute)
85
    {
86 1
        $diff = CarbonInterval::instance($diff);
87

88
        // Work-around for https://bugs.php.net/bug.php?id=77145
89
        // @codeCoverageIgnoreStart
90
        if ($diff->f > 0 && $diff->y === -1 && $diff->m === 11 && $diff->d >= 27 && $diff->h === 23 && $diff->i === 59 && $diff->s === 59) {
91
            $diff->y = 0;
92
            $diff->m = 0;
93
            $diff->d = 0;
94
            $diff->h = 0;
95
            $diff->i = 0;
96
            $diff->s = 0;
97
            $diff->f = (1000000 - round($diff->f * 1000000)) / 1000000;
98
            $diff->invert();
99
        } elseif ($diff->f < 0) {
100
            static::fixNegativeMicroseconds($diff);
101
        }
102
        // @codeCoverageIgnoreEnd
103

104 1
        if ($absolute && $diff->invert) {
105 1
            $diff->invert();
106
        }
107

108 1
        return $diff;
109
    }
110

111
    /**
112
     * Get the difference as a DateInterval instance.
113
     * Return relative interval (negative if
114
     *
115
     * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date
116
     * @param bool                                                   $absolute Get the absolute of the difference
117
     *
118
     * @return DateInterval
119
     */
120 1
    public function diff($date = null, $absolute = false)
121
    {
122 1
        return parent::diff($this->resolveCarbon($date), (bool) $absolute);
123
    }
124

125
    /**
126
     * Get the difference as a CarbonInterval instance.
127
     * Return absolute interval (always positive) unless you pass false to the second argument.
128
     *
129
     * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date
130
     * @param bool                                                   $absolute Get the absolute of the difference
131
     *
132
     * @return CarbonInterval
133
     */
134 1
    public function diffAsCarbonInterval($date = null, $absolute = true)
135
    {
136 1
        return static::fixDiffInterval($this->diff($this->resolveCarbon($date), $absolute), $absolute);
137
    }
138

139
    /**
140
     * Get the difference in years
141
     *
142
     * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date
143
     * @param bool                                                   $absolute Get the absolute of the difference
144
     *
145
     * @return int
146
     */
147 1
    public function diffInYears($date = null, $absolute = true)
148
    {
149 1
        return (int) $this->diff($this->resolveCarbon($date), $absolute)->format('%r%y');
150
    }
151

152
    /**
153
     * Get the difference in quarters rounded down.
154
     *
155
     * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date
156
     * @param bool                                                   $absolute Get the absolute of the difference
157
     *
158
     * @return int
159
     */
160 1
    public function diffInQuarters($date = null, $absolute = true)
161
    {
162 1
        return (int) ($this->diffInMonths($date, $absolute) / static::MONTHS_PER_QUARTER);
163
    }
164

165
    /**
166
     * Get the difference in months rounded down.
167
     *
168
     * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date
169
     * @param bool                                                   $absolute Get the absolute of the difference
170
     *
171
     * @return int
172
     */
173 1
    public function diffInMonths($date = null, $absolute = true)
174
    {
175 1
        $date = $this->resolveCarbon($date);
176

177 1
        return $this->diffInYears($date, $absolute) * static::MONTHS_PER_YEAR + (int) $this->diff($date, $absolute)->format('%r%m');
178
    }
179

180
    /**
181
     * Get the difference in weeks rounded down.
182
     *
183
     * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date
184
     * @param bool                                                   $absolute Get the absolute of the difference
185
     *
186
     * @return int
187
     */
188 1
    public function diffInWeeks($date = null, $absolute = true)
189
    {
190 1
        return (int) ($this->diffInDays($date, $absolute) / static::DAYS_PER_WEEK);
191
    }
192

193
    /**
194
     * Get the difference in days rounded down.
195
     *
196
     * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date
197
     * @param bool                                                   $absolute Get the absolute of the difference
198
     *
199
     * @return int
200
     */
201 1
    public function diffInDays($date = null, $absolute = true)
202
    {
203 1
        return (int) $this->diff($this->resolveCarbon($date), $absolute)->format('%r%a');
204
    }
205

206
    /**
207
     * Get the difference in days using a filter closure rounded down.
208
     *
209
     * @param Closure                                                $callback
210
     * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date
211
     * @param bool                                                   $absolute Get the absolute of the difference
212
     *
213
     * @return int
214
     */
215 1
    public function diffInDaysFiltered(Closure $callback, $date = null, $absolute = true)
216
    {
217 1
        return $this->diffFiltered(CarbonInterval::day(), $callback, $date, $absolute);
218
    }
219

220
    /**
221
     * Get the difference in hours using a filter closure rounded down.
222
     *
223
     * @param Closure                                                $callback
224
     * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date
225
     * @param bool                                                   $absolute Get the absolute of the difference
226
     *
227
     * @return int
228
     */
229 1
    public function diffInHoursFiltered(Closure $callback, $date = null, $absolute = true)
230
    {
231 1
        return $this->diffFiltered(CarbonInterval::hour(), $callback, $date, $absolute);
232
    }
233

234
    /**
235
     * Get the difference by the given interval using a filter closure.
236
     *
237
     * @param CarbonInterval                                         $ci       An interval to traverse by
238
     * @param Closure                                                $callback
239
     * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date
240
     * @param bool                                                   $absolute Get the absolute of the difference
241
     *
242
     * @return int
243
     */
244 1
    public function diffFiltered(CarbonInterval $ci, Closure $callback, $date = null, $absolute = true)
245
    {
246 1
        $start = $this;
247 1
        $end = $this->resolveCarbon($date);
248 1
        $inverse = false;
249

250 1
        if ($end < $start) {
251 1
            $start = $end;
252 1
            $end = $this;
253 1
            $inverse = true;
254
        }
255

256 1
        $options = CarbonPeriod::EXCLUDE_END_DATE | ($this->isMutable() ? 0 : CarbonPeriod::IMMUTABLE);
257 1
        $diff = $ci->toPeriod($start, $end, $options)->filter($callback)->count();
258

259 1
        return $inverse && !$absolute ? -$diff : $diff;
260
    }
261

262
    /**
263
     * Get the difference in weekdays rounded down.
264
     *
265
     * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date
266
     * @param bool                                                   $absolute Get the absolute of the difference
267
     *
268
     * @return int
269
     */
270 1
    public function diffInWeekdays($date = null, $absolute = true)
271
    {
272
        return $this->diffInDaysFiltered(function (CarbonInterface $date) {
273 1
            return $date->isWeekday();
274 1
        }, $date, $absolute);
275
    }
276

277
    /**
278
     * Get the difference in weekend days using a filter rounded down.
279
     *
280
     * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date
281
     * @param bool                                                   $absolute Get the absolute of the difference
282
     *
283
     * @return int
284
     */
285 1
    public function diffInWeekendDays($date = null, $absolute = true)
286
    {
287
        return $this->diffInDaysFiltered(function (CarbonInterface $date) {
288 1
            return $date->isWeekend();
289 1
        }, $date, $absolute);
290
    }
291

292
    /**
293
     * Get the difference in hours rounded down.
294
     *
295
     * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date
296
     * @param bool                                                   $absolute Get the absolute of the difference
297
     *
298
     * @return int
299
     */
300 1
    public function diffInHours($date = null, $absolute = true)
301
    {
302 1
        return (int) ($this->diffInSeconds($date, $absolute) / static::SECONDS_PER_MINUTE / static::MINUTES_PER_HOUR);
303
    }
304

305
    /**
306
     * Get the difference in hours rounded down using timestamps.
307
     *
308
     * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date
309
     * @param bool                                                   $absolute Get the absolute of the difference
310
     *
311
     * @return int
312
     */
313 1
    public function diffInRealHours($date = null, $absolute = true)
314
    {
315 1
        return (int) ($this->diffInRealSeconds($date, $absolute) / static::SECONDS_PER_MINUTE / static::MINUTES_PER_HOUR);
316
    }
317

318
    /**
319
     * Get the difference in minutes rounded down.
320
     *
321
     * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date
322
     * @param bool                                                   $absolute Get the absolute of the difference
323
     *
324
     * @return int
325
     */
326 1
    public function diffInMinutes($date = null, $absolute = true)
327
    {
328 1
        return (int) ($this->diffInSeconds($date, $absolute) / static::SECONDS_PER_MINUTE);
329
    }
330

331
    /**
332
     * Get the difference in minutes rounded down using timestamps.
333
     *
334
     * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date
335
     * @param bool                                                   $absolute Get the absolute of the difference
336
     *
337
     * @return int
338
     */
339 1
    public function diffInRealMinutes($date = null, $absolute = true)
340
    {
341 1
        return (int) ($this->diffInRealSeconds($date, $absolute) / static::SECONDS_PER_MINUTE);
342
    }
343

344
    /**
345
     * Get the difference in seconds rounded down.
346
     *
347
     * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date
348
     * @param bool                                                   $absolute Get the absolute of the difference
349
     *
350
     * @return int
351
     */
352 1
    public function diffInSeconds($date = null, $absolute = true)
353
    {
354 1
        $diff = $this->diff($date);
355

356 1
        if ($diff->days === 0) {
357 1
            $diff = static::fixDiffInterval($diff, $absolute);
358
        }
359

360 1
        $value = (((($diff->m || $diff->y ? $diff->days : $diff->d) * static::HOURS_PER_DAY) +
361 1
            $diff->h) * static::MINUTES_PER_HOUR +
362 1
            $diff->i) * static::SECONDS_PER_MINUTE +
363 1
            $diff->s;
364

365 1
        return $absolute || !$diff->invert ? $value : -$value;
366
    }
367

368
    /**
369
     * Get the difference in microseconds.
370
     *
371
     * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date
372
     * @param bool                                                   $absolute Get the absolute of the difference
373
     *
374
     * @return int
375
     */
376 1
    public function diffInMicroseconds($date = null, $absolute = true)
377
    {
378 1
        $diff = $this->diff($date);
379 1
        $value = (int) round(((((($diff->m || $diff->y ? $diff->days : $diff->d) * static::HOURS_PER_DAY) +
380 1
            $diff->h) * static::MINUTES_PER_HOUR +
381 1
            $diff->i) * static::SECONDS_PER_MINUTE +
382 1
            ($diff->f + $diff->s)) * static::MICROSECONDS_PER_SECOND);
383

384 1
        return $absolute || !$diff->invert ? $value : -$value;
385
    }
386

387
    /**
388
     * Get the difference in milliseconds rounded down.
389
     *
390
     * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date
391
     * @param bool                                                   $absolute Get the absolute of the difference
392
     *
393
     * @return int
394
     */
395 1
    public function diffInMilliseconds($date = null, $absolute = true)
396
    {
397 1
        return (int) ($this->diffInMicroseconds($date, $absolute) / static::MICROSECONDS_PER_MILLISECOND);
398
    }
399

400
    /**
401
     * Get the difference in seconds using timestamps.
402
     *
403
     * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date
404
     * @param bool                                                   $absolute Get the absolute of the difference
405
     *
406
     * @return int
407
     */
408 1
    public function diffInRealSeconds($date = null, $absolute = true)
409
    {
410
        /** @var CarbonInterface $date */
411 1
        $date = $this->resolveCarbon($date);
412 1
        $value = $date->getTimestamp() - $this->getTimestamp();
413

414 1
        return $absolute ? abs($value) : $value;
415
    }
416

417
    /**
418
     * Get the difference in microseconds using timestamps.
419
     *
420
     * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date
421
     * @param bool                                                   $absolute Get the absolute of the difference
422
     *
423
     * @return int
424
     */
425 1
    public function diffInRealMicroseconds($date = null, $absolute = true)
426
    {
427
        /** @var CarbonInterface $date */
428 1
        $date = $this->resolveCarbon($date);
429 1
        $value = ($date->timestamp - $this->timestamp) * static::MICROSECONDS_PER_SECOND +
430 1
            $date->micro - $this->micro;
431

432 1
        return $absolute ? abs($value) : $value;
433
    }
434

435
    /**
436
     * Get the difference in milliseconds rounded down using timestamps.
437
     *
438
     * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date
439
     * @param bool                                                   $absolute Get the absolute of the difference
440
     *
441
     * @return int
442
     */
443 1
    public function diffInRealMilliseconds($date = null, $absolute = true)
444
    {
445 1
        return (int) ($this->diffInRealMicroseconds($date, $absolute) / static::MICROSECONDS_PER_MILLISECOND);
446
    }
447

448
    /**
449
     * Get the difference in seconds as float (microsecond-precision).
450
     *
451
     * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date
452
     * @param bool                                                   $absolute Get the absolute of the difference
453
     *
454
     * @return float
455
     */
456 1
    public function floatDiffInSeconds($date = null, $absolute = true)
457
    {
458 1
        return $this->diffInMicroseconds($date, $absolute) / static::MICROSECONDS_PER_SECOND;
459
    }
460

461
    /**
462
     * Get the difference in minutes as float (microsecond-precision).
463
     *
464
     * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date
465
     * @param bool                                                   $absolute Get the absolute of the difference
466
     *
467
     * @return float
468
     */
469 1
    public function floatDiffInMinutes($date = null, $absolute = true)
470
    {
471 1
        return $this->floatDiffInSeconds($date, $absolute) / static::SECONDS_PER_MINUTE;
472
    }
473

474
    /**
475
     * Get the difference in hours as float (microsecond-precision).
476
     *
477
     * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date
478
     * @param bool                                                   $absolute Get the absolute of the difference
479
     *
480
     * @return float
481
     */
482 1
    public function floatDiffInHours($date = null, $absolute = true)
483
    {
484 1
        return $this->floatDiffInMinutes($date, $absolute) / static::MINUTES_PER_HOUR;
485
    }
486

487
    /**
488
     * Get the difference in days as float (microsecond-precision).
489
     *
490
     * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date
491
     * @param bool                                                   $absolute Get the absolute of the difference
492
     *
493
     * @return float
494
     */
495 1
    public function floatDiffInDays($date = null, $absolute = true)
496
    {
497 1
        $hoursDiff = $this->floatDiffInHours($date, $absolute);
498

499 1
        return ($hoursDiff < 0 ? -1 : 1) * $this->diffInDays($date) + fmod($hoursDiff, static::HOURS_PER_DAY) / static::HOURS_PER_DAY;
500
    }
501

502
    /**
503
     * Get the difference in weeks as float (microsecond-precision).
504
     *
505
     * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date
506
     * @param bool                                                   $absolute Get the absolute of the difference
507
     *
508
     * @return float
509
     */
510 1
    public function floatDiffInWeeks($date = null, $absolute = true)
511
    {
512 1
        return $this->floatDiffInDays($date, $absolute) / static::DAYS_PER_WEEK;
513
    }
514

515
    /**
516
     * Get the difference in months as float (microsecond-precision).
517
     *
518
     * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date
519
     * @param bool                                                   $absolute Get the absolute of the difference
520
     *
521
     * @return float
522
     */
523 1
    public function floatDiffInMonths($date = null, $absolute = true)
524
    {
525 1
        $start = $this;
526 1
        $end = $this->resolveCarbon($date);
527 1
        $ascending = ($start <= $end);
528 1
        $sign = $absolute || $ascending ? 1 : -1;
529 1
        if (!$ascending) {
530 1
            [$start, $end] = [$end, $start];
531
        }
532 1
        $monthsDiff = $start->diffInMonths($end);
533
        /** @var Carbon|CarbonImmutable $floorEnd */
534 1
        $floorEnd = $start->copy()->addMonths($monthsDiff);
535

536 1
        if ($floorEnd >= $end) {
537 1
            return $sign * $monthsDiff;
538
        }
539

540
        /** @var Carbon|CarbonImmutable $startOfMonthAfterFloorEnd */
541 1
        $startOfMonthAfterFloorEnd = $floorEnd->copy()->addMonth()->startOfMonth();
542

543 1
        if ($startOfMonthAfterFloorEnd > $end) {
544 1
            return $sign * ($monthsDiff + $floorEnd->floatDiffInDays($end) / $floorEnd->daysInMonth);
545
        }
546

547 1
        return $sign * ($monthsDiff + $floorEnd->floatDiffInDays($startOfMonthAfterFloorEnd) / $floorEnd->daysInMonth + $startOfMonthAfterFloorEnd->floatDiffInDays($end) / $end->daysInMonth);
548
    }
549

550
    /**
551
     * Get the difference in year as float (microsecond-precision).
552
     *
553
     * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date
554
     * @param bool                                                   $absolute Get the absolute of the difference
555
     *
556
     * @return float
557
     */
558 1
    public function floatDiffInYears($date = null, $absolute = true)
559
    {
560 1
        $start = $this;
561 1
        $end = $this->resolveCarbon($date);
562 1
        $ascending = ($start <= $end);
563 1
        $sign = $absolute || $ascending ? 1 : -1;
564 1
        if (!$ascending) {
565 1
            [$start, $end] = [$end, $start];
566
        }
567 1
        $yearsDiff = $start->diffInYears($end);
568
        /** @var Carbon|CarbonImmutable $floorEnd */
569 1
        $floorEnd = $start->copy()->addYears($yearsDiff);
570

571 1
        if ($floorEnd >= $end) {
572 1
            return $sign * $yearsDiff;
573
        }
574

575
        /** @var Carbon|CarbonImmutable $startOfYearAfterFloorEnd */
576 1
        $startOfYearAfterFloorEnd = $floorEnd->copy()->addYear()->startOfYear();
577

578 1
        if ($startOfYearAfterFloorEnd > $end) {
579 1
            return $sign * ($yearsDiff + $floorEnd->floatDiffInDays($end) / $floorEnd->daysInYear);
580
        }
581

582 1
        return $sign * ($yearsDiff + $floorEnd->floatDiffInDays($startOfYearAfterFloorEnd) / $floorEnd->daysInYear + $startOfYearAfterFloorEnd->floatDiffInDays($end) / $end->daysInYear);
583
    }
584

585
    /**
586
     * Get the difference in seconds as float (microsecond-precision) using timestamps.
587
     *
588
     * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date
589
     * @param bool                                                   $absolute Get the absolute of the difference
590
     *
591
     * @return float
592
     */
593 1
    public function floatDiffInRealSeconds($date = null, $absolute = true)
594
    {
595 1
        return $this->diffInRealMicroseconds($date, $absolute) / static::MICROSECONDS_PER_SECOND;
596
    }
597

598
    /**
599
     * Get the difference in minutes as float (microsecond-precision) using timestamps.
600
     *
601
     * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date
602
     * @param bool                                                   $absolute Get the absolute of the difference
603
     *
604
     * @return float
605
     */
606 1
    public function floatDiffInRealMinutes($date = null, $absolute = true)
607
    {
608 1
        return $this->floatDiffInRealSeconds($date, $absolute) / static::SECONDS_PER_MINUTE;
609
    }
610

611
    /**
612
     * Get the difference in hours as float (microsecond-precision) using timestamps.
613
     *
614
     * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date
615
     * @param bool                                                   $absolute Get the absolute of the difference
616
     *
617
     * @return float
618
     */
619 1
    public function floatDiffInRealHours($date = null, $absolute = true)
620
    {
621 1
        return $this->floatDiffInRealMinutes($date, $absolute) / static::MINUTES_PER_HOUR;
622
    }
623

624
    /**
625
     * Get the difference in days as float (microsecond-precision).
626
     *
627
     * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date
628
     * @param bool                                                   $absolute Get the absolute of the difference
629
     *
630
     * @return float
631
     */
632 1
    public function floatDiffInRealDays($date = null, $absolute = true)
633
    {
634 1
        $hoursDiff = $this->floatDiffInRealHours($date, $absolute);
635

636 1
        return ($hoursDiff < 0 ? -1 : 1) * $this->diffInDays($date) + fmod($hoursDiff, static::HOURS_PER_DAY) / static::HOURS_PER_DAY;
637
    }
638

639
    /**
640
     * Get the difference in weeks as float (microsecond-precision).
641
     *
642
     * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date
643
     * @param bool                                                   $absolute Get the absolute of the difference
644
     *
645
     * @return float
646
     */
647 1
    public function floatDiffInRealWeeks($date = null, $absolute = true)
648
    {
649 1
        return $this->floatDiffInRealDays($date, $absolute) / static::DAYS_PER_WEEK;
650
    }
651

652
    /**
653
     * Get the difference in months as float (microsecond-precision) using timestamps.
654
     *
655
     * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date
656
     * @param bool                                                   $absolute Get the absolute of the difference
657
     *
658
     * @return float
659
     */
660 1
    public function floatDiffInRealMonths($date = null, $absolute = true)
661
    {
662 1
        $start = $this;
663 1
        $end = $this->resolveCarbon($date);
664 1
        $ascending = ($start <= $end);
665 1
        $sign = $absolute || $ascending ? 1 : -1;
666 1
        if (!$ascending) {
667 1
            [$start, $end] = [$end, $start];
668
        }
669 1
        $monthsDiff = $start->diffInMonths($end);
670
        /** @var Carbon|CarbonImmutable $floorEnd */
671 1
        $floorEnd = $start->copy()->addMonths($monthsDiff);
672

673 1
        if ($floorEnd >= $end) {
674 1
            return $sign * $monthsDiff;
675
        }
676

677
        /** @var Carbon|CarbonImmutable $startOfMonthAfterFloorEnd */
678 1
        $startOfMonthAfterFloorEnd = $floorEnd->copy()->addMonth()->startOfMonth();
679

680 1
        if ($startOfMonthAfterFloorEnd > $end) {
681 1
            return $sign * ($monthsDiff + $floorEnd->floatDiffInRealDays($end) / $floorEnd->daysInMonth);
682
        }
683

684 1
        return $sign * ($monthsDiff + $floorEnd->floatDiffInRealDays($startOfMonthAfterFloorEnd) / $floorEnd->daysInMonth + $startOfMonthAfterFloorEnd->floatDiffInRealDays($end) / $end->daysInMonth);
685
    }
686

687
    /**
688
     * Get the difference in year as float (microsecond-precision) using timestamps.
689
     *
690
     * @param \Carbon\CarbonInterface|\DateTimeInterface|string|null $date
691
     * @param bool                                                   $absolute Get the absolute of the difference
692
     *
693
     * @return float
694
     */
695 1
    public function floatDiffInRealYears($date = null, $absolute = true)
696
    {
697 1
        $start = $this;
698 1
        $end = $this->resolveCarbon($date);
699 1
        $ascending = ($start <= $end);
700 1
        $sign = $absolute || $ascending ? 1 : -1;
701 1
        if (!$ascending) {
702 1
            [$start, $end] = [$end, $start];
703
        }
704 1
        $yearsDiff = $start->diffInYears($end);
705
        /** @var Carbon|CarbonImmutable $floorEnd */
706 1
        $floorEnd = $start->copy()->addYears($yearsDiff);
707

708 1
        if ($floorEnd >= $end) {
709 1
            return $sign * $yearsDiff;
710
        }
711

712
        /** @var Carbon|CarbonImmutable $startOfYearAfterFloorEnd */
713 1
        $startOfYearAfterFloorEnd = $floorEnd->copy()->addYear()->startOfYear();
714

715 1
        if ($startOfYearAfterFloorEnd > $end) {
716 1
            return $sign * ($yearsDiff + $floorEnd->floatDiffInRealDays($end) / $floorEnd->daysInYear);
717
        }
718

719 1
        return $sign * ($yearsDiff + $floorEnd->floatDiffInRealDays($startOfYearAfterFloorEnd) / $floorEnd->daysInYear + $startOfYearAfterFloorEnd->floatDiffInRealDays($end) / $end->daysInYear);
720
    }
721

722
    /**
723
     * The number of seconds since midnight.
724
     *
725
     * @return int
726
     */
727 1
    public function secondsSinceMidnight()
728
    {
729 1
        return $this->diffInSeconds($this->copy()->startOfDay());
730
    }
731

732
    /**
733
     * The number of seconds until 23:59:59.
734
     *
735
     * @return int
736
     */
737 1
    public function secondsUntilEndOfDay()
738
    {
739 1
        return $this->diffInSeconds($this->copy()->endOfDay());
740
    }
741

742
    /**
743
     * Get the difference in a human readable format in the current locale from current instance to an other
744
     * instance given (or now if null given).
745
     *
746
     * @example
747
     * ```
748
     * echo Carbon::tomorrow()->diffForHumans() . "\n";
749
     * echo Carbon::tomorrow()->diffForHumans(['parts' => 2]) . "\n";
750
     * echo Carbon::tomorrow()->diffForHumans(['parts' => 3, 'join' => true]) . "\n";
751
     * echo Carbon::tomorrow()->diffForHumans(Carbon::yesterday()) . "\n";
752
     * echo Carbon::tomorrow()->diffForHumans(Carbon::yesterday(), ['short' => true]) . "\n";
753
     * ```
754
     *
755
     * @param Carbon|\DateTimeInterface|string|array|null $other   if array passed, will be used as parameters array, see $syntax below;
756
     *                                                             if null passed, now will be used as comparison reference;
757
     *                                                             if any other type, it will be converted to date and used as reference.
758
     * @param int|array                                   $syntax  if array passed, parameters will be extracted from it, the array may contains:
759
     *                                                             - 'syntax' entry (see below)
760
     *                                                             - 'short' entry (see below)
761
     *                                                             - 'parts' entry (see below)
762
     *                                                             - 'options' entry (see below)
763
     *                                                             - 'join' entry determines how to join multiple parts of the string
764
     *                                                             `  - if $join is a string, it's used as a joiner glue
765
     *                                                             `  - if $join is a callable/closure, it get the list of string and should return a string
766
     *                                                             `  - if $join is an array, the first item will be the default glue, and the second item
767
     *                                                             `    will be used instead of the glue for the last item
768
     *                                                             `  - if $join is true, it will be guessed from the locale ('list' translation file entry)
769
     *                                                             `  - if $join is missing, a space will be used as glue
770
     *                                                             - 'other' entry (see above)
771
     *                                                             if int passed, it add modifiers:
772
     *                                                             Possible values:
773
     *                                                             - CarbonInterface::DIFF_ABSOLUTE          no modifiers
774
     *                                                             - CarbonInterface::DIFF_RELATIVE_TO_NOW   add ago/from now modifier
775
     *                                                             - CarbonInterface::DIFF_RELATIVE_TO_OTHER add before/after modifier
776
     *                                                             Default value: CarbonInterface::DIFF_ABSOLUTE
777
     * @param bool                                        $short   displays short format of time units
778
     * @param int                                         $parts   maximum number of parts to display (default value: 1: single unit)
779
     * @param int                                         $options human diff options
780
     *
781
     * @return string
782
     */
783 1
    public function diffForHumans($other = null, $syntax = null, $short = false, $parts = 1, $options = null)
784
    {
785
        /* @var CarbonInterface $this */
786 1
        if (\is_array($other)) {
787 1
            $other['syntax'] = \array_key_exists('syntax', $other) ? $other['syntax'] : $syntax;
788 1
            $syntax = $other;
789 1
            $other = $syntax['other'] ?? null;
790
        }
791

792 1
        $intSyntax = &$syntax;
793 1
        if (\is_array($syntax)) {
794 1
            $syntax['syntax'] = $syntax['syntax'] ?? null;
795 1
            $intSyntax = &$syntax['syntax'];
796
        }
797 1
        $intSyntax = (int) ($intSyntax === null ? static::DIFF_RELATIVE_AUTO : $intSyntax);
798 1
        $intSyntax = $intSyntax === static::DIFF_RELATIVE_AUTO && $other === null ? static::DIFF_RELATIVE_TO_NOW : $intSyntax;
799

800 1
        $parts = min(7, max(1, (int) $parts));
801

802 1
        return $this->diffAsCarbonInterval($other, false)
803 1
            ->setLocalTranslator($this->getLocalTranslator())
804 1
            ->forHumans($syntax, (bool) $short, $parts, $options ?? $this->localHumanDiffOptions ?? static::getHumanDiffOptions());
805
    }
806

807
    /**
808
     * @alias diffForHumans
809
     *
810
     * Get the difference in a human readable format in the current locale from current instance to an other
811
     * instance given (or now if null given).
812
     *
813
     * @param Carbon|\DateTimeInterface|string|array|null $other   if array passed, will be used as parameters array, see $syntax below;
814
     *                                                             if null passed, now will be used as comparison reference;
815
     *                                                             if any other type, it will be converted to date and used as reference.
816
     * @param int|array                                   $syntax  if array passed, parameters will be extracted from it, the array may contains:
817
     *                                                             - 'syntax' entry (see below)
818
     *                                                             - 'short' entry (see below)
819
     *                                                             - 'parts' entry (see below)
820
     *                                                             - 'options' entry (see below)
821
     *                                                             - 'join' entry determines how to join multiple parts of the string
822
     *                                                             `  - if $join is a string, it's used as a joiner glue
823
     *                                                             `  - if $join is a callable/closure, it get the list of string and should return a string
824
     *                                                             `  - if $join is an array, the first item will be the default glue, and the second item
825
     *                                                             `    will be used instead of the glue for the last item
826
     *                                                             `  - if $join is true, it will be guessed from the locale ('list' translation file entry)
827
     *                                                             `  - if $join is missing, a space will be used as glue
828
     *                                                             - 'other' entry (see above)
829
     *                                                             if int passed, it add modifiers:
830
     *                                                             Possible values:
831
     *                                                             - CarbonInterface::DIFF_ABSOLUTE          no modifiers
832
     *                                                             - CarbonInterface::DIFF_RELATIVE_TO_NOW   add ago/from now modifier
833
     *                                                             - CarbonInterface::DIFF_RELATIVE_TO_OTHER add before/after modifier
834
     *                                                             Default value: CarbonInterface::DIFF_ABSOLUTE
835
     * @param bool                                        $short   displays short format of time units
836
     * @param int                                         $parts   maximum number of parts to display (default value: 1: single unit)
837
     * @param int                                         $options human diff options
838
     *
839
     * @return string
840
     */
841 1
    public function from($other = null, $syntax = null, $short = false, $parts = 1, $options = null)
842
    {
843 1
        return $this->diffForHumans($other, $syntax, $short, $parts, $options);
844
    }
845

846
    /**
847
     * @alias diffForHumans
848
     *
849
     * Get the difference in a human readable format in the current locale from current instance to an other
850
     * instance given (or now if null given).
851
     */
852 1
    public function since($other = null, $syntax = null, $short = false, $parts = 1, $options = null)
853
    {
854 1
        return $this->diffForHumans($other, $syntax, $short, $parts, $options);
855
    }
856

857
    /**
858
     * Get the difference in a human readable format in the current locale from an other
859
     * instance given (or now if null given) to current instance.
860
     *
861
     * When comparing a value in the past to default now:
862
     * 1 hour from now
863
     * 5 months from now
864
     *
865
     * When comparing a value in the future to default now:
866
     * 1 hour ago
867
     * 5 months ago
868
     *
869
     * When comparing a value in the past to another value:
870
     * 1 hour after
871
     * 5 months after
872
     *
873
     * When comparing a value in the future to another value:
874
     * 1 hour before
875
     * 5 months before
876
     *
877
     * @param Carbon|\DateTimeInterface|string|array|null $other   if array passed, will be used as parameters array, see $syntax below;
878
     *                                                             if null passed, now will be used as comparison reference;
879
     *                                                             if any other type, it will be converted to date and used as reference.
880
     * @param int|array                                   $syntax  if array passed, parameters will be extracted from it, the array may contains:
881
     *                                                             - 'syntax' entry (see below)
882
     *                                                             - 'short' entry (see below)
883
     *                                                             - 'parts' entry (see below)
884
     *                                                             - 'options' entry (see below)
885
     *                                                             - 'join' entry determines how to join multiple parts of the string
886
     *                                                             `  - if $join is a string, it's used as a joiner glue
887
     *                                                             `  - if $join is a callable/closure, it get the list of string and should return a string
888
     *                                                             `  - if $join is an array, the first item will be the default glue, and the second item
889
     *                                                             `    will be used instead of the glue for the last item
890
     *                                                             `  - if $join is true, it will be guessed from the locale ('list' translation file entry)
891
     *                                                             `  - if $join is missing, a space will be used as glue
892
     *                                                             - 'other' entry (see above)
893
     *                                                             if int passed, it add modifiers:
894
     *                                                             Possible values:
895
     *                                                             - CarbonInterface::DIFF_ABSOLUTE          no modifiers
896
     *                                                             - CarbonInterface::DIFF_RELATIVE_TO_NOW   add ago/from now modifier
897
     *                                                             - CarbonInterface::DIFF_RELATIVE_TO_OTHER add before/after modifier
898
     *                                                             Default value: CarbonInterface::DIFF_ABSOLUTE
899
     * @param bool                                        $short   displays short format of time units
900
     * @param int                                         $parts   maximum number of parts to display (default value: 1: single unit)
901
     * @param int                                         $options human diff options
902
     *
903
     * @return string
904
     */
905 1
    public function to($other = null, $syntax = null, $short = false, $parts = 1, $options = null)
906
    {
907 1
        if (!$syntax && !$other) {
908 1
            $syntax = CarbonInterface::DIFF_RELATIVE_TO_NOW;
909
        }
910

911 1
        return $this->resolveCarbon($other)->diffForHumans($this, $syntax, $short, $parts, $options);
912
    }
913

914
    /**
915
     * @alias to
916
     *
917
     * Get the difference in a human readable format in the current locale from an other
918
     * instance given (or now if null given) to current instance.
919
     *
920
     * @param Carbon|\DateTimeInterface|string|array|null $other   if array passed, will be used as parameters array, see $syntax below;
921
     *                                                             if null passed, now will be used as comparison reference;
922
     *                                                             if any other type, it will be converted to date and used as reference.
923
     * @param int|array                                   $syntax  if array passed, parameters will be extracted from it, the array may contains:
924
     *                                                             - 'syntax' entry (see below)
925
     *                                                             - 'short' entry (see below)
926
     *                                                             - 'parts' entry (see below)
927
     *                                                             - 'options' entry (see below)
928
     *                                                             - 'join' entry determines how to join multiple parts of the string
929
     *                                                             `  - if $join is a string, it's used as a joiner glue
930
     *                                                             `  - if $join is a callable/closure, it get the list of string and should return a string
931
     *                                                             `  - if $join is an array, the first item will be the default glue, and the second item
932
     *                                                             `    will be used instead of the glue for the last item
933
     *                                                             `  - if $join is true, it will be guessed from the locale ('list' translation file entry)
934
     *                                                             `  - if $join is missing, a space will be used as glue
935
     *                                                             - 'other' entry (see above)
936
     *                                                             if int passed, it add modifiers:
937
     *                                                             Possible values:
938
     *                                                             - CarbonInterface::DIFF_ABSOLUTE          no modifiers
939
     *                                                             - CarbonInterface::DIFF_RELATIVE_TO_NOW   add ago/from now modifier
940
     *                                                             - CarbonInterface::DIFF_RELATIVE_TO_OTHER add before/after modifier
941
     *                                                             Default value: CarbonInterface::DIFF_ABSOLUTE
942
     * @param bool                                        $short   displays short format of time units
943
     * @param int                                         $parts   maximum number of parts to display (default value: 1: single unit)
944
     * @param int                                         $options human diff options
945
     *
946
     * @return string
947
     */
948 1
    public function until($other = null, $syntax = null, $short = false, $parts = 1, $options = null)
949
    {
950 1
        return $this->to($other, $syntax, $short, $parts, $options);
951
    }
952

953
    /**
954
     * Get the difference in a human readable format in the current locale from current
955
     * instance to now.
956
     *
957
     * @param int|array $syntax  if array passed, parameters will be extracted from it, the array may contains:
958
     *                           - 'syntax' entry (see below)
959
     *                           - 'short' entry (see below)
960
     *                           - 'parts' entry (see below)
961
     *                           - 'options' entry (see below)
962
     *                           - 'join' entry determines how to join multiple parts of the string
963
     *                           `  - if $join is a string, it's used as a joiner glue
964
     *                           `  - if $join is a callable/closure, it get the list of string and should return a string
965
     *                           `  - if $join is an array, the first item will be the default glue, and the second item
966
     *                           `    will be used instead of the glue for the last item
967
     *                           `  - if $join is true, it will be guessed from the locale ('list' translation file entry)
968
     *                           `  - if $join is missing, a space will be used as glue
969
     *                           if int passed, it add modifiers:
970
     *                           Possible values:
971
     *                           - CarbonInterface::DIFF_ABSOLUTE          no modifiers
972
     *                           - CarbonInterface::DIFF_RELATIVE_TO_NOW   add ago/from now modifier
973
     *                           - CarbonInterface::DIFF_RELATIVE_TO_OTHER add before/after modifier
974
     *                           Default value: CarbonInterface::DIFF_ABSOLUTE
975
     * @param bool      $short   displays short format of time units
976
     * @param int       $parts   maximum number of parts to display (default value: 1: single unit)
977
     * @param int       $options human diff options
978
     *
979
     * @return string
980
     */
981 1
    public function fromNow($syntax = null, $short = false, $parts = 1, $options = null)
982
    {
983 1
        $other = null;
984

985 1
        if ($syntax instanceof DateTimeInterface) {
986 1
            [$other, $syntax, $short, $parts, $options] = array_pad(\func_get_args(), 5, null);
987
        }
988

989 1
        return $this->from($other, $syntax, $short, $parts, $options);
990
    }
991

992
    /**
993
     * Get the difference in a human readable format in the current locale from an other
994
     * instance given to now
995
     *
996
     * @param int|array $syntax  if array passed, parameters will be extracted from it, the array may contains:
997
     *                           - 'syntax' entry (see below)
998
     *                           - 'short' entry (see below)
999
     *                           - 'parts' entry (see below)
1000
     *                           - 'options' entry (see below)
1001
     *                           - 'join' entry determines how to join multiple parts of the string
1002
     *                           `  - if $join is a string, it's used as a joiner glue
1003
     *                           `  - if $join is a callable/closure, it get the list of string and should return a string
1004
     *                           `  - if $join is an array, the first item will be the default glue, and the second item
1005
     *                           `    will be used instead of the glue for the last item
1006
     *                           `  - if $join is true, it will be guessed from the locale ('list' translation file entry)
1007
     *                           `  - if $join is missing, a space will be used as glue
1008
     *                           if int passed, it add modifiers:
1009
     *                           Possible values:
1010
     *                           - CarbonInterface::DIFF_ABSOLUTE          no modifiers
1011
     *                           - CarbonInterface::DIFF_RELATIVE_TO_NOW   add ago/from now modifier
1012
     *                           - CarbonInterface::DIFF_RELATIVE_TO_OTHER add before/after modifier
1013
     *                           Default value: CarbonInterface::DIFF_ABSOLUTE
1014
     * @param bool      $short   displays short format of time units
1015
     * @param int       $parts   maximum number of parts to display (default value: 1: single part)
1016
     * @param int       $options human diff options
1017
     *
1018
     * @return string
1019
     */
1020 1
    public function toNow($syntax = null, $short = false, $parts = 1, $options = null)
1021
    {
1022 1
        return $this->to(null, $syntax, $short, $parts, $options);
1023
    }
1024

1025
    /**
1026
     * Get the difference in a human readable format in the current locale from an other
1027
     * instance given to now
1028
     *
1029
     * @param int|array $syntax  if array passed, parameters will be extracted from it, the array may contains:
1030
     *                           - 'syntax' entry (see below)
1031
     *                           - 'short' entry (see below)
1032
     *                           - 'parts' entry (see below)
1033
     *                           - 'options' entry (see below)
1034
     *                           - 'join' entry determines how to join multiple parts of the string
1035
     *                           `  - if $join is a string, it's used as a joiner glue
1036
     *                           `  - if $join is a callable/closure, it get the list of string and should return a string
1037
     *                           `  - if $join is an array, the first item will be the default glue, and the second item
1038
     *                           `    will be used instead of the glue for the last item
1039
     *                           `  - if $join is true, it will be guessed from the locale ('list' translation file entry)
1040
     *                           `  - if $join is missing, a space will be used as glue
1041
     *                           if int passed, it add modifiers:
1042
     *                           Possible values:
1043
     *                           - CarbonInterface::DIFF_ABSOLUTE          no modifiers
1044
     *                           - CarbonInterface::DIFF_RELATIVE_TO_NOW   add ago/from now modifier
1045
     *                           - CarbonInterface::DIFF_RELATIVE_TO_OTHER add before/after modifier
1046
     *                           Default value: CarbonInterface::DIFF_ABSOLUTE
1047
     * @param bool      $short   displays short format of time units
1048
     * @param int       $parts   maximum number of parts to display (default value: 1: single part)
1049
     * @param int       $options human diff options
1050
     *
1051
     * @return string
1052
     */
1053 1
    public function ago($syntax = null, $short = false, $parts = 1, $options = null)
1054
    {
1055 1
        $other = null;
1056

1057 1
        if ($syntax instanceof DateTimeInterface) {
1058 1
            [$other, $syntax, $short, $parts, $options] = array_pad(\func_get_args(), 5, null);
1059
        }
1060

1061 1
        return $this->from($other, $syntax, $short, $parts, $options);
1062
    }
1063

1064
    /**
1065
     * Get the difference in a human readable format in the current locale from current instance to an other
1066
     * instance given (or now if null given).
1067
     *
1068
     * @return string
1069
     */
1070 1
    public function timespan($other = null, $timezone = null)
1071
    {
1072 1
        if (!$other instanceof DateTimeInterface) {
1073 1
            $other = static::parse($other, $timezone);
1074
        }
1075

1076 1
        return $this->diffForHumans($other, [
1077 1
            'join' => ', ',
1078 1
            'syntax' => CarbonInterface::DIFF_ABSOLUTE,
1079 1
            'options' => CarbonInterface::NO_ZERO_DIFF,
1080
            'parts' => -1,
1081
        ]);
1082
    }
1083

1084
    /**
1085
     * Returns either the close date "Friday 15h30", or a calendar date "10/09/2017" is farthest than 7 days from now.
1086
     *
1087
     * @param Carbon|\DateTimeInterface|string|null $referenceTime
1088
     * @param array                                 $formats
1089
     *
1090
     * @return string
1091
     */
1092 1
    public function calendar($referenceTime = null, array $formats = [])
1093
    {
1094
        /** @var CarbonInterface $current */
1095 1
        $current = $this->copy()->startOfDay();
1096
        /** @var CarbonInterface $other */
1097 1
        $other = $this->resolveCarbon($referenceTime)->copy()->setTimezone($this->getTimezone())->startOfDay();
1098 1
        $diff = $other->diffInDays($current, false);
1099 1
        $format = $diff < -6 ? 'sameElse' : (
1100 1
            $diff < -1 ? 'lastWeek' : (
1101 1
                $diff < 0 ? 'lastDay' : (
1102 1
                    $diff < 1 ? 'sameDay' : (
1103 1
                        $diff < 2 ? 'nextDay' : (
1104 1
                            $diff < 7 ? 'nextWeek' : 'sameElse'
1105
                        )
1106
                    )
1107
                )
1108
            )
1109
        );
1110 1
        $format = array_merge($this->getCalendarFormats(), $formats)[$format];
1111 1
        if ($format instanceof Closure) {
1112 1
            $format = $format($current, $other) ?? '';
1113
        }
1114

1115 1
        return $this->isoFormat(\strval($format));
1116
    }
1117
}

Read our documentation on viewing source code .

Loading