Skip to content

[WC-3536][WC-3545]: Fix Data Grid 2 Excel date export writing the wrong day - #2382

Open
yordan-st wants to merge 4 commits into
mainfrom
fix/WC-3536_datagrid-excel-export-formats
Open

[WC-3536][WC-3545]: Fix Data Grid 2 Excel date export writing the wrong day#2382
yordan-st wants to merge 4 commits into
mainfrom
fix/WC-3536_datagrid-excel-export-formats

Conversation

@yordan-st

Copy link
Copy Markdown
Contributor

Pull request type

Bug fix (non-breaking change which fixes an issue)


Description

Exporting a Data Grid 2 date column to Excel wrote the wrong wall clock: a value the grid renders as 1/1/2007 exported as serial 3908231-Dec-2006, one full calendar day early. Before the 3.11.0/3.11.3 export work the same cell held 39082.958333 (31-Dec-2006 23:00), so users saw a stray time instead; the day shift was always present, the serial fraction merely masked which day it landed on.

Root cause is in the widget's own export path, not in the Mendix client or the date picker. SheetJS is internally inconsistent about which fields of a JS Date represent the sheet's wall clock: a raw Date through utils.aoa_to_sheet converts on the local fields, but a cell object ({ t: "d", v: Date }) defers conversion to write time, where the UTC fields are read. cell-readers.ts builds cell objects, and the Mendix client hands over a local-anchored Date, so the session's UTC offset leaked into every cell — then stripTime(), truncating on those same UTC fields, turned the stray hour into the previous day. Localize = OFF on the attribute is incidental; localized attributes were affected identically.

The fix re-anchors a date's local fields onto UTC before the cell is built, so a t: "d" cell carries exactly the wall clock the grid displays, independent of the session offset and of DST. This also fixes a second, unreported symptom found while diagnosing: time-bearing formats (dd-MMM-yyyy hh:mm) skipped stripTime() and exported the time shifted by the offset (13:35 for a 14:35 value). customContent date strings now get a zone-aware parse — strings naming a zone, and date-only ISO strings (UTC per the ECMAScript spec), are left as-is; only genuinely local-parsed strings are re-anchored.

Design and rationale: packages/pluggableWidgets/datagrid-web/openspec/changes/fix-excel-export-date-timezone/.

Scope note — WC-3536 reports three complaints, only this one needed code:

  • Long-number precision: already fixed in Data Widgets 3.11.3, re-confirmed here.
  • Boolean TRUE/FALSE vs the grid's Yes/No: not a defect (Excel renders a typed boolean cell as TRUE/FALSE by definition). Referred to the PM for a product decision; deliberately unimplemented in either direction.

No XML or property changes, so no mendix/docs PR is needed. Changelog entry added under [Unreleased] in datagrid-web. Export_To_Excel.js and the bundled SheetJS in @mendix/data-widgets are untouched.

Ticket: https://mendix.atlassian.net/browse/WC-3536

What should be covered while testing?

Unit suite is green 235/235 under eight timezones (Europe/Amsterdam, America/New_York, America/Anchorage, Pacific/Kiritimati +14, Pacific/Niue −11, Asia/Kathmandu +5:45, Australia/Lord_Howe +10:30 with 30-minute DST, UTC). Verified end to end against the reporter's own app on Mendix 10.24.16.

