Skip to content

Sweep toISOString().split('T')[0] -> toLocalDateInputValue across frontend date inputs #1287

Description

@cristim

Problem

Several places use someDate.toISOString().split('T')[0] to produce a YYYY-MM-DD value for <input type="date"> (or for date filters). toISOString() returns the UTC calendar date, but <input type="date"> is rendered in the user's local calendar. The two diverge by a day for any user whose local clock has crossed midnight UTC (so e.g. a US west-coast user after ~4-5pm local sees defaults / mins resolve to "tomorrow" instead of "today").

PR #1258 fixed the two occurrences in frontend/src/plans.ts::openAddPurchasesModal via a new toLocalDateInputValue(Date) helper. The same pattern survives in:

  • frontend/src/history.ts:179startInput.value = start.toISOString().split('T')[0]
  • frontend/src/history.ts:182endInput.value = end.toISOString().split('T')[0]
  • frontend/src/history.ts:243-244minDate / maxDate of the analytics range
  • frontend/src/apikeys.ts:359 — default expiry date for new API keys

Impact

  • Analytics filter defaults shift by a day for evening-hours users west of UTC. Visible as "I clicked default ‘last 30 days’ at 11pm and got 31 days back."
  • API-key default expiry is off by a day on creation.

Severity is low — values are pre-fills, the user can fix them — but the inconsistency with the plans.ts fix invites future contributors to copy the wrong pattern.

Suggested fix

Promote toLocalDateInputValue from plans.ts to frontend/src/utils.ts (or a small dates.ts neighbour) and replace the four call sites above. Regression tests should mirror the QA 5.6 test in plans-range-validation.test.ts.

Acceptance criteria

  • Single shared helper exists in frontend/src/utils.ts (or similar).
  • All four call sites use it; plans.ts switches from the local helper to the shared one.
  • grep -rE "toISOString\\(\\)\\.split\\('T'\\)\\[0\\]" frontend/src returns nothing outside tests.
  • No behaviour change for users in UTC; values match local calendar for everyone else.

Related

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions