diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 25f0fc47..61167005 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -575,21 +575,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Calculation/DateTimeExcel/TimeValue.php - - - message: "#^Binary operation \"/\" between int\\|string and \\(float\\|int\\) results in an error\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/DateTimeExcel/YearFrac.php - - - - message: "#^Binary operation \"/\" between int\\|string and 360 results in an error\\.$#" - count: 3 - path: src/PhpSpreadsheet/Calculation/DateTimeExcel/YearFrac.php - - - - message: "#^Binary operation \"/\" between int\\|string and 365 results in an error\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/DateTimeExcel/YearFrac.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Engine\\\\Logger\\:\\:writeDebugLog\\(\\) has parameter \\$args with no type specified\\.$#" count: 1 @@ -870,6 +855,11 @@ parameters: count: 1 path: src/PhpSpreadsheet/Calculation/Financial.php + - + message: "#^Parameter \\#1 \\$year of static method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\DateTimeExcel\\\\Helpers\\:\\:isLeapYear\\(\\) expects int\\|string, array\\|int\\|string given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Amortization.php + - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\\\Interest\\:\\:rateNextGuess\\(\\) has no return type specified\\.$#" count: 1 @@ -925,11 +915,21 @@ parameters: count: 1 path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/InterestAndPrincipal.php + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Variable\\\\NonPeriodic\\:\\:xnpvOrdered\\(\\) should return float\\|string but returns array\\|string\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Variable/NonPeriodic.php + - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Variable\\\\Periodic\\:\\:presentValue\\(\\) has parameter \\$args with no type specified\\.$#" count: 1 path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Variable/Periodic.php + - + message: "#^Parameter \\#1 \\$year of static method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Helpers\\:\\:daysPerYear\\(\\) expects int\\|string, array\\|int\\|string given\\.$#" + count: 3 + path: src/PhpSpreadsheet/Calculation/Financial/Coupons.php + - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Depreciation\\:\\:validateCost\\(\\) has parameter \\$cost with no type specified\\.$#" count: 1 @@ -975,11 +975,71 @@ parameters: count: 2 path: src/PhpSpreadsheet/Calculation/Financial/Dollar.php + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\AccruedInterest\\:\\:atMaturity\\(\\) should return float\\|string but returns array\\|string\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Securities/AccruedInterest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\AccruedInterest\\:\\:periodic\\(\\) should return float\\|string but returns array\\|string\\.$#" + count: 2 + path: src/PhpSpreadsheet/Calculation/Financial/Securities/AccruedInterest.php + - message: "#^Binary operation \"/\" between float\\|string and float\\|string results in an error\\.$#" count: 2 path: src/PhpSpreadsheet/Calculation/Financial/Securities/Price.php + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\Price\\:\\:priceAtMaturity\\(\\) should return float\\|string but returns array\\|string\\.$#" + count: 3 + path: src/PhpSpreadsheet/Calculation/Financial/Securities/Price.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\Price\\:\\:priceDiscounted\\(\\) should return float\\|string but returns array\\|string\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Securities/Price.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\Price\\:\\:received\\(\\) should return float\\|string but returns array\\|string\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Securities/Price.php + + - + message: "#^Parameter \\#1 \\$year of static method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Helpers\\:\\:daysPerYear\\(\\) expects int\\|string, array\\|int\\|string given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Securities/Price.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\Rates\\:\\:discount\\(\\) should return float\\|string but returns array\\|string\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Securities/Rates.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\Rates\\:\\:interest\\(\\) should return float\\|string but returns array\\|string\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Securities/Rates.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\Yields\\:\\:yieldAtMaturity\\(\\) should return float\\|string but returns array\\|string\\.$#" + count: 3 + path: src/PhpSpreadsheet/Calculation/Financial/Securities/Yields.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\Yields\\:\\:yieldDiscounted\\(\\) should return float\\|string but returns array\\|string\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Securities/Yields.php + + - + message: "#^Parameter \\#1 \\$year of static method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Helpers\\:\\:daysPerYear\\(\\) expects int\\|string, array\\|int\\|string given\\.$#" + count: 2 + path: src/PhpSpreadsheet/Calculation/Financial/Securities/Yields.php + + - + message: "#^Parameter \\#1 \\$year of static method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Helpers\\:\\:daysPerYear\\(\\) expects int\\|string, array\\|int\\|string given\\.$#" + count: 3 + path: src/PhpSpreadsheet/Calculation/Financial/TreasuryBill.php + - message: "#^Cannot call method getTokenSubType\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\FormulaToken\\|null\\.$#" count: 4 @@ -1916,7 +1976,7 @@ parameters: path: src/PhpSpreadsheet/Calculation/TextData/Format.php - - message: "#^Parameter \\#1 \\$dateValue of static method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\DateTimeExcel\\\\DateValue\\:\\:fromString\\(\\) expects string, mixed given\\.$#" + message: "#^Parameter \\#1 \\$dateValue of static method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\DateTimeExcel\\\\DateValue\\:\\:fromString\\(\\) expects array\\|string, mixed given\\.$#" count: 1 path: src/PhpSpreadsheet/Calculation/TextData/Format.php @@ -1931,7 +1991,7 @@ parameters: path: src/PhpSpreadsheet/Calculation/TextData/Format.php - - message: "#^Parameter \\#1 \\$timeValue of static method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\DateTimeExcel\\\\TimeValue\\:\\:fromString\\(\\) expects string, mixed given\\.$#" + message: "#^Parameter \\#1 \\$timeValue of static method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\DateTimeExcel\\\\TimeValue\\:\\:fromString\\(\\) expects array\\|string, mixed given\\.$#" count: 1 path: src/PhpSpreadsheet/Calculation/TextData/Format.php diff --git a/src/PhpSpreadsheet/Calculation/ArrayEnabled.php b/src/PhpSpreadsheet/Calculation/ArrayEnabled.php index bc852415..fa90017d 100644 --- a/src/PhpSpreadsheet/Calculation/ArrayEnabled.php +++ b/src/PhpSpreadsheet/Calculation/ArrayEnabled.php @@ -3,6 +3,7 @@ namespace PhpOffice\PhpSpreadsheet\Calculation; use PhpOffice\PhpSpreadsheet\Calculation\Engine\ArrayArgumentHelper; +use PhpOffice\PhpSpreadsheet\Calculation\Engine\ArrayArgumentProcessor; trait ArrayEnabled { @@ -37,154 +38,19 @@ trait ArrayEnabled self::initialiseHelper($arguments); $arguments = self::$arrayArgumentHelper->arguments(); - if (self::$arrayArgumentHelper->hasArrayArgument() === false) { - return [$method(...$arguments)]; - } - - if (self::$arrayArgumentHelper->arrayArguments() === 1) { - $nthArgument = self::$arrayArgumentHelper->getFirstArrayArgumentNumber(); - - return self::evaluateNthArgumentAsArray($method, $nthArgument, ...$arguments); - } - - $singleRowVectorIndex = self::$arrayArgumentHelper->getSingleRowVector(); - $singleColumnVectorIndex = self::$arrayArgumentHelper->getSingleColumnVector(); - if ($singleRowVectorIndex !== null && $singleColumnVectorIndex !== null) { - // Basic logic for a single row vector and a single column vector - return self::evaluateVectorPair($method, $singleRowVectorIndex, $singleColumnVectorIndex, ...$arguments); - } - - $matrixPair = self::$arrayArgumentHelper->getMatrixPair(); - if ($matrixPair !== []) { - if ( - (self::$arrayArgumentHelper->isVector($matrixPair[0]) === true && - self::$arrayArgumentHelper->isVector($matrixPair[1]) === false) || - (self::$arrayArgumentHelper->isVector($matrixPair[0]) === false && - self::$arrayArgumentHelper->isVector($matrixPair[1]) === true) - ) { - // Logic for a matrix and a vector (row or column) - return self::evaluateVectorMatrixPair($method, $matrixPair, ...$arguments); - } - // Logic for matrix/matrix, column vector/column vector or row vector/row vector - return self::evaluateMatrixPair($method, $matrixPair, ...$arguments); - } - - // Still need to work out the logic for more than two array arguments, - // For the moment, we're throwing an Exception when we initialise the ArrayArgumentHelper - return ['#VALUE!']; + return ArrayArgumentProcessor::processArguments(self::$arrayArgumentHelper, $method, ...$arguments); } /** * @param mixed ...$arguments */ - private static function evaluateVectorMatrixPair(callable $method, array $matrixIndexes, ...$arguments): array + protected static function evaluateArrayArgumentsSubset(callable $method, int $limit, ...$arguments): array { - $matrix2 = array_pop($matrixIndexes); - /** @var array $matrixValues2 */ - $matrixValues2 = $arguments[$matrix2]; - $matrix1 = array_pop($matrixIndexes); - /** @var array $matrixValues1 */ - $matrixValues1 = $arguments[$matrix1]; + self::initialiseHelper(array_slice($arguments, 0, $limit)); + $trailingArguments = array_slice($arguments, $limit); + $arguments = self::$arrayArgumentHelper->arguments(); + $arguments = array_merge($arguments, $trailingArguments); - $rows = min(array_map([self::$arrayArgumentHelper, 'rowCount'], [$matrix1, $matrix2])); - $columns = min(array_map([self::$arrayArgumentHelper, 'columnCount'], [$matrix1, $matrix2])); - - if ($rows === 1) { - $rows = max(array_map([self::$arrayArgumentHelper, 'rowCount'], [$matrix1, $matrix2])); - } - if ($columns === 1) { - $columns = max(array_map([self::$arrayArgumentHelper, 'columnCount'], [$matrix1, $matrix2])); - } - - $result = []; - for ($rowIndex = 0; $rowIndex < $rows; ++$rowIndex) { - for ($columnIndex = 0; $columnIndex < $columns; ++$columnIndex) { - $rowIndex1 = self::$arrayArgumentHelper->isRowVector($matrix1) ? 0 : $rowIndex; - $columnIndex1 = self::$arrayArgumentHelper->isColumnVector($matrix1) ? 0 : $columnIndex; - $value1 = $matrixValues1[$rowIndex1][$columnIndex1]; - $rowIndex2 = self::$arrayArgumentHelper->isRowVector($matrix2) ? 0 : $rowIndex; - $columnIndex2 = self::$arrayArgumentHelper->isColumnVector($matrix2) ? 0 : $columnIndex; - $value2 = $matrixValues2[$rowIndex2][$columnIndex2]; - $arguments[$matrix1] = $value1; - $arguments[$matrix2] = $value2; - - $result[$rowIndex][$columnIndex] = $method(...$arguments); - } - } - - return $result; - } - - /** - * @param mixed ...$arguments - */ - private static function evaluateMatrixPair(callable $method, array $matrixIndexes, ...$arguments): array - { - $matrix2 = array_pop($matrixIndexes); - /** @var array $matrixValues2 */ - $matrixValues2 = $arguments[$matrix2]; - $matrix1 = array_pop($matrixIndexes); - /** @var array $matrixValues1 */ - $matrixValues1 = $arguments[$matrix1]; - - $result = []; - foreach ($matrixValues1 as $rowIndex => $row) { - foreach ($row as $columnIndex => $value1) { - if (isset($matrixValues2[$rowIndex][$columnIndex]) === false) { - continue; - } - - $value2 = $matrixValues2[$rowIndex][$columnIndex]; - $arguments[$matrix1] = $value1; - $arguments[$matrix2] = $value2; - - $result[$rowIndex][$columnIndex] = $method(...$arguments); - } - } - - return $result; - } - - /** - * @param mixed ...$arguments - */ - private static function evaluateVectorPair(callable $method, int $rowIndex, int $columnIndex, ...$arguments): array - { - $rowVector = Functions::flattenArray($arguments[$rowIndex]); - $columnVector = Functions::flattenArray($arguments[$columnIndex]); - - $result = []; - foreach ($columnVector as $column) { - $rowResults = []; - foreach ($rowVector as $row) { - $arguments[$rowIndex] = $row; - $arguments[$columnIndex] = $column; - - $rowResults[] = $method(...$arguments); - } - $result[] = $rowResults; - } - - return $result; - } - - /** - * Note, offset is from 1 (for the first argument) rather than from 0. - * - * @param mixed ...$arguments - */ - private static function evaluateNthArgumentAsArray(callable $method, int $nthArgument, ...$arguments): array - { - $values = array_slice($arguments, $nthArgument - 1, 1); - /** @var array $values */ - $values = array_pop($values); - - $result = []; - foreach ($values as $value) { - $arguments[$nthArgument - 1] = $value; - $result[] = $method(...$arguments); - } - - return $result; + return ArrayArgumentProcessor::processArguments(self::$arrayArgumentHelper, $method, ...$arguments); } } diff --git a/src/PhpSpreadsheet/Calculation/Calculation.php b/src/PhpSpreadsheet/Calculation/Calculation.php index 20e877c2..f28d258e 100644 --- a/src/PhpSpreadsheet/Calculation/Calculation.php +++ b/src/PhpSpreadsheet/Calculation/Calculation.php @@ -4368,6 +4368,12 @@ class Calculation if (($operandData['reference'] === null) && (is_array($operand))) { $rKeys = array_keys($operand); $rowKey = array_shift($rKeys); + if (is_array($operand[$rowKey]) === false) { + $operandData['value'] = $operand[$rowKey]; + + return $operand[$rowKey]; + } + $cKeys = array_keys(array_keys($operand[$rowKey])); $colKey = array_shift($cKeys); if (ctype_upper("$colKey")) { diff --git a/src/PhpSpreadsheet/Calculation/DateTime.php b/src/PhpSpreadsheet/Calculation/DateTime.php index 44a38c19..79fa8dc0 100644 --- a/src/PhpSpreadsheet/Calculation/DateTime.php +++ b/src/PhpSpreadsheet/Calculation/DateTime.php @@ -278,9 +278,9 @@ class DateTime * or a standard date string * @param mixed $endDate Excel date serial value, PHP date/time stamp, PHP DateTime object * or a standard date string - * @param string $unit + * @param array|string $unit * - * @return int|string Interval between the dates + * @return array|int|string Interval between the dates */ public static function DATEDIF($startDate = 0, $endDate = 0, $unit = 'D') { @@ -300,12 +300,12 @@ class DateTime * @See DateTimeExcel\Days::between() * Use the between method in the DateTimeExcel\Days class instead * - * @param DateTimeInterface|float|int|string $endDate Excel date serial value (float), + * @param array|DateTimeInterface|float|int|string $endDate Excel date serial value (float), * PHP date timestamp (integer), PHP DateTime object, or a standard date string - * @param DateTimeInterface|float|int|string $startDate Excel date serial value (float), + * @param array|DateTimeInterface|float|int|string $startDate Excel date serial value (float), * PHP date timestamp (integer), PHP DateTime object, or a standard date string * - * @return int|string Number of days between start date and end date or an error + * @return array|int|string Number of days between start date and end date or an error */ public static function DAYS($endDate = 0, $startDate = 0) { @@ -331,7 +331,7 @@ class DateTime * PHP DateTime object, or a standard date string * @param mixed $endDate Excel date serial value (float), PHP date timestamp (integer), * PHP DateTime object, or a standard date string - * @param bool $method US or European Method + * @param array|bool $method US or European Method * FALSE or omitted: U.S. (NASD) method. If the starting date is * the last day of a month, it becomes equal to the 30th of the * same month. If the ending date is the last day of a month and @@ -343,7 +343,7 @@ class DateTime * occur on the 31st of a month become equal to the 30th of the * same month. * - * @return int|string Number of days between start date and end date + * @return array|int|string Number of days between start date and end date */ public static function DAYS360($startDate = 0, $endDate = 0, $method = false) { @@ -373,14 +373,14 @@ class DateTime * PHP DateTime object, or a standard date string * @param mixed $endDate Excel date serial value (float), PHP date timestamp (integer), * PHP DateTime object, or a standard date string - * @param int $method Method used for the calculation + * @param array|int $method Method used for the calculation * 0 or omitted US (NASD) 30/360 * 1 Actual/actual * 2 Actual/360 * 3 Actual/365 * 4 European 30/360 * - * @return float|string fraction of the year, or a string containing an error + * @return array|float|string fraction of the year, or a string containing an error */ public static function YEARFRAC($startDate = 0, $endDate = 0, $method = 0) { @@ -409,7 +409,7 @@ class DateTime * PHP DateTime object, or a standard date string * @param mixed $dateArgs * - * @return int|string Interval between the dates + * @return array|int|string Interval between the dates */ public static function NETWORKDAYS($startDate, $endDate, ...$dateArgs) { @@ -464,7 +464,7 @@ class DateTime * @param mixed $dateValue Excel date serial value (float), PHP date timestamp (integer), * PHP DateTime object, or a standard date string * - * @return int|string Day of the month + * @return array|int|string Day of the month */ public static function DAYOFMONTH($dateValue = 1) { @@ -492,7 +492,7 @@ class DateTime * 2 Numbers 1 (Monday) through 7 (Sunday). * 3 Numbers 0 (Monday) through 6 (Sunday). * - * @return int|string Day of the week value + * @return array|int|string Day of the week value */ public static function WEEKDAY($dateValue = 1, $style = 1) { @@ -704,7 +704,7 @@ class DateTime * 17 Week begins on Sunday. * 21 ISO (Jan. 4 is week 1, begins on Monday). * - * @return int|string Week Number + * @return array|int|string Week Number */ public static function WEEKNUM($dateValue = 1, $method = self::STARTWEEK_SUNDAY) { @@ -727,7 +727,7 @@ class DateTime * @param mixed $dateValue Excel date serial value (float), PHP date timestamp (integer), * PHP DateTime object, or a standard date string * - * @return int|string Week Number + * @return array|int|string Week Number */ public static function ISOWEEKNUM($dateValue = 1) { @@ -751,7 +751,7 @@ class DateTime * @param mixed $dateValue Excel date serial value (float), PHP date timestamp (integer), * PHP DateTime object, or a standard date string * - * @return int|string Month of the year + * @return array|int|string Month of the year */ public static function MONTHOFYEAR($dateValue = 1) { @@ -775,7 +775,7 @@ class DateTime * @param mixed $dateValue Excel date serial value (float), PHP date timestamp (integer), * PHP DateTime object, or a standard date string * - * @return int|string Year + * @return array|int|string Year */ public static function YEAR($dateValue = 1) { @@ -799,7 +799,7 @@ class DateTime * @param mixed $timeValue Excel date serial value (float), PHP date timestamp (integer), * PHP DateTime object, or a standard time string * - * @return int|string Hour + * @return array|int|string Hour */ public static function HOUROFDAY($timeValue = 0) { @@ -823,7 +823,7 @@ class DateTime * @param mixed $timeValue Excel date serial value (float), PHP date timestamp (integer), * PHP DateTime object, or a standard time string * - * @return int|string Minute + * @return array|int|string Minute */ public static function MINUTE($timeValue = 0) { @@ -847,7 +847,7 @@ class DateTime * @param mixed $timeValue Excel date serial value (float), PHP date timestamp (integer), * PHP DateTime object, or a standard time string * - * @return int|string Second + * @return array|int|string Second */ public static function SECOND($timeValue = 0) { diff --git a/src/PhpSpreadsheet/Calculation/DateTimeExcel/DateParts.php b/src/PhpSpreadsheet/Calculation/DateTimeExcel/DateParts.php index 37ea0315..b669eb0a 100644 --- a/src/PhpSpreadsheet/Calculation/DateTimeExcel/DateParts.php +++ b/src/PhpSpreadsheet/Calculation/DateTimeExcel/DateParts.php @@ -2,12 +2,15 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel; +use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled; use PhpOffice\PhpSpreadsheet\Calculation\Exception; use PhpOffice\PhpSpreadsheet\Calculation\Functions; use PhpOffice\PhpSpreadsheet\Shared\Date as SharedDateHelper; class DateParts { + use ArrayEnabled; + /** * DAYOFMONTH. * @@ -19,11 +22,18 @@ class DateParts * * @param mixed $dateValue Excel date serial value (float), PHP date timestamp (integer), * PHP DateTime object, or a standard date string + * Or can be an array of date values * - * @return int|string Day of the month + * @return array|int|string Day of the month + * If an array of numbers is passed as the argument, then the returned result will also be an array + * with the same dimensions */ public static function day($dateValue) { + if (is_array($dateValue)) { + return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $dateValue); + } + $weirdResult = self::weirdCondition($dateValue); if ($weirdResult >= 0) { return $weirdResult; @@ -52,11 +62,18 @@ class DateParts * * @param mixed $dateValue Excel date serial value (float), PHP date timestamp (integer), * PHP DateTime object, or a standard date string + * Or can be an array of date values * - * @return int|string Month of the year + * @return array|int|string Month of the year + * If an array of numbers is passed as the argument, then the returned result will also be an array + * with the same dimensions */ public static function month($dateValue) { + if (is_array($dateValue)) { + return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $dateValue); + } + try { $dateValue = Helpers::getDateValue($dateValue); } catch (Exception $e) { @@ -83,11 +100,18 @@ class DateParts * * @param mixed $dateValue Excel date serial value (float), PHP date timestamp (integer), * PHP DateTime object, or a standard date string + * Or can be an array of date values * - * @return int|string Year + * @return array|int|string Year + * If an array of numbers is passed as the argument, then the returned result will also be an array + * with the same dimensions */ public static function year($dateValue) { + if (is_array($dateValue)) { + return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $dateValue); + } + try { $dateValue = Helpers::getDateValue($dateValue); } catch (Exception $e) { diff --git a/src/PhpSpreadsheet/Calculation/DateTimeExcel/DateValue.php b/src/PhpSpreadsheet/Calculation/DateTimeExcel/DateValue.php index 3b215506..f8fe3e8a 100644 --- a/src/PhpSpreadsheet/Calculation/DateTimeExcel/DateValue.php +++ b/src/PhpSpreadsheet/Calculation/DateTimeExcel/DateValue.php @@ -3,11 +3,14 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel; use DateTimeImmutable; +use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled; use PhpOffice\PhpSpreadsheet\Calculation\Functions; use PhpOffice\PhpSpreadsheet\Shared\Date as SharedDateHelper; class DateValue { + use ArrayEnabled; + /** * DATEVALUE. * @@ -21,7 +24,7 @@ class DateValue * Excel Function: * DATEVALUE(dateValue) * - * @param string $dateValue Text that represents a date in a Microsoft Excel date format. + * @param array|string $dateValue Text that represents a date in a Microsoft Excel date format. * For example, "1/30/2008" or "30-Jan-2008" are text strings within * quotation marks that represent dates. Using the default date * system in Excel for Windows, date_text must represent a date from @@ -29,12 +32,19 @@ class DateValue * system in Excel for the Macintosh, date_text must represent a date * from January 1, 1904, to December 31, 9999. DATEVALUE returns the * #VALUE! error value if date_text is out of this range. + * Or can be an array of date values * * @return mixed Excel date/time serial value, PHP date/time serial value or PHP date/time object, * depending on the value of the ReturnDateType flag + * If an array of numbers is passed as the argument, then the returned result will also be an array + * with the same dimensions */ public static function fromString($dateValue) { + if (is_array($dateValue)) { + return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $dateValue); + } + $dti = new DateTimeImmutable(); $baseYear = SharedDateHelper::getExcelCalendar(); $dateValue = trim(Functions::flattenSingleValue($dateValue ?? ''), '"'); diff --git a/src/PhpSpreadsheet/Calculation/DateTimeExcel/Days.php b/src/PhpSpreadsheet/Calculation/DateTimeExcel/Days.php index 5a97d8df..5392b2c3 100644 --- a/src/PhpSpreadsheet/Calculation/DateTimeExcel/Days.php +++ b/src/PhpSpreadsheet/Calculation/DateTimeExcel/Days.php @@ -3,12 +3,15 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel; use DateTimeInterface; +use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled; use PhpOffice\PhpSpreadsheet\Calculation\Exception; use PhpOffice\PhpSpreadsheet\Calculation\Functions; use PhpOffice\PhpSpreadsheet\Shared\Date as SharedDateHelper; class Days { + use ArrayEnabled; + /** * DAYS. * @@ -17,15 +20,23 @@ class Days * Excel Function: * DAYS(endDate, startDate) * - * @param DateTimeInterface|float|int|string $endDate Excel date serial value (float), - * PHP date timestamp (integer), PHP DateTime object, or a standard date string - * @param DateTimeInterface|float|int|string $startDate Excel date serial value (float), - * PHP date timestamp (integer), PHP DateTime object, or a standard date string + * @param array|DateTimeInterface|float|int|string $endDate Excel date serial value (float), + * PHP date timestamp (integer), PHP DateTime object, or a standard date string + * Or can be an array of date values + * @param array|DateTimeInterface|float|int|string $startDate Excel date serial value (float), + * PHP date timestamp (integer), PHP DateTime object, or a standard date string + * Or can be an array of date values * - * @return int|string Number of days between start date and end date or an error + * @return array|int|string Number of days between start date and end date or an error + * If an array of values is passed for the $startDate or $endDays,arguments, then the returned result + * will also be an array with matching dimensions */ public static function between($endDate, $startDate) { + if (is_array($endDate) || is_array($startDate)) { + return self::evaluateArrayArguments([self::class, __FUNCTION__], $endDate, $startDate); + } + try { $startDate = Helpers::getDateValue($startDate); $endDate = Helpers::getDateValue($endDate); diff --git a/src/PhpSpreadsheet/Calculation/DateTimeExcel/Days360.php b/src/PhpSpreadsheet/Calculation/DateTimeExcel/Days360.php index bbc5d16a..2220aaee 100644 --- a/src/PhpSpreadsheet/Calculation/DateTimeExcel/Days360.php +++ b/src/PhpSpreadsheet/Calculation/DateTimeExcel/Days360.php @@ -2,12 +2,15 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel; +use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled; use PhpOffice\PhpSpreadsheet\Calculation\Exception; use PhpOffice\PhpSpreadsheet\Calculation\Functions; use PhpOffice\PhpSpreadsheet\Shared\Date as SharedDateHelper; class Days360 { + use ArrayEnabled; + /** * DAYS360. * @@ -18,11 +21,13 @@ class Days360 * Excel Function: * DAYS360(startDate,endDate[,method]) * - * @param mixed $startDate Excel date serial value (float), PHP date timestamp (integer), + * @param array|mixed $startDate Excel date serial value (float), PHP date timestamp (integer), * PHP DateTime object, or a standard date string - * @param mixed $endDate Excel date serial value (float), PHP date timestamp (integer), + * Or can be an array of date values + * @param array|mixed $endDate Excel date serial value (float), PHP date timestamp (integer), * PHP DateTime object, or a standard date string - * @param mixed $method US or European Method as a bool + * Or can be an array of date values + * @param array|mixed $method US or European Method as a bool * FALSE or omitted: U.S. (NASD) method. If the starting date is * the last day of a month, it becomes equal to the 30th of the * same month. If the ending date is the last day of a month and @@ -33,11 +38,18 @@ class Days360 * TRUE: European method. Starting dates and ending dates that * occur on the 31st of a month become equal to the 30th of the * same month. + * Or can be an array of methods * - * @return int|string Number of days between start date and end date + * @return array|int|string Number of days between start date and end date + * If an array of values is passed for the $startDate or $endDays,arguments, then the returned result + * will also be an array with matching dimensions */ public static function between($startDate = 0, $endDate = 0, $method = false) { + if (is_array($startDate) || is_array($endDate) || is_array($method)) { + return self::evaluateArrayArguments([self::class, __FUNCTION__], $startDate, $endDate, $method); + } + try { $startDate = Helpers::getDateValue($startDate); $endDate = Helpers::getDateValue($endDate); diff --git a/src/PhpSpreadsheet/Calculation/DateTimeExcel/Difference.php b/src/PhpSpreadsheet/Calculation/DateTimeExcel/Difference.php index 6adeca17..1f4812f2 100644 --- a/src/PhpSpreadsheet/Calculation/DateTimeExcel/Difference.php +++ b/src/PhpSpreadsheet/Calculation/DateTimeExcel/Difference.php @@ -4,25 +4,37 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel; use DateInterval; use DateTime; +use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled; use PhpOffice\PhpSpreadsheet\Calculation\Exception; use PhpOffice\PhpSpreadsheet\Calculation\Functions; use PhpOffice\PhpSpreadsheet\Shared\Date as SharedDateHelper; class Difference { + use ArrayEnabled; + /** * DATEDIF. * * @param mixed $startDate Excel date serial value, PHP date/time stamp, PHP DateTime object * or a standard date string + * Or can be an array of date values * @param mixed $endDate Excel date serial value, PHP date/time stamp, PHP DateTime object * or a standard date string - * @param string $unit + * Or can be an array of date values + * @param array|string $unit + * Or can be an array of unit values * - * @return int|string Interval between the dates + * @return array|int|string Interval between the dates + * If an array of values is passed for the $startDate or $endDays,arguments, then the returned result + * will also be an array with matching dimensions */ public static function interval($startDate, $endDate, $unit = 'D') { + if (is_array($startDate) || is_array($endDate) || is_array($unit)) { + return self::evaluateArrayArguments([self::class, __FUNCTION__], $startDate, $endDate, $unit); + } + try { $startDate = Helpers::getDateValue($startDate); $endDate = Helpers::getDateValue($endDate); diff --git a/src/PhpSpreadsheet/Calculation/DateTimeExcel/Month.php b/src/PhpSpreadsheet/Calculation/DateTimeExcel/Month.php index 560b7a80..c72d006b 100644 --- a/src/PhpSpreadsheet/Calculation/DateTimeExcel/Month.php +++ b/src/PhpSpreadsheet/Calculation/DateTimeExcel/Month.php @@ -2,10 +2,13 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel; +use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled; use PhpOffice\PhpSpreadsheet\Calculation\Exception; class Month { + use ArrayEnabled; + /** * EDATE. * @@ -19,15 +22,23 @@ class Month * * @param mixed $dateValue Excel date serial value (float), PHP date timestamp (integer), * PHP DateTime object, or a standard date string - * @param int $adjustmentMonths The number of months before or after start_date. + * Or can be an array of date values + * @param array|int $adjustmentMonths The number of months before or after start_date. * A positive value for months yields a future date; * a negative value yields a past date. + * Or can be an array of adjustment values * - * @return mixed Excel date/time serial value, PHP date/time serial value or PHP date/time object, + * @return array|mixed Excel date/time serial value, PHP date/time serial value or PHP date/time object, * depending on the value of the ReturnDateType flag + * If an array of values is passed as the argument, then the returned result will also be an array + * with the same dimensions */ public static function adjust($dateValue, $adjustmentMonths) { + if (is_array($dateValue) || is_array($adjustmentMonths)) { + return self::evaluateArrayArguments([self::class, __FUNCTION__], $dateValue, $adjustmentMonths); + } + try { $dateValue = Helpers::getDateValue($dateValue, false); $adjustmentMonths = Helpers::validateNumericNull($adjustmentMonths); @@ -54,15 +65,23 @@ class Month * * @param mixed $dateValue Excel date serial value (float), PHP date timestamp (integer), * PHP DateTime object, or a standard date string - * @param int $adjustmentMonths The number of months before or after start_date. + * Or can be an array of date values + * @param array|int $adjustmentMonths The number of months before or after start_date. * A positive value for months yields a future date; * a negative value yields a past date. + * Or can be an array of adjustment values * - * @return mixed Excel date/time serial value, PHP date/time serial value or PHP date/time object, + * @return array|mixed Excel date/time serial value, PHP date/time serial value or PHP date/time object, * depending on the value of the ReturnDateType flag + * If an array of values is passed as the argument, then the returned result will also be an array + * with the same dimensions */ public static function lastDay($dateValue, $adjustmentMonths) { + if (is_array($dateValue) || is_array($adjustmentMonths)) { + return self::evaluateArrayArguments([self::class, __FUNCTION__], $dateValue, $adjustmentMonths); + } + try { $dateValue = Helpers::getDateValue($dateValue, false); $adjustmentMonths = Helpers::validateNumericNull($adjustmentMonths); diff --git a/src/PhpSpreadsheet/Calculation/DateTimeExcel/NetworkDays.php b/src/PhpSpreadsheet/Calculation/DateTimeExcel/NetworkDays.php index d0f53cf3..9a87af27 100644 --- a/src/PhpSpreadsheet/Calculation/DateTimeExcel/NetworkDays.php +++ b/src/PhpSpreadsheet/Calculation/DateTimeExcel/NetworkDays.php @@ -2,11 +2,14 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel; +use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled; use PhpOffice\PhpSpreadsheet\Calculation\Exception; use PhpOffice\PhpSpreadsheet\Calculation\Functions; class NetworkDays { + use ArrayEnabled; + /** * NETWORKDAYS. * @@ -20,14 +23,26 @@ class NetworkDays * * @param mixed $startDate Excel date serial value (float), PHP date timestamp (integer), * PHP DateTime object, or a standard date string + * Or can be an array of date values * @param mixed $endDate Excel date serial value (float), PHP date timestamp (integer), * PHP DateTime object, or a standard date string - * @param mixed $dateArgs + * Or can be an array of date values + * @param mixed $dateArgs An array of dates (such as holidays) to exclude from the calculation * - * @return int|string Interval between the dates + * @return array|int|string Interval between the dates */ public static function count($startDate, $endDate, ...$dateArgs) { + if (is_array($startDate) || is_array($endDate)) { + return self::evaluateArrayArgumentsSubset( + [self::class, __FUNCTION__], + 2, + $startDate, + $endDate, + ...$dateArgs + ); + } + try { // Retrieve the mandatory start and end date that are referenced in the function definition $sDate = Helpers::getDateValue($startDate); diff --git a/src/PhpSpreadsheet/Calculation/DateTimeExcel/Time.php b/src/PhpSpreadsheet/Calculation/DateTimeExcel/Time.php index fb5e4965..e176e6e1 100644 --- a/src/PhpSpreadsheet/Calculation/DateTimeExcel/Time.php +++ b/src/PhpSpreadsheet/Calculation/DateTimeExcel/Time.php @@ -3,12 +3,15 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel; use DateTime; +use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled; use PhpOffice\PhpSpreadsheet\Calculation\Exception; use PhpOffice\PhpSpreadsheet\Calculation\Functions; use PhpOffice\PhpSpreadsheet\Shared\Date as SharedDateHelper; class Time { + use ArrayEnabled; + /** * TIME. * @@ -20,23 +23,31 @@ class Time * Excel Function: * TIME(hour,minute,second) * - * @param mixed $hour A number from 0 (zero) to 32767 representing the hour. + * @param array|int $hour A number from 0 (zero) to 32767 representing the hour. * Any value greater than 23 will be divided by 24 and the remainder * will be treated as the hour value. For example, TIME(27,0,0) = * TIME(3,0,0) = .125 or 3:00 AM. - * @param mixed $minute A number from 0 to 32767 representing the minute. + * @param array|int $minute A number from 0 to 32767 representing the minute. * Any value greater than 59 will be converted to hours and minutes. * For example, TIME(0,750,0) = TIME(12,30,0) = .520833 or 12:30 PM. - * @param mixed $second A number from 0 to 32767 representing the second. + * @param array|int $second A number from 0 to 32767 representing the second. * Any value greater than 59 will be converted to hours, minutes, * and seconds. For example, TIME(0,0,2000) = TIME(0,33,22) = .023148 * or 12:33:20 AM + * If an array of numbers is passed as the argument, then the returned result will also be an array + * with the same dimensions * - * @return mixed Excel date/time serial value, PHP date/time serial value or PHP date/time object, + * @return array|mixed Excel date/time serial value, PHP date/time serial value or PHP date/time object, * depending on the value of the ReturnDateType flag + * If an array of numbers is passed as the argument, then the returned result will also be an array + * with the same dimensions */ public static function fromHMS($hour, $minute, $second) { + if (is_array($hour) || is_array($minute) || is_array($second)) { + return self::evaluateArrayArguments([self::class, __FUNCTION__], $hour, $minute, $second); + } + try { $hour = self::toIntWithNullBool($hour); $minute = self::toIntWithNullBool($minute); diff --git a/src/PhpSpreadsheet/Calculation/DateTimeExcel/TimeParts.php b/src/PhpSpreadsheet/Calculation/DateTimeExcel/TimeParts.php index 49cd983d..7969e4e3 100644 --- a/src/PhpSpreadsheet/Calculation/DateTimeExcel/TimeParts.php +++ b/src/PhpSpreadsheet/Calculation/DateTimeExcel/TimeParts.php @@ -2,12 +2,15 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel; +use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled; use PhpOffice\PhpSpreadsheet\Calculation\Exception; use PhpOffice\PhpSpreadsheet\Calculation\Functions; use PhpOffice\PhpSpreadsheet\Shared\Date as SharedDateHelper; class TimeParts { + use ArrayEnabled; + /** * HOUROFDAY. * @@ -19,11 +22,18 @@ class TimeParts * * @param mixed $timeValue Excel date serial value (float), PHP date timestamp (integer), * PHP DateTime object, or a standard time string + * Or can be an array of date/time values * - * @return int|string Hour + * @return array|int|string Hour + * If an array of numbers is passed as the argument, then the returned result will also be an array + * with the same dimensions */ public static function hour($timeValue) { + if (is_array($timeValue)) { + return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $timeValue); + } + try { $timeValue = Functions::flattenSingleValue($timeValue); Helpers::nullFalseTrueToNumber($timeValue); @@ -53,11 +63,18 @@ class TimeParts * * @param mixed $timeValue Excel date serial value (float), PHP date timestamp (integer), * PHP DateTime object, or a standard time string + * Or can be an array of date/time values * - * @return int|string Minute + * @return array|int|string Minute + * If an array of numbers is passed as the argument, then the returned result will also be an array + * with the same dimensions */ public static function minute($timeValue) { + if (is_array($timeValue)) { + return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $timeValue); + } + try { $timeValue = Functions::flattenSingleValue($timeValue); Helpers::nullFalseTrueToNumber($timeValue); @@ -87,11 +104,18 @@ class TimeParts * * @param mixed $timeValue Excel date serial value (float), PHP date timestamp (integer), * PHP DateTime object, or a standard time string + * Or can be an array of date/time values * - * @return int|string Second + * @return array|int|string Second + * If an array of numbers is passed as the argument, then the returned result will also be an array + * with the same dimensions */ public static function second($timeValue) { + if (is_array($timeValue)) { + return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $timeValue); + } + try { $timeValue = Functions::flattenSingleValue($timeValue); Helpers::nullFalseTrueToNumber($timeValue); diff --git a/src/PhpSpreadsheet/Calculation/DateTimeExcel/TimeValue.php b/src/PhpSpreadsheet/Calculation/DateTimeExcel/TimeValue.php index c9645e66..5a36f1b0 100644 --- a/src/PhpSpreadsheet/Calculation/DateTimeExcel/TimeValue.php +++ b/src/PhpSpreadsheet/Calculation/DateTimeExcel/TimeValue.php @@ -3,11 +3,14 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel; use Datetime; +use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled; use PhpOffice\PhpSpreadsheet\Calculation\Functions; use PhpOffice\PhpSpreadsheet\Shared\Date as SharedDateHelper; class TimeValue { + use ArrayEnabled; + /** * TIMEVALUE. * @@ -21,16 +24,23 @@ class TimeValue * Excel Function: * TIMEVALUE(timeValue) * - * @param string $timeValue A text string that represents a time in any one of the Microsoft + * @param array|string $timeValue A text string that represents a time in any one of the Microsoft * Excel time formats; for example, "6:45 PM" and "18:45" text strings * within quotation marks that represent time. * Date information in time_text is ignored. + * Or can be an array of date/time values * * @return mixed Excel date/time serial value, PHP date/time serial value or PHP date/time object, * depending on the value of the ReturnDateType flag + * If an array of numbers is passed as the argument, then the returned result will also be an array + * with the same dimensions */ public static function fromString($timeValue) { + if (is_array($timeValue)) { + return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $timeValue); + } + $timeValue = trim(Functions::flattenSingleValue($timeValue ?? ''), '"'); $timeValue = str_replace(['/', '.'], '-', $timeValue); diff --git a/src/PhpSpreadsheet/Calculation/DateTimeExcel/Week.php b/src/PhpSpreadsheet/Calculation/DateTimeExcel/Week.php index 66362221..cc51d24f 100644 --- a/src/PhpSpreadsheet/Calculation/DateTimeExcel/Week.php +++ b/src/PhpSpreadsheet/Calculation/DateTimeExcel/Week.php @@ -3,12 +3,15 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel; use DateTime; +use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled; use PhpOffice\PhpSpreadsheet\Calculation\Exception; use PhpOffice\PhpSpreadsheet\Calculation\Functions; use PhpOffice\PhpSpreadsheet\Shared\Date as SharedDateHelper; class Week { + use ArrayEnabled; + /** * WEEKNUM. * @@ -24,7 +27,8 @@ class Week * * @param mixed $dateValue Excel date serial value (float), PHP date timestamp (integer), * PHP DateTime object, or a standard date string - * @param int $method Week begins on Sunday or Monday + * Or can be an array of date values + * @param array|int $method Week begins on Sunday or Monday * 1 or omitted Week begins on Sunday. * 2 Week begins on Monday. * 11 Week begins on Monday. @@ -35,11 +39,18 @@ class Week * 16 Week begins on Saturday. * 17 Week begins on Sunday. * 21 ISO (Jan. 4 is week 1, begins on Monday). + * Or can be an array of methods * - * @return int|string Week Number + * @return array|int|string Week Number + * If an array of values is passed as the argument, then the returned result will also be an array + * with the same dimensions */ public static function number($dateValue, $method = Constants::STARTWEEK_SUNDAY) { + if (is_array($dateValue) || is_array($method)) { + return self::evaluateArrayArguments([self::class, __FUNCTION__], $dateValue, $method); + } + $origDateValueNull = empty($dateValue); try { @@ -88,11 +99,18 @@ class Week * * @param mixed $dateValue Excel date serial value (float), PHP date timestamp (integer), * PHP DateTime object, or a standard date string + * Or can be an array of date values * - * @return int|string Week Number + * @return array|int|string Week Number + * If an array of numbers is passed as the argument, then the returned result will also be an array + * with the same dimensions */ public static function isoWeekNumber($dateValue) { + if (is_array($dateValue)) { + return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $dateValue); + } + if (self::apparentBug($dateValue)) { return 52; } @@ -119,17 +137,25 @@ class Week * Excel Function: * WEEKDAY(dateValue[,style]) * - * @param null|float|int|string $dateValue Excel date serial value (float), PHP date timestamp (integer), + * @param null|array|float|int|string $dateValue Excel date serial value (float), PHP date timestamp (integer), * PHP DateTime object, or a standard date string + * Or can be an array of date values * @param mixed $style A number that determines the type of return value * 1 or omitted Numbers 1 (Sunday) through 7 (Saturday). * 2 Numbers 1 (Monday) through 7 (Sunday). * 3 Numbers 0 (Monday) through 6 (Sunday). + * Or can be an array of styles * - * @return int|string Day of the week value + * @return array|int|string Day of the week value + * If an array of values is passed as the argument, then the returned result will also be an array + * with the same dimensions */ public static function day($dateValue, $style = 1) { + if (is_array($dateValue) || is_array($style)) { + return self::evaluateArrayArguments([self::class, __FUNCTION__], $dateValue, $style); + } + try { $dateValue = Helpers::getDateValue($dateValue); $style = self::validateStyle($style); diff --git a/src/PhpSpreadsheet/Calculation/DateTimeExcel/WorkDay.php b/src/PhpSpreadsheet/Calculation/DateTimeExcel/WorkDay.php index 89e47b96..1f5735e8 100644 --- a/src/PhpSpreadsheet/Calculation/DateTimeExcel/WorkDay.php +++ b/src/PhpSpreadsheet/Calculation/DateTimeExcel/WorkDay.php @@ -2,11 +2,14 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel; +use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled; use PhpOffice\PhpSpreadsheet\Calculation\Exception; use PhpOffice\PhpSpreadsheet\Calculation\Functions; class WorkDay { + use ArrayEnabled; + /** * WORKDAY. * @@ -18,27 +21,37 @@ class WorkDay * Excel Function: * WORKDAY(startDate,endDays[,holidays[,holiday[,...]]]) * - * @param mixed $startDate Excel date serial value (float), PHP date timestamp (integer), + * @param array|mixed $startDate Excel date serial value (float), PHP date timestamp (integer), * PHP DateTime object, or a standard date string - * @param int $endDays The number of nonweekend and nonholiday days before or after + * Or can be an array of date values + * @param array|int $endDays The number of nonweekend and nonholiday days before or after * startDate. A positive value for days yields a future date; a * negative value yields a past date. - * @param mixed $dateArgs + * Or can be an array of int values + * @param null|mixed $dateArgs An array of dates (such as holidays) to exclude from the calculation * - * @return mixed Excel date/time serial value, PHP date/time serial value or PHP date/time object, + * @return array|mixed Excel date/time serial value, PHP date/time serial value or PHP date/time object, * depending on the value of the ReturnDateType flag + * If an array of values is passed for the $startDate or $endDays,arguments, then the returned result + * will also be an array with matching dimensions */ public static function date($startDate, $endDays, ...$dateArgs) { + if (is_array($startDate) || is_array($endDays)) { + return self::evaluateArrayArgumentsSubset( + [self::class, __FUNCTION__], + 2, + $startDate, + $endDays, + ...$dateArgs + ); + } + // Retrieve the mandatory start date and days that are referenced in the function definition try { $startDate = Helpers::getDateValue($startDate); $endDays = Helpers::validateNumericNull($endDays); - $dateArgs = Functions::flattenArray($dateArgs); - $holidayArray = []; - foreach ($dateArgs as $holidayDate) { - $holidayArray[] = Helpers::getDateValue($holidayDate); - } + $holidayArray = array_map([Helpers::class, 'getDateValue'], Functions::flattenArray($dateArgs)); } catch (Exception $e) { return $e->getMessage(); } @@ -64,9 +77,8 @@ class WorkDay private static function incrementing(float $startDate, int $endDays, array $holidayArray) { // Adjust the start date if it falls over a weekend - $startDoW = self::getWeekDay($startDate, 3); - if (self::getWeekDay($startDate, 3) >= 5) { + if ($startDoW >= 5) { $startDate += 7 - $startDoW; --$endDays; } @@ -126,9 +138,8 @@ class WorkDay private static function decrementing(float $startDate, int $endDays, array $holidayArray) { // Adjust the start date if it falls over a weekend - $startDoW = self::getWeekDay($startDate, 3); - if (self::getWeekDay($startDate, 3) >= 5) { + if ($startDoW >= 5) { $startDate += -$startDoW + 4; ++$endDays; } @@ -172,6 +183,7 @@ class WorkDay } // Adjust the calculated end date if it falls over a weekend $endDoW = self::getWeekDay($endDate, 3); + /** int $endDoW */ if ($endDoW >= 5) { $endDate += -$endDoW + 4; } @@ -182,8 +194,8 @@ class WorkDay private static function getWeekDay(float $date, int $wd): int { - $result = Week::day($date, $wd); + $result = Functions::scalar(Week::day($date, $wd)); - return is_string($result) ? -1 : $result; + return is_int($result) ? $result : -1; } } diff --git a/src/PhpSpreadsheet/Calculation/DateTimeExcel/YearFrac.php b/src/PhpSpreadsheet/Calculation/DateTimeExcel/YearFrac.php index da2ac12f..6babf633 100644 --- a/src/PhpSpreadsheet/Calculation/DateTimeExcel/YearFrac.php +++ b/src/PhpSpreadsheet/Calculation/DateTimeExcel/YearFrac.php @@ -2,12 +2,15 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel; +use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled; use PhpOffice\PhpSpreadsheet\Calculation\Exception; use PhpOffice\PhpSpreadsheet\Calculation\Functions; use PhpOffice\PhpSpreadsheet\Shared\Date as SharedDateHelper; class YearFrac { + use ArrayEnabled; + /** * YEARFRAC. * @@ -23,19 +26,28 @@ class YearFrac * * @param mixed $startDate Excel date serial value (float), PHP date timestamp (integer), * PHP DateTime object, or a standard date string + * Or can be an array of methods * @param mixed $endDate Excel date serial value (float), PHP date timestamp (integer), * PHP DateTime object, or a standard date string - * @param int $method Method used for the calculation + * Or can be an array of methods + * @param array|int $method Method used for the calculation * 0 or omitted US (NASD) 30/360 * 1 Actual/actual * 2 Actual/360 * 3 Actual/365 * 4 European 30/360 + * Or can be an array of methods * - * @return float|string fraction of the year, or a string containing an error + * @return array|float|string fraction of the year, or a string containing an error + * If an array of values is passed for the $startDate or $endDays,arguments, then the returned result + * will also be an array with matching dimensions */ public static function fraction($startDate, $endDate, $method = 0) { + if (is_array($startDate) || is_array($endDate) || is_array($method)) { + return self::evaluateArrayArguments([self::class, __FUNCTION__], $startDate, $endDate, $method); + } + try { $method = (int) Helpers::validateNumericNull($method); $sDate = Helpers::getDateValue($startDate); @@ -50,15 +62,15 @@ class YearFrac switch ($method) { case 0: - return Days360::between($startDate, $endDate) / 360; + return Functions::scalar(Days360::between($startDate, $endDate)) / 360; case 1: return self::method1($startDate, $endDate); case 2: - return Difference::interval($startDate, $endDate) / 360; + return Functions::scalar(Difference::interval($startDate, $endDate)) / 360; case 3: - return Difference::interval($startDate, $endDate) / 365; + return Functions::scalar(Difference::interval($startDate, $endDate)) / 365; case 4: - return Days360::between($startDate, $endDate, true) / 360; + return Functions::scalar(Days360::between($startDate, $endDate, true)) / 360; } return Functions::NAN(); @@ -87,7 +99,7 @@ class YearFrac private static function method1(float $startDate, float $endDate): float { - $days = Difference::interval($startDate, $endDate); + $days = Functions::scalar(Difference::interval($startDate, $endDate)); $startYear = (int) DateParts::year($startDate); $endYear = (int) DateParts::year($endDate); $years = $endYear - $startYear + 1; diff --git a/src/PhpSpreadsheet/Calculation/Engine/ArrayArgumentProcessor.php b/src/PhpSpreadsheet/Calculation/Engine/ArrayArgumentProcessor.php new file mode 100644 index 00000000..4e377fe5 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/Engine/ArrayArgumentProcessor.php @@ -0,0 +1,174 @@ +hasArrayArgument() === false) { + return [$method(...$arguments)]; + } + + if (self::$arrayArgumentHelper->arrayArguments() === 1) { + $nthArgument = self::$arrayArgumentHelper->getFirstArrayArgumentNumber(); + + return self::evaluateNthArgumentAsArray($method, $nthArgument, ...$arguments); + } + + $singleRowVectorIndex = self::$arrayArgumentHelper->getSingleRowVector(); + $singleColumnVectorIndex = self::$arrayArgumentHelper->getSingleColumnVector(); + if ($singleRowVectorIndex !== null && $singleColumnVectorIndex !== null) { + // Basic logic for a single row vector and a single column vector + return self::evaluateVectorPair($method, $singleRowVectorIndex, $singleColumnVectorIndex, ...$arguments); + } + + $matrixPair = self::$arrayArgumentHelper->getMatrixPair(); + if ($matrixPair !== []) { + if ( + (self::$arrayArgumentHelper->isVector($matrixPair[0]) === true && + self::$arrayArgumentHelper->isVector($matrixPair[1]) === false) || + (self::$arrayArgumentHelper->isVector($matrixPair[0]) === false && + self::$arrayArgumentHelper->isVector($matrixPair[1]) === true) + ) { + // Logic for a matrix and a vector (row or column) + return self::evaluateVectorMatrixPair($method, $matrixPair, ...$arguments); + } + // Logic for matrix/matrix, column vector/column vector or row vector/row vector + return self::evaluateMatrixPair($method, $matrixPair, ...$arguments); + } + + // Still need to work out the logic for more than two array arguments, + // For the moment, we're throwing an Exception when we initialise the ArrayArgumentHelper + return ['#VALUE!']; + } + + /** + * @param mixed ...$arguments + */ + private static function evaluateVectorMatrixPair(callable $method, array $matrixIndexes, ...$arguments): array + { + $matrix2 = array_pop($matrixIndexes); + /** @var array $matrixValues2 */ + $matrixValues2 = $arguments[$matrix2]; + $matrix1 = array_pop($matrixIndexes); + /** @var array $matrixValues1 */ + $matrixValues1 = $arguments[$matrix1]; + + $rows = min(array_map([self::$arrayArgumentHelper, 'rowCount'], [$matrix1, $matrix2])); + $columns = min(array_map([self::$arrayArgumentHelper, 'columnCount'], [$matrix1, $matrix2])); + + if ($rows === 1) { + $rows = max(array_map([self::$arrayArgumentHelper, 'rowCount'], [$matrix1, $matrix2])); + } + if ($columns === 1) { + $columns = max(array_map([self::$arrayArgumentHelper, 'columnCount'], [$matrix1, $matrix2])); + } + + $result = []; + for ($rowIndex = 0; $rowIndex < $rows; ++$rowIndex) { + for ($columnIndex = 0; $columnIndex < $columns; ++$columnIndex) { + $rowIndex1 = self::$arrayArgumentHelper->isRowVector($matrix1) ? 0 : $rowIndex; + $columnIndex1 = self::$arrayArgumentHelper->isColumnVector($matrix1) ? 0 : $columnIndex; + $value1 = $matrixValues1[$rowIndex1][$columnIndex1]; + $rowIndex2 = self::$arrayArgumentHelper->isRowVector($matrix2) ? 0 : $rowIndex; + $columnIndex2 = self::$arrayArgumentHelper->isColumnVector($matrix2) ? 0 : $columnIndex; + $value2 = $matrixValues2[$rowIndex2][$columnIndex2]; + $arguments[$matrix1] = $value1; + $arguments[$matrix2] = $value2; + + $result[$rowIndex][$columnIndex] = $method(...$arguments); + } + } + + return $result; + } + + /** + * @param mixed ...$arguments + */ + private static function evaluateMatrixPair(callable $method, array $matrixIndexes, ...$arguments): array + { + $matrix2 = array_pop($matrixIndexes); + /** @var array $matrixValues2 */ + $matrixValues2 = $arguments[$matrix2]; + $matrix1 = array_pop($matrixIndexes); + /** @var array $matrixValues1 */ + $matrixValues1 = $arguments[$matrix1]; + + $result = []; + foreach ($matrixValues1 as $rowIndex => $row) { + foreach ($row as $columnIndex => $value1) { + if (isset($matrixValues2[$rowIndex][$columnIndex]) === false) { + continue; + } + + $value2 = $matrixValues2[$rowIndex][$columnIndex]; + $arguments[$matrix1] = $value1; + $arguments[$matrix2] = $value2; + + $result[$rowIndex][$columnIndex] = $method(...$arguments); + } + } + + return $result; + } + + /** + * @param mixed ...$arguments + */ + private static function evaluateVectorPair(callable $method, int $rowIndex, int $columnIndex, ...$arguments): array + { + $rowVector = Functions::flattenArray($arguments[$rowIndex]); + $columnVector = Functions::flattenArray($arguments[$columnIndex]); + + $result = []; + foreach ($columnVector as $column) { + $rowResults = []; + foreach ($rowVector as $row) { + $arguments[$rowIndex] = $row; + $arguments[$columnIndex] = $column; + + $rowResults[] = $method(...$arguments); + } + $result[] = $rowResults; + } + + return $result; + } + + /** + * Note, offset is from 1 (for the first argument) rather than from 0. + * + * @param mixed ...$arguments + */ + private static function evaluateNthArgumentAsArray(callable $method, int $nthArgument, ...$arguments): array + { + $values = array_slice($arguments, $nthArgument - 1, 1); + /** @var array $values */ + $values = array_pop($values); + + $result = []; + foreach ($values as $value) { + $arguments[$nthArgument - 1] = $value; + $result[] = $method(...$arguments); + } + + return $result; + } +} diff --git a/src/PhpSpreadsheet/Calculation/Functions.php b/src/PhpSpreadsheet/Calculation/Functions.php index 75d4582b..0ccf72e9 100644 --- a/src/PhpSpreadsheet/Calculation/Functions.php +++ b/src/PhpSpreadsheet/Calculation/Functions.php @@ -608,6 +608,24 @@ class Functions return $arrayValues; } + /** + * @param mixed $value + * + * @return null|mixed + */ + public static function scalar($value) + { + if (!is_array($value)) { + return $value; + } + + do { + $value = array_pop($value); + } while (is_array($value)); + + return $value; + } + /** * Convert a multi-dimensional array to a simple 1-dimensional array, but retain an element of indexing. * diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DateDifTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DateDifTest.php index d7d69376..77af98ee 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DateDifTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DateDifTest.php @@ -2,6 +2,8 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\DateTime; +use PhpOffice\PhpSpreadsheet\Calculation\Calculation; + class DateDifTest extends AllSetupTeardown { /** @@ -22,4 +24,30 @@ class DateDifTest extends AllSetupTeardown { return require 'tests/data/Calculation/DateTime/DATEDIF.php'; } + + /** + * @dataProvider providerDateDifArray + */ + public function testDateDifArray(array $expectedResult, string $startDate, string $endDate, ?string $methods): void + { + $calculation = Calculation::getInstance(); + + if ($methods === null) { + $formula = "=DATEDIF({$startDate}, {$endDate})"; + } else { + $formula = "=DATEDIF({$startDate}, {$endDate}, {$methods})"; + } + $result = $calculation->_calculateFormulaValue($formula); + self::assertEqualsWithDelta($expectedResult, $result, 1.0e-14); + } + + public function providerDateDifArray(): array + { + return [ + 'row vector #1' => [[[364, 202, '#NUM!']], '{"2022-01-01", "2022-06-12", "2023-07-22"}', '"2022-12-31"', null], + 'column vector #1' => [[[364], [362], [359]], '{"2022-01-01"; "2022-01-03"; "2022-01-06"}', '"2022-12-31"', null], + 'matrix #1' => [[[365, 266], [139, 1]], '{"2022-01-01", "2022-04-10"; "2022-08-15", "2022-12-31"}', '"2023-01-01"', null], + 'column vector with methods' => [[[364, 11], [242, 7], [173, 5]], '{"2022-01-01"; "2022-05-03"; "2022-07-11"}', '"2022-12-31"', '{"D", "M"}'], + ]; + } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DateValueTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DateValueTest.php index 521bde1f..1a3790e8 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DateValueTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DateValueTest.php @@ -4,6 +4,7 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\DateTime; use DateTimeImmutable; use DateTimeInterface; +use PhpOffice\PhpSpreadsheet\Calculation\Calculation; use PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel\DateValue; class DateValueTest extends AllSetupTeardown @@ -72,4 +73,25 @@ class DateValueTest extends AllSetupTeardown self::assertEquals('#VALUE!', DateValue::fromString('1903-12-31')); self::assertEquals('#VALUE!', DateValue::fromString('1900-02-29')); } + + /** + * @dataProvider providerDateValueArray + */ + public function testDateValueArray(array $expectedResult, string $array): void + { + $calculation = Calculation::getInstance(); + + $formula = "=DATEVALUE({$array})"; + $result = $calculation->_calculateFormulaValue($formula); + self::assertEqualsWithDelta($expectedResult, $result, 1.0e-14); + } + + public function providerDateValueArray(): array + { + return [ + 'row vector' => [[[44562, 44724, 45129]], '{"2022-01-01", "2022-06-12", "2023-07-22"}'], + 'column vector' => [[[44562], [44564], [44567]], '{"2022-01-01"; "2022-01-03"; "2022-01-06"}'], + 'matrix' => [[[44562, 44571], [44788, 44926]], '{"2022-01-01", "2022-01-10"; "2022-08-15", "2022-12-31"}'], + ]; + } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DayTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DayTest.php index af196050..8f5e947b 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DayTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DayTest.php @@ -2,6 +2,8 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\DateTime; +use PhpOffice\PhpSpreadsheet\Calculation\Calculation; + class DayTest extends AllSetupTeardown { /** @@ -41,4 +43,25 @@ class DayTest extends AllSetupTeardown { return require 'tests/data/Calculation/DateTime/DAYOpenOffice.php'; } + + /** + * @dataProvider providerDayArray + */ + public function testDayArray(array $expectedResult, string $array): void + { + $calculation = Calculation::getInstance(); + + $formula = "=DAY({$array})"; + $result = $calculation->_calculateFormulaValue($formula); + self::assertEqualsWithDelta($expectedResult, $result, 1.0e-14); + } + + public function providerDayArray(): array + { + return [ + 'row vector' => [[[1, 12, 22]], '{"2022-01-01", "2022-06-12", "2023-07-22"}'], + 'column vector' => [[[1], [3], [6]], '{"2022-01-01"; "2022-01-03"; "2022-01-06"}'], + 'matrix' => [[[1, 10], [15, 31]], '{"2022-01-01", "2022-01-10"; "2022-08-15", "2022-12-31"}'], + ]; + } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/Days360Test.php b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/Days360Test.php index 5a3e235d..554d5153 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/Days360Test.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/Days360Test.php @@ -2,6 +2,8 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\DateTime; +use PhpOffice\PhpSpreadsheet\Calculation\Calculation; + class Days360Test extends AllSetupTeardown { /** @@ -23,4 +25,30 @@ class Days360Test extends AllSetupTeardown { return require 'tests/data/Calculation/DateTime/DAYS360.php'; } + + /** + * @dataProvider providerDays360Array + */ + public function testDays360Array(array $expectedResult, string $startDate, string $endDate, ?string $methods): void + { + $calculation = Calculation::getInstance(); + + if ($methods === null) { + $formula = "=DAYS360({$startDate}, {$endDate})"; + } else { + $formula = "=DAYS360({$startDate}, {$endDate}, {$methods})"; + } + $result = $calculation->_calculateFormulaValue($formula); + self::assertEqualsWithDelta($expectedResult, $result, 1.0e-14); + } + + public function providerDays360Array(): array + { + return [ + 'row vector #1' => [[[360, 199, -201]], '{"2022-01-01", "2022-06-12", "2023-07-22"}', '"2022-12-31"', null], + 'column vector #1' => [[[360], [358], [355]], '{"2022-01-01"; "2022-01-03"; "2022-01-06"}', '"2022-12-31"', null], + 'matrix #1' => [[[0, -9], [-224, -360]], '{"2022-01-01", "2022-01-10"; "2022-08-15", "2022-12-31"}', '"2021-12-31"', null], + 'column vector with methods' => [[[360, 359], [358, 357], [355, 354]], '{"2022-01-01"; "2022-01-03"; "2022-01-06"}', '"2022-12-31"', '{FALSE, TRUE}'], + ]; + } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DaysTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DaysTest.php index a63e45cc..236b5178 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DaysTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DaysTest.php @@ -5,6 +5,7 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\DateTime; use DateTime; use DateTimeImmutable; use Exception; +use PhpOffice\PhpSpreadsheet\Calculation\Calculation; use PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel\Days; class DaysTest extends AllSetupTeardown @@ -42,4 +43,25 @@ class DaysTest extends AllSetupTeardown $obj2 = new DateTimeImmutable('2000-2-29'); self::assertSame('#VALUE!', Days::between($obj1, $obj2)); } + + /** + * @dataProvider providerDaysArray + */ + public function testDaysArray(array $expectedResult, string $startDate, string $endDate): void + { + $calculation = Calculation::getInstance(); + + $formula = "=DAYS({$startDate}, {$endDate})"; + $result = $calculation->_calculateFormulaValue($formula); + self::assertEqualsWithDelta($expectedResult, $result, 1.0e-14); + } + + public function providerDaysArray(): array + { + return [ + 'row vector #1' => [[[-364, -202, 203]], '{"2022-01-01", "2022-06-12", "2023-07-22"}', '"2022-12-31"'], + 'column vector #1' => [[[-364], [-362], [-359]], '{"2022-01-01"; "2022-01-03"; "2022-01-06"}', '"2022-12-31"'], + 'matrix #1' => [[[1, 10], [227, 365]], '{"2022-01-01", "2022-01-10"; "2022-08-15", "2022-12-31"}', '"2021-12-31"'], + ]; + } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/EDateTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/EDateTest.php index 22613fe5..5b8479cb 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/EDateTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/EDateTest.php @@ -2,6 +2,7 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\DateTime; +use PhpOffice\PhpSpreadsheet\Calculation\Calculation; use PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel\Month; class EDateTest extends AllSetupTeardown @@ -46,4 +47,28 @@ class EDateTest extends AllSetupTeardown // ... with the correct value self::assertEquals($result->format('d-M-Y'), '26-Dec-2011'); } + + /** + * @dataProvider providerEDateArray + */ + public function testEDateArray(array $expectedResult, string $dateValues, string $methods): void + { + $calculation = Calculation::getInstance(); + + $formula = "=EDATE({$dateValues}, {$methods})"; + $result = $calculation->_calculateFormulaValue($formula); + self::assertEqualsWithDelta($expectedResult, $result, 1.0e-14); + } + + public function providerEDateArray(): array + { + return [ + 'row vector #1' => [[[44593, 44632, 45337]], '{"2022-01-01", "2022-02-12", "2024-01-15"}', '1'], + 'column vector #1' => [[[44593], [44632], [45337]], '{"2022-01-01"; "2022-02-12"; "2024-01-15"}', '1'], + 'matrix #1' => [[[44593, 44632], [44652, 45343]], '{"2022-01-01", "2022-02-12"; "2022-03-01", "2024-01-21"}', '1'], + 'row vector #2' => [[[44573, 44604, 44632]], '"2022-02-12"', '{-1, 0, 1}'], + 'column vector #2' => [[[44573], [44604], [44632]], '"2022-02-12"', '{-1; 0; 1}'], + 'matrix #2' => [[[44573, 44604], [44632, 45334]], '"2022-02-12"', '{-1, 0; 1, 24}'], + ]; + } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/EoMonthTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/EoMonthTest.php index 3c39fbbc..935b3cbc 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/EoMonthTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/EoMonthTest.php @@ -2,6 +2,7 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\DateTime; +use PhpOffice\PhpSpreadsheet\Calculation\Calculation; use PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel\Month; class EoMonthTest extends AllSetupTeardown @@ -45,4 +46,28 @@ class EoMonthTest extends AllSetupTeardown // ... with the correct value self::assertSame($result->format('d-M-Y'), '31-Dec-2011'); } + + /** + * @dataProvider providerEoMonthArray + */ + public function testEoMonthArray(array $expectedResult, string $dateValues, string $methods): void + { + $calculation = Calculation::getInstance(); + + $formula = "=EOMONTH({$dateValues}, {$methods})"; + $result = $calculation->_calculateFormulaValue($formula); + self::assertEqualsWithDelta($expectedResult, $result, 1.0e-14); + } + + public function providerEoMonthArray(): array + { + return [ + 'row vector #1' => [[[44620, 44651, 45351]], '{"2022-01-01", "2022-02-12", "2024-01-15"}', '1'], + 'column vector #1' => [[[44620], [44651], [45351]], '{"2022-01-01"; "2022-02-12"; "2024-01-15"}', '1'], + 'matrix #1' => [[[44620, 44651], [44681, 45351]], '{"2022-01-01", "2022-02-12"; "2022-03-01", "2024-01-21"}', '1'], + 'row vector #2' => [[[44592, 44620, 44651]], '"2022-02-12"', '{-1, 0, 1}'], + 'column vector #2' => [[[44592], [44620], [44651]], '"2022-02-12"', '{-1; 0; 1}'], + 'matrix #2' => [[[44592, 44620], [44651, 45351]], '"2022-02-12"', '{-1, 0; 1, 24}'], + ]; + } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/HourTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/HourTest.php index c1e4f29c..c9445116 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/HourTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/HourTest.php @@ -2,6 +2,8 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\DateTime; +use PhpOffice\PhpSpreadsheet\Calculation\Calculation; + class HourTest extends AllSetupTeardown { /** @@ -22,4 +24,25 @@ class HourTest extends AllSetupTeardown { return require 'tests/data/Calculation/DateTime/HOUR.php'; } + + /** + * @dataProvider providerHourArray + */ + public function testHourArray(array $expectedResult, string $array): void + { + $calculation = Calculation::getInstance(); + + $formula = "=HOUR({$array})"; + $result = $calculation->_calculateFormulaValue($formula); + self::assertEqualsWithDelta($expectedResult, $result, 1.0e-14); + } + + public function providerHourArray(): array + { + return [ + 'row vector' => [[[1, 13, 19]], '{"2022-02-09 01:02:03", "2022-02-09 13:14:15", "2022-02-09 19:20:21"}'], + 'column vector' => [[[1], [13], [19]], '{"2022-02-09 01:02:03"; "2022-02-09 13:14:15"; "2022-02-09 19:20:21"}'], + 'matrix' => [[[1, 13], [19, 23]], '{"2022-02-09 01:02:03", "2022-02-09 13:14:15"; "2022-02-09 19:20:21", "1999-12-31 23:59:59"}'], + ]; + } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/IsoWeekNumTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/IsoWeekNumTest.php index 29e35b38..1704bd6d 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/IsoWeekNumTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/IsoWeekNumTest.php @@ -2,6 +2,8 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\DateTime; +use PhpOffice\PhpSpreadsheet\Calculation\Calculation; + class IsoWeekNumTest extends AllSetupTeardown { /** @@ -44,4 +46,25 @@ class IsoWeekNumTest extends AllSetupTeardown { return require 'tests/data/Calculation/DateTime/ISOWEEKNUM1904.php'; } + + /** + * @dataProvider providerIsoWeekNumArray + */ + public function testIsoWeekNumArray(array $expectedResult, string $array): void + { + $calculation = Calculation::getInstance(); + + $formula = "=ISOWEEKNUM({$array})"; + $result = $calculation->_calculateFormulaValue($formula); + self::assertEqualsWithDelta($expectedResult, $result, 1.0e-14); + } + + public function providerIsoWeekNumArray(): array + { + return [ + 'row vector' => [[[52, 23, 29]], '{"2022-01-01", "2022-06-12", "2023-07-22"}'], + 'column vector' => [[[52], [13], [26]], '{"2023-01-01"; "2023-04-01"; "2023-07-01"}'], + 'matrix' => [[[53, 52], [52, 52]], '{"2021-01-01", "2021-12-31"; "2023-01-01", "2023-12-31"}'], + ]; + } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/MinuteTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/MinuteTest.php index b5207d7e..bebc79ed 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/MinuteTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/MinuteTest.php @@ -2,6 +2,8 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\DateTime; +use PhpOffice\PhpSpreadsheet\Calculation\Calculation; + class MinuteTest extends AllSetupTeardown { /** @@ -22,4 +24,25 @@ class MinuteTest extends AllSetupTeardown { return require 'tests/data/Calculation/DateTime/MINUTE.php'; } + + /** + * @dataProvider providerMinuteArray + */ + public function testMinuteArray(array $expectedResult, string $array): void + { + $calculation = Calculation::getInstance(); + + $formula = "=MINUTE({$array})"; + $result = $calculation->_calculateFormulaValue($formula); + self::assertEqualsWithDelta($expectedResult, $result, 1.0e-14); + } + + public function providerMinuteArray(): array + { + return [ + 'row vector' => [[[2, 14, 20]], '{"2022-02-09 01:02:03", "2022-02-09 13:14:15", "2022-02-09 19:20:21"}'], + 'column vector' => [[[2], [14], [20]], '{"2022-02-09 01:02:03"; "2022-02-09 13:14:15"; "2022-02-09 19:20:21"}'], + 'matrix' => [[[2, 14], [20, 59]], '{"2022-02-09 01:02:03", "2022-02-09 13:14:15"; "2022-02-09 19:20:21", "1999-12-31 23:59:59"}'], + ]; + } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/MonthTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/MonthTest.php index 30465e87..90449286 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/MonthTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/MonthTest.php @@ -2,6 +2,8 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\DateTime; +use PhpOffice\PhpSpreadsheet\Calculation\Calculation; + class MonthTest extends AllSetupTeardown { /** @@ -22,4 +24,25 @@ class MonthTest extends AllSetupTeardown { return require 'tests/data/Calculation/DateTime/MONTH.php'; } + + /** + * @dataProvider providerMonthArray + */ + public function testMonthArray(array $expectedResult, string $array): void + { + $calculation = Calculation::getInstance(); + + $formula = "=MONTH({$array})"; + $result = $calculation->_calculateFormulaValue($formula); + self::assertEqualsWithDelta($expectedResult, $result, 1.0e-14); + } + + public function providerMonthArray(): array + { + return [ + 'row vector' => [[[1, 6, 1]], '{"2022-01-01", "2022-06-01", "2023-01-01"}'], + 'column vector' => [[[1], [3], [6]], '{"2022-01-01"; "2022-03-01"; "2022-06-01"}'], + 'matrix' => [[[1, 4], [8, 12]], '{"2022-01-01", "2022-04-01"; "2022-08-01", "2022-12-01"}'], + ]; + } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/NetworkDaysTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/NetworkDaysTest.php index d6b1a89f..d5378b35 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/NetworkDaysTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/NetworkDaysTest.php @@ -2,6 +2,8 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\DateTime; +use PhpOffice\PhpSpreadsheet\Calculation\Calculation; + class NetworkDaysTest extends AllSetupTeardown { /** @@ -49,4 +51,33 @@ class NetworkDaysTest extends AllSetupTeardown { return require 'tests/data/Calculation/DateTime/NETWORKDAYS.php'; } + + /** + * @dataProvider providerNetWorkDaysArray + */ + public function testNetWorkDaysArray(array $expectedResult, string $startDate, string $endDays, ?string $holidays): void + { + $calculation = Calculation::getInstance(); + + if ($holidays === null) { + $formula = "=NETWORKDAYS({$startDate}, {$endDays})"; + } else { + $formula = "=NETWORKDAYS({$startDate}, {$endDays}, {$holidays})"; + } + $result = $calculation->_calculateFormulaValue($formula); + self::assertEqualsWithDelta($expectedResult, $result, 1.0e-14); + } + + public function providerNetWorkDaysArray(): array + { + return [ + 'row vector #1' => [[[234, 233, 232]], '{"2022-02-01", "2022-02-02", "2022-02-03"}', '"2022-12-25"', null], + 'column vector #1' => [[[234], [233], [232]], '{"2022-02-01"; "2022-02-02"; "2022-02-03"}', '"2022-12-25"', null], + 'matrix #1' => [[[234, 233], [232, 231]], '{"2022-02-01", "2022-02-02"; "2022-02-03", "2022-02-04"}', '"2022-12-25"', null], + 'row vector #2' => [[[234, -27]], '"2022-02-01"', '{"2022-12-25", "2021-12-25"}', null], + 'column vector #2' => [[[234], [-27]], '"2022-02-01"', '{"2022-12-25"; "2021-12-25"}', null], + 'row vector with Holiday' => [[[233, -27]], '"2022-02-01"', '{"2022-12-25", "2021-12-25"}', '{"2022-02-02"}'], + 'row vector with Holidays' => [[[232, -27]], '"2022-02-01"', '{"2022-12-25", "2021-12-25"}', '{"2022-02-02", "2022-02-03"}'], + ]; + } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/SecondTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/SecondTest.php index 1a411d45..c5b808f2 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/SecondTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/SecondTest.php @@ -2,6 +2,8 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\DateTime; +use PhpOffice\PhpSpreadsheet\Calculation\Calculation; + class SecondTest extends AllSetupTeardown { /** @@ -22,4 +24,25 @@ class SecondTest extends AllSetupTeardown { return require 'tests/data/Calculation/DateTime/SECOND.php'; } + + /** + * @dataProvider providerSecondArray + */ + public function testSecondArray(array $expectedResult, string $array): void + { + $calculation = Calculation::getInstance(); + + $formula = "=SECOND({$array})"; + $result = $calculation->_calculateFormulaValue($formula); + self::assertEqualsWithDelta($expectedResult, $result, 1.0e-14); + } + + public function providerSecondArray(): array + { + return [ + 'row vector' => [[[3, 15, 21]], '{"2022-02-09 01:02:03", "2022-02-09 13:14:15", "2022-02-09 19:20:21"}'], + 'column vector' => [[[3], [15], [21]], '{"2022-02-09 01:02:03"; "2022-02-09 13:14:15"; "2022-02-09 19:20:21"}'], + 'matrix' => [[[3, 15], [21, 59]], '{"2022-02-09 01:02:03", "2022-02-09 13:14:15"; "2022-02-09 19:20:21", "1999-12-31 23:59:59"}'], + ]; + } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/TimeTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/TimeTest.php index 3ee1aa55..88271fea 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/TimeTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/TimeTest.php @@ -2,7 +2,9 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\DateTime; +use PhpOffice\PhpSpreadsheet\Calculation\Calculation; use PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel\Time; +use PhpOffice\PhpSpreadsheet\Calculation\Exception; class TimeTest extends AllSetupTeardown { @@ -60,4 +62,95 @@ class TimeTest extends AllSetupTeardown $result = Time::fromHMS(0, 0, 0); self::assertEquals(0, $result); } + + /** + * @dataProvider providerTimeArray + */ + public function testTimeArray(array $expectedResult, string $hour, string $minute, string $second): void + { + $calculation = Calculation::getInstance(); + + $formula = "=TIME({$hour}, {$minute}, {$second})"; + $result = $calculation->_calculateFormulaValue($formula); + self::assertEqualsWithDelta($expectedResult, $result, 1.0e-14); + } + + public function providerTimeArray(): array + { + return [ + 'row vector hour' => [[[0.250706018518519, 0.50070601851852, 0.75070601851852]], '{6,12,18}', '1', '1'], + 'column vector hour' => [[[0.250706018518519], [0.50070601851852], [0.75070601851852]], '{6;12;18}', '1', '1'], + 'matrix hour' => [[[0.250706018518519, 0.50070601851852], [0.75070601851852, 0.95903935185185]], '{6,12;18,23}', '1', '1'], + 'row vector minute' => [[[0.96667824074074, 0.97501157407407, 0.98334490740741, 0.99931712962963]], '23', '{12, 24, 36, 59}', '1'], + 'column vector minute' => [[[0.96734953703704], [0.97568287037037], [0.98401620370370], [0.99998842592593]], '23', '{12; 24; 36; 59}', '59'], + 'matrix minute' => [[[0.50833333333333, 0.51666666666667], [0.52083333333333, 0.5]], '12', '{12, 24; 30, 0}', '0'], + 'row vector second' => [[[0.50069444444444, 0.50137731481481]], '12', '1', '{0,59}'], + 'column vector second' => [[[0.99930555555556], [0.99998842592593]], '23', '59', '{0;59}'], + 'vectors hour and minute' => [ + [ + [0.87570601851852, 0.88473379629630, 0.89376157407407, 0.90626157407407], + [0.91737268518519, 0.92640046296296, 0.93542824074074, 0.94792824074074], + [0.95903935185185, 0.96806712962963, 0.97709490740741, 0.98959490740741], + ], + '{21;22;23}', + '{1, 14, 27, 45}', + '1', + ], + 'vectors hour and second' => [ + [ + [0.126041666666667, 0.126215277777778], + [0.334375, 0.33454861111111], + [0.584375, 0.58454861111111], + ], + '{3;8;14}', + '1', + '{30,45}', + ], + 'vectors minute and second' => [ + [ + [0.75833333333333, 0.75834490740741], + [0.76041666666667, 0.76042824074074], + [0.77083333333333, 0.77084490740741], + [0.75, 0.750011574074074], + ], + '18', + '{12; 15; 30; 0}', + '{0,1}', + ], + 'matrices hour and minute' => [ + [ + [0.25070601851852, 0.50278935185185], + [0.75487268518519, 0.96528935185185], + ], + '{6, 12; 18, 23}', + '{1, 4; 7, 10}', + '1', + ], + ]; + } + + /** + * @dataProvider providerTimeArrayException + */ + public function testTimeArrayException(string $hour, string $minute, string $second): void + { + $calculation = Calculation::getInstance(); + + $this->expectException(Exception::class); + $this->expectExceptionMessage('Formulae with more than two array arguments are not supported'); + + $formula = "=TIME({$hour}, {$minute}, {$second})"; + $calculation->_calculateFormulaValue($formula); + } + + public function providerTimeArrayException(): array + { + return [ + 'matrix arguments with 3 array values' => [ + '{6, 12; 16, 23}', + '{1, 4; 7, 10}', + '{0,1}', + ], + ]; + } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/TimeValueTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/TimeValueTest.php index 6995c312..0eb235f7 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/TimeValueTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/TimeValueTest.php @@ -2,6 +2,7 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\DateTime; +use PhpOffice\PhpSpreadsheet\Calculation\Calculation; use PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel\TimeValue; class TimeValueTest extends AllSetupTeardown @@ -48,4 +49,25 @@ class TimeValueTest extends AllSetupTeardown // ... with the correct value self::assertEquals($result->format('H:i:s'), '07:30:20'); } + + /** + * @dataProvider providerTimeValueArray + */ + public function testTimeValueArray(array $expectedResult, string $array): void + { + $calculation = Calculation::getInstance(); + + $formula = "=TIMEVALUE({$array})"; + $result = $calculation->_calculateFormulaValue($formula); + self::assertEqualsWithDelta($expectedResult, $result, 1.0e-14); + } + + public function providerTimeValueArray(): array + { + return [ + 'row vector' => [[[0.04309027777777, 0.5515625, 0.80579861111111]], '{"2022-02-09 01:02:03", "2022-02-09 13:14:15", "2022-02-09 19:20:21"}'], + 'column vector' => [[[0.04309027777777], [0.5515625], [0.80579861111111]], '{"2022-02-09 01:02:03"; "2022-02-09 13:14:15"; "2022-02-09 19:20:21"}'], + 'matrix' => [[[0.04309027777777, 0.5515625], [0.80579861111111, 0.99998842592592]], '{"2022-02-09 01:02:03", "2022-02-09 13:14:15"; "2022-02-09 19:20:21", "1999-12-31 23:59:59"}'], + ]; + } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/WeekDayTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/WeekDayTest.php index 3c7f682d..e8d90f5f 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/WeekDayTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/WeekDayTest.php @@ -2,6 +2,7 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\DateTime; +use PhpOffice\PhpSpreadsheet\Calculation\Calculation; use PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel\Week; class WeekDayTest extends AllSetupTeardown @@ -32,4 +33,27 @@ class WeekDayTest extends AllSetupTeardown self::assertEquals(6, Week::day('1904-01-01')); self::assertEquals(6, Week::day(null)); } + + /** + * @dataProvider providerWeekDayArray + */ + public function testWeekDayArray(array $expectedResult, string $dateValues, string $styles): void + { + $calculation = Calculation::getInstance(); + + $formula = "=WEEKDAY({$dateValues}, {$styles})"; + $result = $calculation->_calculateFormulaValue($formula); + self::assertEqualsWithDelta($expectedResult, $result, 1.0e-14); + } + + public function providerWeekDayArray(): array + { + return [ + 'row vector #1' => [[[7, 1, 7]], '{"2022-01-01", "2022-06-12", "2023-07-22"}', '1'], + 'column vector #1' => [[[1], [7], [7]], '{"2023-01-01"; "2023-04-01"; "2023-07-01"}', '1'], + 'matrix #1' => [[[6, 6], [1, 1]], '{"2021-01-01", "2021-12-31"; "2023-01-01", "2023-12-31"}', '1'], + 'row vector #2' => [[[7, 6]], '"2022-01-01"', '{1, 2}'], + 'column vector #2' => [[[1], [7]], '"2023-01-01"', '{1; 2}'], + ]; + } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/WeekNumTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/WeekNumTest.php index caa71f17..b2a067e9 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/WeekNumTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/WeekNumTest.php @@ -2,6 +2,8 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\DateTime; +use PhpOffice\PhpSpreadsheet\Calculation\Calculation; + class WeekNumTest extends AllSetupTeardown { /** @@ -42,4 +44,28 @@ class WeekNumTest extends AllSetupTeardown { return require 'tests/data/Calculation/DateTime/WEEKNUM1904.php'; } + + /** + * @dataProvider providerWeekNumArray + */ + public function testWeekNumArray(array $expectedResult, string $dateValues, string $methods): void + { + $calculation = Calculation::getInstance(); + + $formula = "=WEEKNUM({$dateValues}, {$methods})"; + $result = $calculation->_calculateFormulaValue($formula); + self::assertEqualsWithDelta($expectedResult, $result, 1.0e-14); + } + + public function providerWeekNumArray(): array + { + return [ + 'row vector #1' => [[[1, 25, 29]], '{"2022-01-01", "2022-06-12", "2023-07-22"}', '1'], + 'column vector #1' => [[[1], [13], [26]], '{"2023-01-01"; "2023-04-01"; "2023-07-01"}', '1'], + 'matrix #1' => [[[1, 53], [1, 53]], '{"2021-01-01", "2021-12-31"; "2023-01-01", "2023-12-31"}', '1'], + 'row vector #2' => [[[25, 24]], '"2022-06-12"', '{1, 2}'], + 'column vector #2' => [[[13], [14]], '"2023-04-01"', '{1; 2}'], + 'matrix #2' => [[[53, 53], [53, 52]], '"2021-12-31"', '{1, 2; 16, 21}'], + ]; + } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/WorkDayTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/WorkDayTest.php index 3cfa9219..3b73828f 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/WorkDayTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/WorkDayTest.php @@ -2,6 +2,8 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\DateTime; +use PhpOffice\PhpSpreadsheet\Calculation\Calculation; + class WorkDayTest extends AllSetupTeardown { /** @@ -49,4 +51,33 @@ class WorkDayTest extends AllSetupTeardown { return require 'tests/data/Calculation/DateTime/WORKDAY.php'; } + + /** + * @dataProvider providerWorkDayArray + */ + public function testWorkDayArray(array $expectedResult, string $startDate, string $endDays, ?string $holidays): void + { + $calculation = Calculation::getInstance(); + + if ($holidays === null) { + $formula = "=WORKDAY({$startDate}, {$endDays})"; + } else { + $formula = "=WORKDAY({$startDate}, {$endDays}, {$holidays})"; + } + $result = $calculation->_calculateFormulaValue($formula); + self::assertEqualsWithDelta($expectedResult, $result, 1.0e-14); + } + + public function providerWorkDayArray(): array + { + return [ + 'row vector #1' => [[[44595, 44596, 44599]], '{"2022-02-01", "2022-02-02", "2022-02-03"}', '2', null], + 'column vector #1' => [[[44595], [44596], [44599]], '{"2022-02-01"; "2022-02-02"; "2022-02-03"}', '2', null], + 'matrix #1' => [[[44595, 44596], [44599, 44600]], '{"2022-02-01", "2022-02-02"; "2022-02-03", "2022-02-04"}', '2', null], + 'row vector #2' => [[[44595, 44596]], '"2022-02-01"', '{2, 3}', null], + 'column vector #2' => [[[44595], [44596]], '"2022-02-01"', '{2; 3}', null], + 'row vector with Holiday' => [[[44596, 44599]], '"2022-02-01"', '{2, 3}', '{"2022-02-02"}'], + 'row vector with Holidays' => [[[44599, 44600]], '"2022-02-01"', '{2, 3}', '{"2022-02-02", "2022-02-03"}'], + ]; + } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/YearFracTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/YearFracTest.php index d7427bfd..9c78fbbe 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/YearFracTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/YearFracTest.php @@ -2,6 +2,8 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\DateTime; +use PhpOffice\PhpSpreadsheet\Calculation\Calculation; + class YearFracTest extends AllSetupTeardown { /** @@ -41,4 +43,30 @@ class YearFracTest extends AllSetupTeardown { return require 'tests/data/Calculation/DateTime/YEARFRAC.php'; } + + /** + * @dataProvider providerYearFracArray + */ + public function testYearFracArray(array $expectedResult, string $startDate, string $endDate, ?string $methods): void + { + $calculation = Calculation::getInstance(); + + if ($methods === null) { + $formula = "=YEARFRAC({$startDate}, {$endDate})"; + } else { + $formula = "=YEARFRAC({$startDate}, {$endDate}, {$methods})"; + } + $result = $calculation->_calculateFormulaValue($formula); + self::assertEqualsWithDelta($expectedResult, $result, 1.0e-14); + } + + public function providerYearFracArray(): array + { + return [ + 'row vector #1' => [[[1.0, 0.55277777777778, 0.56111111111111]], '{"2022-01-01", "2022-06-12", "2023-07-22"}', '"2022-12-31"', null], + 'column vector #1' => [[[1.0], [0.99444444444445], [0.98611111111111]], '{"2022-01-01"; "2022-01-03"; "2022-01-06"}', '"2022-12-31"', null], + 'matrix #1' => [[[0.002777777777778, 0.027777777777778], [0.625, 1.0]], '{"2022-01-01", "2022-01-10"; "2022-08-15", "2022-12-31"}', '"2021-12-31"', null], + 'column vector with methods' => [[[0.99726027397260, 0.99722222222222], [0.99178082191781, 0.99166666666667], [0.98356164383562, 0.98333333333333]], '{"2022-01-01"; "2022-01-03"; "2022-01-06"}', '"2022-12-31"', '{1, 4}'], + ]; + } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/YearTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/YearTest.php index a31ac7aa..3e320c24 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/YearTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/YearTest.php @@ -2,6 +2,8 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\DateTime; +use PhpOffice\PhpSpreadsheet\Calculation\Calculation; + class YearTest extends AllSetupTeardown { /** @@ -22,4 +24,25 @@ class YearTest extends AllSetupTeardown { return require 'tests/data/Calculation/DateTime/YEAR.php'; } + + /** + * @dataProvider providerYearArray + */ + public function testYearArray(array $expectedResult, string $array): void + { + $calculation = Calculation::getInstance(); + + $formula = "=YEAR({$array})"; + $result = $calculation->_calculateFormulaValue($formula); + self::assertEqualsWithDelta($expectedResult, $result, 1.0e-14); + } + + public function providerYearArray(): array + { + return [ + 'row vector' => [[[2021, 2022, 2023]], '{"2021-01-01", "2022-01-01", "2023-01-01"}'], + 'column vector' => [[[2021], [2022], [2023]], '{"2021-01-01"; "2022-01-01"; "2023-01-01"}'], + 'matrix' => [[[2021, 2022], [2023, 1999]], '{"2021-01-01", "2022-01-01"; "2023-01-01", "1999-12-31"}'], + ]; + } }