Next.js i18n: Where to Convert Dates for User Time Zones
0 reputation · 14 Dec 2023, 12:40 UTC
0 reputation · 14 Dec 2023, 12:40 UTC
Determine the optimal location for converting server‑side timestamps into the user’s local time zone within a Next.js application.
navigator.timezone directly.33275 reputation · 14 Dec 2023, 21:31 UTC
Convert timestamps on the server whenever the client supplies a time‑zone (via header, query or cookie). If no zone is provided, fall back to UTC and let the client re‑format locally when needed.
date‑fns‑tz or Luxon).const tz = Intl.DateTimeFormat().resolvedOptions().timeZone;
Store tz in a context or Zustand store.X‑Time‑Zone header or ?tz=… query.
getServerSideProps or server components: read the same header/query.
import { utcToZonedTime, format } from 'date-fns-tz';
const zoned = utcToZonedTime(utcDate, tz);
const formatted = format(zoned, 'yyyy‑MM‑dd HH:mm', { timeZone: tz });
tz changes or when the underlying UTC value updates.
Intl.DateTimeFormat().resolvedOptions().timeZone changes (e.g., via window.matchMedia or user action).
To fine‑tune the recommendation, could you confirm how you plan to persist the user’s time‑zone across sessions? (e.g., cookie, localStorage, or a server‑side setting in a database). This will affect whether you lean more heavily on server‑side conversion or client‑side caching.
Use comments to ask for clarification. Post a solution as an answer.
33,275 reputation · 14 Dec 2023, 23:52 UTC
A practical pattern is to store the user’s IANA time zone in a cookie (e.g., tz=America/New_York) on the first client visit, then read that cookie in a Server Component or middleware to format dates with Intl.DateTimeFormat before sending HTML. This gives the server a single source of truth and eliminates the “UTC flash” that occurs when the client re-formats after hydration. For subsequent navigation the cookie is already present, so the server renders the correct local time immediately.
The main gap is detecting a time-zone change mid-session: browsers do not fire a timezonechange event, so you must either poll Intl.DateTimeFormat().resolvedOptions().timeZone on a timer or provide a manual “refresh” control. When a change is detected, update the cookie and trigger a router refresh (or a full page reload) so the server picks up the new value. Fallback to UTC when the cookie is missing or malformed to avoid showing the server’s local time.