Umgang mit Zeitzonen in TanStack Start v1
Zeiten in der lokalen Zeitzone der Benutzer anzeigen
Problem
Wenn Anwendungen Zeiten anzeigen, repräsentieren sie einen einzelnen Moment, der je nach Standort der betrachtenden Person unterschiedlich erscheint. Wenn ein Server "20:00 Uhr" in seiner eigenen Zeitzone oder UTC rendert, sehen Benutzer in anderen Zeitzonen eine falsche lokale Zeit, was zu Verwirrung darüber führt, wann Ereignisse tatsächlich stattfinden. Benutzer erwarten, dass Zeiten automatisch ihre lokale Zeitzone widerspiegeln, aber ohne ordnungsgemäße Handhabung sehen sie Zeiten in der Zeitzone, die der Server beim Rendering verwendet hat. Diese Diskrepanz führt dazu, dass Benutzer Termine verpassen, Zeitpläne missverstehen und das Vertrauen in die Zuverlässigkeit der Anwendung verlieren.
Lösung
Übergeben Sie eine timeZone-Option an Datumsformatierungsmethoden, um zu steuern, wie Daten interpretiert und angezeigt werden. Die formatDate-Funktion akzeptiert Intl.DateTimeFormatOptions, die Zeitzonenkonfiguration enthalten. Speichern Sie Zeitstempel in einem universellen Format wie ISO 8601-Strings oder Unix-Zeitstempel und formatieren Sie sie dann auf dem Client, wo die Zeitzone des Browsers automatisch verfügbar ist. Die Intl.DateTimeFormat-API verwendet die Standard-Zeitzone der Benutzer, 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 Sie eine zeitzonenbewusste Datumsformatierungskomponente
Verwenden Sie den useIntl-Hook, um auf das intl-Objekt und seine formatDate-Methode zuzugreifen. Diese Komponente akzeptiert einen ISO-Zeitstempel und formatiert ihn für die lokale Zeitzone der Benutzer.
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 der Benutzer an, wenn keine explizite timeZone angegeben ist, und konvertiert den UTC-Zeitstempel in die lokale Zeit.
2. Verwenden Sie die Komponente zur Anzeige von Ereigniszeiten
Importieren und verwenden Sie die LocalTime-Komponente überall dort, wo Sie Zeitstempel anzeigen müssen. Die Komponente übernimmt die Zeitzonenkonvertierung automatisch basierend auf den Browsereinstellungen jedes Benutzers.
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 Benutzer sieht die Ereigniszeiten in seine lokale Zeitzone konvertiert. Der ISO-Zeitstempel vom Server wird gemäß den Gebietsschema- und Zeitzonenpräferenzen des Benutzers geparst und formatiert.
3. Formatieren Sie Zeiten mit expliziter Zeitzonenangabe
Wenn Benutzer wissen müssen, welche Zeitzone eine Zeit repräsentiert, fügen Sie den Zeitzonennamen in die Formatierungsoptionen ein.
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 undefined ist, verwendet der Browser die lokale Zeitzone des Benutzers. Dies ist nützlich, um Zeiten in einer bestimmten Zeitzone anzuzeigen, unabhängig davon, wo sich der Benutzer befindet.
4. Erstellen Sie einen Helper für relative Zeitanzeige
Zeigen Sie für kürzliche Ereignisse relative Zeiten wie "vor 2 Stunden" an, während Sie die absolute Zeit in einem Tooltip beibehalten.
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 Zeitspannen anzuzeigen, während das title-Attribut die exakte lokale Zeit für Benutzer beibehält, die mit der Maus darüber fahren. Beide Formate respektieren automatisch die Zeitzone und das Gebietsschema des Benutzers.