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