See Release Notes
Long Term Support Release
Differences Between: [Versions 400 and 401]
1 <?php 2 3 namespace PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel; 4 5 use DateTime; 6 use PhpOffice\PhpSpreadsheet\Calculation\Exception; 7 use PhpOffice\PhpSpreadsheet\Calculation\Functions; 8 use PhpOffice\PhpSpreadsheet\Calculation\Information\ExcelError; 9 use PhpOffice\PhpSpreadsheet\Shared\Date as SharedDateHelper; 10 11 class Helpers 12 { 13 /** 14 * Identify if a year is a leap year or not. 15 * 16 * @param int|string $year The year to test 17 * 18 * @return bool TRUE if the year is a leap year, otherwise FALSE 19 */ 20 public static function isLeapYear($year): bool 21 { 22 return (($year % 4) === 0) && (($year % 100) !== 0) || (($year % 400) === 0); 23 } 24 25 /** 26 * getDateValue. 27 * 28 * @param mixed $dateValue 29 * 30 * @return float Excel date/time serial value 31 */ 32 public static function getDateValue($dateValue, bool $allowBool = true): float 33 { 34 if (is_object($dateValue)) { 35 $retval = SharedDateHelper::PHPToExcel($dateValue); 36 if (is_bool($retval)) { 37 throw new Exception(ExcelError::VALUE()); 38 } 39 40 return $retval; 41 } 42 43 self::nullFalseTrueToNumber($dateValue, $allowBool); 44 if (!is_numeric($dateValue)) { 45 $saveReturnDateType = Functions::getReturnDateType(); 46 Functions::setReturnDateType(Functions::RETURNDATE_EXCEL); 47 $dateValue = DateValue::fromString($dateValue); 48 Functions::setReturnDateType($saveReturnDateType); 49 if (!is_numeric($dateValue)) { 50 throw new Exception(ExcelError::VALUE()); 51 } 52 } 53 if ($dateValue < 0 && Functions::getCompatibilityMode() !== Functions::COMPATIBILITY_OPENOFFICE) { 54 throw new Exception(ExcelError::NAN()); 55 } 56 57 return (float) $dateValue; 58 } 59 60 /** 61 * getTimeValue. 62 * 63 * @param string $timeValue 64 * 65 * @return mixed Excel date/time serial value, or string if error 66 */ 67 public static function getTimeValue($timeValue) 68 { 69 $saveReturnDateType = Functions::getReturnDateType(); 70 Functions::setReturnDateType(Functions::RETURNDATE_EXCEL); 71 $timeValue = TimeValue::fromString($timeValue); 72 Functions::setReturnDateType($saveReturnDateType); 73 74 return $timeValue; 75 } 76 77 /** 78 * Adjust date by given months. 79 * 80 * @param mixed $dateValue 81 */ 82 public static function adjustDateByMonths($dateValue = 0, float $adjustmentMonths = 0): DateTime 83 { 84 // Execute function 85 $PHPDateObject = SharedDateHelper::excelToDateTimeObject($dateValue); 86 $oMonth = (int) $PHPDateObject->format('m'); 87 $oYear = (int) $PHPDateObject->format('Y'); 88 89 $adjustmentMonthsString = (string) $adjustmentMonths; 90 if ($adjustmentMonths > 0) { 91 $adjustmentMonthsString = '+' . $adjustmentMonths; 92 } 93 if ($adjustmentMonths != 0) { 94 $PHPDateObject->modify($adjustmentMonthsString . ' months'); 95 } 96 $nMonth = (int) $PHPDateObject->format('m'); 97 $nYear = (int) $PHPDateObject->format('Y'); 98 99 $monthDiff = ($nMonth - $oMonth) + (($nYear - $oYear) * 12); 100 if ($monthDiff != $adjustmentMonths) { 101 $adjustDays = (int) $PHPDateObject->format('d'); 102 $adjustDaysString = '-' . $adjustDays . ' days'; 103 $PHPDateObject->modify($adjustDaysString); 104 } 105 106 return $PHPDateObject; 107 } 108 109 /** 110 * Help reduce perceived complexity of some tests. 111 * 112 * @param mixed $value 113 * @param mixed $altValue 114 */ 115 public static function replaceIfEmpty(&$value, $altValue): void 116 { 117 $value = $value ?: $altValue; 118 } 119 120 /** 121 * Adjust year in ambiguous situations. 122 */ 123 public static function adjustYear(string $testVal1, string $testVal2, string &$testVal3): void 124 { 125 if (!is_numeric($testVal1) || $testVal1 < 31) { 126 if (!is_numeric($testVal2) || $testVal2 < 12) { 127 if (is_numeric($testVal3) && $testVal3 < 12) { 128 $testVal3 += 2000; 129 } 130 } 131 } 132 } 133 134 /** 135 * Return result in one of three formats. 136 * 137 * @return mixed 138 */ 139 public static function returnIn3FormatsArray(array $dateArray, bool $noFrac = false) 140 { 141 $retType = Functions::getReturnDateType(); 142 if ($retType === Functions::RETURNDATE_PHP_DATETIME_OBJECT) { 143 return new DateTime( 144 $dateArray['year'] 145 . '-' . $dateArray['month'] 146 . '-' . $dateArray['day'] 147 . ' ' . $dateArray['hour'] 148 . ':' . $dateArray['minute'] 149 . ':' . $dateArray['second'] 150 ); 151 } 152 $excelDateValue = 153 SharedDateHelper::formattedPHPToExcel( 154 $dateArray['year'], 155 $dateArray['month'], 156 $dateArray['day'], 157 $dateArray['hour'], 158 $dateArray['minute'], 159 $dateArray['second'] 160 ); 161 if ($retType === Functions::RETURNDATE_EXCEL) { 162 return $noFrac ? floor($excelDateValue) : (float) $excelDateValue; 163 } 164 // RETURNDATE_UNIX_TIMESTAMP) 165 166 return (int) SharedDateHelper::excelToTimestamp($excelDateValue); 167 } 168 169 /** 170 * Return result in one of three formats. 171 * 172 * @return mixed 173 */ 174 public static function returnIn3FormatsFloat(float $excelDateValue) 175 { 176 $retType = Functions::getReturnDateType(); 177 if ($retType === Functions::RETURNDATE_EXCEL) { 178 return $excelDateValue; 179 } 180 if ($retType === Functions::RETURNDATE_UNIX_TIMESTAMP) { 181 return (int) SharedDateHelper::excelToTimestamp($excelDateValue); 182 } 183 // RETURNDATE_PHP_DATETIME_OBJECT 184 185 return SharedDateHelper::excelToDateTimeObject($excelDateValue); 186 } 187 188 /** 189 * Return result in one of three formats. 190 * 191 * @return mixed 192 */ 193 public static function returnIn3FormatsObject(DateTime $PHPDateObject) 194 { 195 $retType = Functions::getReturnDateType(); 196 if ($retType === Functions::RETURNDATE_PHP_DATETIME_OBJECT) { 197 return $PHPDateObject; 198 } 199 if ($retType === Functions::RETURNDATE_EXCEL) { 200 return (float) SharedDateHelper::PHPToExcel($PHPDateObject); 201 } 202 // RETURNDATE_UNIX_TIMESTAMP 203 $stamp = SharedDateHelper::PHPToExcel($PHPDateObject); 204 $stamp = is_bool($stamp) ? ((int) $stamp) : $stamp; 205 206 return (int) SharedDateHelper::excelToTimestamp($stamp); 207 } 208 209 private static function baseDate(): int 210 { 211 if (Functions::getCompatibilityMode() === Functions::COMPATIBILITY_OPENOFFICE) { 212 return 0; 213 } 214 if (SharedDateHelper::getExcelCalendar() === SharedDateHelper::CALENDAR_MAC_1904) { 215 return 0; 216 } 217 218 return 1; 219 } 220 221 /** 222 * Many functions accept null/false/true argument treated as 0/0/1. 223 * 224 * @param mixed $number 225 */ 226 public static function nullFalseTrueToNumber(&$number, bool $allowBool = true): void 227 { 228 $number = Functions::flattenSingleValue($number); 229 $nullVal = self::baseDate(); 230 if ($number === null) { 231 $number = $nullVal; 232 } elseif ($allowBool && is_bool($number)) { 233 $number = $nullVal + (int) $number; 234 } 235 } 236 237 /** 238 * Many functions accept null argument treated as 0. 239 * 240 * @param mixed $number 241 * 242 * @return float|int 243 */ 244 public static function validateNumericNull($number) 245 { 246 $number = Functions::flattenSingleValue($number); 247 if ($number === null) { 248 return 0; 249 } 250 if (is_int($number)) { 251 return $number; 252 } 253 if (is_numeric($number)) { 254 return (float) $number; 255 } 256 257 throw new Exception(ExcelError::VALUE()); 258 } 259 260 /** 261 * Many functions accept null/false/true argument treated as 0/0/1. 262 * 263 * @param mixed $number 264 * 265 * @return float 266 */ 267 public static function validateNotNegative($number) 268 { 269 if (!is_numeric($number)) { 270 throw new Exception(ExcelError::VALUE()); 271 } 272 if ($number >= 0) { 273 return (float) $number; 274 } 275 276 throw new Exception(ExcelError::NAN()); 277 } 278 279 public static function silly1900(DateTime $PHPDateObject, string $mod = '-1 day'): void 280 { 281 $isoDate = $PHPDateObject->format('c'); 282 if ($isoDate < '1900-03-01') { 283 $PHPDateObject->modify($mod); 284 } 285 } 286 287 public static function dateParse(string $string): array 288 { 289 return self::forceArray(date_parse($string)); 290 } 291 292 public static function dateParseSucceeded(array $dateArray): bool 293 { 294 return $dateArray['error_count'] === 0; 295 } 296 297 /** 298 * Despite documentation, date_parse probably never returns false. 299 * Just in case, this routine helps guarantee it. 300 * 301 * @param array|false $dateArray 302 */ 303 private static function forceArray($dateArray): array 304 { 305 return is_array($dateArray) ? $dateArray : ['error_count' => 1]; 306 } 307 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body