From cc07072cbbeda9e45df5ee514ae303668f2062f1 Mon Sep 17 00:00:00 2001 From: Adrien Loison Date: Sat, 24 Sep 2016 10:46:42 -0700 Subject: [PATCH] Better support for Date custom format (#316) - To determine if a style should apply a date format, the presence of "applyNumberFormat" attribute on the "cellXfs" section of styles.xml is now optional. We only look at the "numFmtId" attribute (but early return if "applyNumberFormat" is set to "0"). - The format code can contain lowercase AND now uppercase characters as its pattern. - "General" format code used as a custom format is now supported. It seems to be used by a bunch of programs... --- src/Spout/Reader/Wrapper/SimpleXMLElement.php | 2 +- .../Reader/XLSX/Helper/CellValueFormatter.php | 8 +- src/Spout/Reader/XLSX/Helper/StyleHelper.php | 164 +++++++++++------- .../Reader/XLSX/Helper/StyleHelperTest.php | 65 +++++-- tests/Spout/Reader/XLSX/ReaderTest.php | 15 ++ ...te_formats_and_no_apply_number_format.xlsx | Bin 0 -> 21882 bytes 6 files changed, 174 insertions(+), 80 deletions(-) create mode 100644 tests/resources/xlsx/sheet_with_custom_date_formats_and_no_apply_number_format.xlsx diff --git a/src/Spout/Reader/Wrapper/SimpleXMLElement.php b/src/Spout/Reader/Wrapper/SimpleXMLElement.php index 2bd836d..3790341 100644 --- a/src/Spout/Reader/Wrapper/SimpleXMLElement.php +++ b/src/Spout/Reader/Wrapper/SimpleXMLElement.php @@ -152,7 +152,7 @@ class SimpleXMLElement /** * Returns the immediate children. * - * @return array The children + * @return SimpleXMLElement[] The children */ public function children() { diff --git a/src/Spout/Reader/XLSX/Helper/CellValueFormatter.php b/src/Spout/Reader/XLSX/Helper/CellValueFormatter.php index 2a9d398..b4c6256 100644 --- a/src/Spout/Reader/XLSX/Helper/CellValueFormatter.php +++ b/src/Spout/Reader/XLSX/Helper/CellValueFormatter.php @@ -228,8 +228,8 @@ class CellValueFormatter $dateObj->setTime($hours, $minutes, $seconds); if ($this->shouldFormatDates) { - $styleNumberFormat = $this->styleHelper->getNumberFormat($cellStyleId); - $phpDateFormat = DateFormatHelper::toPHPDateFormat($styleNumberFormat); + $styleNumberFormatCode = $this->styleHelper->getNumberFormatCode($cellStyleId); + $phpDateFormat = DateFormatHelper::toPHPDateFormat($styleNumberFormatCode); return $dateObj->format($phpDateFormat); } else { return $dateObj; @@ -257,8 +257,8 @@ class CellValueFormatter $dateObj->modify('+' . $secondsRemainder . 'seconds'); if ($this->shouldFormatDates) { - $styleNumberFormat = $this->styleHelper->getNumberFormat($cellStyleId); - $phpDateFormat = DateFormatHelper::toPHPDateFormat($styleNumberFormat); + $styleNumberFormatCode = $this->styleHelper->getNumberFormatCode($cellStyleId); + $phpDateFormat = DateFormatHelper::toPHPDateFormat($styleNumberFormatCode); return $dateObj->format($phpDateFormat); } else { return $dateObj; diff --git a/src/Spout/Reader/XLSX/Helper/StyleHelper.php b/src/Spout/Reader/XLSX/Helper/StyleHelper.php index 85278bf..000adab 100644 --- a/src/Spout/Reader/XLSX/Helper/StyleHelper.php +++ b/src/Spout/Reader/XLSX/Helper/StyleHelper.php @@ -29,6 +29,8 @@ class StyleHelper /** By convention, default style ID is 0 */ const DEFAULT_STYLE_ID = 0; + const NUMBER_FORMAT_GENERAL = 'General'; + /** * @see https://msdn.microsoft.com/en-us/library/ff529597(v=office.12).aspx * @var array Mapping between built-in numFmtId and the associated format - for dates only @@ -51,18 +53,48 @@ class StyleHelper /** @var string Path of the XLSX file being read */ protected $filePath; + /** @var array Array containing the IDs of built-in number formats indicating a date */ + protected $builtinNumFmtIdIndicatingDates; + /** @var array Array containing a mapping NUM_FMT_ID => FORMAT_CODE */ protected $customNumberFormats; /** @var array Array containing a mapping STYLE_ID => [STYLE_ATTRIBUTES] */ protected $stylesAttributes; + /** @var array Cache containing a mapping NUM_FMT_ID => IS_DATE_FORMAT. Used to avoid lots of recalculations */ + protected $numFmtIdToIsDateFormatCache = []; + /** * @param string $filePath Path of the XLSX file being read */ public function __construct($filePath) { $this->filePath = $filePath; + $this->builtinNumFmtIdIndicatingDates = array_keys(self::$builtinNumFmtIdToNumFormatMapping); + } + + /** + * Returns whether the style with the given ID should consider + * numeric values as timestamps and format the cell as a date. + * + * @param int $styleId Zero-based style ID + * @return bool Whether the cell with the given cell should display a date instead of a numeric value + */ + public function shouldFormatNumericValueAsDate($styleId) + { + $stylesAttributes = $this->getStylesAttributes(); + + // Default style (0) does not format numeric values as timestamps. Only custom styles do. + // Also if the style ID does not exist in the styles.xml file, format as numeric value. + // Using isset here because it is way faster than array_key_exists... + if ($styleId === self::DEFAULT_STYLE_ID || !isset($stylesAttributes[$styleId])) { + return false; + } + + $styleAttributes = $stylesAttributes[$styleId]; + + return $this->doesStyleIndicateDate($styleAttributes); } /** @@ -125,9 +157,15 @@ class StyleHelper { while ($xmlReader->read()) { if ($xmlReader->isPositionedOnStartingNode(self::XML_NODE_XF)) { + $numFmtId = $xmlReader->getAttribute(self::XML_ATTRIBUTE_NUM_FMT_ID); + $normalizedNumFmtId = ($numFmtId !== null) ? intval($numFmtId) : null; + + $applyNumberFormat = $xmlReader->getAttribute(self::XML_ATTRIBUTE_APPLY_NUMBER_FORMAT); + $normalizedApplyNumberFormat = ($applyNumberFormat !== null) ? !!$applyNumberFormat : null; + $this->stylesAttributes[] = [ - self::XML_ATTRIBUTE_NUM_FMT_ID => intval($xmlReader->getAttribute(self::XML_ATTRIBUTE_NUM_FMT_ID)), - self::XML_ATTRIBUTE_APPLY_NUMBER_FORMAT => !!($xmlReader->getAttribute(self::XML_ATTRIBUTE_APPLY_NUMBER_FORMAT)), + self::XML_ATTRIBUTE_NUM_FMT_ID => $normalizedNumFmtId, + self::XML_ATTRIBUTE_APPLY_NUMBER_FORMAT => $normalizedApplyNumberFormat, ]; } else if ($xmlReader->isPositionedOnEndingNode(self::XML_NODE_CELL_XFS)) { // Once done reading "cellXfs" node's children @@ -161,86 +199,92 @@ class StyleHelper } /** - * Returns whether the style with the given ID should consider - * numeric values as timestamps and format the cell as a date. - * - * @param int $styleId Zero-based style ID - * @return bool Whether the cell with the given cell should display a date instead of a numeric value + * @param array $styleAttributes Array containing the style attributes (2 keys: "applyNumberFormat" and "numFmtId") + * @return bool Whether the style with the given attributes indicates that the number is a date */ - public function shouldFormatNumericValueAsDate($styleId) + protected function doesStyleIndicateDate($styleAttributes) { - $stylesAttributes = $this->getStylesAttributes(); - - // Default style (0) does not format numeric values as timestamps. Only custom styles do. - // Also if the style ID does not exist in the styles.xml file, format as numeric value. - // Using isset here because it is way faster than array_key_exists... - if ($styleId === self::DEFAULT_STYLE_ID || !isset($stylesAttributes[$styleId])) { - return false; - } - - $styleAttributes = $stylesAttributes[$styleId]; - $applyNumberFormat = $styleAttributes[self::XML_ATTRIBUTE_APPLY_NUMBER_FORMAT]; - if (!$applyNumberFormat) { + $numFmtId = $styleAttributes[self::XML_ATTRIBUTE_NUM_FMT_ID]; + + // A style may apply a date format if it has: + // - "applyNumberFormat" attribute not set to "false" + // - "numFmtId" attribute set + // This is a preliminary check, as having "numFmtId" set just means the style should apply a specific number format, + // but this is not necessarily a date. + if ($applyNumberFormat === false || $numFmtId === null) { return false; } - $numFmtId = $styleAttributes[self::XML_ATTRIBUTE_NUM_FMT_ID]; return $this->doesNumFmtIdIndicateDate($numFmtId); } /** + * Returns whether the number format ID indicates that the number is a date. + * The result is cached to avoid recomputing the same thing over and over, as + * "numFmtId" attributes can be shared between multiple styles. + * * @param int $numFmtId - * @return bool Whether the number format ID indicates that the number is a timestamp + * @return bool Whether the number format ID indicates that the number is a date */ protected function doesNumFmtIdIndicateDate($numFmtId) { - return ( - !$this->doesNumFmtIdIndicateGeneralFormat($numFmtId) && - ( + if (!isset($this->numFmtIdToIsDateFormatCache[$numFmtId])) { + $formatCode = $this->getFormatCodeForNumFmtId($numFmtId); + + $this->numFmtIdToIsDateFormatCache[$numFmtId] = ( $this->isNumFmtIdBuiltInDateFormat($numFmtId) || - $this->isNumFmtIdCustomDateFormat($numFmtId) - ) - ); + $this->isFormatCodeCustomDateFormat($formatCode) + ); + } + + return $this->numFmtIdToIsDateFormatCache[$numFmtId]; } /** * @param int $numFmtId - * @return bool Whether the number format ID indicates the "General" format (0 by convention) + * @return string|null The custom number format or NULL if none defined for the given numFmtId */ - protected function doesNumFmtIdIndicateGeneralFormat($numFmtId) - { - return ($numFmtId === 0); - } - - /** - * @param int $numFmtId - * @return bool Whether the number format ID indicates that the number is a timestamp - */ - protected function isNumFmtIdBuiltInDateFormat($numFmtId) - { - $builtInDateFormatIds = array_keys(self::$builtinNumFmtIdToNumFormatMapping); - return in_array($numFmtId, $builtInDateFormatIds); - } - - /** - * @param int $numFmtId - * @return bool Whether the number format ID indicates that the number is a timestamp - */ - protected function isNumFmtIdCustomDateFormat($numFmtId) + protected function getFormatCodeForNumFmtId($numFmtId) { $customNumberFormats = $this->getCustomNumberFormats(); // Using isset here because it is way faster than array_key_exists... - if (!isset($customNumberFormats[$numFmtId])) { + return (isset($customNumberFormats[$numFmtId])) ? $customNumberFormats[$numFmtId] : null; + } + + /** + * @param int $numFmtId + * @return bool Whether the number format ID indicates that the number is a date + */ + protected function isNumFmtIdBuiltInDateFormat($numFmtId) + { + return in_array($numFmtId, $this->builtinNumFmtIdIndicatingDates); + } + + /** + * @param string|null $formatCode + * @return bool Whether the given format code indicates that the number is a date + */ + protected function isFormatCodeCustomDateFormat($formatCode) + { + // if no associated format code or if using the default "General" format + if ($formatCode === null || strcasecmp($formatCode, self::NUMBER_FORMAT_GENERAL) === 0) { return false; } - $customNumberFormat = $customNumberFormats[$numFmtId]; + return $this->isFormatCodeMatchingDateFormatPattern($formatCode); + } + /** + * @param string $formatCode + * @return bool Whether the given format code matches a date format pattern + */ + protected function isFormatCodeMatchingDateFormatPattern($formatCode) + { // Remove extra formatting (what's between [ ], the brackets should not be preceded by a "\") $pattern = '((?getStylesAttributes(); $styleAttributes = $stylesAttributes[$styleId]; $numFmtId = $styleAttributes[self::XML_ATTRIBUTE_NUM_FMT_ID]; if ($this->isNumFmtIdBuiltInDateFormat($numFmtId)) { - $numberFormat = self::$builtinNumFmtIdToNumFormatMapping[$numFmtId]; + $numberFormatCode = self::$builtinNumFmtIdToNumFormatMapping[$numFmtId]; } else { $customNumberFormats = $this->getCustomNumberFormats(); - $numberFormat = $customNumberFormats[$numFmtId]; + $numberFormatCode = $customNumberFormats[$numFmtId]; } - return $numberFormat; + return $numberFormatCode; } } diff --git a/tests/Spout/Reader/XLSX/Helper/StyleHelperTest.php b/tests/Spout/Reader/XLSX/Helper/StyleHelperTest.php index 57e8acb..c06d94f 100644 --- a/tests/Spout/Reader/XLSX/Helper/StyleHelperTest.php +++ b/tests/Spout/Reader/XLSX/Helper/StyleHelperTest.php @@ -11,16 +11,16 @@ class StyleHelperTest extends \PHPUnit_Framework_TestCase { /** - * @param array $styleAttributes + * @param array|void $styleAttributes * @param array|void $customNumberFormats * @return StyleHelper */ - private function getStyleHelperMock($styleAttributes, $customNumberFormats = []) + private function getStyleHelperMock($styleAttributes = [], $customNumberFormats = []) { /** @var StyleHelper $styleHelper */ $styleHelper = $this->getMockBuilder('\Box\Spout\Reader\XLSX\Helper\StyleHelper') + ->setConstructorArgs(['/path/to/file.xlsx']) ->setMethods(['getCustomNumberFormats', 'getStylesAttributes']) - ->disableOriginalConstructor() ->getMock(); $styleHelper->method('getStylesAttributes')->willReturn($styleAttributes); @@ -34,27 +34,17 @@ class StyleHelperTest extends \PHPUnit_Framework_TestCase */ public function testShouldFormatNumericValueAsDateWithDefaultStyle() { - $styleHelper = $this->getStyleHelperMock([]); + $styleHelper = $this->getStyleHelperMock(); $shouldFormatAsDate = $styleHelper->shouldFormatNumericValueAsDate(0); $this->assertFalse($shouldFormatAsDate); } - /** - * @return void - */ - public function testShouldFormatNumericValueAsDateWhenStyleIdNotListed() - { - $styleHelper = $this->getStyleHelperMock([['applyNumberFormat' => true]]); - $shouldFormatAsDate = $styleHelper->shouldFormatNumericValueAsDate(1); - $this->assertFalse($shouldFormatAsDate); - } - /** * @return void */ public function testShouldFormatNumericValueAsDateWhenShouldNotApplyNumberFormat() { - $styleHelper = $this->getStyleHelperMock([[], ['applyNumberFormat' => false]]); + $styleHelper = $this->getStyleHelperMock([[], ['applyNumberFormat' => false, 'numFmtId' => 14]]); $shouldFormatAsDate = $styleHelper->shouldFormatNumericValueAsDate(1); $this->assertFalse($shouldFormatAsDate); } @@ -69,6 +59,26 @@ class StyleHelperTest extends \PHPUnit_Framework_TestCase $this->assertFalse($shouldFormatAsDate); } + /** + * @return void + */ + public function testShouldFormatNumericValueAsDateWithNonDateBuiltinFormat() + { + $styleHelper = $this->getStyleHelperMock([[], ['applyNumberFormat' => true, 'numFmtId' => 9]]); + $shouldFormatAsDate = $styleHelper->shouldFormatNumericValueAsDate(1); + $this->assertFalse($shouldFormatAsDate); + } + + /** + * @return void + */ + public function testShouldFormatNumericValueAsDateWithNoNumFmtId() + { + $styleHelper = $this->getStyleHelperMock([[], ['applyNumberFormat' => true, 'numFmtId' => null]]); + $shouldFormatAsDate = $styleHelper->shouldFormatNumericValueAsDate(1); + $this->assertFalse($shouldFormatAsDate); + } + /** * @return void */ @@ -84,6 +94,28 @@ class StyleHelperTest extends \PHPUnit_Framework_TestCase } } + /** + * @return void + */ + public function testShouldFormatNumericValueAsDateWhenApplyNumberFormatNotSetAndUsingBuiltinDateFormat() + { + $styleHelper = $this->getStyleHelperMock([[], ['applyNumberFormat' => null, 'numFmtId' => 14]]); + $shouldFormatAsDate = $styleHelper->shouldFormatNumericValueAsDate(1); + + $this->assertTrue($shouldFormatAsDate); + } + + /** + * @return void + */ + public function testShouldFormatNumericValueAsDateWhenApplyNumberFormatNotSetAndUsingBuiltinNonDateFormat() + { + $styleHelper = $this->getStyleHelperMock([[], ['applyNumberFormat' => null, 'numFmtId' => 9]]); + $shouldFormatAsDate = $styleHelper->shouldFormatNumericValueAsDate(1); + + $this->assertFalse($shouldFormatAsDate); + } + /** * @return void */ @@ -106,6 +138,7 @@ class StyleHelperTest extends \PHPUnit_Framework_TestCase ['[$-409]d\-mmm\-yy;@', true], ['[$-409]d\-mmm\-yyyy;@', true], ['mm/dd/yy;@', true], + ['MM/DD/YY;@', true], ['[$-F800]dddd\,\ mmmm\ dd\,\ yyyy', true], ['m/d;@', true], ['m/d/yy;@', true], @@ -117,9 +150,11 @@ class StyleHelperTest extends \PHPUnit_Framework_TestCase ['[$-409]m/d/yy\ h:mm\ AM/PM;@', true], ['m/d/yy\ h:mm;@', true], ['[$-409]mmmmm;@', true], + ['[$-409]MMmmM;@', true], ['[$-409]mmmmm\-yy;@', true], ['m/d/yyyy;@', true], ['[$-409]m/d/yy\--h:mm;@', true], + ['General', false], ['GENERAL', false], ['\ma\yb\e', false], ['[Red]foo;', false], diff --git a/tests/Spout/Reader/XLSX/ReaderTest.php b/tests/Spout/Reader/XLSX/ReaderTest.php index 0deb84c..dffbc26 100644 --- a/tests/Spout/Reader/XLSX/ReaderTest.php +++ b/tests/Spout/Reader/XLSX/ReaderTest.php @@ -279,6 +279,21 @@ class ReaderTest extends \PHPUnit_Framework_TestCase $this->assertEquals($expectedRows, $allRows); } + /** + * @return void + */ + public function testReadShouldApplyCustomDateFormatNumberEvenIfApplyNumberFormatNotSpecified() + { + $shouldFormatDates = true; + $allRows = $this->getAllRowsForFile('sheet_with_custom_date_formats_and_no_apply_number_format.xlsx', $shouldFormatDates); + + $expectedRows = [ + // "General", "GENERAL", "MM/DD/YYYY", "MM/dd/YYYY", "H:MM:SS" + ['42382', '42382', '01/13/2016', '01/13/2016', '4:43:25'], + ]; + $this->assertEquals($expectedRows, $allRows); + } + /** * @return void */ diff --git a/tests/resources/xlsx/sheet_with_custom_date_formats_and_no_apply_number_format.xlsx b/tests/resources/xlsx/sheet_with_custom_date_formats_and_no_apply_number_format.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..8718e71650c0ec5df03ba0e71dab7dc2050f3fd6 GIT binary patch literal 21882 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 Tx8p{F22FONw?w+uSKa>rNuJAp literal 0 HcmV?d00001