Refactor ISO data type validation from cell to shared date; add extra checks for invalid dates; and appropriate unit tests
This commit is contained in:
parent
9cf526a920
commit
ef4029df63
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
namespace PhpOffice\PhpSpreadsheet\Cell;
|
||||
|
||||
use DateTime;
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Information\ExcelError;
|
||||
use PhpOffice\PhpSpreadsheet\Collection\Cells;
|
||||
|
|
@ -240,18 +239,7 @@ class Cell
|
|||
|
||||
break;
|
||||
case DataType::TYPE_ISO_DATE:
|
||||
if (!is_string($value)) {
|
||||
throw new Exception('Non-string supplied for datatype Date');
|
||||
}
|
||||
$date = new DateTime($value);
|
||||
$newValue = SharedDate::PHPToExcel($date);
|
||||
if ($newValue === false) {
|
||||
throw new Exception("Invalid string $value supplied for datatype Date");
|
||||
}
|
||||
if (preg_match('/^\\d\\d:\\d\\d:\\d\\d/', $value) == 1) {
|
||||
$newValue = fmod($newValue, 1.0);
|
||||
}
|
||||
$this->value = $newValue;
|
||||
$this->value = SharedDate::convertIsoDate($value);
|
||||
$dataType = DataType::TYPE_NUMERIC;
|
||||
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -9,7 +9,9 @@ use PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel;
|
|||
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Information\ExcelError;
|
||||
use PhpOffice\PhpSpreadsheet\Cell\Cell;
|
||||
use PhpOffice\PhpSpreadsheet\Exception;
|
||||
use PhpOffice\PhpSpreadsheet\Exception as PhpSpreadsheetException;
|
||||
use PhpOffice\PhpSpreadsheet\Shared\Date as SharedDate;
|
||||
use PhpOffice\PhpSpreadsheet\Style\NumberFormat;
|
||||
|
||||
class Date
|
||||
|
|
@ -158,6 +160,36 @@ class Date
|
|||
throw new PhpSpreadsheetException('Invalid timezone');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return float|int
|
||||
*/
|
||||
public static function convertIsoDate($value)
|
||||
{
|
||||
if (!is_string($value)) {
|
||||
throw new Exception('Non-string value supplied for Iso Date conversion');
|
||||
}
|
||||
|
||||
$date = new DateTime($value);
|
||||
$dateErrors = DateTime::getLastErrors();
|
||||
|
||||
if (is_array($dateErrors) && ($dateErrors['warning_count'] > 0 || $dateErrors['error_count'] > 0)) {
|
||||
throw new Exception("Invalid string $value supplied for datatype Date");
|
||||
}
|
||||
|
||||
$newValue = SharedDate::PHPToExcel($date);
|
||||
if ($newValue === false) {
|
||||
throw new Exception("Invalid string $value supplied for datatype Date");
|
||||
}
|
||||
|
||||
if (preg_match('/^\\d\\d:\\d\\d:\\d\\d/', $value) == 1) {
|
||||
$newValue = fmod($newValue, 1.0);
|
||||
}
|
||||
|
||||
return $newValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a MS serialized datetime value from Excel to a PHP Date/Time object.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace PhpOffice\PhpSpreadsheetTests\Cell;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Cell\DataType;
|
||||
use PhpOffice\PhpSpreadsheet\Exception;
|
||||
use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
||||
use PhpOffice\PhpSpreadsheet\Style\Color;
|
||||
|
|
@ -33,6 +34,19 @@ class CellTest extends TestCase
|
|||
return require 'tests/data/Cell/SetValueExplicit.php';
|
||||
}
|
||||
|
||||
public function testInvalidIsoDateSetValueExplicit(): void
|
||||
{
|
||||
$spreadsheet = new Spreadsheet();
|
||||
$cell = $spreadsheet->getActiveSheet()->getCell('A1');
|
||||
|
||||
$dateValue = '2022-02-29'; // Invalid leap year
|
||||
$this->expectException(Exception::class);
|
||||
$this->expectExceptionMessage("Invalid string {$dateValue} supplied for datatype Date");
|
||||
$cell->setValueExplicit($dateValue, DataType::TYPE_ISO_DATE);
|
||||
|
||||
$spreadsheet->disconnectWorksheets();
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider providerSetValueExplicitException
|
||||
*
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
namespace PhpOffice\PhpSpreadsheetTests\Shared;
|
||||
|
||||
use DateTimeZone;
|
||||
use PhpOffice\PhpSpreadsheet\Exception;
|
||||
use PhpOffice\PhpSpreadsheet\Shared\Date;
|
||||
use PhpOffice\PhpSpreadsheet\Style\NumberFormat;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
|
@ -209,6 +210,15 @@ class DateTest extends TestCase
|
|||
return require 'tests/data/Shared/Date/ExcelToTimestamp1900Timezone.php';
|
||||
}
|
||||
|
||||
public function testConvertIsoDateError(): void
|
||||
{
|
||||
Date::setExcelCalendar(Date::CALENDAR_WINDOWS_1900);
|
||||
|
||||
$this->expectException(Exception::class);
|
||||
$this->expectExceptionMessage('Non-string value supplied for Iso Date conversion');
|
||||
Date::convertIsoDate(false);
|
||||
}
|
||||
|
||||
public function testVarious(): void
|
||||
{
|
||||
Date::setDefaultTimeZone('UTC');
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
<?php
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Information\ExcelError;
|
||||
use PhpOffice\PhpSpreadsheet\Cell\DataType;
|
||||
|
||||
return [
|
||||
|
|
@ -39,12 +40,27 @@ return [
|
|||
DataType::TYPE_NUMERIC,
|
||||
],
|
||||
[
|
||||
'#DIV/0!',
|
||||
44613.43090277778,
|
||||
'2022-02-21 10:20:30',
|
||||
DataType::TYPE_ISO_DATE,
|
||||
],
|
||||
[
|
||||
44613.0,
|
||||
'2022-02-21',
|
||||
DataType::TYPE_ISO_DATE,
|
||||
],
|
||||
[
|
||||
-30879.0,
|
||||
'1815-06-15', // Dates outside the Excel Range should fail really
|
||||
DataType::TYPE_ISO_DATE,
|
||||
],
|
||||
[
|
||||
ExcelError::DIV0(),
|
||||
'#DIV/0!',
|
||||
DataType::TYPE_ERROR,
|
||||
],
|
||||
[
|
||||
'#NULL!',
|
||||
ExcelError::null(),
|
||||
'NOT A VALID ERROR TYPE VALUE',
|
||||
DataType::TYPE_ERROR,
|
||||
],
|
||||
|
|
|
|||
Loading…
Reference in New Issue