Skip to content

[repo:objectui] Pure date fields shift one day for viewers west of UTC — '2026-08-01' renders 7月31日 in PDT; the display formatter parses the date-only string via new Date('YYYY-MM-DD') (UTC midnight) then reads local getters #14887

Description

@baozhoutao

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); dateThu 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).

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions