Skip to content

Date management

rocambille edited this page May 10, 2026 · 1 revision

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.

The mental model

StartER recommends using a "UTC for storage, fixed timezone for UI" strategy.

  1. Database/API: always store and exchange dates in UTC (ISO 8601 string ending with Z).
  2. Internal logic: use native Date objects in UTC.
  3. 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").

The datetime helper

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

From API to form inputs

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

From form data to API

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
  });
};

For display

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

Best practices

  • Never trust the user's browser timezone for business logic: always rely on the project's fixed timezone or UTC.
  • Keep it native: the datetime helper is lightweight and avoids the overhead of large libraries like Moment.js or Luxon.

Clone this wiki locally