Relative Zeitangaben in Next.js (Pages Router) v16 formatieren

Zeitstempel als Phrasen wie „vor 2 Tagen“ formatieren

Problem

Zeitstempel als relative Zeitangaben wie „vor 2 Tagen“ oder „in 3 Stunden“ darzustellen, sorgt für ein unmittelbares und kontextbezogenes Nutzererlebnis. Allerdings folgen diese Phrasen komplexen grammatikalischen Mustern, die sich je nach Sprache stark unterscheiden. Im Englischen steht „ago“ nach der Zeitangabe für die Vergangenheit und „in“ vor der Zeitangabe für die Zukunft. Andere Sprachen verwenden jedoch andere Wortstellungen, beugen Zeiteinheiten je nach Anzahl oder nutzen ganz andere grammatische Strukturen. Wer diese Phrasen manuell durch String-Konkatenation zusammensetzt, erhält in allen Sprachen außer der Ausgangssprache fehlerhafte Ausgaben – und verschlechtert so das Nutzererlebnis für internationale Zielgruppen.

Lösung

Nutze das relative Zeitformat von react-intl, um numerische Zeitdifferenzen in grammatikalisch korrekte Phrasen für die jeweilige Nutzersprache umzuwandeln. Berechne die Differenz zwischen einem Zeitstempel und dem aktuellen Zeitpunkt, bestimme die passende Einheit (Sekunden, Minuten, Stunden, Tage) und übergib beide Werte an die Formatierungs-APIs von react-intl. Die zugrundeliegende Intl.RelativeTimeFormat-API übernimmt automatisch die grammatikalischen Regeln, Wortstellung und Flexion für die jeweilige Sprache.

Schritte

1. Hilfsfunktion zur Berechnung relativer Zeitwerte erstellen

Die Zeitdifferenz muss in einen numerischen Wert und eine passende Einheit umgewandelt werden. Entwickle eine Funktion, die einen Zeitstempel mit der aktuellen Zeit vergleicht und die beste Einheit auswählt.

export function getRelativeTimeValue(date: Date | number) {
  const now = Date.now();
  const timestamp = typeof date === "number" ? date : date.getTime();
  const diffInSeconds = (timestamp - now) / 1000;

  const minute = 60;
  const hour = minute * 60;
  const day = hour * 24;
  const week = day * 7;
  const month = day * 30;
  const year = day * 365;

  const absDiff = Math.abs(diffInSeconds);

  if (absDiff < minute) {
    return { value: Math.round(diffInSeconds), unit: "second" as const };
  } else if (absDiff < hour) {
    return {
      value: Math.round(diffInSeconds / minute),
      unit: "minute" as const,
    };
  } else if (absDiff < day) {
    return { value: Math.round(diffInSeconds / hour), unit: "hour" as const };
  } else if (absDiff < week) {
    return { value: Math.round(diffInSeconds / day), unit: "day" as const };
  } else if (absDiff < month) {
    return { value: Math.round(diffInSeconds / week), unit: "week" as const };
  } else if (absDiff < year) {
    return { value: Math.round(diffInSeconds / month), unit: "month" as const };
  } else {
    return { value: Math.round(diffInSeconds / year), unit: "year" as const };
  }
}

Diese Funktion gibt einen vorzeichenbehafteten numerischen Wert zurück (negativ für die Vergangenheit, positiv für die Zukunft) sowie die passendste Einheit basierend auf der Größe der Differenz.

2. Relative Zeit mit dem useIntl-Hook formatieren

Die Funktion formatRelativeTime gibt einen formatierten String für die relative Zeit zurück und erwartet einen numerischen Wert, eine Einheit und Optionen, die dem Intl.RelativeTimeFormatOptions-Standard entsprechen. Nutze den Helfer aus Schritt 1, um Wert und Einheit zu erhalten, und formatiere sie anschließend.

import { useIntl } from "react-intl";
import { getRelativeTimeValue } from "@/lib/relative-time";

export default function CommentTimestamp({ date }: { date: Date }) {
  const intl = useIntl();
  const { value, unit } = getRelativeTimeValue(date);

  return (
    <time dateTime={date.toISOString()}>
      {intl.formatRelativeTime(value, unit)}
    </time>
  );
}

Die formatRelativeTime-Methode erzeugt lokalisierte Ausdrücke wie „vor 2 Tagen“ auf Englisch oder „il y a 2 jours“ auf Französisch.

3. Verwenden Sie FormattedRelativeTime für deklaratives Formatieren

FormattedRelativeTime bietet erweiterte Funktionen wie automatische Aktualisierung und verwendet die formatRelativeTime-API mit Props für Wert, Einheit und relative Formatierungsoptionen. Für Komponenten, die automatische Updates benötigen, verwenden Sie die Komponentenform.

import { FormattedRelativeTime } from "react-intl";
import { getRelativeTimeValue } from "@/lib/relative-time";

export default function LiveTimestamp({ date }: { date: Date }) {
  const { value, unit } = getRelativeTimeValue(date);

  return (
    <time dateTime={date.toISOString()}>
      <FormattedRelativeTime
        value={value}
        unit={unit}
        numeric="auto"
        updateIntervalInSeconds={10}
      />
    </time>
  );
}

Die Prop updateIntervalInSeconds steuert, wie häufig die Komponente neu gerendert wird, damit die angezeigte Zeitangabe stets aktuell bleibt.

4. Formatierungsstil anpassen

Die Komponente akzeptiert RelativeTimeFormatOptions, einschließlich der Eigenschaften numeric und style. Passen Sie diese Optionen an, um das Ausgabeformat zu steuern.

import { FormattedRelativeTime } from "react-intl";
import { getRelativeTimeValue } from "@/lib/relative-time";

export default function CompactTimestamp({ date }: { date: Date }) {
  const { value, unit } = getRelativeTimeValue(date);

  return (
    <FormattedRelativeTime
      value={value}
      unit={unit}
      numeric="auto"
      style="narrow"
    />
  );
}

Wenn numeric="auto" gesetzt ist, werden Ausdrücke wie „gestern“ statt „vor 1 Tag“ verwendet, sofern passend, und style="narrow" erzeugt kürzere Formen wie „vor 2 Mon.“ statt „vor 2 Monaten“.