From 43589bc9b6f5bf1e24689a8e7521a1ec01fe523e Mon Sep 17 00:00:00 2001 From: oleibman <10341515+oleibman@users.noreply.github.com> Date: Sat, 22 Jun 2024 22:09:22 -0700 Subject: [PATCH 1/2] Make Base Date a Property of Spreadsheet This change is extracted from PR #2787 by @MarkBaker. That change mostly deals with array functions, and that part will be superseded by PR #3962. However, this part of 2787 is not included in 3962. Fix #1036 (closed as stale in 2019 and just reopened). Excel spreadsheets can have either of 2 base dates, 1900 or 1904, and the numeric value of any date cells will vary depending on which base date is in use. PhpSpreadsheet has, till now, handled that as a static property of Shared/Date. This does not work well if two spreadsheets with different base dates are open simultaneously. The code is changed to store the base date as a property of the spreadsheet when an Xls/Xlsx spreadsheet is loaded, and use that property when saving an Xls/Xlsx spreadsheet. Any call to `getCalculatedValue` or `getFormattedValue` will temporarily set the Shared/Date value to that of the spreadsheet, and restore it at completion. In order to avoid a BC break, the Xls and Xlsx readers will continue to populate the Shared/Date value as before. --- src/PhpSpreadsheet/Cell/Cell.php | 11 +- src/PhpSpreadsheet/Reader/Xls.php | 2 + src/PhpSpreadsheet/Reader/Xlsx.php | 2 + src/PhpSpreadsheet/Shared/Date.php | 11 +- src/PhpSpreadsheet/Spreadsheet.php | 25 ++++ src/PhpSpreadsheet/Writer/Xls/Workbook.php | 6 +- src/PhpSpreadsheet/Writer/Xlsx/Workbook.php | 6 +- .../Reader/Xls/DateReaderTest.php | 127 ++++++++++++++++ .../Reader/Xlsx/DateReaderTest.php | 135 ++++++++++++++++++ tests/data/Reader/XLS/1900_Calendar.xls | Bin 0 -> 28160 bytes tests/data/Reader/XLS/1904_Calendar.xls | Bin 0 -> 28160 bytes tests/data/Reader/XLSX/1900_Calendar.xlsx | Bin 0 -> 10134 bytes tests/data/Reader/XLSX/1904_Calendar.xlsx | Bin 0 -> 10119 bytes 13 files changed, 312 insertions(+), 13 deletions(-) create mode 100644 tests/PhpSpreadsheetTests/Reader/Xls/DateReaderTest.php create mode 100644 tests/PhpSpreadsheetTests/Reader/Xlsx/DateReaderTest.php create mode 100644 tests/data/Reader/XLS/1900_Calendar.xls create mode 100644 tests/data/Reader/XLS/1904_Calendar.xls create mode 100644 tests/data/Reader/XLSX/1900_Calendar.xlsx create mode 100644 tests/data/Reader/XLSX/1904_Calendar.xlsx diff --git a/src/PhpSpreadsheet/Cell/Cell.php b/src/PhpSpreadsheet/Cell/Cell.php index 3dc6c2eab6..bbc37e698d 100644 --- a/src/PhpSpreadsheet/Cell/Cell.php +++ b/src/PhpSpreadsheet/Cell/Cell.php @@ -187,10 +187,15 @@ public function getValueString(): string */ public function getFormattedValue(): string { - return (string) NumberFormat::toFormattedString( + $currentCalendar = SharedDate::getExcelCalendar(); + SharedDate::setExcelCalendar($this->getWorksheet()->getParent()?->getExcelCalendar()); + $formattedValue = (string) NumberFormat::toFormattedString( $this->getCalculatedValue(), (string) $this->getStyle()->getNumberFormat()->getFormatCode(true) ); + SharedDate::setExcelCalendar($currentCalendar); + + return $formattedValue; } protected static function updateIfCellIsTableHeader(?Worksheet $workSheet, self $cell, mixed $oldValue, mixed $newValue): void @@ -364,6 +369,8 @@ public function getCalculatedValue(bool $resetLog = true): mixed { if ($this->dataType === DataType::TYPE_FORMULA) { try { + $currentCalendar = SharedDate::getExcelCalendar(); + SharedDate::setExcelCalendar($this->getWorksheet()->getParent()?->getExcelCalendar()); $index = $this->getWorksheet()->getParentOrThrow()->getActiveSheetIndex(); $selected = $this->getWorksheet()->getSelectedCells(); $result = Calculation::getInstance( @@ -379,6 +386,7 @@ public function getCalculatedValue(bool $resetLog = true): mixed } } } catch (SpreadsheetException $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) { @@ -391,6 +399,7 @@ public function getCalculatedValue(bool $resetLog = true): mixed $ex ); } + 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 58a22835de..be9ccb2681 100644 --- a/src/PhpSpreadsheet/Reader/Xls.php +++ b/src/PhpSpreadsheet/Reader/Xls.php @@ -1927,8 +1927,10 @@ private function readDateMode(): void // 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 9bfb354342..166146a9c9 100644 --- a/src/PhpSpreadsheet/Reader/Xlsx.php +++ b/src/PhpSpreadsheet/Reader/Xlsx.php @@ -709,12 +709,14 @@ protected function loadSpreadsheetFromFile(string $filename): Spreadsheet $xmlWorkbookNS = $this->loadZip($relTarget, $mainNS); // Set base date + $excel->setExcelCalendar(Date::CALENDAR_WINDOWS_1900); if ($xmlWorkbookNS->workbookPr) { Date::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 ed19534de0..b8feeb9c20 100644 --- a/src/PhpSpreadsheet/Shared/Date.php +++ b/src/PhpSpreadsheet/Shared/Date.php @@ -10,7 +10,6 @@ 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 @@ -64,15 +63,15 @@ class Date /** * Set the Excel calendar (Windows 1900 or Mac 1904). * - * @param int $baseYear Excel base date (1900 or 1904) + * @param ?int $baseYear Excel base date (1900 or 1904) * * @return bool Success or failure */ - public static function setExcelCalendar(int $baseYear): bool + public static function setExcelCalendar(?int $baseYear): bool { if ( - ($baseYear == self::CALENDAR_WINDOWS_1900) - || ($baseYear == self::CALENDAR_MAC_1904) + ($baseYear === self::CALENDAR_WINDOWS_1900) + || ($baseYear === self::CALENDAR_MAC_1904) ) { self::$excelCalendar = $baseYear; @@ -173,7 +172,7 @@ public static function convertIsoDate(mixed $value): float|int throw new Exception("Invalid string $value supplied for datatype Date"); } - $newValue = SharedDate::PHPToExcel($date); + $newValue = self::PHPToExcel($date); if ($newValue === false) { throw new Exception("Invalid string $value supplied for datatype Date"); } diff --git a/src/PhpSpreadsheet/Spreadsheet.php b/src/PhpSpreadsheet/Spreadsheet.php index 095507d7b7..e571cc4f6b 100644 --- a/src/PhpSpreadsheet/Spreadsheet.php +++ b/src/PhpSpreadsheet/Spreadsheet.php @@ -7,6 +7,7 @@ use PhpOffice\PhpSpreadsheet\Document\Properties; use PhpOffice\PhpSpreadsheet\Document\Security; 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; @@ -31,6 +32,8 @@ class Spreadsheet implements JsonSerializable self::VISIBILITY_VERY_HIDDEN, ]; + protected int $excelCalendar = Date::CALENDAR_WINDOWS_1900; + /** * Unique ID. */ @@ -1553,4 +1556,26 @@ public function getTableByName(string $tableName): ?Table return $table; } + + /** + * @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 int Excel base date (1900 or 1904) + */ + public function getExcelCalendar(): int + { + return $this->excelCalendar; + } } diff --git a/src/PhpSpreadsheet/Writer/Xls/Workbook.php b/src/PhpSpreadsheet/Writer/Xls/Workbook.php index 62d4b08d9d..a1a5faf8f4 100644 --- a/src/PhpSpreadsheet/Writer/Xls/Workbook.php +++ b/src/PhpSpreadsheet/Writer/Xls/Workbook.php @@ -910,9 +910,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 5604be5443..0cdfb3cd87 100644 --- a/src/PhpSpreadsheet/Writer/Xlsx/Workbook.php +++ b/src/PhpSpreadsheet/Writer/Xlsx/Workbook.php @@ -40,7 +40,7 @@ public function writeWorkbook(Spreadsheet $spreadsheet, bool $recalcRequired = f $this->writeFileVersion($objWriter); // workbookPr - $this->writeWorkbookPr($objWriter); + $this->writeWorkbookPr($objWriter, $spreadsheet); // workbookProtection $this->writeWorkbookProtection($objWriter, $spreadsheet); @@ -81,11 +81,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/Reader/Xls/DateReaderTest.php b/tests/PhpSpreadsheetTests/Reader/Xls/DateReaderTest.php new file mode 100644 index 0000000000..58bcbb95b4 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Reader/Xls/DateReaderTest.php @@ -0,0 +1,127 @@ +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()); + $spreadsheet->disconnectWorksheets(); + } + + 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()); + $spreadsheet->disconnectWorksheets(); + } + + 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()); + $spreadsheet->disconnectWorksheets(); + } + + 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()); + $spreadsheet->disconnectWorksheets(); + } + + public function testSwitchCalendars(): void + { + $filename1904 = 'tests/data/Reader/XLS/1904_Calendar.xls'; + $reader1904 = new Xls(); + $spreadsheet1904 = $reader1904->load($filename1904); + $worksheet1904 = $spreadsheet1904->getActiveSheet(); + $date1 = Date::convertIsoDate('2022-01-01'); + self::assertSame(43100.0, $date1); + + $filename1900 = 'tests/data/Reader/XLS/1900_Calendar.xls'; + $reader1900 = new Xls(); + $spreadsheet1900 = $reader1900->load($filename1900); + $worksheet1900 = $spreadsheet1900->getActiveSheet(); + $date2 = Date::convertIsoDate('2022-01-01'); + self::assertSame(44562.0, $date2); + + 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()); + $spreadsheet1900->disconnectWorksheets(); + $spreadsheet1904->disconnectWorksheets(); + } +} diff --git a/tests/PhpSpreadsheetTests/Reader/Xlsx/DateReaderTest.php b/tests/PhpSpreadsheetTests/Reader/Xlsx/DateReaderTest.php new file mode 100644 index 0000000000..7eaee0df73 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Reader/Xlsx/DateReaderTest.php @@ -0,0 +1,135 @@ +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()); + $spreadsheet->disconnectWorksheets(); + } + + 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()); + $spreadsheet->disconnectWorksheets(); + } + + 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()); + $spreadsheet->disconnectWorksheets(); + } + + 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()); + $spreadsheet->disconnectWorksheets(); + } + + public function testSwitchCalendars(): void + { + $filename1904 = 'tests/data/Reader/XLSX/1904_Calendar.xlsx'; + $reader1904 = new Xlsx(); + $spreadsheet1904 = $reader1904->load($filename1904); + $worksheet1904 = $spreadsheet1904->getActiveSheet(); + $date1 = Date::convertIsoDate('2022-01-01'); + self::assertSame(43100.0, $date1); + + $filename1900 = 'tests/data/Reader/XLSX/1900_Calendar.xlsx'; + $reader1900 = new Xlsx(); + $spreadsheet1900 = $reader1900->load($filename1900); + $worksheet1900 = $spreadsheet1900->getActiveSheet(); + $date2 = Date::convertIsoDate('2022-01-01'); + self::assertSame(44562.0, $date2); + + 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()); + $spreadsheet1900->disconnectWorksheets(); + $spreadsheet1904->disconnectWorksheets(); + } +} diff --git a/tests/data/Reader/XLS/1900_Calendar.xls b/tests/data/Reader/XLS/1900_Calendar.xls new file mode 100644 index 0000000000000000000000000000000000000000..714670a7dc10c2236f73d4e9fc33e28372a894f2 GIT binary patch literal 28160 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%0D$yI_;qx0w=!}3 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 Q01!bxGLQ+&Q~bR9fAqm=g8%>k literal 0 HcmV?d00001 From fe162bcf0e522016a0387c8cb76fa3567a56f1c4 Mon Sep 17 00:00:00 2001 From: oleibman <10341515+oleibman@users.noreply.github.com> Date: Tue, 25 Jun 2024 21:58:10 -0700 Subject: [PATCH 2/2] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c8612cad6c..229a320227 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org). ### Changed - On read, Xlsx Reader had been breaking up union ranges into separate individual ranges. It will now try to preserve range as it was read in. [PR #4042](https://github.com/PHPOffice/PhpSpreadsheet/pull/4042) +- Xlsx/Xls spreadsheet calculation and formatting of dates will use base date of spreadsheet even when spreadsheets with different base dates are simultaneously open. [Issue #1036](https://github.com/PHPOffice/PhpSpreadsheet/issues/1036) [Issue #1635](https://github.com/PHPOffice/PhpSpreadsheet/issues/1635) [PR #4071](https://github.com/PHPOffice/PhpSpreadsheet/pull/4071) ### Deprecated