-
Notifications
You must be signed in to change notification settings - Fork 7
Date management
Summary: Date management is notoriously difficult in JavaScript because of how new Date() handles timezones. This page explains how to handle dates and times reliably in your application using the provided datetime helper.
StartER recommends using a "UTC for storage, fixed timezone for UI" strategy.
-
Database/API: always store and exchange dates in UTC (ISO 8601 string ending with
Z). -
Internal logic: use native
Dateobjects in UTC. - UI: display and capture dates in a fixed timezone (the timezone where your project operates).
Important
Avoid using new Date("2026-05-05") directly. In JavaScript, a date-only string is interpreted as midnight UTC, which can result in "yesterday" for users located in timezones west of UTC.
The timezone is defined by the VITE_TIMEZONE environment variable. It is recommended to set it to the fixed timezone of the location where your project operates (e.g. "Europe/Paris").
Tip
For more details, see The Subtle Trap of ISO Date Strings in JavaScript.
StartER provides a robust, zero-dependency helper in src/react/helpers/datetime.ts. It leverages the native Intl API to handle shifts and daylight savings.
The default timezone is defined by the VITE_TIMEZONE environment variable (defaults to Europe/Paris).
When you receive a UTC date from your API and want to display it in a form:
import { toInputDate, toInputTime } from "../helpers/datetime";
const event = { start_time: "2026-05-05T10:00:00Z" };
// In Paris (UTC+2), these will produce:
const dateValue = toInputDate(event.start_time); // "2026-05-05"
const timeValue = toInputTime(event.start_time); // "12:00"
return (
<form>
<input type="date" defaultValue={dateValue} />
<input type="time" defaultValue={timeValue} />
</form>
);To convert separate date and time strings back into a UTC Date object:
import { fromInputParts } from "../helpers/datetime";
const handleSubmit = (formData) => {
const iso = fromInputParts(formData.date, formData.time).toISOString();
// Send as ISO string to API
await apiMutate("/api/events", "post", {
start_time: iso
});
};To display a localized date to the user:
import { toDisplayString, setDisplayOptions } from "../helpers/datetime";
// Default: 5 mai 2026 à 12:00
const label = toDisplayString(event.start_time);
// Custom options
const usLabel = toDisplayString(event.start_time, {
timeZone: "America/New_York",
locale: "en-US",
dateStyle: "full",
});
// To set options for all subsequent calls, you can use setDisplayOptions
setDisplayOptions({
timeZone: "America/New_York",
locale: "en-US",
dateStyle: "full",
});
// The options are preserved for the next call
const usLabel2 = toDisplayString(event.start_time);- Never trust the user's browser timezone for business logic: always rely on the project's fixed timezone or UTC.
-
Keep it native: the
datetimehelper is lightweight and avoids the overhead of large libraries like Moment.js or Luxon.
AI co-creation
Getting started
Explanations
How-To Guides
Reference
Digging deeper