Skip to content

Commit d0b3e74

Browse files
committed
Date Disambiguation
Give everyone the same ability demonstrated for Ods in new Sample 56.
1 parent 4674319 commit d0b3e74

File tree

3 files changed

+134
-70
lines changed

3 files changed

+134
-70
lines changed

src/PhpSpreadsheet/Spreadsheet.php

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace PhpOffice\PhpSpreadsheet;
44

5+
use Composer\Pcre\Preg;
56
use JsonSerializable;
67
use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
78
use PhpOffice\PhpSpreadsheet\Cell\IValueBinder;
@@ -1060,7 +1061,7 @@ public function getDefinedName(string $definedName, ?Worksheet $worksheet = null
10601061
// then look for local defined name (has priority over global defined name if both names exist)
10611062
if ($worksheet !== null) {
10621063
$wsTitle = StringHelper::strToUpper($worksheet->getTitle());
1063-
$definedName = (string) preg_replace('/^.*!/', '', $definedName);
1064+
$definedName = Preg::replace('/^.*!/', '', $definedName);
10641065
foreach ($this->definedNames as $dn) {
10651066
$sheet = $dn->getScope() ?? $dn->getWorksheet();
10661067
$upper = StringHelper::strToUpper($dn->getName());
@@ -1863,6 +1864,37 @@ public function replaceBuiltinNumberFormat(int $builtinFormatIndex, string $form
18631864
}
18641865
}
18651866

1867+
/**
1868+
* Change all 2-digit-year date styles to use 4-digit year;
1869+
* change all dd-mm-yyyy and mm-dd-yyyy styles to yyyy-mm-dd;
1870+
* dd-mmm-yyyy is unambiguous and left unchanged.
1871+
*/
1872+
public function disambiguateDateStyles(): void
1873+
{
1874+
foreach ($this->cellXfCollection as $style) {
1875+
$numberFormat = $style->getNumberFormat();
1876+
$oldFormat = (string) $numberFormat->getFormatCode();
1877+
$newFormat = Preg::replace('/\byy\b/i', 'yyyy', $oldFormat);
1878+
$newFormat = Preg::replace(
1879+
'~\bdd?(-|/|"-"|"/")'
1880+
. 'mm?(-|/|"-"|"/")'
1881+
. 'yyyy~',
1882+
'yyyy-mm-dd',
1883+
$newFormat
1884+
);
1885+
$newFormat = Preg::replace(
1886+
'~\bmm?(-|/|"-"|"/")'
1887+
. 'dd?(-|/|"-"|"/")'
1888+
. 'yyyy~',
1889+
'yyyy-mm-dd',
1890+
$newFormat
1891+
);
1892+
if ($newFormat !== $oldFormat) {
1893+
$numberFormat->setFormatCode($newFormat);
1894+
}
1895+
}
1896+
}
1897+
18661898
public function returnArrayAsArray(): void
18671899
{
18681900
$this->calculationEngine->setInstanceArrayReturnType(

tests/PhpSpreadsheetTests/Reader/Xlsx/ReplaceBuiltinNumberFormatTest.php

Lines changed: 0 additions & 69 deletions
This file was deleted.
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PhpOffice\PhpSpreadsheetTests\Style;
6+
7+
use PhpOffice\PhpSpreadsheet\Spreadsheet;
8+
use PhpOffice\PhpSpreadsheet\Style\NumberFormat;
9+
use PHPUnit\Framework\TestCase;
10+
11+
class ReplaceBuiltinNumberFormatTest extends TestCase
12+
{
13+
private ?Spreadsheet $spreadsheet = null;
14+
15+
protected function tearDown(): void
16+
{
17+
if ($this->spreadsheet !== null) {
18+
$this->spreadsheet->disconnectWorksheets();
19+
$this->spreadsheet = null;
20+
}
21+
}
22+
23+
public function testReplaceBuiltinNumberFormat(): void
24+
{
25+
$spreadsheet = $this->spreadsheet = new Spreadsheet();
26+
$sheet = $this->spreadsheet->getActiveSheet();
27+
$sheet->fromArray([45486, 1023, 45487, 45488, 45489, 45480, 45479, 45478, 45477, 45476, 45475]);
28+
$sheet->getStyle('A1')->getNumberFormat()
29+
->setBuiltInFormatCode(NumberFormat::SHORT_DATE_INDEX);
30+
$sheet->getStyle('B1')->getNumberFormat()
31+
->setFormatCode('#,##0.00');
32+
$sheet->getStyle('C1')->getNumberFormat()
33+
->setBuiltInFormatCode(NumberFormat::SHORT_DATE_INDEX);
34+
$sheet->getStyle('D1')->getNumberFormat()
35+
->setFormatCode('dd-MMM-yyyy');
36+
$sheet->getStyle('E1')->getNumberFormat()
37+
->setBuiltInFormatCode(16);
38+
$sheet->getStyle('F1')->getNumberFormat()
39+
->setFormatCode('d-MMM-yy');
40+
$sheet->getStyle('G1')->getNumberFormat()
41+
->setFormatCode('dd/m/yy');
42+
$sheet->getStyle('H1')->getNumberFormat()
43+
->setFormatCode('mm-dd-yy');
44+
$sheet->getStyle('I1')->getNumberFormat()
45+
->setFormatCode('yy-mm-dd');
46+
$sheet->getStyle('J1')->getNumberFormat()
47+
->setFormatCode('m/d/yyyy h:mm');
48+
$sheet->getStyle('K1')->getNumberFormat()
49+
->setFormatCode('d"/"m"/"yy');
50+
$values = $sheet->toArray();
51+
$expected = [[
52+
'7/13/2024', // builtin style 14
53+
'1,023.00', // #,##0.00
54+
'7/14/2024', // builtin style 14
55+
'15-Jul-2024', // dd-MMM-yyyy
56+
'16-Jul', // builtin style 16
57+
'7-Jul-24', // d-MMM-yy
58+
'06/7/24', // dd/m/yy
59+
'07-05-24', // mm-dd-yy
60+
'24-07-04', // yy-mm-dd
61+
'7/3/2024 0:00', // m/d/yyyy h:mm
62+
'2/7/24', // d"/"m"/"yy
63+
]];
64+
self::assertSame($expected, $values);
65+
$spreadsheet->replaceBuiltinNumberFormat(
66+
NumberFormat::SHORT_DATE_INDEX,
67+
'yyyy-mm-dd'
68+
);
69+
$newValues = $sheet->toArray();
70+
$newExpected = [[
71+
'2024-07-13', // yyyy-mm-dd changed from builtin style 14
72+
'1,023.00', // unchanged #,##0.00
73+
'2024-07-14', // yyyy-mm-dd changed from builtin style 14
74+
'15-Jul-2024', // unchanged dd-MMM-yyyy
75+
'16-Jul', // unchanged builtin style 16
76+
'7-Jul-24', // unchanged d-MMM-yy
77+
'06/7/24', // unchanged dd/m/yy
78+
'07-05-24', // unchanged mm-dd-yy
79+
'24-07-04', // unchanged yy-mm-dd
80+
'7/3/2024 0:00', // unchanged m/d/yyyy h:mm
81+
'2/7/24', // unchanged d"/"m"/"yy
82+
]];
83+
self::assertSame($newExpected, $newValues);
84+
$spreadsheet->disambiguateDateStyles();
85+
$newValues2 = $sheet->toArray();
86+
$newExpected2 = [[
87+
'2024-07-13', // unchanged yyyy-mm-dd
88+
'1,023.00', // unchanged #,##0.00
89+
'2024-07-14', // unchanged yyyy-mm-dd
90+
'15-Jul-2024', // unchanged dd-MMM-yyyy
91+
'16-Jul', // unchanged builtin style 16
92+
'7-Jul-2024', // changed from d-MMM-yy to d-MMM-yyyy
93+
'2024-07-06', // changed from dd/m/yy to yyyy-mm-dd
94+
'2024-07-05', // changed from mm-dd-yy tp yyyy-mm-dd
95+
'2024-07-04', // changed from yy-mm-dd to yyyy-mm-dd
96+
'2024-07-03 0:00', // changed m/d/yyyy h:mm to yyyy-mm-dd h:mm
97+
'2024-07-02', // changed d"/"m"/"yy to yyyy-mm-dd
98+
]];
99+
self::assertSame($newExpected2, $newValues2);
100+
}
101+
}

0 commit comments

Comments
 (0)