Fix #2966: convert formula result to Date when numFmt is date-like#55
Fix #2966: convert formula result to Date when numFmt is date-like#55senoff wants to merge 1 commit into
Conversation
…like When a cell's formula result is cached as t="str" with a numeric Excel date serial in <v> (some non-Excel writers do this), the reader left the result as a string instead of converting it to a JS Date the way it does for plain numeric formula results. After PR exceljs#2956's guard, this no longer produced an Invalid Date, but the value was still wrong for downstream consumers that expect a Date. The standard (non-streaming) reconcile path and the streaming reader both now coerce string-typed formula results that look like a finite number before passing through excelToDate. Genuine non-numeric display strings (e.g., "27/08/2025 19:33:34") fall through unchanged so we never fabricate an Invalid Date. Adds spec/integration/issues/issue-2966-formula-result-date-numfmt covering: numeric serial with no t, numeric serial with t="str", a non-numeric display string, and the streaming reader. Two unrelated multi-line function calls in the touched files were collapsed to single-line form to satisfy the prettier+eslint hook (prettier wants a trailing comma, eslint forbids it on functions). Behavior is unchanged. Refs: exceljs#2966 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
Local test run on this branch —
No regressions vs baseline. Skipped Posted because the |
|
Superseded by #76 ( The regenerated PR strips the scope violations from this one (the
|
Bug
Tracked at exceljs#2966.
When a cell holds a formula whose cached result is a numeric Excel date
serial and the cell's
numFmtis a date format (e.g.m/d/yyyy), thereader is supposed to materialize
cell.value.resultas a JSDate.It does in the common case (
<v>46143</v>with notattribute), butnot when an off-spec writer marks the formula cell with
t=\"str\"and still puts a numeric serial inside
<v>. After PR exceljs#2956's guardin
excelToDate, the reader stopped throwingInvalid Datefor thatshape, but the value was left as the raw string "46143.20833333333"
The streaming
WorkbookReaderhad the same gap and never applieddate conversion to formula results at all.
Fix
lib/xlsx/xform/sheet/cell-xform.js(reconcile, Formula branch) andlib/stream/xlsx/worksheet-reader.js(formula cell handling) both now:numFmtis date-like (utils.isDateFmt).resultis a string but parses as a finite number that round-tripsexactly, coerce to that number first.
utils.excelToDate, which already handles plain numbersand (post-Fix the return value from dateToExcel() when it's passed a non-numeric value. exceljs/exceljs#2956) returns non-numeric input unchanged.
Genuine display strings like
\"27/08/2025 19:33:34\"cannot bereliably parsed as an Excel serial, so they fall through unchanged - we
never fabricate an Invalid Date.
Tests
spec/integration/issues/issue-2966-formula-result-date-numfmt.spec.jscovers four shapes:
<v>, notattribute (regression baseline)<v>witht=\"str\"(the actual bug)t=\"str\"(must not become Invalid Date)t=\"str\"becomes aDateFixtures are built programmatically: a workbook is written with the
real
m/d/yyyystyle, then the<c>element is rewritten in-place viaJSZip so the malformed shapes can be exercised without checking binary
fixtures into the repo.
npm run test:unit,npm run test:integration, andnpm run test:end-to-endall pass.Notes
Two unrelated multi-line function calls in the touched files were
collapsed to single-line form to satisfy the prettier+eslint hook
(prettier wants
trailingComma: \"all\", eslint enforcescomma-dangle.functions: \"never\"). Behavior is unchanged.