Setup: a Data Grid 2 over an entity with a Date and time attribute (test with Localize both on and off — both were affected), plus an Export to Excel button wired to the Export_To_Excel JS action. Use a session timezone with a non-zero UTC offset — the bug is invisible in UTC.

  1. Date-only format, midnight values. Set the column's export type to Date with format dd-MMM-yyyy. Add rows at midnight in both DST states (e.g. 1/1/2007, 3/30/2004, 9/3/2012). Export and confirm every exported date is the same calendar day the grid shows, with no time component and no fractional serial.
  2. Time-bearing format. Add a second column on the same attribute with format dd-MMM-yyyy hh:mm and a row at a non-midnight time (e.g. 14:35). Confirm the exported time matches the grid exactly and is not shifted by the session offset.
  3. Non-midnight value with a date-only format. Confirm the 14:35 row exports on the correct day with the time dropped. (This case was already correct before the fix — it should stay correct.)
  4. Default export type. Add a third column on the same attribute with export type Default. Confirm the exported date is on the day the grid shows.
  5. Custom content column. Add a column with custom content and export type Date, exporting a date string. Check a zoneless string (2007-01-01T00:00:00), a date-only ISO string (2007-01-01), and a string with an explicit zone (2007-01-01T00:00:00Z). All three should land on 01-Jan-2007. Worth repeating in a negative-offset timezone (e.g. America/New_York), which is where the date-only ISO case is most likely to regress.
  6. Negative and fractional offsets. Repeat step 1 with the session timezone set to a negative offset and to a half-hour offset (e.g. Asia/Kathmandu).
  7. Regression check on the 3.11.3 work. Confirm numeric columns still export with the grid's decimals and thousands grouping, and that values over 15 significant digits still export as exact text.

@yordan-st
yordan-st marked this pull request as ready for review August 13, 2026 14:37
@yordan-st
yordan-st requested a review from a team as a code owner August 13, 2026 14:37
@github-actions

This comment has been minimized.

@r0b1n r0b1n changed the title [WC-3536]: Fix Data Grid 2 Excel date export writing the wrong day [WC-3536][WC-3545]: Fix Data Grid 2 Excel date export writing the wrong day Aug 20, 2026
@r0b1n
r0b1n force-pushed the fix/WC-3536_datagrid-excel-export-formats branch from c806b14 to 9ea9240 Compare August 20, 2026 07:14
@github-actions

This comment has been minimized.

@yordan-st
yordan-st force-pushed the fix/WC-3536_datagrid-excel-export-formats branch from 9ea9240 to 3c22ba7 Compare August 20, 2026 11:54
@github-actions

This comment has been minimized.

@yordan-st
yordan-st force-pushed the fix/WC-3536_datagrid-excel-export-formats branch from 3c22ba7 to e8f0e78 Compare August 21, 2026 13:39
@github-actions

Copy link
Copy Markdown
Contributor

AI Code Review

✅ Approved — no issues found


What was reviewed

File Change
packages/pluggableWidgets/datagrid-web/CHANGELOG.md New [Unreleased] entry for date export fix
packages/pluggableWidgets/datagrid-web/src/features/data-export/cell-readers.ts Added toExcelWallClock(), parseExportDate(), EXPLICIT_ZONE/DATE_ONLY_ISO regexes; both attribute and customContent date branches routed through them
packages/pluggableWidgets/datagrid-web/src/features/data-export/__tests__/cell-readers.spec.ts New timezone handling describe block; five pre-existing tests made timezone-agnostic
packages/pluggableWidgets/datagrid-web/openspec/changes/fix-excel-export-date-timezone/* Design, proposal, spec, and tasks documentation

Skipped (out of scope): dist/, pnpm-lock.yaml


Positives

  • Root-cause diagnosis is precise and fully traceable. The SheetJS local-vs-UTC field inconsistency for t: "d" cell objects vs raw Date through aoa_to_sheet is documented with the exact serials from the throwaway harness, making the invariant exploitable by a future maintainer without re-deriving it.
  • Minimal blast radius. The entire fix is two pure functions (toExcelWallClock, parseExportDate) plus one wiring change per branch in cell-readers.ts. No XML, no shared packages, no Export_To_Excel.js touched.
  • Timezone-agnostic tests by construction. Using new Date(year, month, day) (local-anchored input) vs new Date(Date.UTC(year, month, day)) (UTC expectation) means the test holds under every offset and DST rule without pinning process.env.TZ — and fails loudly if the SheetJS contract ever flips.
  • Both symptoms of the same root cause fixed together. The PR correctly identifies that the time-bearing format branch (hasTimeComponent) was also affected and routes it through toExcelWallClock — not just the reported date-only case.
  • parseExportDate guards the date-only ISO edge case correctly. The DATE_ONLY_ISO regex prevents re-anchoring "2007-01-01" in negative-offset sessions, where a blanket re-anchor would regress the export to the previous day.
  • CHANGELOG entry is user-facing only — describes observable behavior change without leaking implementation details, per repo convention.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant