See Release Notes
Long Term Support Release
Differences Between: [Versions 400 and 401] [Versions 401 and 402] [Versions 401 and 403]
1 <?php 2 3 namespace PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel; 4 5 use DateInterval; 6 use DateTime; 7 use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled; 8 use PhpOffice\PhpSpreadsheet\Calculation\Exception; 9 use PhpOffice\PhpSpreadsheet\Calculation\Information\ExcelError; 10 use PhpOffice\PhpSpreadsheet\Shared\Date as SharedDateHelper; 11 12 class Difference 13 { 14 use ArrayEnabled; 15 16 /** 17 * DATEDIF. 18 * 19 * @param mixed $startDate Excel date serial value, PHP date/time stamp, PHP DateTime object 20 * or a standard date string 21 * Or can be an array of date values 22 * @param mixed $endDate Excel date serial value, PHP date/time stamp, PHP DateTime object 23 * or a standard date string 24 * Or can be an array of date values 25 * @param array|string $unit 26 * Or can be an array of unit values 27 * 28 * @return array|int|string Interval between the dates 29 * If an array of values is passed for the $startDate or $endDays,arguments, then the returned result 30 * will also be an array with matching dimensions 31 */ 32 public static function interval($startDate, $endDate, $unit = 'D') 33 { 34 if (is_array($startDate) || is_array($endDate) || is_array($unit)) { 35 return self::evaluateArrayArguments([self::class, __FUNCTION__], $startDate, $endDate, $unit); 36 } 37 38 try { 39 $startDate = Helpers::getDateValue($startDate); 40 $endDate = Helpers::getDateValue($endDate); 41 $difference = self::initialDiff($startDate, $endDate); 42 $unit = strtoupper($unit); 43 } catch (Exception $e) { 44 return $e->getMessage(); 45 } 46 47 // Execute function 48 $PHPStartDateObject = SharedDateHelper::excelToDateTimeObject($startDate); 49 $startDays = (int) $PHPStartDateObject->format('j'); 50 $startMonths = (int) $PHPStartDateObject->format('n'); 51 $startYears = (int) $PHPStartDateObject->format('Y'); 52 53 $PHPEndDateObject = SharedDateHelper::excelToDateTimeObject($endDate); 54 $endDays = (int) $PHPEndDateObject->format('j'); 55 $endMonths = (int) $PHPEndDateObject->format('n'); 56 $endYears = (int) $PHPEndDateObject->format('Y'); 57 58 $PHPDiffDateObject = $PHPEndDateObject->diff($PHPStartDateObject); 59 60 $retVal = false; 61 $retVal = self::replaceRetValue($retVal, $unit, 'D') ?? self::datedifD($difference); 62 $retVal = self::replaceRetValue($retVal, $unit, 'M') ?? self::datedifM($PHPDiffDateObject); 63 $retVal = self::replaceRetValue($retVal, $unit, 'MD') ?? self::datedifMD($startDays, $endDays, $PHPEndDateObject, $PHPDiffDateObject); 64 $retVal = self::replaceRetValue($retVal, $unit, 'Y') ?? self::datedifY($PHPDiffDateObject); 65 $retVal = self::replaceRetValue($retVal, $unit, 'YD') ?? self::datedifYD($difference, $startYears, $endYears, $PHPStartDateObject, $PHPEndDateObject); 66 $retVal = self::replaceRetValue($retVal, $unit, 'YM') ?? self::datedifYM($PHPDiffDateObject); 67 68 return is_bool($retVal) ? ExcelError::VALUE() : $retVal; 69 } 70 71 private static function initialDiff(float $startDate, float $endDate): float 72 { 73 // Validate parameters 74 if ($startDate > $endDate) { 75 throw new Exception(ExcelError::NAN()); 76 } 77 78 return $endDate - $startDate; 79 } 80 81 /** 82 * Decide whether it's time to set retVal. 83 * 84 * @param bool|int $retVal 85 * 86 * @return null|bool|int 87 */ 88 private static function replaceRetValue($retVal, string $unit, string $compare) 89 { 90 if ($retVal !== false || $unit !== $compare) { 91 return $retVal; 92 } 93 94 return null; 95 } 96 97 private static function datedifD(float $difference): int 98 { 99 return (int) $difference; 100 } 101 102 private static function datedifM(DateInterval $PHPDiffDateObject): int 103 { 104 return 12 * (int) $PHPDiffDateObject->format('%y') + (int) $PHPDiffDateObject->format('%m'); 105 } 106 107 private static function datedifMD(int $startDays, int $endDays, DateTime $PHPEndDateObject, DateInterval $PHPDiffDateObject): int 108 { 109 if ($endDays < $startDays) { 110 $retVal = $endDays; 111 $PHPEndDateObject->modify('-' . $endDays . ' days'); 112 $adjustDays = (int) $PHPEndDateObject->format('j'); 113 $retVal += ($adjustDays - $startDays); 114 } else { 115 $retVal = (int) $PHPDiffDateObject->format('%d'); 116 } 117 118 return $retVal; 119 } 120 121 private static function datedifY(DateInterval $PHPDiffDateObject): int 122 { 123 return (int) $PHPDiffDateObject->format('%y'); 124 } 125 126 private static function datedifYD(float $difference, int $startYears, int $endYears, DateTime $PHPStartDateObject, DateTime $PHPEndDateObject): int 127 { 128 $retVal = (int) $difference; 129 if ($endYears > $startYears) { 130 $isLeapStartYear = $PHPStartDateObject->format('L'); 131 $wasLeapEndYear = $PHPEndDateObject->format('L'); 132 133 // Adjust end year to be as close as possible as start year 134 while ($PHPEndDateObject >= $PHPStartDateObject) { 135 $PHPEndDateObject->modify('-1 year'); 136 $endYears = $PHPEndDateObject->format('Y'); 137 } 138 $PHPEndDateObject->modify('+1 year'); 139 140 // Get the result 141 $retVal = $PHPEndDateObject->diff($PHPStartDateObject)->days; 142 143 // Adjust for leap years cases 144 $isLeapEndYear = $PHPEndDateObject->format('L'); 145 $limit = new DateTime($PHPEndDateObject->format('Y-02-29')); 146 if (!$isLeapStartYear && !$wasLeapEndYear && $isLeapEndYear && $PHPEndDateObject >= $limit) { 147 --$retVal; 148 } 149 } 150 151 return (int) $retVal; 152 } 153 154 private static function datedifYM(DateInterval $PHPDiffDateObject): int 155 { 156 return (int) $PHPDiffDateObject->format('%m'); 157 } 158 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body