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

Zeiten in der lokalen Zeitzone des Benutzers anzeigen

Problem

Wenn Anwendungen Uhrzeiten anzeigen, ohne den Standort des Benutzers zu berücksichtigen, entstehen Verwirrungen. Ein Meeting, das für "15:00 Uhr" angesetzt ist, 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-Zeitstempeln und formatieren Sie diese dann zur Anzeige in der lokalen Zeitzone des Benutzers auf dem Client. Erkennen Sie die Zeitzone des Benutzers mit der Internationalization API des Browsers und übergeben Sie diese an die Formatierungsfunktionen von react-intl. Dies stellt sicher, dass jeder Benutzer Zeiten sieht, die an seine eigene Zeitzone angepasst sind, wodurch Unklarheiten darüber beseitigt werden, wann Ereignisse stattfinden.

Schritte

1. Erkennen der Zeitzone des Benutzers auf dem Client

Der Browser-Befehl Intl.DateTimeFormat().resolvedOptions().timeZone gibt die IANA-Zeitzonenkennung des Benutzers zurück, wie 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 läuft nur auf dem Client, vermeidet Hydration-Diskrepanzen und verwendet standardmäßig UTC, bis die Zeitzone erkannt wird.

2. Formatieren von Datumsangaben mit der Zeitzone des Benutzers mittels FormattedDate

Ü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 Prop timeZone stellt sicher, dass das Datum in der lokalen Zeitzone des Benutzers und nicht in der des Servers oder in UTC formatiert wird.

3. Formatieren Sie Zeiten imperativ mit useIntl

Für Szenarien, in denen Sie einen formatierten String 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. Übergeben Sie Server-Zeitstempel als ISO-Strings

In getServerSideProps rufen Sie Daten zum Anfragezeitpunkt ab und übergeben sie als Props an die Seitenkomponente. Serialisieren Sie Datumsangaben als ISO 8601-Strings, 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-Strings bewahren den exakten Zeitpunkt, wodurch die clientseitige Formatierung sie präzise in jede Zeitzone konvertieren kann.