Skip to content

Commit a002288

Browse files
authored
Merge pull request #2937 from PHPOffice/2.x-Calendar-Changes
2.x calendar changes
2 parents 76314dd + aba94a1 commit a002288

File tree

17 files changed

+315
-28
lines changed

17 files changed

+315
-28
lines changed

phpstan-baseline.neon

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -990,11 +990,6 @@ parameters:
990990
count: 6
991991
path: src/PhpSpreadsheet/Cell/Cell.php
992992

993-
-
994-
message: "#^Unreachable statement \\- code above always terminates\\.$#"
995-
count: 1
996-
path: src/PhpSpreadsheet/Cell/Cell.php
997-
998993
-
999994
message: "#^Call to an undefined method object\\:\\:getHashCode\\(\\)\\.$#"
1000995
count: 1

src/PhpSpreadsheet/Cell/Cell.php

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -176,16 +176,21 @@ public function getValue()
176176

177177
/**
178178
* Get cell value with formatting.
179-
*
180-
* @return string
181179
*/
182-
public function getFormattedValue()
180+
public function getFormattedValue(): string
183181
{
184-
return (string) NumberFormat::toFormattedString(
182+
$currentCalendar = SharedDate::getExcelCalendar();
183+
SharedDate::setExcelCalendar($this->getWorksheet()->getParent()->getExcelCalendar());
184+
185+
$formattedValue = (string) NumberFormat::toFormattedString(
185186
$this->getCalculatedValue(),
186187
$this->getStyle()
187188
->getNumberFormat()->getFormatCode()
188189
);
190+
191+
SharedDate::setExcelCalendar($currentCalendar);
192+
193+
return $formattedValue;
189194
}
190195

191196
/**
@@ -342,8 +347,6 @@ public function setValueExplicit($value, $dataType, bool $isArrayFormula = false
342347
break;
343348
default:
344349
throw new Exception('Invalid datatype: ' . $dataType);
345-
346-
break;
347350
}
348351

349352
// set the datatype
@@ -402,6 +405,9 @@ private function processArrayResult(
402405
public function getCalculatedValue(bool $asArray = false, bool $resetLog = true)
403406
{
404407
if ($this->dataType === DataType::TYPE_FORMULA) {
408+
$currentCalendar = SharedDate::getExcelCalendar();
409+
SharedDate::setExcelCalendar($this->getWorksheet()->getParent()->getExcelCalendar());
410+
405411
try {
406412
$coordinate = $this->getCoordinate();
407413
$worksheet = $this->getWorksheet();
@@ -430,6 +436,7 @@ public function getCalculatedValue(bool $asArray = false, bool $resetLog = true)
430436
$this->getWorksheet()->setSelectedCells($selected);
431437
$this->getWorksheet()->getParent()->setActiveSheetIndex($index);
432438
} catch (Exception $ex) {
439+
SharedDate::setExcelCalendar($currentCalendar);
433440
if (($ex->getMessage() === 'Unable to access External Workbook') && ($this->calculatedValue !== null)) {
434441
return $this->calculatedValue; // Fallback for calculations referencing external files.
435442
} 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)
441448
);
442449
}
443450

451+
SharedDate::setExcelCalendar($currentCalendar);
444452
if ($result === '#Not Yet Implemented') {
445453
return $this->calculatedValue; // Fallback if calculation engine does not support the formula.
446454
}

src/PhpSpreadsheet/Reader/Xls.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2026,9 +2026,9 @@ private function readDateMode(): void
20262026
$this->pos += 4 + $length;
20272027

20282028
// offset: 0; size: 2; 0 = base 1900, 1 = base 1904
2029-
Date::setExcelCalendar(Date::CALENDAR_WINDOWS_1900);
2029+
$this->spreadsheet->setExcelCalendar(Date::CALENDAR_WINDOWS_1900);
20302030
if (ord($recordData[0]) == 1) {
2031-
Date::setExcelCalendar(Date::CALENDAR_MAC_1904);
2031+
$this->spreadsheet->setExcelCalendar(Date::CALENDAR_MAC_1904);
20322032
}
20332033
}
20342034

src/PhpSpreadsheet/Reader/Xlsx.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -681,11 +681,11 @@ protected function loadSpreadsheetFromFile(string $filename): Spreadsheet
681681

682682
// Set base date
683683
if ($xmlWorkbookNS->workbookPr) {
684-
Date::setExcelCalendar(Date::CALENDAR_WINDOWS_1900);
684+
$excel->setExcelCalendar(Date::CALENDAR_WINDOWS_1900);
685685
$attrs1904 = self::getAttributes($xmlWorkbookNS->workbookPr);
686686
if (isset($attrs1904['date1904'])) {
687687
if (self::boolean((string) $attrs1904['date1904'])) {
688-
Date::setExcelCalendar(Date::CALENDAR_MAC_1904);
688+
$excel->setExcelCalendar(Date::CALENDAR_MAC_1904);
689689
}
690690
}
691691
}

src/PhpSpreadsheet/Shared/Date.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ class Date
6767
protected static $defaultTimeZone;
6868

6969
/**
70-
* Set the Excel calendar (Windows 1900 or Mac 1904).
70+
* Set the Excel Date Calendar (Windows 1900 or Mac 1904) used for calculations and formatting.
7171
*
7272
* @param int $baseYear Excel base date (1900 or 1904)
7373
*
@@ -85,7 +85,8 @@ public static function setExcelCalendar($baseYear)
8585
}
8686

8787
/**
88-
* Return the Excel calendar (Windows 1900 or Mac 1904).
88+
* Return the Excel Date Calendar (Windows 1900 or Mac 1904)
89+
* to be used for current calculations and formatting.
8990
*
9091
* @return int Excel base date (1900 or 1904)
9192
*/

src/PhpSpreadsheet/Spreadsheet.php

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
66
use PhpOffice\PhpSpreadsheet\Reader\Xlsx as XlsxReader;
7+
use PhpOffice\PhpSpreadsheet\Shared\Date;
78
use PhpOffice\PhpSpreadsheet\Shared\File;
89
use PhpOffice\PhpSpreadsheet\Shared\StringHelper;
910
use PhpOffice\PhpSpreadsheet\Style\Style;
@@ -13,7 +14,7 @@
1314

1415
class Spreadsheet
1516
{
16-
// Allowable values for workbook window visilbity
17+
// Allowable values for workbook window visibility
1718
const VISIBILITY_VISIBLE = 'visible';
1819
const VISIBILITY_HIDDEN = 'hidden';
1920
const VISIBILITY_VERY_HIDDEN = 'veryHidden';
@@ -55,6 +56,14 @@ class Spreadsheet
5556
*/
5657
private $workSheetCollection = [];
5758

59+
/**
60+
* Base calendar year to use for calculations
61+
* Value is either CALENDAR_WINDOWS_1900 (1900) or CALENDAR_MAC_1904 (1904).
62+
*
63+
* @var int
64+
*/
65+
protected $excelCalendar = Date::CALENDAR_WINDOWS_1900;
66+
5867
/**
5968
* Calculation Engine.
6069
*
@@ -202,6 +211,34 @@ class Spreadsheet
202211
*/
203212
private $tabRatio = 600;
204213

214+
/**
215+
* Set the Excel Calendar (Windows 1900 or Mac 1904).
216+
*
217+
* @param int $baseYear Excel base date (1900 or 1904)
218+
*
219+
* @return bool Success or failure
220+
*/
221+
public function setExcelCalendar(int $baseYear): bool
222+
{
223+
if (($baseYear == Date::CALENDAR_WINDOWS_1900) || ($baseYear == Date::CALENDAR_MAC_1904)) {
224+
$this->excelCalendar = $baseYear;
225+
226+
return true;
227+
}
228+
229+
return false;
230+
}
231+
232+
/**
233+
* Return the Excel Calendar (Windows 1900 or Mac 1904).
234+
*
235+
* @return int Excel base date (1900 or 1904)
236+
*/
237+
public function getExcelCalendar(): int
238+
{
239+
return $this->excelCalendar;
240+
}
241+
205242
/**
206243
* The workbook has macros ?
207244
*

src/PhpSpreadsheet/Writer/Xls/Workbook.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -960,9 +960,9 @@ private function writeDateMode(): void
960960
$record = 0x0022; // Record identifier
961961
$length = 0x0002; // Bytes to follow
962962

963-
$f1904 = (Date::getExcelCalendar() === Date::CALENDAR_MAC_1904)
964-
? 1
965-
: 0; // Flag for 1904 date system
963+
$f1904 = ($this->spreadsheet->getExcelCalendar() === Date::CALENDAR_MAC_1904)
964+
? 1 // Flag for 1904 date system
965+
: 0; // Flag for 1900 date system
966966

967967
$header = pack('vv', $record, $length);
968968
$data = pack('v', $f1904);

src/PhpSpreadsheet/Writer/Xlsx/Workbook.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ public function writeWorkbook(Spreadsheet $spreadsheet, $recalcRequired = false)
3939
$this->writeFileVersion($objWriter);
4040

4141
// workbookPr
42-
$this->writeWorkbookPr($objWriter);
42+
$this->writeWorkbookPr($objWriter, $spreadsheet);
4343

4444
// workbookProtection
4545
$this->writeWorkbookProtection($objWriter, $spreadsheet);
@@ -80,11 +80,11 @@ private function writeFileVersion(XMLWriter $objWriter): void
8080
/**
8181
* Write WorkbookPr.
8282
*/
83-
private function writeWorkbookPr(XMLWriter $objWriter): void
83+
private function writeWorkbookPr(XMLWriter $objWriter, Spreadsheet $spreadsheet): void
8484
{
8585
$objWriter->startElement('workbookPr');
8686

87-
if (Date::getExcelCalendar() === Date::CALENDAR_MAC_1904) {
87+
if ($spreadsheet->getExcelCalendar() === Date::CALENDAR_MAC_1904) {
8888
$objWriter->writeAttribute('date1904', '1');
8989
}
9090

tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/AllSetupTeardown.php

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,13 @@ protected function tearDown(): void
5555
}
5656
}
5757

58-
protected static function setMac1904(): void
58+
protected static function setMac1904(?Worksheet $worksheet = null): void
5959
{
60-
Date::setExcelCalendar(Date::CALENDAR_MAC_1904);
60+
if ($worksheet === null) {
61+
Date::setExcelCalendar(Date::CALENDAR_MAC_1904);
62+
} else {
63+
$worksheet->getParent()->setExcelCalendar(Date::CALENDAR_MAC_1904);
64+
}
6165
}
6266

6367
protected static function setUnixReturn(): void

tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/IsoWeekNumTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@ public function providerISOWEEKNUM(): array
3535
public function testISOWEEKNUM1904($expectedResult, $dateValue): void
3636
{
3737
$this->mightHaveException($expectedResult);
38-
self::setMac1904();
3938
$sheet = $this->getSheet();
39+
self::setMac1904($sheet);
4040
$sheet->getCell('A1')->setValue("=ISOWEEKNUM($dateValue)");
4141
$sheet->getCell('B1')->setValue('1954-11-23');
4242
self::assertSame($expectedResult, $sheet->getCell('A1')->getCalculatedValue());

0 commit comments

Comments
 (0)