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