Skip to content

Commit 3964087

Browse files
committed
Test for calendar when reading Excel Files.
Set Excel calendar to be used for calculations and formatting for the calendar stored against the spreadsheet.
1 parent 95cf51b commit 3964087

File tree

9 files changed

+166
-18
lines changed

9 files changed

+166
-18
lines changed

phpstan-baseline.neon

Lines changed: 0 additions & 10 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
@@ -2580,11 +2575,6 @@ parameters:
25802575
count: 1
25812576
path: src/PhpSpreadsheet/Shared/OLERead.php
25822577

2583-
-
2584-
message: "#^Call to an undefined method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Calculation\\:\\:_calculateFormulaValue\\(\\)\\.$#"
2585-
count: 1
2586-
path: src/PhpSpreadsheet/Shared/StringHelper.php
2587-
25882578
-
25892579
message: "#^Static method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\TimeZone\\:\\:validateTimeZone\\(\\) is unused\\.$#"
25902580
count: 1

src/PhpSpreadsheet/Cell/Cell.php

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use PhpOffice\PhpSpreadsheet\Style\Style;
1616
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
1717
use Throwable;
18+
use function _PHPStan_59fb0a3b2\RingCentral\Psr7\str;
1819

1920
class Cell
2021
{
@@ -176,16 +177,22 @@ public function getValue()
176177

177178
/**
178179
* Get cell value with formatting.
179-
*
180-
* @return string
181180
*/
182-
public function getFormattedValue()
181+
public function getFormattedValue(): string
183182
{
184-
return (string) NumberFormat::toFormattedString(
183+
$currentCalendar = SharedDate::getExcelCalendar();
184+
SharedDate::setExcelCalendar($this->getWorksheet()->getParent()->getExcelCalendar());
185+
186+
$formattedValue = (string) NumberFormat::toFormattedString(
185187
$this->getCalculatedValue(),
186188
$this->getStyle()
187189
->getNumberFormat()->getFormatCode()
188190
);
191+
192+
SharedDate::setExcelCalendar($currentCalendar);
193+
194+
return $formattedValue;
195+
189196
}
190197

191198
/**
@@ -342,8 +349,6 @@ public function setValueExplicit($value, $dataType, bool $isArrayFormula = false
342349
break;
343350
default:
344351
throw new Exception('Invalid datatype: ' . $dataType);
345-
346-
break;
347352
}
348353

349354
// set the datatype
@@ -403,6 +408,8 @@ public function getCalculatedValue(bool $asArray = false, bool $resetLog = true)
403408
{
404409
if ($this->dataType === DataType::TYPE_FORMULA) {
405410
try {
411+
// $currentCalendar = SharedDate::getExcelCalendar();
412+
// SharedDate::setExcelCalendar($this->getWorksheet()->getParent()->getExcelCalendar());
406413
$coordinate = $this->getCoordinate();
407414
$worksheet = $this->getWorksheet();
408415
$value = $this->value;
@@ -430,6 +437,7 @@ public function getCalculatedValue(bool $asArray = false, bool $resetLog = true)
430437
$this->getWorksheet()->setSelectedCells($selected);
431438
$this->getWorksheet()->getParent()->setActiveSheetIndex($index);
432439
} catch (Exception $ex) {
440+
// SharedDate::setExcelCalendar($currentCalendar);
433441
if (($ex->getMessage() === 'Unable to access External Workbook') && ($this->calculatedValue !== null)) {
434442
return $this->calculatedValue; // Fallback for calculations referencing external files.
435443
} elseif (preg_match('/[Uu]ndefined (name|offset: 2|array key 2)/', $ex->getMessage()) === 1) {
@@ -441,6 +449,7 @@ public function getCalculatedValue(bool $asArray = false, bool $resetLog = true)
441449
);
442450
}
443451

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

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 Default 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 Default 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
*/
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<?php
2+
3+
namespace PhpOffice\PhpSpreadsheetTests\Reader\Xls;
4+
5+
use PhpOffice\PhpSpreadsheet\Reader\Xls;
6+
use PhpOffice\PhpSpreadsheet\Shared\Date;
7+
use PHPUnit\Framework\TestCase;
8+
9+
class DateReaderTest extends TestCase
10+
{
11+
protected function tearDown(): void
12+
{
13+
Date::setExcelCalendar(Date::CALENDAR_WINDOWS_1900);
14+
}
15+
16+
public function testReadExcel1900Spreadsheet(): void
17+
{
18+
$filename = 'tests/data/Reader/XLS/1900_Calendar.xls';
19+
$reader = new Xls();
20+
$spreadsheet = $reader->load($filename);
21+
22+
self::assertSame(Date::CALENDAR_WINDOWS_1900, $spreadsheet->getExcelCalendar());
23+
24+
$worksheet = $spreadsheet->getActiveSheet();
25+
self::assertSame(44562, $worksheet->getCell('A1')->getValue());
26+
self::assertSame('2022-01-01', $worksheet->getCell('A1')->getFormattedValue());
27+
self::assertSame(44926, $worksheet->getCell('A2')->getValue());
28+
self::assertSame('2022-12-31', $worksheet->getCell('A2')->getFormattedValue());
29+
}
30+
31+
public function testReadExcel1904Spreadsheet(): void
32+
{
33+
$filename = 'tests/data/Reader/XLS/1904_Calendar.xls';
34+
$reader = new Xls();
35+
$spreadsheet = $reader->load($filename);
36+
37+
self::assertSame(Date::CALENDAR_MAC_1904, $spreadsheet->getExcelCalendar());
38+
39+
$worksheet = $spreadsheet->getActiveSheet();
40+
self::assertSame(43100, $worksheet->getCell('A1')->getValue());
41+
self::assertSame('2022-01-01', $worksheet->getCell('A1')->getFormattedValue());
42+
self::assertSame(43464, $worksheet->getCell('A2')->getValue());
43+
self::assertSame('2022-12-31', $worksheet->getCell('A2')->getFormattedValue());
44+
}
45+
}
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
<?php
2+
3+
namespace PhpOffice\PhpSpreadsheetTests\Reader\Xlsx;
4+
5+
use PhpOffice\PhpSpreadsheet\Reader\Xlsx;
6+
use PhpOffice\PhpSpreadsheet\Shared\Date;
7+
use PHPUnit\Framework\TestCase;
8+
9+
class DateReaderTest extends TestCase
10+
{
11+
protected function tearDown(): void
12+
{
13+
Date::setExcelCalendar(Date::CALENDAR_WINDOWS_1900);
14+
}
15+
16+
public function testReadExcel1900Spreadsheet(): void
17+
{
18+
$filename = 'tests/data/Reader/XLSX/1900_Calendar.xlsx';
19+
$reader = new Xlsx();
20+
$spreadsheet = $reader->load($filename);
21+
22+
self::assertSame(Date::CALENDAR_WINDOWS_1900, $spreadsheet->getExcelCalendar());
23+
24+
$worksheet = $spreadsheet->getActiveSheet();
25+
self::assertSame(44562, $worksheet->getCell('A1')->getValue());
26+
self::assertSame('2022-01-01', $worksheet->getCell('A1')->getFormattedValue());
27+
self::assertSame(44926, $worksheet->getCell('A2')->getValue());
28+
self::assertSame('2022-12-31', $worksheet->getCell('A2')->getFormattedValue());
29+
self::assertSame(44561, $worksheet->getCell('B1')->getCalculatedValue());
30+
self::assertSame('2021-12-31', $worksheet->getCell('B1')->getFormattedValue());
31+
self::assertSame(44927, $worksheet->getCell('B2')->getCalculatedValue());
32+
self::assertSame('2023-01-01', $worksheet->getCell('B2')->getFormattedValue());
33+
}
34+
35+
public function testReadExcel1904Spreadsheet(): void
36+
{
37+
$filename = 'tests/data/Reader/XLSX/1904_Calendar.xlsx';
38+
$reader = new Xlsx();
39+
$spreadsheet = $reader->load($filename);
40+
41+
self::assertSame(Date::CALENDAR_MAC_1904, $spreadsheet->getExcelCalendar());
42+
43+
$worksheet = $spreadsheet->getActiveSheet();
44+
self::assertSame(43100, $worksheet->getCell('A1')->getValue());
45+
self::assertSame('2022-01-01', $worksheet->getCell('A1')->getFormattedValue());
46+
self::assertSame(43464, $worksheet->getCell('A2')->getValue());
47+
self::assertSame('2022-12-31', $worksheet->getCell('A2')->getFormattedValue());
48+
self::assertSame(43099, $worksheet->getCell('B1')->getCalculatedValue());
49+
self::assertSame('2021-12-31', $worksheet->getCell('B1')->getFormattedValue());
50+
self::assertSame(43465, $worksheet->getCell('B2')->getCalculatedValue());
51+
self::assertSame('2023-01-01', $worksheet->getCell('B2')->getFormattedValue());
52+
}
53+
54+
public function testSwitchCalendars(): void
55+
{
56+
$filename1900 = 'tests/data/Reader/XLSX/1900_Calendar.xlsx';
57+
$reader1900 = new Xlsx();
58+
$spreadsheet1900 = $reader1900->load($filename1900);
59+
$worksheet1900 = $spreadsheet1900->getActiveSheet();
60+
61+
$filename1904 = 'tests/data/Reader/XLSX/1904_Calendar.xlsx';
62+
$reader1904 = new Xlsx();
63+
$spreadsheet1904 = $reader1904->load($filename1904);
64+
$worksheet1904 = $spreadsheet1904->getActiveSheet();
65+
66+
self::assertSame(44562, $worksheet1900->getCell('A1')->getValue());
67+
self::assertSame('2022-01-01', $worksheet1900->getCell('A1')->getFormattedValue());
68+
self::assertSame(44926, $worksheet1900->getCell('A2')->getValue());
69+
self::assertSame('2022-12-31', $worksheet1900->getCell('A2')->getFormattedValue());
70+
self::assertSame(44561, $worksheet1900->getCell('B1')->getCalculatedValue());
71+
self::assertSame('2021-12-31', $worksheet1900->getCell('B1')->getFormattedValue());
72+
self::assertSame(44927, $worksheet1900->getCell('B2')->getCalculatedValue());
73+
self::assertSame('2023-01-01', $worksheet1900->getCell('B2')->getFormattedValue());
74+
75+
self::assertSame(43100, $worksheet1904->getCell('A1')->getValue());
76+
self::assertSame('2022-01-01', $worksheet1904->getCell('A1')->getFormattedValue());
77+
self::assertSame(43464, $worksheet1904->getCell('A2')->getValue());
78+
self::assertSame('2022-12-31', $worksheet1904->getCell('A2')->getFormattedValue());
79+
self::assertSame(43099, $worksheet1904->getCell('B1')->getCalculatedValue());
80+
self::assertSame('2021-12-31', $worksheet1904->getCell('B1')->getFormattedValue());
81+
self::assertSame(43465, $worksheet1904->getCell('B2')->getCalculatedValue());
82+
self::assertSame('2023-01-01', $worksheet1904->getCell('B2')->getFormattedValue());
83+
84+
// Check that accessing date values from one spreadsheet doesn't break accessing correct values from another
85+
self::assertSame(44561, $worksheet1900->getCell('B1')->getCalculatedValue());
86+
self::assertSame('2021-12-31', $worksheet1900->getCell('B1')->getFormattedValue());
87+
self::assertSame(44927, $worksheet1900->getCell('B2')->getCalculatedValue());
88+
self::assertSame('2023-01-01', $worksheet1900->getCell('B2')->getFormattedValue());
89+
self::assertSame(44562, $worksheet1900->getCell('A1')->getValue());
90+
self::assertSame('2022-01-01', $worksheet1900->getCell('A1')->getFormattedValue());
91+
self::assertSame(44926, $worksheet1900->getCell('A2')->getValue());
92+
self::assertSame('2022-12-31', $worksheet1900->getCell('A2')->getFormattedValue());
93+
94+
self::assertSame(43099, $worksheet1904->getCell('B1')->getCalculatedValue());
95+
self::assertSame('2021-12-31', $worksheet1904->getCell('B1')->getFormattedValue());
96+
self::assertSame(43465, $worksheet1904->getCell('B2')->getCalculatedValue());
97+
self::assertSame('2023-01-01', $worksheet1904->getCell('B2')->getFormattedValue());
98+
self::assertSame(43100, $worksheet1904->getCell('A1')->getValue());
99+
self::assertSame('2022-01-01', $worksheet1904->getCell('A1')->getFormattedValue());
100+
self::assertSame(43464, $worksheet1904->getCell('A2')->getValue());
101+
self::assertSame('2022-12-31', $worksheet1904->getCell('A2')->getFormattedValue());
102+
}
103+
}
27.5 KB
Binary file not shown.
27.5 KB
Binary file not shown.
9.9 KB
Binary file not shown.
9.88 KB
Binary file not shown.

0 commit comments

Comments
 (0)