Summary
A pure date field stored as 2026-08-01 is displayed as 7月31日 in a browser whose local timezone is west of UTC (observed: macOS in PDT, UTC-7). The date-only ISO string is parsed with new Date('2026-08-01') (UTC midnight) and then read back with local getters, so every date-only value shifts one calendar day for any user west of UTC — and the relative branch in the same formatter (#14885) is off by one for the same reason (2026-08-31 reads 4天前 on 2026-09-03).
The stored value is correct; only the display is wrong. Same formatter as #14885, different defect (value correctness vs. presentation choice).
Minimal reproduction
Platform 17.2.0 console. Machine timezone America/Los_Angeles (PDT, UTC-7); date → Thu Sep 3 03:35 PDT 2026.
Object kpi_plan with period_start: Field.date({ label: '周期开始' }), seeded period_start: '2026-08-01', period_end: '2026-08-31'.
GET /api/v1/data/kpi_plan → "period_start":"2026-08-01","period_end":"2026-08-31"
List cell 周期开始 → 7月31日 ← expected 8月1日
List cell 周期结束 → 4天前 ← expected 3天前 (or, per #14885, 8月31日)
Same page opened from a UTC+8 browser earlier the same day shows 8月1日 / 3天前 — the display depends on the viewer's timezone although the value has no time component.
Where
ui-components chunk, date display formatter:
function Ltt(e, t) {
...
let n = e instanceof Date ? e : new Date(e); // '2026-08-01' → 2026-08-01T00:00:00Z
let r = new Date(),
i = new Date(r.getFullYear(), r.getMonth(), r.getDate()),
a = new Date(n.getFullYear(), n.getMonth(), n.getDate()).getTime() - i.getTime(); // local getters → Jul 31 in UTC-7
let o = Math.round(a / 864e5);
if (o < -7 || o > 7) return k9(n, void 0, t); // k9 → toLocaleDateString(...) on the shifted Date
...
Per ECMAScript, a date-only ISO form is parsed as UTC while date-time forms without offset are parsed as local — so new Date('YYYY-MM-DD') is exactly the wrong constructor for a calendar date.
Expected
- A
date value (no time component) renders the same calendar date for every viewer, in every timezone. Parse YYYY-MM-DD into local components (new Date(y, m - 1, d)) or format the string directly; never through a UTC-midnight Date.
- Same care in the date input/editor and in export, if they share the helper (not checked).
datetime fields keep timezone conversion — that is the case where it is wanted.
Environment
@objectstack/console 17.2.0 · objectstack dev · Chrome on macOS, tz PDT. App: objectstack-ai/kpi, object kpi_plan. Related: #14885 (relative rendering of the same field).
Summary
A pure
datefield stored as2026-08-01is displayed as 7月31日 in a browser whose local timezone is west of UTC (observed: macOS inPDT, UTC-7). The date-only ISO string is parsed withnew Date('2026-08-01')(UTC midnight) and then read back with local getters, so every date-only value shifts one calendar day for any user west of UTC — and the relative branch in the same formatter (#14885) is off by one for the same reason (2026-08-31reads4天前on2026-09-03).The stored value is correct; only the display is wrong. Same formatter as #14885, different defect (value correctness vs. presentation choice).
Minimal reproduction
Platform 17.2.0 console. Machine timezone
America/Los_Angeles(PDT, UTC-7);date→Thu Sep 3 03:35 PDT 2026.Object
kpi_planwithperiod_start: Field.date({ label: '周期开始' }), seededperiod_start: '2026-08-01',period_end: '2026-08-31'.Same page opened from a UTC+8 browser earlier the same day shows
8月1日/3天前— the display depends on the viewer's timezone although the value has no time component.Where
ui-componentschunk, date display formatter:Per ECMAScript, a date-only ISO form is parsed as UTC while date-time forms without offset are parsed as local — so
new Date('YYYY-MM-DD')is exactly the wrong constructor for a calendar date.Expected
datevalue (no time component) renders the same calendar date for every viewer, in every timezone. ParseYYYY-MM-DDinto local components (new Date(y, m - 1, d)) or format the string directly; never through a UTC-midnightDate.datetimefields keep timezone conversion — that is the case where it is wanted.Environment
@objectstack/console17.2.0 ·objectstack dev· Chrome on macOS, tz PDT. App: objectstack-ai/kpi, objectkpi_plan. Related: #14885 (relative rendering of the same field).