Umgang mit Zeitzonen in React Router v7
Zeiten in der lokalen Zeitzone der Benutzer anzeigen
Problem
Wenn Anwendungen Zeiten anzeigen, ohne den Standort der Benutzer zu berücksichtigen, führt dies zu Verwirrung und Fehlern. Ein Server könnte eine Ereigniszeit als "2024-03-15T20:00:00Z" speichern und "20:00 Uhr" direkt aus diesem UTC-Wert rendern. Benutzer in verschiedenen Zeitzonen sehen dieselbe Uhrzeit, interpretieren sie jedoch als lokal, was zu verpassten Terminen und Planungskonflikten führt. Das grundlegende Problem besteht darin, dass ein einzelner Zeitpunkt je nach geografischem Standort unterschiedliche Darstellungen hat, und die Anzeige von Zeiten in der falschen Zone macht sie bedeutungslos oder irreführend.
Dieses Problem verstärkt sich, wenn Benutzer über Regionen hinweg zusammenarbeiten. Ein für 15:00 Uhr auf dem Server geplantes Ereignis wird überall in der Benutzeroberfläche als 15:00 Uhr angezeigt, obwohl es für denselben tatsächlichen Zeitpunkt in Tokio als 6:00 Uhr, in London als 14:00 Uhr und in New York als 9:00 Uhr erscheinen sollte.
Lösung
Speichern Sie alle Zeitstempel in einem universellen Format wie ISO 8601-Strings mit UTC-Indikatoren oder Unix-Zeitstempeln. Wenn Sie diese Zeiten Benutzern anzeigen, konvertieren Sie sie in JavaScript-Date-Objekte und formatieren Sie sie mithilfe von Internationalisierungs-APIs, die die Zeitzone des Browsers berücksichtigen. Moderne Browser erkennen automatisch die lokale Zeitzone der Benutzer, und Formatierungsbibliotheken nutzen dies, um UTC-Zeitstempel ohne manuelle Offset-Berechnungen in die korrekte lokale Darstellung zu konvertieren.
Dieser Ansatz trennt Speicherung von Darstellung. Der Server sendet einen kanonischen Zeitstempel, und jeder Client rendert ihn entsprechend seiner eigenen Zeitzone, wodurch sichergestellt wird, dass alle die korrekte lokale Zeit für denselben globalen Zeitpunkt sehen.
Schritte
1. Zeitstempel im ISO 8601-Format von Ihrer Datenquelle senden
Stellen Sie sicher, dass Ihre API oder Ihr Data Loader Zeitstempel als ISO 8601-Strings mit UTC-Indikatoren oder als Unix-Zeitstempel in Millisekunden zurückgibt.
export async function loader() {
const event = await fetchEvent();
return {
title: event.title,
startTime: "2024-03-15T20:00:00Z",
endTime: "2024-03-15T22:00:00Z",
};
}
Das Suffix Z kennzeichnet UTC-Zeit. Wenn dieser String in ein JavaScript-Date-Objekt geparst wird, speichert der Browser ihn intern als UTC-Zeitstempel.
2. Eine Komponente erstellen, die Zeiten mit react-intl formatiert
Importieren Sie Formatierungskomponenten aus react-intl und übergeben Sie Date-Objekte, die aus Ihren ISO-Strings erstellt wurden.
import { FormattedDate, FormattedTime } from "react-intl";
import type { Route } from "./+types/event";
export default function EventDetails({ loaderData }: Route.ComponentProps) {
const startTime = new Date(loaderData.startTime);
const endTime = new Date(loaderData.endTime);
return (
<div>
<h1>{loaderData.title}</h1>
<p>
<FormattedDate
value={startTime}
year="numeric"
month="long"
day="numeric"
/>
{" at "}
<FormattedTime value={startTime} />
{" to "}
<FormattedTime value={endTime} />
</p>
</div>
);
}
Die Komponenten FormattedDate und FormattedTime verwenden automatisch die vom Browser erkannte Zeitzone, um die korrekte Ortszeit anzuzeigen. Ein Benutzer in New York sieht "15. März 2024 um 15:00 Uhr", während ein Benutzer in Tokio "16. März 2024 um 05:00 Uhr" für denselben UTC-Zeitstempel sieht.
3. Die imperative API für dynamische Formatierungsanforderungen verwenden
Wenn Sie formatierte Zeiten in Attributen, berechneten Werten oder Nicht-JSX-Kontexten benötigen, verwenden Sie den Hook useIntl.
import { useIntl } from "react-intl";
import type { Route } from "./+types/event";
export default function EventCard({ loaderData }: Route.ComponentProps) {
const intl = useIntl();
const startTime = new Date(loaderData.startTime);
const formattedDate = intl.formatDate(startTime, {
year: "numeric",
month: "short",
day: "numeric",
});
const formattedTime = intl.formatTime(startTime, {
hour: "numeric",
minute: "2-digit",
});
return (
<div>
<h2>{loaderData.title}</h2>
<time dateTime={loaderData.startTime}>
{formattedDate} at {formattedTime}
</time>
</div>
);
}
Die Methoden formatDate und formatTime geben Strings zurück, die gemäß der Locale und Zeitzone des Benutzers formatiert sind. Das Attribut dateTime bewahrt den ursprünglichen ISO-String für die maschinelle Lesbarkeit, während der angezeigte Text die benutzerfreundliche Ortszeit zeigt.