diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 316663bb11..085cf964cd 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -990,11 +990,6 @@ parameters: 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\\(\\)\\.$#" count: 1 diff --git a/src/PhpSpreadsheet/Cell/Cell.php b/src/PhpSpreadsheet/Cell/Cell.php index 56b5f5f8ca..e8594506f6 100644 --- a/src/PhpSpreadsheet/Cell/Cell.php +++ b/src/PhpSpreadsheet/Cell/Cell.php @@ -176,16 +176,21 @@ public function getValue() /** * Get cell value with formatting. - * - * @return string */ - public function getFormattedValue() + public function getFormattedValue(): string { - return (string) NumberFormat::toFormattedString( + $currentCalendar = SharedDate::getExcelCalendar(); + SharedDate::setExcelCalendar($this->getWorksheet()->getParent()->getExcelCalendar()); + + $formattedValue = (string) NumberFormat::toFormattedString( $this->getCalculatedValue(), $this->getStyle() ->getNumberFormat()->getFormatCode() ); + + SharedDate::setExcelCalendar($currentCalendar); + + return $formattedValue; } /** @@ -342,8 +347,6 @@ public function setValueExplicit($value, $dataType, bool $isArrayFormula = false break; default: throw new Exception('Invalid datatype: ' . $dataType); - - break; } // set the datatype @@ -402,6 +405,9 @@ private function processArrayResult( public function getCalculatedValue(bool $asArray = false, bool $resetLog = true) { if ($this->dataType === DataType::TYPE_FORMULA) { + $currentCalendar = SharedDate::getExcelCalendar(); + SharedDate::setExcelCalendar($this->getWorksheet()->getParent()->getExcelCalendar()); + try { $coordinate = $this->getCoordinate(); $worksheet = $this->getWorksheet(); @@ -430,6 +436,7 @@ public function getCalculatedValue(bool $asArray = false, bool $resetLog = true) $this->getWorksheet()->setSelectedCells($selected); $this->getWorksheet()->getParent()->setActiveSheetIndex($index); } catch (Exception $ex) { + SharedDate::setExcelCalendar($currentCalendar); if (($ex->getMessage() === 'Unable to access External Workbook') && ($this->calculatedValue !== null)) { return $this->calculatedValue; // Fallback for calculations referencing external files. } elseif (preg_match('/[Uu]ndefined (name|offset: 2|array key 2)/', $ex->getMessage()) === 1) { @@ -441,6 +448,7 @@ public function getCalculatedValue(bool $asArray = false, bool $resetLog = true) ); } + SharedDate::setExcelCalendar($currentCalendar); if ($result === '#Not Yet Implemented') { return $this->calculatedValue; // Fallback if calculation engine does not support the formula. } diff --git a/src/PhpSpreadsheet/Reader/Xls.php b/src/PhpSpreadsheet/Reader/Xls.php index 9aee18ee18..98de1c029d 100644 --- a/src/PhpSpreadsheet/Reader/Xls.php +++ b/src/PhpSpreadsheet/Reader/Xls.php @@ -2026,9 +2026,9 @@ private function readDateMode(): void $this->pos += 4 + $length; // offset: 0; size: 2; 0 = base 1900, 1 = base 1904 - Date::setExcelCalendar(Date::CALENDAR_WINDOWS_1900); + $this->spreadsheet->setExcelCalendar(Date::CALENDAR_WINDOWS_1900); if (ord($recordData[0]) == 1) { - Date::setExcelCalendar(Date::CALENDAR_MAC_1904); + $this->spreadsheet->setExcelCalendar(Date::CALENDAR_MAC_1904); } } diff --git a/src/PhpSpreadsheet/Reader/Xlsx.php b/src/PhpSpreadsheet/Reader/Xlsx.php index f793a66ae6..8f88f29412 100644 --- a/src/PhpSpreadsheet/Reader/Xlsx.php +++ b/src/PhpSpreadsheet/Reader/Xlsx.php @@ -681,11 +681,11 @@ protected function loadSpreadsheetFromFile(string $filename): Spreadsheet // Set base date if ($xmlWorkbookNS->workbookPr) { - Date::setExcelCalendar(Date::CALENDAR_WINDOWS_1900); + $excel->setExcelCalendar(Date::CALENDAR_WINDOWS_1900); $attrs1904 = self::getAttributes($xmlWorkbookNS->workbookPr); if (isset($attrs1904['date1904'])) { if (self::boolean((string) $attrs1904['date1904'])) { - Date::setExcelCalendar(Date::CALENDAR_MAC_1904); + $excel->setExcelCalendar(Date::CALENDAR_MAC_1904); } } } diff --git a/src/PhpSpreadsheet/Shared/Date.php b/src/PhpSpreadsheet/Shared/Date.php index 8cac2c63e8..547e875ca7 100644 --- a/src/PhpSpreadsheet/Shared/Date.php +++ b/src/PhpSpreadsheet/Shared/Date.php @@ -67,7 +67,7 @@ class Date protected static $defaultTimeZone; /** - * Set the Excel calendar (Windows 1900 or Mac 1904). + * Set the Excel Date Calendar (Windows 1900 or Mac 1904) used for calculations and formatting. * * @param int $baseYear Excel base date (1900 or 1904) * @@ -85,7 +85,8 @@ public static function setExcelCalendar($baseYear) } /** - * Return the Excel calendar (Windows 1900 or Mac 1904). + * Return the Excel Date Calendar (Windows 1900 or Mac 1904) + * to be used for current calculations and formatting. * * @return int Excel base date (1900 or 1904) */ diff --git a/src/PhpSpreadsheet/Spreadsheet.php b/src/PhpSpreadsheet/Spreadsheet.php index 4bb9398712..ab2196e8b1 100644 --- a/src/PhpSpreadsheet/Spreadsheet.php +++ b/src/PhpSpreadsheet/Spreadsheet.php @@ -4,6 +4,7 @@ use PhpOffice\PhpSpreadsheet\Calculation\Calculation; use PhpOffice\PhpSpreadsheet\Reader\Xlsx as XlsxReader; +use PhpOffice\PhpSpreadsheet\Shared\Date; use PhpOffice\PhpSpreadsheet\Shared\File; use PhpOffice\PhpSpreadsheet\Shared\StringHelper; use PhpOffice\PhpSpreadsheet\Style\Style; @@ -13,7 +14,7 @@ class Spreadsheet { - // Allowable values for workbook window visilbity + // Allowable values for workbook window visibility const VISIBILITY_VISIBLE = 'visible'; const VISIBILITY_HIDDEN = 'hidden'; const VISIBILITY_VERY_HIDDEN = 'veryHidden'; @@ -55,6 +56,14 @@ class Spreadsheet */ private $workSheetCollection = []; + /** + * Base calendar year to use for calculations + * Value is either CALENDAR_WINDOWS_1900 (1900) or CALENDAR_MAC_1904 (1904). + * + * @var int + */ + protected $excelCalendar = Date::CALENDAR_WINDOWS_1900; + /** * Calculation Engine. * @@ -202,6 +211,34 @@ class Spreadsheet */ private $tabRatio = 600; + /** + * Set the Excel Calendar (Windows 1900 or Mac 1904). + * + * @param int $baseYear Excel base date (1900 or 1904) + * + * @return bool Success or failure + */ + public function setExcelCalendar(int $baseYear): bool + { + if (($baseYear == Date::CALENDAR_WINDOWS_1900) || ($baseYear == Date::CALENDAR_MAC_1904)) { + $this->excelCalendar = $baseYear; + + return true; + } + + return false; + } + + /** + * Return the Excel Calendar (Windows 1900 or Mac 1904). + * + * @return int Excel base date (1900 or 1904) + */ + public function getExcelCalendar(): int + { + return $this->excelCalendar; + } + /** * The workbook has macros ? * diff --git a/src/PhpSpreadsheet/Writer/Xls/Workbook.php b/src/PhpSpreadsheet/Writer/Xls/Workbook.php index ccffa181b6..876f2bded0 100644 --- a/src/PhpSpreadsheet/Writer/Xls/Workbook.php +++ b/src/PhpSpreadsheet/Writer/Xls/Workbook.php @@ -960,9 +960,9 @@ private function writeDateMode(): void $record = 0x0022; // Record identifier $length = 0x0002; // Bytes to follow - $f1904 = (Date::getExcelCalendar() === Date::CALENDAR_MAC_1904) - ? 1 - : 0; // Flag for 1904 date system + $f1904 = ($this->spreadsheet->getExcelCalendar() === Date::CALENDAR_MAC_1904) + ? 1 // Flag for 1904 date system + : 0; // Flag for 1900 date system $header = pack('vv', $record, $length); $data = pack('v', $f1904); diff --git a/src/PhpSpreadsheet/Writer/Xlsx/Workbook.php b/src/PhpSpreadsheet/Writer/Xlsx/Workbook.php index f9d7197d7a..176039d660 100644 --- a/src/PhpSpreadsheet/Writer/Xlsx/Workbook.php +++ b/src/PhpSpreadsheet/Writer/Xlsx/Workbook.php @@ -39,7 +39,7 @@ public function writeWorkbook(Spreadsheet $spreadsheet, $recalcRequired = false) $this->writeFileVersion($objWriter); // workbookPr - $this->writeWorkbookPr($objWriter); + $this->writeWorkbookPr($objWriter, $spreadsheet); // workbookProtection $this->writeWorkbookProtection($objWriter, $spreadsheet); @@ -80,11 +80,11 @@ private function writeFileVersion(XMLWriter $objWriter): void /** * Write WorkbookPr. */ - private function writeWorkbookPr(XMLWriter $objWriter): void + private function writeWorkbookPr(XMLWriter $objWriter, Spreadsheet $spreadsheet): void { $objWriter->startElement('workbookPr'); - if (Date::getExcelCalendar() === Date::CALENDAR_MAC_1904) { + if ($spreadsheet->getExcelCalendar() === Date::CALENDAR_MAC_1904) { $objWriter->writeAttribute('date1904', '1'); } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/AllSetupTeardown.php b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/AllSetupTeardown.php index 9fb5dfa58b..0cb3b62bd2 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/AllSetupTeardown.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/AllSetupTeardown.php @@ -55,9 +55,13 @@ protected function tearDown(): void } } - protected static function setMac1904(): void + protected static function setMac1904(?Worksheet $worksheet = null): void { - Date::setExcelCalendar(Date::CALENDAR_MAC_1904); + if ($worksheet === null) { + Date::setExcelCalendar(Date::CALENDAR_MAC_1904); + } else { + $worksheet->getParent()->setExcelCalendar(Date::CALENDAR_MAC_1904); + } } protected static function setUnixReturn(): void diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/IsoWeekNumTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/IsoWeekNumTest.php index a6615ff623..86b1389ba4 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/IsoWeekNumTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/IsoWeekNumTest.php @@ -35,8 +35,8 @@ public function providerISOWEEKNUM(): array public function testISOWEEKNUM1904($expectedResult, $dateValue): void { $this->mightHaveException($expectedResult); - self::setMac1904(); $sheet = $this->getSheet(); + self::setMac1904($sheet); $sheet->getCell('A1')->setValue("=ISOWEEKNUM($dateValue)"); $sheet->getCell('B1')->setValue('1954-11-23'); self::assertSame($expectedResult, $sheet->getCell('A1')->getCalculatedValue()); diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/WeekNumTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/WeekNumTest.php index 65b00516e0..c1c2fe774e 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/WeekNumTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/WeekNumTest.php @@ -33,8 +33,8 @@ public function providerWEEKNUM(): array public function testWEEKNUM1904($expectedResult, string $formula): void { $this->mightHaveException($expectedResult); - self::setMac1904(); $sheet = $this->getSheet(); + self::setMac1904($sheet); $sheet->getCell('B1')->setValue('1954-11-23'); $sheet->getCell('A1')->setValue("=WEEKNUM($formula)"); self::assertSame($expectedResult, $sheet->getCell('A1')->getCalculatedValue()); diff --git a/tests/PhpSpreadsheetTests/Reader/Xls/DateReaderTest.php b/tests/PhpSpreadsheetTests/Reader/Xls/DateReaderTest.php new file mode 100644 index 0000000000..5ba83166bc --- /dev/null +++ b/tests/PhpSpreadsheetTests/Reader/Xls/DateReaderTest.php @@ -0,0 +1,117 @@ +load($filename); + + self::assertSame(Date::CALENDAR_WINDOWS_1900, $spreadsheet->getExcelCalendar()); + + $worksheet = $spreadsheet->getActiveSheet(); + self::assertSame(44562, $worksheet->getCell('A1')->getValue()); + self::assertSame('2022-01-01', $worksheet->getCell('A1')->getFormattedValue()); + self::assertSame(44926, $worksheet->getCell('A2')->getValue()); + self::assertSame('2022-12-31', $worksheet->getCell('A2')->getFormattedValue()); + } + + public function testReadExcel1904Spreadsheet(): void + { + $filename = 'tests/data/Reader/XLS/1904_Calendar.xls'; + $reader = new Xls(); + $spreadsheet = $reader->load($filename); + + self::assertSame(Date::CALENDAR_MAC_1904, $spreadsheet->getExcelCalendar()); + + $worksheet = $spreadsheet->getActiveSheet(); + self::assertSame(43100, $worksheet->getCell('A1')->getValue()); + self::assertSame('2022-01-01', $worksheet->getCell('A1')->getFormattedValue()); + self::assertSame(43464, $worksheet->getCell('A2')->getValue()); + self::assertSame('2022-12-31', $worksheet->getCell('A2')->getFormattedValue()); + } + + public function testNewDateInLoadedExcel1900Spreadsheet(): void + { + $filename = 'tests/data/Reader/XLS/1900_Calendar.xls'; + $reader = new Xls(); + $spreadsheet = $reader->load($filename); + + $worksheet = $spreadsheet->getActiveSheet(); + $worksheet->getCell('A4')->setValue('=DATE(2023,1,1)'); + self::assertEquals(44927, $worksheet->getCell('A4')->getCalculatedValue()); + } + + public function testNewDateInLoadedExcel1904Spreadsheet(): void + { + $filename = 'tests/data/Reader/XLS/1904_Calendar.xls'; + $reader = new Xls(); + $spreadsheet = $reader->load($filename); + + $worksheet = $spreadsheet->getActiveSheet(); + $worksheet->getCell('A4')->setValue('=DATE(2023,1,1)'); + self::assertEquals(43465, $worksheet->getCell('A4')->getCalculatedValue()); + } + + public function testSwitchCalendars(): void + { + $filename1900 = 'tests/data/Reader/XLS/1900_Calendar.xls'; + $reader1900 = new Xls(); + $spreadsheet1900 = $reader1900->load($filename1900); + $worksheet1900 = $spreadsheet1900->getActiveSheet(); + + $filename1904 = 'tests/data/Reader/XLS/1904_Calendar.xls'; + $reader1904 = new Xls(); + $spreadsheet1904 = $reader1904->load($filename1904); + $worksheet1904 = $spreadsheet1904->getActiveSheet(); + + self::assertSame(44562, $worksheet1900->getCell('A1')->getValue()); + self::assertSame('2022-01-01', $worksheet1900->getCell('A1')->getFormattedValue()); + self::assertSame(44926, $worksheet1900->getCell('A2')->getValue()); + self::assertSame('2022-12-31', $worksheet1900->getCell('A2')->getFormattedValue()); + self::assertSame(44561, $worksheet1900->getCell('B1')->getCalculatedValue()); + self::assertSame('2021-12-31', $worksheet1900->getCell('B1')->getFormattedValue()); + self::assertSame(44927, $worksheet1900->getCell('B2')->getCalculatedValue()); + self::assertSame('2023-01-01', $worksheet1900->getCell('B2')->getFormattedValue()); + + self::assertSame(43100, $worksheet1904->getCell('A1')->getValue()); + self::assertSame('2022-01-01', $worksheet1904->getCell('A1')->getFormattedValue()); + self::assertSame(43464, $worksheet1904->getCell('A2')->getValue()); + self::assertSame('2022-12-31', $worksheet1904->getCell('A2')->getFormattedValue()); + self::assertSame(43099, $worksheet1904->getCell('B1')->getCalculatedValue()); + self::assertSame('2021-12-31', $worksheet1904->getCell('B1')->getFormattedValue()); + self::assertSame(43465, $worksheet1904->getCell('B2')->getCalculatedValue()); + self::assertSame('2023-01-01', $worksheet1904->getCell('B2')->getFormattedValue()); + + // Check that accessing date values from one spreadsheet doesn't break accessing correct values from another + self::assertSame(44561, $worksheet1900->getCell('B1')->getCalculatedValue()); + self::assertSame('2021-12-31', $worksheet1900->getCell('B1')->getFormattedValue()); + self::assertSame(44927, $worksheet1900->getCell('B2')->getCalculatedValue()); + self::assertSame('2023-01-01', $worksheet1900->getCell('B2')->getFormattedValue()); + self::assertSame(44562, $worksheet1900->getCell('A1')->getValue()); + self::assertSame('2022-01-01', $worksheet1900->getCell('A1')->getFormattedValue()); + self::assertSame(44926, $worksheet1900->getCell('A2')->getValue()); + self::assertSame('2022-12-31', $worksheet1900->getCell('A2')->getFormattedValue()); + + self::assertSame(43099, $worksheet1904->getCell('B1')->getCalculatedValue()); + self::assertSame('2021-12-31', $worksheet1904->getCell('B1')->getFormattedValue()); + self::assertSame(43465, $worksheet1904->getCell('B2')->getCalculatedValue()); + self::assertSame('2023-01-01', $worksheet1904->getCell('B2')->getFormattedValue()); + self::assertSame(43100, $worksheet1904->getCell('A1')->getValue()); + self::assertSame('2022-01-01', $worksheet1904->getCell('A1')->getFormattedValue()); + self::assertSame(43464, $worksheet1904->getCell('A2')->getValue()); + self::assertSame('2022-12-31', $worksheet1904->getCell('A2')->getFormattedValue()); + } +} diff --git a/tests/PhpSpreadsheetTests/Reader/Xlsx/DateReaderTest.php b/tests/PhpSpreadsheetTests/Reader/Xlsx/DateReaderTest.php new file mode 100644 index 0000000000..042683f9c3 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Reader/Xlsx/DateReaderTest.php @@ -0,0 +1,125 @@ +load($filename); + + self::assertSame(Date::CALENDAR_WINDOWS_1900, $spreadsheet->getExcelCalendar()); + + $worksheet = $spreadsheet->getActiveSheet(); + self::assertSame(44562, $worksheet->getCell('A1')->getValue()); + self::assertSame('2022-01-01', $worksheet->getCell('A1')->getFormattedValue()); + self::assertSame(44926, $worksheet->getCell('A2')->getValue()); + self::assertSame('2022-12-31', $worksheet->getCell('A2')->getFormattedValue()); + self::assertSame(44561, $worksheet->getCell('B1')->getCalculatedValue()); + self::assertSame('2021-12-31', $worksheet->getCell('B1')->getFormattedValue()); + self::assertSame(44927, $worksheet->getCell('B2')->getCalculatedValue()); + self::assertSame('2023-01-01', $worksheet->getCell('B2')->getFormattedValue()); + } + + public function testReadExcel1904Spreadsheet(): void + { + $filename = 'tests/data/Reader/XLSX/1904_Calendar.xlsx'; + $reader = new Xlsx(); + $spreadsheet = $reader->load($filename); + + self::assertSame(Date::CALENDAR_MAC_1904, $spreadsheet->getExcelCalendar()); + + $worksheet = $spreadsheet->getActiveSheet(); + self::assertSame(43100, $worksheet->getCell('A1')->getValue()); + self::assertSame('2022-01-01', $worksheet->getCell('A1')->getFormattedValue()); + self::assertSame(43464, $worksheet->getCell('A2')->getValue()); + self::assertSame('2022-12-31', $worksheet->getCell('A2')->getFormattedValue()); + self::assertSame(43099, $worksheet->getCell('B1')->getCalculatedValue()); + self::assertSame('2021-12-31', $worksheet->getCell('B1')->getFormattedValue()); + self::assertSame(43465, $worksheet->getCell('B2')->getCalculatedValue()); + self::assertSame('2023-01-01', $worksheet->getCell('B2')->getFormattedValue()); + } + + public function testNewDateInLoadedExcel1900Spreadsheet(): void + { + $filename = 'tests/data/Reader/XLSX/1900_Calendar.xlsx'; + $reader = new Xlsx(); + $spreadsheet = $reader->load($filename); + + $worksheet = $spreadsheet->getActiveSheet(); + $worksheet->getCell('A4')->setValue('=DATE(2023,1,1)'); + self::assertEquals(44927, $worksheet->getCell('A4')->getCalculatedValue()); + } + + public function testNewDateInLoadedExcel1904Spreadsheet(): void + { + $filename = 'tests/data/Reader/XLSX/1904_Calendar.xlsx'; + $reader = new Xlsx(); + $spreadsheet = $reader->load($filename); + + $worksheet = $spreadsheet->getActiveSheet(); + $worksheet->getCell('A4')->setValue('=DATE(2023,1,1)'); + self::assertEquals(43465, $worksheet->getCell('A4')->getCalculatedValue()); + } + + public function testSwitchCalendars(): void + { + $filename1900 = 'tests/data/Reader/XLSX/1900_Calendar.xlsx'; + $reader1900 = new Xlsx(); + $spreadsheet1900 = $reader1900->load($filename1900); + $worksheet1900 = $spreadsheet1900->getActiveSheet(); + + $filename1904 = 'tests/data/Reader/XLSX/1904_Calendar.xlsx'; + $reader1904 = new Xlsx(); + $spreadsheet1904 = $reader1904->load($filename1904); + $worksheet1904 = $spreadsheet1904->getActiveSheet(); + + self::assertSame(44562, $worksheet1900->getCell('A1')->getValue()); + self::assertSame('2022-01-01', $worksheet1900->getCell('A1')->getFormattedValue()); + self::assertSame(44926, $worksheet1900->getCell('A2')->getValue()); + self::assertSame('2022-12-31', $worksheet1900->getCell('A2')->getFormattedValue()); + self::assertSame(44561, $worksheet1900->getCell('B1')->getCalculatedValue()); + self::assertSame('2021-12-31', $worksheet1900->getCell('B1')->getFormattedValue()); + self::assertSame(44927, $worksheet1900->getCell('B2')->getCalculatedValue()); + self::assertSame('2023-01-01', $worksheet1900->getCell('B2')->getFormattedValue()); + + self::assertSame(43100, $worksheet1904->getCell('A1')->getValue()); + self::assertSame('2022-01-01', $worksheet1904->getCell('A1')->getFormattedValue()); + self::assertSame(43464, $worksheet1904->getCell('A2')->getValue()); + self::assertSame('2022-12-31', $worksheet1904->getCell('A2')->getFormattedValue()); + self::assertSame(43099, $worksheet1904->getCell('B1')->getCalculatedValue()); + self::assertSame('2021-12-31', $worksheet1904->getCell('B1')->getFormattedValue()); + self::assertSame(43465, $worksheet1904->getCell('B2')->getCalculatedValue()); + self::assertSame('2023-01-01', $worksheet1904->getCell('B2')->getFormattedValue()); + + // Check that accessing date values from one spreadsheet doesn't break accessing correct values from another + self::assertSame(44561, $worksheet1900->getCell('B1')->getCalculatedValue()); + self::assertSame('2021-12-31', $worksheet1900->getCell('B1')->getFormattedValue()); + self::assertSame(44927, $worksheet1900->getCell('B2')->getCalculatedValue()); + self::assertSame('2023-01-01', $worksheet1900->getCell('B2')->getFormattedValue()); + self::assertSame(44562, $worksheet1900->getCell('A1')->getValue()); + self::assertSame('2022-01-01', $worksheet1900->getCell('A1')->getFormattedValue()); + self::assertSame(44926, $worksheet1900->getCell('A2')->getValue()); + self::assertSame('2022-12-31', $worksheet1900->getCell('A2')->getFormattedValue()); + + self::assertSame(43099, $worksheet1904->getCell('B1')->getCalculatedValue()); + self::assertSame('2021-12-31', $worksheet1904->getCell('B1')->getFormattedValue()); + self::assertSame(43465, $worksheet1904->getCell('B2')->getCalculatedValue()); + self::assertSame('2023-01-01', $worksheet1904->getCell('B2')->getFormattedValue()); + self::assertSame(43100, $worksheet1904->getCell('A1')->getValue()); + self::assertSame('2022-01-01', $worksheet1904->getCell('A1')->getFormattedValue()); + self::assertSame(43464, $worksheet1904->getCell('A2')->getValue()); + self::assertSame('2022-12-31', $worksheet1904->getCell('A2')->getFormattedValue()); + } +} diff --git a/tests/data/Reader/XLS/1900_Calendar.xls b/tests/data/Reader/XLS/1900_Calendar.xls new file mode 100644 index 0000000000..714670a7dc Binary files /dev/null and b/tests/data/Reader/XLS/1900_Calendar.xls differ diff --git a/tests/data/Reader/XLS/1904_Calendar.xls b/tests/data/Reader/XLS/1904_Calendar.xls new file mode 100644 index 0000000000..cde7fc1931 Binary files /dev/null and b/tests/data/Reader/XLS/1904_Calendar.xls differ diff --git a/tests/data/Reader/XLSX/1900_Calendar.xlsx b/tests/data/Reader/XLSX/1900_Calendar.xlsx new file mode 100644 index 0000000000..dfd78efc7c Binary files /dev/null and b/tests/data/Reader/XLSX/1900_Calendar.xlsx differ diff --git a/tests/data/Reader/XLSX/1904_Calendar.xlsx b/tests/data/Reader/XLSX/1904_Calendar.xlsx new file mode 100644 index 0000000000..f3a8a12d8e Binary files /dev/null and b/tests/data/Reader/XLSX/1904_Calendar.xlsx differ