Dates and time zones¶
This page explains how Easy8 frontend code works with dates, datetimes, user time zone settings and the browser-local time zone. The helpers are in the core frontend (app/frontend/src/shared/utils/date.ts).
Why this is tricky¶
Frontend date handling has to reconcile three contexts:
- Storage and API payloads.
- User timezone configured in Easy8.
- Browser-local timezone used by the JavaScript
Dateobject.
Those contexts do not always match, and older endpoints do not return datetime values in one uniform format. Use the shared helper layer instead of parsing API strings yourself.
Some backend responses mix values with a time zone, without a time zone, and date-only strings. Do not rely on raw new Date(...) parsing when the meaning of the value matters.
Behaviour¶
Date-only values¶
Canonical backend date-only format is YYYY-MM-DD.
Date-only values should stay date-only. They are not equivalent to "midnight in some timezone". In new code, use parseDateOnly when you need a Date instance from a date-only value.
parseDateOnly intentionally normalises parsed values to local noon so that timezone conversion does not unexpectedly shift the calendar day.
Datetime values¶
Datetime values are more complicated:
- some values arrive with an explicit timezone,
- some arrive as UTC-like strings without a time zone suffix,
- some older code paths still depend on legacy parsing rules.
The legacy normalisation layer is EASY.utils.parseDate in app/frontend/src/easy_legacy_js/easy_extensions/utils/extensions_utils.js.
That helper:
- validates the incoming ISO-like string,
- uses the current user time zone from
EASY.currentUser.time_zone_identifier, - normalises the value through
moment-timezone, - returns a JavaScript
Datewith the correct user-facing moment in time.
In new code, use the wrappers from app/frontend/src/shared/utils/date.ts instead of calling EASY.utils.parseDate directly.
Display formatting¶
Displayed formats come from global Easy settings:
window.EasySettings.getGlobalDateFormat.valuewindow.EasySettings.getGlobalDateTimeFormat.value
The frontend initialises dayjs and moment locale/week-start behaviour in app/frontend/src/shared/utils/initDateLibs.ts.
Sending values back to the backend¶
When preparing values for requests, use the shared formatting helpers instead of hand-built strings.
Canonical backend formats are defined in app/frontend/src/shared/constants/date.ts:
BE_DATE_FORMAT = "YYYY-MM-DD"BE_DATE_TIME_FORMAT = "YYYY-MM-DD HH:mm"BE_TIME_FORMAT = "HH:mm"
Preferred helpers¶
The shared frontend entrypoint for date work is app/frontend/src/shared/utils/date.ts.
| Helper | Use when |
|---|---|
formatDate(date, withTime) |
You need a user-facing string formatted according to Easy settings. |
formatDateForRequest(date, type) |
You need to send date, datetime, or time back to the backend. |
getDateOrDateTimeFormat(withTime) |
You need the current global frontend display format. |
crossBrowserISOString(date, withTime) |
You need a safer normalised ISO-like value before parsing. |
parseDate(date) |
You need to parse a general date or datetime value through the shared helper layer. |
parseDatetime(date) |
You explicitly work with datetime input and want shared parsing behaviour. |
parseDateOnly(date) |
You work with date-only values and want to preserve the calendar day safely. |
dateISOStringParseZone(date) |
You need an ISO string while preserving zone semantics with dayjs.utc(true). |
moveDate(date, time) |
You need to join a date and a time into one backend-formatted datetime value. |
Recommended usage¶
Example:
import { formatDate, formatDateForRequest, parseDateOnly, parseDatetime } from "@/src/shared/utils/date";
const dueDate = parseDateOnly(issue.due_date);
const startedAt = parseDatetime(activity.started_at);
const dueDateLabel = formatDate(dueDate);
const startedAtLabel = formatDate(startedAt, true);
const payload = {
due_date: formatDateForRequest(dueDate, "date"),
started_at: formatDateForRequest(startedAt, "datetime"),
};
Practical rules¶
- Keep date-only and datetime code paths separate.
- Prefer shared helpers over direct
Dateparsing. - Prefer explicit request formatting over manual string concatenation.
- Use the global Easy date format helpers for user-facing output.
- If you are fixing a timezone bug, inspect whether the value is date-only, datetime-with-zone, or datetime-without-zone before changing code.