Permit Date/Time Entered on Spreadsheet to be Calculated as Float (#3121)
* Permit Date/Time Entered on Spreadsheet to be Calculated as Float Fix #1416. I do not entirely understand the use case for this old issue, but resolving it seems straightforward. Issue complains that user-entered date/time fields may be interpreted as either float or int when PhpSpreadsheet reads them. Issue suggests getCalculatedValue treat all date/time fields as float; that seems like a breaking change. However, adding an option to permit it seems okay. That option might be implemented as either a property of Calculation, or a static property of Cell. Since the changed logic is found in Cell (and Shared/Date), I opted for the latter. In Cell, the property `$parent` is incorrectly described in doc block as `Cells`, and should be `?Cells`. This change eliminates some Phpstan and Scrutinizer problems, and should allow the elimination of some try/catch blocks - I have not done an exhaustive search for those. Calls to `isDateTime` could have affected activeSheet and selectedCells; they no longer can. Optional parameters are added to it and the functions it calls to accommodate the new functionality; the defaults for the new parameters will, of course, return the same result as the earlier versions of the functions would have returned. * Scrutinizer - Self-inflicted Tests used constant which I deprecated.
This commit is contained in:
parent
6842ccb862
commit
e4e99b8a73
|
|
@ -321,6 +321,19 @@ and false is failure (e.g. an invalid DateTimeZone value was passed.)
|
||||||
These functions support a timezone as an optional second parameter.
|
These functions support a timezone as an optional second parameter.
|
||||||
This applies a specific timezone to that function call without affecting the default PhpSpreadsheet Timezone.
|
This applies a specific timezone to that function call without affecting the default PhpSpreadsheet Timezone.
|
||||||
|
|
||||||
|
### Calculating Value of Date/Time Read From Spreadsheet
|
||||||
|
|
||||||
|
Nothing special needs to be done to interpret Date/Time values entered directly into a spreadsheet. They will have been stored as numbers with an appropriate number format set for the cell. However, depending on their value, they may have been stored as either integer or float values. If that is a problem, you can force `getCalculatedValue` to return float rather than int depending on the number format used for the cell.
|
||||||
|
|
||||||
|
```php
|
||||||
|
// All fields with Date, Time, or DateTime styles returned as float.
|
||||||
|
\PhpOffice\PhpSpreadsheet\Cell\Cell::setCalculateDateTimeType(\PhpOffice\PhpSpreadsheet\Cell\Cell::CALCULATE_DATE_TIME_FLOAT);
|
||||||
|
// All fields with Time or DateTime styles returned as float.
|
||||||
|
\PhpOffice\PhpSpreadsheet\Cell\Cell::setCalculateDateTimeType(\PhpOffice\PhpSpreadsheet\Cell\Cell::CALCULATE_TIME_FLOAT);
|
||||||
|
// Default - fields with Date, Time, or DateTime styles returned as they had been stored.
|
||||||
|
\PhpOffice\PhpSpreadsheet\Cell\Cell::setCalculateDateTimeType(\PhpOffice\PhpSpreadsheet\Cell\Cell::CALCULATE_DATE_TIME_ASIS);
|
||||||
|
```
|
||||||
|
|
||||||
## Function Reference
|
## Function Reference
|
||||||
|
|
||||||
### Database Functions
|
### Database Functions
|
||||||
|
|
|
||||||
|
|
@ -684,26 +684,6 @@ parameters:
|
||||||
message: "#^Variable \\$value on left side of \\?\\? always exists and is not nullable\\.$#"
|
message: "#^Variable \\$value on left side of \\?\\? always exists and is not nullable\\.$#"
|
||||||
count: 1
|
count: 1
|
||||||
path: src/PhpSpreadsheet/Calculation/TextData/Text.php
|
path: src/PhpSpreadsheet/Calculation/TextData/Text.php
|
||||||
-
|
|
||||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\:\\:getFormulaAttributes\\(\\) has no return type specified\\.$#"
|
|
||||||
count: 1
|
|
||||||
path: src/PhpSpreadsheet/Cell/Cell.php
|
|
||||||
-
|
|
||||||
message: "#^Parameter \\#2 \\$format of static method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\NumberFormat\\:\\:toFormattedString\\(\\) expects string, string\\|null given\\.$#"
|
|
||||||
count: 1
|
|
||||||
path: src/PhpSpreadsheet/Cell/Cell.php
|
|
||||||
-
|
|
||||||
message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\:\\:\\$formulaAttributes has no type specified\\.$#"
|
|
||||||
count: 1
|
|
||||||
path: src/PhpSpreadsheet/Cell/Cell.php
|
|
||||||
-
|
|
||||||
message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\:\\:\\$parent \\(PhpOffice\\\\PhpSpreadsheet\\\\Collection\\\\Cells\\) in isset\\(\\) is not nullable\\.$#"
|
|
||||||
count: 6
|
|
||||||
path: src/PhpSpreadsheet/Cell/Cell.php
|
|
||||||
-
|
|
||||||
message: "#^Unreachable statement \\- code above always terminates\\.$#"
|
|
||||||
count: 1
|
|
||||||
path: src/PhpSpreadsheet/Cell/Cell.php
|
|
||||||
-
|
-
|
||||||
message: "#^Call to an undefined method object\\:\\:getHashCode\\(\\)\\.$#"
|
message: "#^Call to an undefined method object\\:\\:getHashCode\\(\\)\\.$#"
|
||||||
count: 1
|
count: 1
|
||||||
|
|
@ -1078,22 +1058,6 @@ parameters:
|
||||||
message: "#^Strict comparison using \\=\\=\\= between int and null will always evaluate to false\\.$#"
|
message: "#^Strict comparison using \\=\\=\\= between int and null will always evaluate to false\\.$#"
|
||||||
count: 1
|
count: 1
|
||||||
path: src/PhpSpreadsheet/Settings.php
|
path: src/PhpSpreadsheet/Settings.php
|
||||||
-
|
|
||||||
message: "#^Parameter \\#1 \\$excelFormatCode of static method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Date\\:\\:isDateTimeFormatCode\\(\\) expects string, string\\|null given\\.$#"
|
|
||||||
count: 1
|
|
||||||
path: src/PhpSpreadsheet/Shared/Date.php
|
|
||||||
-
|
|
||||||
message: "#^Parameter \\#1 \\$string of function substr expects string, int given\\.$#"
|
|
||||||
count: 2
|
|
||||||
path: src/PhpSpreadsheet/Shared/Date.php
|
|
||||||
-
|
|
||||||
message: "#^Parameter \\#1 \\$unixTimestamp of static method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Date\\:\\:timestampToExcel\\(\\) expects int, float\\|int\\|string given\\.$#"
|
|
||||||
count: 1
|
|
||||||
path: src/PhpSpreadsheet/Shared/Date.php
|
|
||||||
-
|
|
||||||
message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Date\\:\\:\\$possibleDateFormatCharacters has no type specified\\.$#"
|
|
||||||
count: 1
|
|
||||||
path: src/PhpSpreadsheet/Shared/Date.php
|
|
||||||
-
|
-
|
||||||
message: "#^Cannot access offset 1 on array\\|false\\.$#"
|
message: "#^Cannot access offset 1 on array\\|false\\.$#"
|
||||||
count: 1
|
count: 1
|
||||||
|
|
|
||||||
|
|
@ -95,7 +95,7 @@ $spreadsheet->getActiveSheet()->getStyle('A1:F1')->getFont()->setBold(true);
|
||||||
$spreadsheet->getActiveSheet()->getStyle('A1:F1')->getAlignment()->setWrapText(true);
|
$spreadsheet->getActiveSheet()->getStyle('A1:F1')->getAlignment()->setWrapText(true);
|
||||||
$spreadsheet->getActiveSheet()->getColumnDimension('C')->setWidth(12.5);
|
$spreadsheet->getActiveSheet()->getColumnDimension('C')->setWidth(12.5);
|
||||||
$spreadsheet->getActiveSheet()->getColumnDimension('D')->setWidth(10.5);
|
$spreadsheet->getActiveSheet()->getColumnDimension('D')->setWidth(10.5);
|
||||||
$spreadsheet->getActiveSheet()->getStyle('D2:D' . $row)->getNumberFormat()->setFormatCode(NumberFormat::FORMAT_DATE_YYYYMMDD2);
|
$spreadsheet->getActiveSheet()->getStyle('D2:D' . $row)->getNumberFormat()->setFormatCode(NumberFormat::FORMAT_DATE_YYYYMMDD);
|
||||||
$spreadsheet->getActiveSheet()->getStyle('E2:F' . $row)->getNumberFormat()->setFormatCode(NumberFormat::FORMAT_CURRENCY_USD_SIMPLE);
|
$spreadsheet->getActiveSheet()->getStyle('E2:F' . $row)->getNumberFormat()->setFormatCode(NumberFormat::FORMAT_CURRENCY_USD_SIMPLE);
|
||||||
$spreadsheet->getActiveSheet()->getColumnDimension('F')->setWidth(14);
|
$spreadsheet->getActiveSheet()->getColumnDimension('F')->setWidth(14);
|
||||||
$spreadsheet->getActiveSheet()->freezePane('A2');
|
$spreadsheet->getActiveSheet()->freezePane('A2');
|
||||||
|
|
|
||||||
|
|
@ -95,7 +95,7 @@ $spreadsheet->getActiveSheet()->getStyle('A1:F1')->getFont()->setBold(true);
|
||||||
$spreadsheet->getActiveSheet()->getStyle('A1:F1')->getAlignment()->setWrapText(true);
|
$spreadsheet->getActiveSheet()->getStyle('A1:F1')->getAlignment()->setWrapText(true);
|
||||||
$spreadsheet->getActiveSheet()->getColumnDimension('C')->setWidth(12.5);
|
$spreadsheet->getActiveSheet()->getColumnDimension('C')->setWidth(12.5);
|
||||||
$spreadsheet->getActiveSheet()->getColumnDimension('D')->setWidth(10.5);
|
$spreadsheet->getActiveSheet()->getColumnDimension('D')->setWidth(10.5);
|
||||||
$spreadsheet->getActiveSheet()->getStyle('D2:D' . $row)->getNumberFormat()->setFormatCode(NumberFormat::FORMAT_DATE_YYYYMMDD2);
|
$spreadsheet->getActiveSheet()->getStyle('D2:D' . $row)->getNumberFormat()->setFormatCode(NumberFormat::FORMAT_DATE_YYYYMMDD);
|
||||||
$spreadsheet->getActiveSheet()->getStyle('E2:F' . $row)->getNumberFormat()->setFormatCode(NumberFormat::FORMAT_CURRENCY_USD_SIMPLE);
|
$spreadsheet->getActiveSheet()->getStyle('E2:F' . $row)->getNumberFormat()->setFormatCode(NumberFormat::FORMAT_CURRENCY_USD_SIMPLE);
|
||||||
$spreadsheet->getActiveSheet()->getColumnDimension('F')->setWidth(14);
|
$spreadsheet->getActiveSheet()->getColumnDimension('F')->setWidth(14);
|
||||||
$spreadsheet->getActiveSheet()->freezePane('A2');
|
$spreadsheet->getActiveSheet()->freezePane('A2');
|
||||||
|
|
|
||||||
|
|
@ -95,7 +95,7 @@ $spreadsheet->getActiveSheet()->getStyle('A1:F1')->getFont()->setBold(true);
|
||||||
$spreadsheet->getActiveSheet()->getStyle('A1:F1')->getAlignment()->setWrapText(true);
|
$spreadsheet->getActiveSheet()->getStyle('A1:F1')->getAlignment()->setWrapText(true);
|
||||||
$spreadsheet->getActiveSheet()->getColumnDimension('C')->setWidth(12.5);
|
$spreadsheet->getActiveSheet()->getColumnDimension('C')->setWidth(12.5);
|
||||||
$spreadsheet->getActiveSheet()->getColumnDimension('D')->setWidth(10.5);
|
$spreadsheet->getActiveSheet()->getColumnDimension('D')->setWidth(10.5);
|
||||||
$spreadsheet->getActiveSheet()->getStyle('D2:D' . $row)->getNumberFormat()->setFormatCode(NumberFormat::FORMAT_DATE_YYYYMMDD2);
|
$spreadsheet->getActiveSheet()->getStyle('D2:D' . $row)->getNumberFormat()->setFormatCode(NumberFormat::FORMAT_DATE_YYYYMMDD);
|
||||||
$spreadsheet->getActiveSheet()->getStyle('E2:F' . $row)->getNumberFormat()->setFormatCode(NumberFormat::FORMAT_CURRENCY_USD_SIMPLE);
|
$spreadsheet->getActiveSheet()->getStyle('E2:F' . $row)->getNumberFormat()->setFormatCode(NumberFormat::FORMAT_CURRENCY_USD_SIMPLE);
|
||||||
$spreadsheet->getActiveSheet()->getColumnDimension('F')->setWidth(14);
|
$spreadsheet->getActiveSheet()->getColumnDimension('F')->setWidth(14);
|
||||||
$spreadsheet->getActiveSheet()->freezePane('A2');
|
$spreadsheet->getActiveSheet()->freezePane('A2');
|
||||||
|
|
|
||||||
|
|
@ -81,7 +81,7 @@ $spreadsheet->getActiveSheet()
|
||||||
$spreadsheet->getActiveSheet()
|
$spreadsheet->getActiveSheet()
|
||||||
->getStyle('C9')
|
->getStyle('C9')
|
||||||
->getNumberFormat()
|
->getNumberFormat()
|
||||||
->setFormatCode(NumberFormat::FORMAT_DATE_YYYYMMDD2);
|
->setFormatCode(NumberFormat::FORMAT_DATE_YYYYMMDD);
|
||||||
|
|
||||||
$spreadsheet->getActiveSheet()
|
$spreadsheet->getActiveSheet()
|
||||||
->setCellValue('A10', 'Date/Time')
|
->setCellValue('A10', 'Date/Time')
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,6 @@ use PhpOffice\PhpSpreadsheet\Style\ConditionalFormatting\CellStyleAssessor;
|
||||||
use PhpOffice\PhpSpreadsheet\Style\NumberFormat;
|
use PhpOffice\PhpSpreadsheet\Style\NumberFormat;
|
||||||
use PhpOffice\PhpSpreadsheet\Style\Style;
|
use PhpOffice\PhpSpreadsheet\Style\Style;
|
||||||
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
|
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
|
||||||
use Throwable;
|
|
||||||
|
|
||||||
class Cell
|
class Cell
|
||||||
{
|
{
|
||||||
|
|
@ -52,7 +51,7 @@ class Cell
|
||||||
/**
|
/**
|
||||||
* The collection of cells that this cell belongs to (i.e. The Cell Collection for the parent Worksheet).
|
* The collection of cells that this cell belongs to (i.e. The Cell Collection for the parent Worksheet).
|
||||||
*
|
*
|
||||||
* @var Cells
|
* @var ?Cells
|
||||||
*/
|
*/
|
||||||
private $parent;
|
private $parent;
|
||||||
|
|
||||||
|
|
@ -65,6 +64,8 @@ class Cell
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attributes of the formula.
|
* Attributes of the formula.
|
||||||
|
*
|
||||||
|
* @var mixed
|
||||||
*/
|
*/
|
||||||
private $formulaAttributes;
|
private $formulaAttributes;
|
||||||
|
|
||||||
|
|
@ -75,14 +76,17 @@ class Cell
|
||||||
*/
|
*/
|
||||||
public function updateInCollection(): self
|
public function updateInCollection(): self
|
||||||
{
|
{
|
||||||
$this->parent->update($this);
|
$parent = $this->parent;
|
||||||
|
if ($parent === null) {
|
||||||
|
throw new Exception('Cannot update when cell is not bound to a worksheet');
|
||||||
|
}
|
||||||
|
$parent->update($this);
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function detach(): void
|
public function detach(): void
|
||||||
{
|
{
|
||||||
// @phpstan-ignore-next-line
|
|
||||||
$this->parent = null;
|
$this->parent = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -122,7 +126,12 @@ class Cell
|
||||||
*/
|
*/
|
||||||
public function getColumn()
|
public function getColumn()
|
||||||
{
|
{
|
||||||
return $this->parent->getCurrentColumn();
|
$parent = $this->parent;
|
||||||
|
if ($parent === null) {
|
||||||
|
throw new Exception('Cannot get column when cell is not bound to a worksheet');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $parent->getCurrentColumn();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -132,7 +141,12 @@ class Cell
|
||||||
*/
|
*/
|
||||||
public function getRow()
|
public function getRow()
|
||||||
{
|
{
|
||||||
return $this->parent->getCurrentRow();
|
$parent = $this->parent;
|
||||||
|
if ($parent === null) {
|
||||||
|
throw new Exception('Cannot get row when cell is not bound to a worksheet');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $parent->getCurrentRow();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -142,9 +156,10 @@ class Cell
|
||||||
*/
|
*/
|
||||||
public function getCoordinate()
|
public function getCoordinate()
|
||||||
{
|
{
|
||||||
try {
|
$parent = $this->parent;
|
||||||
$coordinate = $this->parent->getCurrentCoordinate();
|
if ($parent !== null) {
|
||||||
} catch (Throwable $e) {
|
$coordinate = $parent->getCurrentCoordinate();
|
||||||
|
} else {
|
||||||
$coordinate = null;
|
$coordinate = null;
|
||||||
}
|
}
|
||||||
if ($coordinate === null) {
|
if ($coordinate === null) {
|
||||||
|
|
@ -171,8 +186,7 @@ class Cell
|
||||||
{
|
{
|
||||||
return (string) NumberFormat::toFormattedString(
|
return (string) NumberFormat::toFormattedString(
|
||||||
$this->getCalculatedValue(),
|
$this->getCalculatedValue(),
|
||||||
$this->getStyle()
|
(string) $this->getStyle()->getNumberFormat()->getFormatCode()
|
||||||
->getNumberFormat()->getFormatCode()
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -251,8 +265,6 @@ class Cell
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new Exception('Invalid datatype: ' . $dataType);
|
throw new Exception('Invalid datatype: ' . $dataType);
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// set the datatype
|
// set the datatype
|
||||||
|
|
@ -261,6 +273,56 @@ class Cell
|
||||||
return $this->updateInCollection();
|
return $this->updateInCollection();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public const CALCULATE_DATE_TIME_ASIS = 0;
|
||||||
|
public const CALCULATE_DATE_TIME_FLOAT = 1;
|
||||||
|
public const CALCULATE_TIME_FLOAT = 2;
|
||||||
|
|
||||||
|
/** @var int */
|
||||||
|
private static $calculateDateTimeType = self::CALCULATE_DATE_TIME_ASIS;
|
||||||
|
|
||||||
|
public static function getCalculateDateTimeType(): int
|
||||||
|
{
|
||||||
|
return self::$calculateDateTimeType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function setCalculateDateTimeType(int $calculateDateTimeType): void
|
||||||
|
{
|
||||||
|
switch ($calculateDateTimeType) {
|
||||||
|
case self::CALCULATE_DATE_TIME_ASIS:
|
||||||
|
case self::CALCULATE_DATE_TIME_FLOAT:
|
||||||
|
case self::CALCULATE_TIME_FLOAT:
|
||||||
|
self::$calculateDateTimeType = $calculateDateTimeType;
|
||||||
|
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new \PhpOffice\PhpSpreadsheet\Calculation\Exception("Invalid value $calculateDateTimeType for calculated date time type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert date, time, or datetime from int to float if desired.
|
||||||
|
*
|
||||||
|
* @param mixed $result
|
||||||
|
*
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
private function convertDateTimeInt($result)
|
||||||
|
{
|
||||||
|
if (is_int($result)) {
|
||||||
|
if (self::$calculateDateTimeType === self::CALCULATE_TIME_FLOAT) {
|
||||||
|
if (SharedDate::isDateTime($this, $result, false)) {
|
||||||
|
$result = (float) $result;
|
||||||
|
}
|
||||||
|
} elseif (self::$calculateDateTimeType === self::CALCULATE_DATE_TIME_FLOAT) {
|
||||||
|
if (SharedDate::isDateTime($this, $result, true)) {
|
||||||
|
$result = (float) $result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get calculated cell value.
|
* Get calculated cell value.
|
||||||
*
|
*
|
||||||
|
|
@ -277,6 +339,7 @@ class Cell
|
||||||
$result = Calculation::getInstance(
|
$result = Calculation::getInstance(
|
||||||
$this->getWorksheet()->getParent()
|
$this->getWorksheet()->getParent()
|
||||||
)->calculateCellValue($this, $resetLog);
|
)->calculateCellValue($this, $resetLog);
|
||||||
|
$result = $this->convertDateTimeInt($result);
|
||||||
$this->getWorksheet()->setSelectedCells($selected);
|
$this->getWorksheet()->setSelectedCells($selected);
|
||||||
$this->getWorksheet()->getParent()->setActiveSheetIndex($index);
|
$this->getWorksheet()->getParent()->setActiveSheetIndex($index);
|
||||||
// We don't yet handle array returns
|
// We don't yet handle array returns
|
||||||
|
|
@ -306,7 +369,7 @@ class Cell
|
||||||
return $this->value->getPlainText();
|
return $this->value->getPlainText();
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->value;
|
return $this->convertDateTimeInt($this->value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -458,7 +521,7 @@ class Cell
|
||||||
/**
|
/**
|
||||||
* Get cell collection.
|
* Get cell collection.
|
||||||
*
|
*
|
||||||
* @return Cells
|
* @return ?Cells
|
||||||
*/
|
*/
|
||||||
public function getParent()
|
public function getParent()
|
||||||
{
|
{
|
||||||
|
|
@ -470,9 +533,10 @@ class Cell
|
||||||
*/
|
*/
|
||||||
public function getWorksheet(): Worksheet
|
public function getWorksheet(): Worksheet
|
||||||
{
|
{
|
||||||
try {
|
$parent = $this->parent;
|
||||||
$worksheet = $this->parent->getParent();
|
if ($parent !== null) {
|
||||||
} catch (Throwable $e) {
|
$worksheet = $parent->getParent();
|
||||||
|
} else {
|
||||||
$worksheet = null;
|
$worksheet = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -483,6 +547,18 @@ class Cell
|
||||||
return $worksheet;
|
return $worksheet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getWorksheetOrNull(): ?Worksheet
|
||||||
|
{
|
||||||
|
$parent = $this->parent;
|
||||||
|
if ($parent !== null) {
|
||||||
|
$worksheet = $parent->getParent();
|
||||||
|
} else {
|
||||||
|
$worksheet = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $worksheet;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Is this cell in a merge range.
|
* Is this cell in a merge range.
|
||||||
*/
|
*/
|
||||||
|
|
@ -666,6 +742,8 @@ class Cell
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the formula attributes.
|
* Get the formula attributes.
|
||||||
|
*
|
||||||
|
* @return mixed
|
||||||
*/
|
*/
|
||||||
public function getFormulaAttributes()
|
public function getFormulaAttributes()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -301,7 +301,7 @@ class Date
|
||||||
* The use of Unix timestamps, and therefore this function, is discouraged.
|
* The use of Unix timestamps, and therefore this function, is discouraged.
|
||||||
* They are not Y2038-safe on a 32-bit system, and have no timezone info.
|
* They are not Y2038-safe on a 32-bit system, and have no timezone info.
|
||||||
*
|
*
|
||||||
* @param int $unixTimestamp Unix Timestamp
|
* @param float|int|string $unixTimestamp Unix Timestamp
|
||||||
*
|
*
|
||||||
* @return false|float MS Excel serialized date/time value
|
* @return false|float MS Excel serialized date/time value
|
||||||
*/
|
*/
|
||||||
|
|
@ -352,8 +352,8 @@ class Date
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate the Julian Date, then subtract the Excel base date (JD 2415020 = 31-Dec-1899 Giving Excel Date of 0)
|
// Calculate the Julian Date, then subtract the Excel base date (JD 2415020 = 31-Dec-1899 Giving Excel Date of 0)
|
||||||
$century = (int) substr($year, 0, 2);
|
$century = (int) substr((string) $year, 0, 2);
|
||||||
$decade = (int) substr($year, 2, 2);
|
$decade = (int) substr((string) $year, 2, 2);
|
||||||
$excelDate = floor((146097 * $century) / 4) + floor((1461 * $decade) / 4) + floor((153 * $month + 2) / 5) + $day + 1721119 - $myexcelBaseDate + $excel1900isLeapYear;
|
$excelDate = floor((146097 * $century) / 4) + floor((1461 * $decade) / 4) + floor((153 * $month + 2) / 5) + $day + 1721119 - $myexcelBaseDate + $excel1900isLeapYear;
|
||||||
|
|
||||||
$excelTime = (($hours * 3600) + ($minutes * 60) + $seconds) / 86400;
|
$excelTime = (($hours * 3600) + ($minutes * 60) + $seconds) / 86400;
|
||||||
|
|
@ -364,16 +364,30 @@ class Date
|
||||||
/**
|
/**
|
||||||
* Is a given cell a date/time?
|
* Is a given cell a date/time?
|
||||||
*
|
*
|
||||||
|
* @param mixed $value
|
||||||
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public static function isDateTime(Cell $cell)
|
public static function isDateTime(Cell $cell, $value = null, bool $dateWithoutTimeOkay = true)
|
||||||
{
|
{
|
||||||
return is_numeric($cell->getCalculatedValue()) &&
|
$result = false;
|
||||||
self::isDateTimeFormat(
|
$worksheet = $cell->getWorksheetOrNull();
|
||||||
$cell->getWorksheet()->getStyle(
|
$spreadsheet = ($worksheet === null) ? null : $worksheet->getParent();
|
||||||
$cell->getCoordinate()
|
if ($worksheet !== null && $spreadsheet !== null) {
|
||||||
)->getNumberFormat()
|
$index = $spreadsheet->getActiveSheetIndex();
|
||||||
);
|
$selected = $worksheet->getSelectedCells();
|
||||||
|
$result = is_numeric($value ?? $cell->getCalculatedValue()) &&
|
||||||
|
self::isDateTimeFormat(
|
||||||
|
$worksheet->getStyle(
|
||||||
|
$cell->getCoordinate()
|
||||||
|
)->getNumberFormat(),
|
||||||
|
$dateWithoutTimeOkay
|
||||||
|
);
|
||||||
|
$worksheet->setSelectedCells($selected);
|
||||||
|
$spreadsheet->setActiveSheetIndex($index);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -381,12 +395,13 @@ class Date
|
||||||
*
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public static function isDateTimeFormat(NumberFormat $excelFormatCode)
|
public static function isDateTimeFormat(NumberFormat $excelFormatCode, bool $dateWithoutTimeOkay = true)
|
||||||
{
|
{
|
||||||
return self::isDateTimeFormatCode($excelFormatCode->getFormatCode());
|
return self::isDateTimeFormatCode((string) $excelFormatCode->getFormatCode(), $dateWithoutTimeOkay);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static $possibleDateFormatCharacters = 'eymdHs';
|
private const POSSIBLE_DATETIME_FORMAT_CHARACTERS = 'eymdHs';
|
||||||
|
private const POSSIBLE_TIME_FORMAT_CHARACTERS = 'Hs'; // note - no 'm' due to ambiguity
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Is a given number format code a date/time?
|
* Is a given number format code a date/time?
|
||||||
|
|
@ -395,7 +410,7 @@ class Date
|
||||||
*
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public static function isDateTimeFormatCode($excelFormatCode)
|
public static function isDateTimeFormatCode($excelFormatCode, bool $dateWithoutTimeOkay = true)
|
||||||
{
|
{
|
||||||
if (strtolower($excelFormatCode) === strtolower(NumberFormat::FORMAT_GENERAL)) {
|
if (strtolower($excelFormatCode) === strtolower(NumberFormat::FORMAT_GENERAL)) {
|
||||||
// "General" contains an epoch letter 'e', so we trap for it explicitly here (case-insensitive check)
|
// "General" contains an epoch letter 'e', so we trap for it explicitly here (case-insensitive check)
|
||||||
|
|
@ -407,31 +422,8 @@ class Date
|
||||||
}
|
}
|
||||||
|
|
||||||
// Switch on formatcode
|
// Switch on formatcode
|
||||||
switch ($excelFormatCode) {
|
if (in_array($excelFormatCode, NumberFormat::DATE_TIME_OR_DATETIME_ARRAY, true)) {
|
||||||
// Explicitly defined date formats
|
return $dateWithoutTimeOkay || in_array($excelFormatCode, NumberFormat::TIME_OR_DATETIME_ARRAY);
|
||||||
case NumberFormat::FORMAT_DATE_YYYYMMDD:
|
|
||||||
case NumberFormat::FORMAT_DATE_YYYYMMDD2:
|
|
||||||
case NumberFormat::FORMAT_DATE_DDMMYYYY:
|
|
||||||
case NumberFormat::FORMAT_DATE_DMYSLASH:
|
|
||||||
case NumberFormat::FORMAT_DATE_DMYMINUS:
|
|
||||||
case NumberFormat::FORMAT_DATE_DMMINUS:
|
|
||||||
case NumberFormat::FORMAT_DATE_MYMINUS:
|
|
||||||
case NumberFormat::FORMAT_DATE_DATETIME:
|
|
||||||
case NumberFormat::FORMAT_DATE_TIME1:
|
|
||||||
case NumberFormat::FORMAT_DATE_TIME2:
|
|
||||||
case NumberFormat::FORMAT_DATE_TIME3:
|
|
||||||
case NumberFormat::FORMAT_DATE_TIME4:
|
|
||||||
case NumberFormat::FORMAT_DATE_TIME5:
|
|
||||||
case NumberFormat::FORMAT_DATE_TIME6:
|
|
||||||
case NumberFormat::FORMAT_DATE_TIME7:
|
|
||||||
case NumberFormat::FORMAT_DATE_TIME8:
|
|
||||||
case NumberFormat::FORMAT_DATE_YYYYMMDDSLASH:
|
|
||||||
case NumberFormat::FORMAT_DATE_XLSX14:
|
|
||||||
case NumberFormat::FORMAT_DATE_XLSX15:
|
|
||||||
case NumberFormat::FORMAT_DATE_XLSX16:
|
|
||||||
case NumberFormat::FORMAT_DATE_XLSX17:
|
|
||||||
case NumberFormat::FORMAT_DATE_XLSX22:
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Typically number, currency or accounting (or occasionally fraction) formats
|
// Typically number, currency or accounting (or occasionally fraction) formats
|
||||||
|
|
@ -443,8 +435,9 @@ class Date
|
||||||
if (\strpos($excelFormatCode, '-00000') !== false) {
|
if (\strpos($excelFormatCode, '-00000') !== false) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
$possibleFormatCharacters = $dateWithoutTimeOkay ? self::POSSIBLE_DATETIME_FORMAT_CHARACTERS : self::POSSIBLE_TIME_FORMAT_CHARACTERS;
|
||||||
// Try checking for any of the date formatting characters that don't appear within square braces
|
// Try checking for any of the date formatting characters that don't appear within square braces
|
||||||
if (preg_match('/(^|\])[^\[]*[' . self::$possibleDateFormatCharacters . ']/i', $excelFormatCode)) {
|
if (preg_match('/(^|\])[^\[]*[' . $possibleFormatCharacters . ']/i', $excelFormatCode)) {
|
||||||
// We might also have a format mask containing quoted strings...
|
// We might also have a format mask containing quoted strings...
|
||||||
// we don't want to test for any of our characters within the quoted blocks
|
// we don't want to test for any of our characters within the quoted blocks
|
||||||
if (strpos($excelFormatCode, '"') !== false) {
|
if (strpos($excelFormatCode, '"') !== false) {
|
||||||
|
|
@ -453,7 +446,7 @@ class Date
|
||||||
// Only test in alternate array entries (the non-quoted blocks)
|
// Only test in alternate array entries (the non-quoted blocks)
|
||||||
if (
|
if (
|
||||||
($segMatcher = !$segMatcher) &&
|
($segMatcher = !$segMatcher) &&
|
||||||
(preg_match('/(^|\])[^\[]*[' . self::$possibleDateFormatCharacters . ']/i', $subVal))
|
(preg_match('/(^|\])[^\[]*[' . $possibleFormatCharacters . ']/i', $subVal))
|
||||||
) {
|
) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ class NumberFormat extends Supervisor
|
||||||
const FORMAT_PERCENTAGE_0 = '0.0%';
|
const FORMAT_PERCENTAGE_0 = '0.0%';
|
||||||
const FORMAT_PERCENTAGE_00 = '0.00%';
|
const FORMAT_PERCENTAGE_00 = '0.00%';
|
||||||
|
|
||||||
|
/** @deprecated 1.26 use FORMAT_DATE_YYYYMMDD instead */
|
||||||
const FORMAT_DATE_YYYYMMDD2 = 'yyyy-mm-dd';
|
const FORMAT_DATE_YYYYMMDD2 = 'yyyy-mm-dd';
|
||||||
const FORMAT_DATE_YYYYMMDD = 'yyyy-mm-dd';
|
const FORMAT_DATE_YYYYMMDD = 'yyyy-mm-dd';
|
||||||
const FORMAT_DATE_DDMMYYYY = 'dd/mm/yyyy';
|
const FORMAT_DATE_DDMMYYYY = 'dd/mm/yyyy';
|
||||||
|
|
@ -42,6 +43,42 @@ class NumberFormat extends Supervisor
|
||||||
const FORMAT_DATE_TIME8 = 'h:mm:ss;@';
|
const FORMAT_DATE_TIME8 = 'h:mm:ss;@';
|
||||||
const FORMAT_DATE_YYYYMMDDSLASH = 'yyyy/mm/dd;@';
|
const FORMAT_DATE_YYYYMMDDSLASH = 'yyyy/mm/dd;@';
|
||||||
|
|
||||||
|
const DATE_TIME_OR_DATETIME_ARRAY = [
|
||||||
|
self::FORMAT_DATE_YYYYMMDD,
|
||||||
|
self::FORMAT_DATE_DDMMYYYY,
|
||||||
|
self::FORMAT_DATE_DMYSLASH,
|
||||||
|
self::FORMAT_DATE_DMYMINUS,
|
||||||
|
self::FORMAT_DATE_DMMINUS,
|
||||||
|
self::FORMAT_DATE_MYMINUS,
|
||||||
|
self::FORMAT_DATE_XLSX14,
|
||||||
|
self::FORMAT_DATE_XLSX15,
|
||||||
|
self::FORMAT_DATE_XLSX16,
|
||||||
|
self::FORMAT_DATE_XLSX17,
|
||||||
|
self::FORMAT_DATE_XLSX22,
|
||||||
|
self::FORMAT_DATE_DATETIME,
|
||||||
|
self::FORMAT_DATE_TIME1,
|
||||||
|
self::FORMAT_DATE_TIME2,
|
||||||
|
self::FORMAT_DATE_TIME3,
|
||||||
|
self::FORMAT_DATE_TIME4,
|
||||||
|
self::FORMAT_DATE_TIME5,
|
||||||
|
self::FORMAT_DATE_TIME6,
|
||||||
|
self::FORMAT_DATE_TIME7,
|
||||||
|
self::FORMAT_DATE_TIME8,
|
||||||
|
self::FORMAT_DATE_YYYYMMDDSLASH,
|
||||||
|
];
|
||||||
|
const TIME_OR_DATETIME_ARRAY = [
|
||||||
|
self::FORMAT_DATE_XLSX22,
|
||||||
|
self::FORMAT_DATE_DATETIME,
|
||||||
|
self::FORMAT_DATE_TIME1,
|
||||||
|
self::FORMAT_DATE_TIME2,
|
||||||
|
self::FORMAT_DATE_TIME3,
|
||||||
|
self::FORMAT_DATE_TIME4,
|
||||||
|
self::FORMAT_DATE_TIME5,
|
||||||
|
self::FORMAT_DATE_TIME6,
|
||||||
|
self::FORMAT_DATE_TIME7,
|
||||||
|
self::FORMAT_DATE_TIME8,
|
||||||
|
];
|
||||||
|
|
||||||
const FORMAT_CURRENCY_USD_SIMPLE = '"$"#,##0.00_-';
|
const FORMAT_CURRENCY_USD_SIMPLE = '"$"#,##0.00_-';
|
||||||
const FORMAT_CURRENCY_USD = '$#,##0_-';
|
const FORMAT_CURRENCY_USD = '$#,##0_-';
|
||||||
const FORMAT_CURRENCY_EUR_SIMPLE = '#,##0.00_-"€"';
|
const FORMAT_CURRENCY_EUR_SIMPLE = '#,##0.00_-"€"';
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,78 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace PhpOffice\PhpSpreadsheetTests\Cell;
|
||||||
|
|
||||||
|
use PhpOffice\PhpSpreadsheet\Cell\Cell;
|
||||||
|
use PhpOffice\PhpSpreadsheet\Exception as SpreadsheetException;
|
||||||
|
use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
class CellDetachTest extends TestCase
|
||||||
|
{
|
||||||
|
/** @var ?Spreadsheet */
|
||||||
|
private $spreadsheet;
|
||||||
|
|
||||||
|
protected function tearDown(): void
|
||||||
|
{
|
||||||
|
if ($this->spreadsheet !== null) {
|
||||||
|
$this->spreadsheet->disconnectWorksheets();
|
||||||
|
$this->spreadsheet = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider providerMethodName
|
||||||
|
*/
|
||||||
|
public function testDetach(string $method): void
|
||||||
|
{
|
||||||
|
$this->expectException(SpreadsheetException::class);
|
||||||
|
$this->expectExceptionMessage('is not bound to a worksheet');
|
||||||
|
$this->spreadsheet = new Spreadsheet();
|
||||||
|
$sheet = $this->spreadsheet->getActiveSheet();
|
||||||
|
$sheet->getCell('A1')->detach();
|
||||||
|
if (method_exists(Cell::class, $method)) {
|
||||||
|
$sheet->getCell('A1')->$method();
|
||||||
|
} else {
|
||||||
|
self::fail("Cell method $method does not exist");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function providerMethodName(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
['updateInCollection'],
|
||||||
|
['getColumn'],
|
||||||
|
['getRow'],
|
||||||
|
['hasDataValidation'],
|
||||||
|
['getDataValidation'],
|
||||||
|
['hasHyperlink'],
|
||||||
|
['getHyperlink'],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider providerMethodNameSet
|
||||||
|
*/
|
||||||
|
public function testDetachSet(string $method): void
|
||||||
|
{
|
||||||
|
$this->expectException(SpreadsheetException::class);
|
||||||
|
$this->expectExceptionMessage('is not bound to a worksheet');
|
||||||
|
$this->spreadsheet = new Spreadsheet();
|
||||||
|
$sheet = $this->spreadsheet->getActiveSheet();
|
||||||
|
$sheet->getCell('A1')->detach();
|
||||||
|
if (method_exists(Cell::class, $method)) {
|
||||||
|
$sheet->getCell('A1')->$method(null);
|
||||||
|
} else {
|
||||||
|
self::fail("Cell method $method does not exist");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function providerMethodNameSet(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
['setDataValidation'],
|
||||||
|
['setHyperlink'],
|
||||||
|
['setValue'],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -118,8 +118,13 @@ class CellTest extends TestCase
|
||||||
self::assertSame('A1', $cell->getCoordinate());
|
self::assertSame('A1', $cell->getCoordinate());
|
||||||
$this->expectException(Exception::class);
|
$this->expectException(Exception::class);
|
||||||
$this->expectExceptionMessage('Coordinate no longer exists');
|
$this->expectExceptionMessage('Coordinate no longer exists');
|
||||||
$cell->getParent()->delete('A1');
|
$parent = $cell->getParent();
|
||||||
$cell->getCoordinate();
|
if ($parent === null) {
|
||||||
|
self::fail('Unexpected null parent');
|
||||||
|
} else {
|
||||||
|
$parent->delete('A1');
|
||||||
|
$cell->getCoordinate();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testAppliedStyleWithRange(): void
|
public function testAppliedStyleWithRange(): void
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,212 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace PhpOffice\PhpSpreadsheetTests\Shared;
|
||||||
|
|
||||||
|
use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalculationException;
|
||||||
|
use PhpOffice\PhpSpreadsheet\Cell\Cell;
|
||||||
|
use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
||||||
|
use PhpOffice\PhpSpreadsheet\Style\NumberFormat;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
class Date2Test extends TestCase
|
||||||
|
{
|
||||||
|
/** @var ?Spreadsheet */
|
||||||
|
private $spreadsheet;
|
||||||
|
|
||||||
|
/** @var int */
|
||||||
|
private $calculateDateTimeType;
|
||||||
|
|
||||||
|
protected function setUp(): void
|
||||||
|
{
|
||||||
|
$this->calculateDateTimeType = Cell::getCalculateDateTimeType();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function tearDown(): void
|
||||||
|
{
|
||||||
|
Cell::setCalculateDateTimeType($this->calculateDateTimeType);
|
||||||
|
if ($this->spreadsheet !== null) {
|
||||||
|
$this->spreadsheet->disconnectWorksheets();
|
||||||
|
$this->spreadsheet = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testInvalidType(): void
|
||||||
|
{
|
||||||
|
$this->expectException(CalculationException::class);
|
||||||
|
$this->expectExceptionMessage('for calculated date time type');
|
||||||
|
Cell::setCalculateDateTimeType(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider providerTimeOnly
|
||||||
|
*
|
||||||
|
* @param float|int $expectedResult
|
||||||
|
* @param float|int $value
|
||||||
|
* @param string $format
|
||||||
|
*/
|
||||||
|
public function testTimeOnly($expectedResult, $value, ?string $format = null): void
|
||||||
|
{
|
||||||
|
Cell::setCalculateDateTimeType(Cell::CALCULATE_TIME_FLOAT);
|
||||||
|
$this->spreadsheet = new Spreadsheet();
|
||||||
|
self::assertSame(0, $this->spreadsheet->getActiveSheetIndex());
|
||||||
|
$sheet = $this->spreadsheet->getActiveSheet();
|
||||||
|
$newSheet = $this->spreadsheet->createSheet();
|
||||||
|
$newSheet->getCell('B7')->setValue('Here');
|
||||||
|
$sheet->getCell('A1')->setValue($value);
|
||||||
|
if ($format !== null) {
|
||||||
|
$sheet->getStyle('A1')->getNumberFormat()->setFormatCode($format);
|
||||||
|
}
|
||||||
|
$sheet->setSelectedCells('B7');
|
||||||
|
$this->spreadsheet->setActiveSheetIndex(1);
|
||||||
|
self::assertSame($expectedResult, $sheet->getCell('A1')->getCalculatedValue());
|
||||||
|
self::assertSame('B7', $sheet->getSelectedCells());
|
||||||
|
self::assertSame(1, $this->spreadsheet->getActiveSheetIndex());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function providerTimeOnly(): array
|
||||||
|
{
|
||||||
|
$integerValue = 44046;
|
||||||
|
$integerValueAsFloat = (float) $integerValue;
|
||||||
|
$integerValueAsDateFormula = '=DATEVALUE("2020-08-03")';
|
||||||
|
$floatValue = 44015.25;
|
||||||
|
$floatValueAsDateFormula = '=DATEVALUE("2020-07-03")+TIMEVALUE("06:00")';
|
||||||
|
|
||||||
|
return [
|
||||||
|
'default format integer' => [$integerValue, $integerValue],
|
||||||
|
'default format float' => [$floatValue, $floatValue],
|
||||||
|
'date format integer' => [$integerValue, $integerValue, NumberFormat::FORMAT_DATE_YYYYMMDD],
|
||||||
|
'date format float' => [$floatValue, $floatValue, NumberFormat::FORMAT_DATE_YYYYMMDD],
|
||||||
|
'datetime format integer' => [$integerValueAsFloat, $integerValue, 'yyyy-mm-dd h:mm'],
|
||||||
|
'datetime format float' => [$floatValue, $floatValue, 'yyyy-mm-dd h:mm'],
|
||||||
|
'time format integer' => [$integerValueAsFloat, $integerValue, NumberFormat::FORMAT_DATE_TIME1],
|
||||||
|
'time format float' => [$floatValue, $floatValue, NumberFormat::FORMAT_DATE_TIME1],
|
||||||
|
'date formula integer fltfmt' => [$integerValueAsFloat, $integerValueAsDateFormula, NumberFormat::FORMAT_DATE_TIME1],
|
||||||
|
'date formula float' => [$floatValue, $floatValueAsDateFormula, NumberFormat::FORMAT_DATE_TIME1],
|
||||||
|
'date formula integer intfmt but formula returns float' => [$integerValueAsFloat, $integerValueAsDateFormula, NumberFormat::FORMAT_DATE_YYYYMMDD],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider providerDateAndTime
|
||||||
|
*
|
||||||
|
* @param float|int $expectedResult
|
||||||
|
* @param float|int $value
|
||||||
|
* @param string $format
|
||||||
|
*/
|
||||||
|
public function testDateAndTime($expectedResult, $value, ?string $format = null): void
|
||||||
|
{
|
||||||
|
Cell::setCalculateDateTimeType(Cell::CALCULATE_DATE_TIME_FLOAT);
|
||||||
|
$this->spreadsheet = new Spreadsheet();
|
||||||
|
self::assertSame(0, $this->spreadsheet->getActiveSheetIndex());
|
||||||
|
$sheet = $this->spreadsheet->getActiveSheet();
|
||||||
|
$newSheet = $this->spreadsheet->createSheet();
|
||||||
|
$newSheet->getCell('B7')->setValue('Here');
|
||||||
|
$sheet->getCell('A1')->setValue($value);
|
||||||
|
if ($format !== null) {
|
||||||
|
$sheet->getStyle('A1')->getNumberFormat()->setFormatCode($format);
|
||||||
|
}
|
||||||
|
$sheet->setSelectedCells('B7');
|
||||||
|
$this->spreadsheet->setActiveSheetIndex(1);
|
||||||
|
self::assertSame($expectedResult, $sheet->getCell('A1')->getCalculatedValue());
|
||||||
|
self::assertSame('B7', $sheet->getSelectedCells());
|
||||||
|
self::assertSame(1, $this->spreadsheet->getActiveSheetIndex());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function providerDateAndTime(): array
|
||||||
|
{
|
||||||
|
$integerValue = 44046;
|
||||||
|
$integerValueAsFloat = (float) $integerValue;
|
||||||
|
$integerValueAsDateFormula = '=DATEVALUE("2020-08-03")';
|
||||||
|
$floatValue = 44015.25;
|
||||||
|
$floatValueAsDateFormula = '=DATEVALUE("2020-07-03")+TIMEVALUE("06:00")';
|
||||||
|
|
||||||
|
return [
|
||||||
|
'default format integer' => [$integerValue, $integerValue],
|
||||||
|
'default format float' => [$floatValue, $floatValue],
|
||||||
|
'date format integer' => [$integerValueAsFloat, $integerValue, NumberFormat::FORMAT_DATE_YYYYMMDD],
|
||||||
|
'date format float' => [$floatValue, $floatValue, NumberFormat::FORMAT_DATE_YYYYMMDD],
|
||||||
|
'datetime format integer' => [$integerValueAsFloat, $integerValue, 'yyyy-mm-dd h:mm'],
|
||||||
|
'datetime format float' => [$floatValue, $floatValue, 'yyyy-mm-dd h:mm'],
|
||||||
|
'time format integer' => [$integerValueAsFloat, $integerValue, NumberFormat::FORMAT_DATE_TIME1],
|
||||||
|
'time format float' => [$floatValue, $floatValue, NumberFormat::FORMAT_DATE_TIME1],
|
||||||
|
'date formula integer fltfmt' => [$integerValueAsFloat, $integerValueAsDateFormula, NumberFormat::FORMAT_DATE_TIME1],
|
||||||
|
'date formula float' => [$floatValue, $floatValueAsDateFormula, NumberFormat::FORMAT_DATE_TIME1],
|
||||||
|
'date formula integer intfmt but formula returns float' => [$integerValueAsFloat, $integerValueAsDateFormula, NumberFormat::FORMAT_DATE_YYYYMMDD],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider providerAsis
|
||||||
|
*
|
||||||
|
* @param float|int $expectedResult
|
||||||
|
* @param float|int $value
|
||||||
|
* @param string $format
|
||||||
|
*/
|
||||||
|
public function testDefault($expectedResult, $value, ?string $format = null): void
|
||||||
|
{
|
||||||
|
//Cell::setCalculateDateTimeType(Cell::CALCULATE_DATE_TIME_ASIS);
|
||||||
|
$this->spreadsheet = new Spreadsheet();
|
||||||
|
self::assertSame(0, $this->spreadsheet->getActiveSheetIndex());
|
||||||
|
$sheet = $this->spreadsheet->getActiveSheet();
|
||||||
|
$newSheet = $this->spreadsheet->createSheet();
|
||||||
|
$newSheet->getCell('B7')->setValue('Here');
|
||||||
|
$sheet->getCell('A1')->setValue($value);
|
||||||
|
if ($format !== null) {
|
||||||
|
$sheet->getStyle('A1')->getNumberFormat()->setFormatCode($format);
|
||||||
|
}
|
||||||
|
$sheet->setSelectedCells('B7');
|
||||||
|
$this->spreadsheet->setActiveSheetIndex(1);
|
||||||
|
self::assertSame($expectedResult, $sheet->getCell('A1')->getCalculatedValue());
|
||||||
|
self::assertSame('B7', $sheet->getSelectedCells());
|
||||||
|
self::assertSame(1, $this->spreadsheet->getActiveSheetIndex());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider providerAsis
|
||||||
|
*
|
||||||
|
* @param float|int $expectedResult
|
||||||
|
* @param float|int $value
|
||||||
|
* @param string $format
|
||||||
|
*/
|
||||||
|
public function testAsis($expectedResult, $value, ?string $format = null): void
|
||||||
|
{
|
||||||
|
Cell::setCalculateDateTimeType(Cell::CALCULATE_DATE_TIME_ASIS);
|
||||||
|
$this->spreadsheet = new Spreadsheet();
|
||||||
|
self::assertSame(0, $this->spreadsheet->getActiveSheetIndex());
|
||||||
|
$sheet = $this->spreadsheet->getActiveSheet();
|
||||||
|
$newSheet = $this->spreadsheet->createSheet();
|
||||||
|
$newSheet->getCell('B7')->setValue('Here');
|
||||||
|
$sheet->getCell('A1')->setValue($value);
|
||||||
|
if ($format !== null) {
|
||||||
|
$sheet->getStyle('A1')->getNumberFormat()->setFormatCode($format);
|
||||||
|
}
|
||||||
|
$sheet->setSelectedCells('B7');
|
||||||
|
$this->spreadsheet->setActiveSheetIndex(1);
|
||||||
|
self::assertSame($expectedResult, $sheet->getCell('A1')->getCalculatedValue());
|
||||||
|
self::assertSame('B7', $sheet->getSelectedCells());
|
||||||
|
self::assertSame(1, $this->spreadsheet->getActiveSheetIndex());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function providerAsis(): array
|
||||||
|
{
|
||||||
|
$integerValue = 44046;
|
||||||
|
$integerValueAsFloat = (float) $integerValue;
|
||||||
|
$integerValueAsDateFormula = '=DATEVALUE("2020-08-03")';
|
||||||
|
$floatValue = 44015.25;
|
||||||
|
$floatValueAsDateFormula = '=DATEVALUE("2020-07-03")+TIMEVALUE("06:00")';
|
||||||
|
|
||||||
|
return [
|
||||||
|
'default format integer' => [$integerValue, $integerValue],
|
||||||
|
'default format float' => [$floatValue, $floatValue],
|
||||||
|
'date format integer' => [$integerValue, $integerValue, NumberFormat::FORMAT_DATE_YYYYMMDD],
|
||||||
|
'date format float' => [$floatValue, $floatValue, NumberFormat::FORMAT_DATE_YYYYMMDD],
|
||||||
|
'datetime format integer' => [$integerValue, $integerValue, 'yyyy-mm-dd h:mm'],
|
||||||
|
'datetime format float' => [$floatValue, $floatValue, 'yyyy-mm-dd h:mm'],
|
||||||
|
'time format integer' => [$integerValue, $integerValue, NumberFormat::FORMAT_DATE_TIME1],
|
||||||
|
'time format float' => [$floatValue, $floatValue, NumberFormat::FORMAT_DATE_TIME1],
|
||||||
|
'date formula integer fltfmt' => [$integerValueAsFloat, $integerValueAsDateFormula, NumberFormat::FORMAT_DATE_TIME1],
|
||||||
|
'date formula float' => [$floatValue, $floatValueAsDateFormula, NumberFormat::FORMAT_DATE_TIME1],
|
||||||
|
'date formula integer intfmt but formula returns float' => [$integerValueAsFloat, $integerValueAsDateFormula, NumberFormat::FORMAT_DATE_YYYYMMDD],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue