Slight Improvement in Ods Reader Date Handling

Based on recent discussions in #2938, it can do a bit better with date cells that do not use a recognized date style. Improve differentiating `date` from `date+time`, and in deciding whether 4-digit years have been used in the input cells. This causes a change to one test, where the old result incorrectly expected a 2-digit year (you can verify by opening the spreadsheet in question that it is saved with a 4-digit year).
This commit is contained in:
oleibman
2026-08-11 14:09:12 -07:00
parent 540dfb463a
commit 84de45c2f4
3 changed files with 56 additions and 4 deletions
+4 -3
View File
@@ -1081,17 +1081,18 @@ class Ods extends BaseReader
$type = DataType::TYPE_NUMERIC;
$value = $cellData->getAttributeNS($officeNs, 'date-value');
$dataValue = Date::convertIsoDate($value);
$format15 = Preg::isMatch('/\d\d\d\d/', $allCellDataText) ? NumberFormat::FORMAT_DATE_XLSX15_YYYY : NumberFormat::FORMAT_DATE_XLSX15;
if (Preg::isMatch('/^\d\d\d\d-\d\d-\d\d$/', $allCellDataText)) {
$formatting = 'yyyy-mm-dd';
} elseif (Preg::isMatch('/^\d\d?-[a-zA-Z]+-\d\d\d\d$/', $allCellDataText)) {
$formatting = 'd-mmm-yyyy';
} elseif ($dataValue != floor($dataValue)) {
$formatting = NumberFormat::FORMAT_DATE_XLSX15
} elseif ($dataValue != floor($dataValue) || str_contains($allCellDataText, ':')) {
$formatting = $format15
. ' '
. NumberFormat::FORMAT_DATE_TIME4;
} else {
$formatting = NumberFormat::FORMAT_DATE_XLSX15;
$formatting = $format15;
}
break;
@@ -75,4 +75,55 @@ class NumberFormatCallbackTest extends TestCase
return $retVal;
}
public function testMmmdyyyy(): void
{
$spreadsheetOld = new Spreadsheet();
$sheet = $spreadsheetOld->getActiveSheet();
$sheet->getCell('A1')->setValue(46000); // Dec 9, 2025
$sheet->getStyle('A1')
->getNumberFormat()
->setFormatCode('mmm d, yyyy');
$sheet->getCell('A2')->setValue(46000); // Dec 9, 2025
$sheet->getStyle('A2')
->getNumberFormat()
->setFormatCode(
NumberFormat::FORMAT_DATE_DATETIME_BETTER
);
$writer = new OdsWriter($spreadsheetOld);
$this->tempfile = File::temporaryFileName();
$writer = new OdsWriter($spreadsheetOld);
$writer->useAdditionalNumberFormats([
'mmm d, yyyy' => self::mmmdyyyy(...),
]);
$writer->save($this->tempfile);
$spreadsheetOld->disconnectWorksheets();
$reader = new OdsReader();
$spreadsheet = $reader->load($this->tempfile);
$newSheet = $spreadsheet->getActiveSheet();
// no formatCallback used, so we can't duplicate custom format,
// but we will use a similar format,
// with same number of year digits as was written
self::assertSame('9-Dec-2025', $newSheet->getCell('A1')->getFormattedValue());
self::assertSame('9-Dec-2025 0:00:00', $newSheet->getCell('A2')->getFormattedValue());
$spreadsheet->disconnectWorksheets();
}
private static function mmmdyyyy(Style $obj, string $name): void
{
$writer = $obj->getWriter();
$writer->startElement('number:date-style');
$writer->writeAttribute('style:name', $name);
$writer->startElement('number:month');
$writer->writeAttribute('number:textual', 'true');
$writer->endElement(); // number:month
$writer->writeElement('number:text', ' ');
$writer->startElement('number:day');
$writer->endElement(); // number:day
$writer->writeElement('number:text', ', ');
$writer->startElement('number:year');
$writer->writeAttribute('number:style', 'long');
$writer->endElement(); // number:year
$writer->endElement(); // number:date-style
}
}
@@ -143,7 +143,7 @@ class OdsTest extends TestCase
self::assertEquals(0, $firstSheet->getCell('G10')->getValue());
self::assertEquals(DataType::TYPE_NUMERIC, $firstSheet->getCell('A10')->getDataType()); // Date
self::assertEquals('19-Dec-60', $firstSheet->getCell('A10')->getFormattedValue());
self::assertEquals('19-Dec-1960', $firstSheet->getCell('A10')->getFormattedValue());
self::assertEquals(DataType::TYPE_NUMERIC, $firstSheet->getCell('A13')->getDataType()); // Time
self::assertEquals('2:30:00', $firstSheet->getCell('A13')->getFormattedValue());