Wie man Zeitzonen in TanStack Start v1 handhabt
Zeiten in der lokalen Zeitzone des Benutzers anzeigen
Problem
Wenn Anwendungen Uhrzeiten anzeigen, repräsentieren sie einen einzelnen Moment, der je nach Standort des Betrachters unterschiedlich erscheint. Wenn ein Server "20:00 Uhr" in seiner eigenen Zeitzone oder UTC rendert, sehen Benutzer in verschiedenen Zeitzonen eine falsche lokale Zeit, was zu Verwirrung darüber führt, wann Ereignisse tatsächlich stattfinden. Benutzer erwarten, dass Uhrzeiten automatisch ihre lokale Zeitzone widerspiegeln, aber ohne ordnungsgemäße Behandlung sehen sie Zeiten in der Zeitzone, die der Server während des Renderings verwendet hat. Diese Diskrepanz führt dazu, dass Benutzer Termine verpassen, Zeitpläne falsch verstehen und das Vertrauen in die Zuverlässigkeit der Anwendung verlieren.
Lösung
Übergeben Sie eine timeZone-Option an Datumsformatierungsmethoden, um zu steuern, wie Datumsangaben interpretiert und angezeigt werden. Die formatDate-Funktion akzeptiert Intl.DateTimeFormatOptions, die Zeitzonenkonfigurationen enthalten. Speichern Sie Zeitstempel in einem universellen Format wie ISO 8601-Strings oder Unix-Zeitstempeln und formatieren Sie sie dann auf dem Client, wo die Zeitzone des Browsers automatisch verfügbar ist. Die Intl.DateTimeFormat-API verwendet die Standardzeitzone des Benutzers, wenn keine timeZone-Option angegeben ist, wodurch sichergestellt wird, dass Zeiten für den Standort jedes Benutzers korrekt angezeigt werden, ohne manuelle Zeitzonenerkennung.
Schritte
1. Erstellen einer zeitzonenbewussten Datumsformatierungskomponente
Verwenden Sie den useIntl-Hook, um auf das intl-Objekt und dessen formatDate-Methode zuzugreifen. Diese Komponente akzeptiert einen ISO-Zeitstempel und formatiert ihn für die lokale Zeitzone des Benutzers.
import { useIntl } from "react-intl";
interface LocalTimeProps {
timestamp: string;
showDate?: boolean;
showTime?: boolean;
}
export function LocalTime({
timestamp,
showDate = true,
showTime = true,
}: LocalTimeProps) {
const intl = useIntl();
const date = new Date(timestamp);
const formatted = intl.formatDate(date, {
...(showDate && {
year: "numeric",
month: "short",
day: "numeric",
}),
...(showTime && {
hour: "numeric",
minute: "2-digit",
timeZoneName: "short",
}),
});
return <time dateTime={timestamp}>{formatted}</time>;
}
Die FormattedDate-Komponente und die formatDate-Methode verwenden Intl.DateTimeFormat-APIs mit DateTimeFormatOptions. Der Browser wendet automatisch die Zeitzone des Benutzers an, wenn keine explizite timeZone angegeben wird, und konvertiert den UTC-Zeitstempel in die lokale Zeit.
2. Verwende die Komponente zur Anzeige von Ereigniszeiten
Importiere und verwende die LocalTime-Komponente überall dort, wo du Zeitstempel anzeigen musst. Die Komponente übernimmt die Zeitzonenkonvertierung automatisch basierend auf den Browsereinstellungen jedes Nutzers.
import { createFileRoute } from "@tanstack/react-router";
import { LocalTime } from "~/components/LocalTime";
export const Route = createFileRoute("/events/$eventId")({
component: EventDetail,
});
function EventDetail() {
const event = Route.useLoaderData();
return (
<div>
<h1>{event.title}</h1>
<p>
Starts: <LocalTime timestamp={event.startTime} />
</p>
<p>
Ends: <LocalTime timestamp={event.endTime} />
</p>
</div>
);
}
Jeder Nutzer sieht die Ereigniszeiten in seine lokale Zeitzone konvertiert. Der ISO-Zeitstempel vom Server wird entsprechend der Locale- und Zeitzoneneinstellungen des Nutzers geparst und formatiert.
3. Formatiere Zeiten mit expliziter Zeitzonenangabe
Wenn Nutzer wissen müssen, welche Zeitzone eine Zeit repräsentiert, füge den Namen der Zeitzone in den Formatierungsoptionen hinzu.
import { useIntl } from "react-intl";
interface ExplicitTimezoneProps {
timestamp: string;
timezone?: string;
}
export function ExplicitTimezone({
timestamp,
timezone,
}: ExplicitTimezoneProps) {
const intl = useIntl();
const date = new Date(timestamp);
const formatted = intl.formatDate(date, {
year: "numeric",
month: "short",
day: "numeric",
hour: "numeric",
minute: "2-digit",
timeZone: timezone,
timeZoneName: "long",
});
return <time dateTime={timestamp}>{formatted}</time>;
}
Die Angabe einer timeZone-Option zwingt den Formatierer, die Zeit in dieser spezifischen Zeitzone anzuzeigen. Wenn timezone undefiniert ist, verwendet der Browser die lokale Zeitzone des Nutzers. Dies ist nützlich, um Zeiten in einer bestimmten Zeitzone anzuzeigen, unabhängig davon, wo sich der Nutzer befindet.
4. Erstelle einen Helper für die Anzeige relativer Zeiten
Für kürzlich eingetretene Ereignisse zeige relative Zeiten wie "vor 2 Stunden" an, während die absolute Zeit in einem Tooltip erhalten bleibt.
import { useIntl } from "react-intl";
interface RelativeTimeProps {
timestamp: string;
}
export function RelativeTime({ timestamp }: RelativeTimeProps) {
const intl = useIntl();
const date = new Date(timestamp);
const now = Date.now();
const diffInSeconds = Math.floor((now - date.getTime()) / 1000);
const absoluteTime = intl.formatDate(date, {
year: "numeric",
month: "short",
day: "numeric",
hour: "numeric",
minute: "2-digit",
});
let value: number;
let unit: Intl.RelativeTimeFormatUnit;
if (diffInSeconds < 60) {
value = -diffInSeconds;
unit = "second";
} else if (diffInSeconds < 3600) {
value = -Math.floor(diffInSeconds / 60);
unit = "minute";
} else if (diffInSeconds < 86400) {
value = -Math.floor(diffInSeconds / 3600);
unit = "hour";
} else {
value = -Math.floor(diffInSeconds / 86400);
unit = "day";
}
const relativeTime = intl.formatRelativeTime(value, unit);
return (
<time dateTime={timestamp} title={absoluteTime}>
{relativeTime}
</time>
);
}
Die relative Zeit aktualisiert die Anzeige, um benutzerfreundliche Zeiträume anzuzeigen, während das title-Attribut die genaue lokale Zeit für Nutzer bewahrt, die mit der Maus darüber fahren. Beide Formate respektieren automatisch die Zeitzone und Locale des Nutzers.