Umgang mit Zeitzonen in Next.js (Pages Router) v16

Zeiten in der lokalen Zeitzone des Benutzers anzeigen

Problem

Wenn Anwendungen Zeiten anzeigen, ohne den Standort des Benutzers zu berücksichtigen, entsteht Verwirrung. Ein für „15:00 Uhr" geplantes Meeting bedeutet unterschiedliche Zeitpunkte, je nachdem, ob sich der Betrachter in New York, London oder Tokio befindet. Wenn der Server eine Zeit in UTC oder seiner eigenen Zeitzone rendert, sehen Benutzer in anderen Regionen falsche lokale Zeiten, was zu verpassten Terminen und Planungsfehlern führt. Derselbe Zeitstempel muss für jeden Benutzer basierend auf seiner Zeitzone unterschiedlich interpretiert werden.

Lösung

Speichern Sie Zeitstempel in einem universellen Format wie ISO 8601 oder Unix-Zeitstempel und formatieren Sie sie dann für die Anzeige in der lokalen Zeitzone des Benutzers auf dem Client. Erkennen Sie die Zeitzone des Benutzers mithilfe der Internationalization API des Browsers und übergeben Sie sie an die Formatierungsfunktionen von react-intl. Dadurch wird sichergestellt, dass jeder Benutzer Zeiten sieht, die an seine eigene Zeitzone angepasst sind, wodurch Unklarheiten darüber beseitigt werden, wann Ereignisse stattfinden.

Schritte

1. Zeitzone des Benutzers auf dem Client erkennen

Die Methode Intl.DateTimeFormat().resolvedOptions().timeZone des Browsers gibt die IANA-Zeitzonenkennung des Benutzers zurück, z. B. America/New_York oder Europe/London. Erstellen Sie einen benutzerdefinierten Hook, um auf diesen Wert zuzugreifen.

import { useState, useEffect } from "react";

export function useUserTimeZone() {
  const [timeZone, setTimeZone] = useState<string>("UTC");

  useEffect(() => {
    const detected = Intl.DateTimeFormat().resolvedOptions().timeZone;
    setTimeZone(detected);
  }, []);

  return timeZone;
}

Dieser Hook wird nur auf dem Client ausgeführt, wodurch Hydratationsfehler vermieden werden, und verwendet standardmäßig UTC, bis die Zeitzone erkannt wird.

2. Datumsangaben mit der Zeitzone des Benutzers mithilfe von FormattedDate formatieren

Übergeben Sie die Option timeZone an die Formatierungsmethoden von react-intl, um zu steuern, welche Zeitzone für die Anzeige verwendet wird. Verwenden Sie die Komponente <FormattedDate> mit der erkannten Zeitzone.

import { FormattedDate } from "react-intl";
import { useUserTimeZone } from "../hooks/useUserTimeZone";

interface EventDateProps {
  timestamp: string;
}

export function EventDate({ timestamp }: EventDateProps) {
  const userTimeZone = useUserTimeZone();

  return (
    <FormattedDate
      value={new Date(timestamp)}
      timeZone={userTimeZone}
      year="numeric"
      month="long"
      day="numeric"
      hour="numeric"
      minute="2-digit"
      timeZoneName="short"
    />
  );
}

Die timeZone-Eigenschaft stellt sicher, dass das Datum in der lokalen Zeitzone des Benutzers formatiert wird und nicht in der des Servers oder in UTC.

3. Zeiten imperativ mit useIntl formatieren

Für Szenarien, in denen Sie eine formatierte Zeichenkette anstelle einer Komponente benötigen, verwenden Sie den useIntl-Hook, um auf die imperative Formatierungs-API zuzugreifen.

import { useIntl } from "react-intl";
import { useUserTimeZone } from "../hooks/useUserTimeZone";

interface MeetingTimeProps {
  startTime: string;
}

export function MeetingTime({ startTime }: MeetingTimeProps) {
  const intl = useIntl();
  const userTimeZone = useUserTimeZone();

  const formattedTime = intl.formatDate(new Date(startTime), {
    timeZone: userTimeZone,
    hour: "numeric",
    minute: "2-digit",
    timeZoneName: "short",
  });

  return <span title={startTime}>{formattedTime}</span>;
}

Die formatDate-Methode akzeptiert ein zweites Argument mit DateTimeFormatOptions, einschließlich timeZone, was volle Kontrolle darüber ermöglicht, wie der Zeitstempel angezeigt wird.

4. Server-Zeitstempel als ISO-Zeichenketten übergeben

In getServerSideProps rufen Sie Daten zur Anforderungszeit ab und übergeben sie als Props an die Seitenkomponente. Serialisieren Sie Datumsangaben als ISO-8601-Zeichenketten, um Zeitzoneninformationen zu erhalten.

import { GetServerSideProps } from "next";

interface Event {
  id: string;
  title: string;
  startTime: string;
}

interface EventPageProps {
  event: Event;
}

export const getServerSideProps: GetServerSideProps<
  EventPageProps
> = async () => {
  const event = {
    id: "1",
    title: "Team Meeting",
    startTime: new Date("2025-02-15T15:00:00Z").toISOString(),
  };

  return {
    props: { event },
  };
};

export default function EventPage({ event }: EventPageProps) {
  return (
    <div>
      <h1>{event.title}</h1>
      <EventDate timestamp={event.startTime} />
    </div>
  );
}

ISO-Zeichenketten bewahren den exakten Zeitpunkt und ermöglichen es der clientseitigen Formatierung, sie präzise in jede Zeitzone umzuwandeln.