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“.