Skip to content
This repository was archived by the owner on Apr 12, 2022. It is now read-only.

Commit 7047e0e

Browse files
authored
Handle dates as numbers, just like Excel wants (#17)
1 parent e121dda commit 7047e0e

File tree

9 files changed

+129
-22
lines changed

9 files changed

+129
-22
lines changed

.github/workflows/integrate.yaml

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ jobs:
1515
strategy:
1616
matrix:
1717
php-version:
18-
- "7.4"
18+
- "8.0"
1919

2020
steps:
2121
- name: "Checkout"
@@ -62,7 +62,6 @@ jobs:
6262
strategy:
6363
matrix:
6464
php-version:
65-
- "7.4"
6665
- "8.0"
6766

6867
steps:
@@ -107,7 +106,7 @@ jobs:
107106
strategy:
108107
matrix:
109108
php-version:
110-
- "7.4"
109+
- "8.0"
111110

112111
steps:
113112
- name: "Checkout"
@@ -153,7 +152,7 @@ jobs:
153152
strategy:
154153
matrix:
155154
php-version:
156-
- "7.4"
155+
- "8.0"
157156

158157
steps:
159158
- name: "Checkout"
@@ -190,7 +189,7 @@ jobs:
190189
strategy:
191190
matrix:
192191
php-version:
193-
- "7.4"
192+
- "8.0"
194193

195194
steps:
196195
- name: "Checkout"

composer.json

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,17 @@
1010
}
1111
],
1212
"require": {
13-
"php": "^7.4 || ^8.0",
13+
"php": ">=8.0",
1414
"ext-iconv": "*",
1515
"ext-mbstring": "*"
1616
},
1717
"require-dev": {
1818
"malukenho/mcbumpface": "^1.1.5",
19-
"mikey179/vfsstream": "^1.6.8",
20-
"phpoffice/phpspreadsheet": "^1.17.1",
21-
"phpstan/phpstan": "^0.12.86",
22-
"phpstan/phpstan-phpunit": "^0.12.18",
23-
"phpunit/phpunit": "^9.5.4",
19+
"mikey179/vfsstream": "^1.6.9",
20+
"phpoffice/phpspreadsheet": "^1.18.0",
21+
"phpstan/phpstan": "^0.12.94",
22+
"phpstan/phpstan-phpunit": "^0.12.21",
23+
"phpunit/phpunit": "^9.5.8",
2424
"slam/php-cs-fixer-extensions": "^3.0.1",
2525
"slam/php-debug-r": "^1.7.0",
2626
"slam/phpstan-extensions": "^5.1.0"

lib/Helper/CellStyle/Date.php

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,43 @@
99

1010
final class Date implements CellStyleInterface
1111
{
12-
public function decorateValue($value)
12+
public function decorateValue($value): ?int
1313
{
14-
if (empty($value)) {
15-
return $value;
14+
if (! \is_string($value) || 1 !== \preg_match('/^(?<year>\d\d\d\d)-(?<month>\d\d)-(?<day>\d\d)$/', $value, $matches)) {
15+
return null;
1616
}
1717

18-
return \implode('/', \array_reverse(\explode('-', $value)));
18+
$year = (int) $matches['year'];
19+
$month = (int) $matches['month'];
20+
$day = (int) $matches['day'];
21+
22+
// Fudge factor for the erroneous fact that the year 1900 is treated as a Leap Year in MS Excel
23+
// This affects every date following 28th February 1900
24+
$excel1900isLeapYear = true;
25+
if ((1900 === $year) && ($month <= 2)) {
26+
$excel1900isLeapYear = false;
27+
}
28+
$myexcelBaseDate = 2415020;
29+
30+
// Julian base date Adjustment
31+
if ($month > 2) {
32+
$month -= 3;
33+
} else {
34+
$month += 9;
35+
--$year;
36+
}
37+
38+
// Calculate the Julian Date, then subtract the Excel base date (JD 2415020 = 31-Dec-1899 Giving Excel Date of 0)
39+
$century = (int) \substr((string) $year, 0, 2);
40+
$decade = (int) \substr((string) $year, 2, 2);
41+
$excelDate = \floor((146097 * $century) / 4) + \floor((1461 * $decade) / 4) + \floor((153 * $month + 2) / 5) + $day + 1721119 - $myexcelBaseDate + $excel1900isLeapYear;
42+
43+
return (int) $excelDate;
1944
}
2045

2146
public function styleCell(Format $format): void
2247
{
2348
$format->setAlign('center');
49+
$format->setNumFormat('DD/MM/YYYY');
2450
}
2551
}

lib/Helper/TableWorkbook.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,9 @@ private function writeRow(Table $table, array $row, ?string $type = null): void
185185
$write = 'writeString';
186186
}
187187

188-
$content = $cellStyle->decorateValue($content);
188+
if ('title' !== $type) {
189+
$content = $cellStyle->decorateValue($content);
190+
}
189191
$content = $this->sanitize($content);
190192

191193
$sheet->{$write}($table->getRowCurrent(), $table->getColumnCurrent(), $content, $format);

phpstan-baseline.neon

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
parameters:
2+
ignoreErrors:
3+
-
4+
message: "#^Call to static method PHPUnit\\\\Framework\\\\Assert\\:\\:assertArrayHasKey\\(\\) with 'foo' and Slam\\\\Excel\\\\Helper\\\\ColumnCollection will always evaluate to false\\.$#"
5+
count: 1
6+
path: tests/Helper/ColumnCollectionTest.php
7+

phpstan.neon

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,13 @@
11
includes:
2-
- phar://phpstan.phar/conf/config.levelmax.neon
32
- vendor/phpstan/phpstan-phpunit/extension.neon
43
- vendor/slam/phpstan-extensions/conf/slam-rules.neon
4+
- phpstan-baseline.neon
55

66
parameters:
7+
level: max
78
checkMissingIterableValueType: false
89
paths:
910
- lib/
1011
- tests/
1112
excludes_analyse:
1213
- %currentWorkingDirectory%/lib/Pear/*
13-
ignoreErrors:
14-
-
15-
message: '#Cannot call method \w+\(\) on PhpOffice\\PhpSpreadsheet\\Cell\\Cell\|null#'
16-
path: %currentWorkingDirectory%/tests/Helper/TableWorkbookTest.php

tests/Helper/CellStyle/DateTest.php

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Slam\Excel\Tests\Helper\CellStyle;
6+
7+
use PHPUnit\Framework\TestCase;
8+
use Slam\Excel\Helper\CellStyle\Date;
9+
10+
final class DateTest extends TestCase
11+
{
12+
/**
13+
* @dataProvider provide1900Dates
14+
*
15+
* @see https://github.com/PHPOffice/PhpSpreadsheet/blob/188d026615f2c79b6a196c97ed8ca82407f47e57/tests/PhpSpreadsheetTests/Shared/DateTest.php#L119-L130
16+
*/
17+
public function testDateTimeFormattedPHPToExcel1900(?int $expected, ?string $from): void
18+
{
19+
self::assertSame($expected, (new Date())->decorateValue($from));
20+
}
21+
22+
public function provide1900Dates(): array
23+
{
24+
return [
25+
'null' => [
26+
null,
27+
null,
28+
],
29+
'empty-string' => [
30+
null,
31+
'',
32+
],
33+
'non-date-string' => [
34+
null,
35+
'foobar',
36+
],
37+
'PHP 32-bit Earliest Date 14-Dec-1901' => [
38+
714,
39+
'1901-12-14',
40+
],
41+
'31-Dec-1903' => [
42+
1461,
43+
'1903-12-31',
44+
],
45+
'Excel 1904 Calendar Base Date 01-Jan-1904' => [
46+
1462,
47+
'1904-01-01',
48+
],
49+
'02-Jan-1904' => [
50+
1463,
51+
'1904-01-02',
52+
],
53+
'19-Dec-1960' => [
54+
22269,
55+
'1960-12-19',
56+
],
57+
'PHP Base Date 01-Jan-1970' => [
58+
25569,
59+
'1970-01-01',
60+
],
61+
'07-Dec-1982' => [
62+
30292,
63+
'1982-12-07',
64+
],
65+
'12-Jun-2008' => [
66+
39611,
67+
'2008-06-12',
68+
],
69+
'PHP 32-bit Latest Date 19-Jan-2038' => [
70+
50424,
71+
'2038-01-19',
72+
],
73+
];
74+
}
75+
}

tests/Helper/TableWorkbookTest.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ protected function setUp(): void
2020
{
2121
$this->vfs = vfs\vfsStream::setup('root', 0770);
2222
$this->filename = vfs\vfsStream::url('root/test-encoding.xls');
23+
// $this->filename = __DIR__ . '/test.xls';
2324
}
2425

2526
public function testPostGenerationDetails(): void
@@ -138,7 +139,7 @@ public function testCellStyles(): void
138139
'A4' => 'text',
139140
'B4' => 3.45,
140141
'C4' => 1234567.8,
141-
'D4' => '02/03/2017',
142+
'D4' => 42796,
142143
'E4' => 1234567.89,
143144
'F4' => 'AABB',
144145
];

tests/Helper/test.xls

3.5 KB
Binary file not shown.

0 commit comments

Comments
 (0)