Comment gérer les fuseaux horaires dans Next.js (Pages Router) v16
Afficher les heures dans le fuseau horaire local de l'utilisateur
Problème
Lorsque les applications affichent des heures sans tenir compte de la localisation de l'utilisateur, cela crée de la confusion. Une réunion prévue à « 15h00 » correspond à des moments différents selon que l'utilisateur se trouve à New York, Londres ou Tokyo. Si le serveur affiche une heure en UTC ou dans son propre fuseau horaire, les utilisateurs d'autres régions voient des heures locales incorrectes, ce qui entraîne des rendez-vous manqués et des erreurs de planification. Le même horodatage doit être interprété différemment pour chaque utilisateur en fonction de son fuseau horaire.
Solution
Stockez les horodatages dans un format universel tel que ISO 8601 ou les horodatages Unix, puis formatez-les pour l'affichage dans le fuseau horaire local de l'utilisateur côté client. Détectez le fuseau horaire de l'utilisateur à l'aide de l'API d'internationalisation du navigateur et transmettez-le aux fonctions de formatage de react-intl. Cela garantit que chaque utilisateur voit les heures ajustées à son propre fuseau horaire, éliminant toute ambiguïté sur le moment où les événements se produisent.
Étapes
1. Détecter le fuseau horaire de l'utilisateur côté client
La méthode Intl.DateTimeFormat().resolvedOptions().timeZone du navigateur renvoie l'identifiant de fuseau horaire IANA de l'utilisateur, tel que America/New_York ou Europe/London. Créez un hook personnalisé pour accéder à cette valeur.
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;
}
Ce hook s'exécute uniquement côté client, évitant les incompatibilités d'hydratation, et utilise UTC par défaut jusqu'à ce que le fuseau horaire soit détecté.
2. Formater les dates avec le fuseau horaire de l'utilisateur en utilisant FormattedDate
Transmettez l'option timeZone aux méthodes de formatage de react-intl pour contrôler quel fuseau horaire est utilisé pour l'affichage. Utilisez le composant <FormattedDate> avec le fuseau horaire détecté.
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"
/>
);
}
La prop timeZone garantit que la date est formatée dans le fuseau horaire local de l'utilisateur plutôt que celui du serveur ou UTC.
3. Formater les heures de manière impérative avec useIntl
Pour les scénarios où vous avez besoin d'une chaîne formatée plutôt qu'un composant, utilisez le hook useIntl pour accéder à l'API de formatage impératif.
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>;
}
La méthode formatDate accepte un second argument avec DateTimeFormatOptions, incluant timeZone, permettant un contrôle total sur la façon dont l'horodatage est affiché.
4. Transmettre les horodatages du serveur sous forme de chaînes ISO
Dans getServerSideProps, récupérez les données au moment de la requête et transmettez-les au composant de page en tant que props. Sérialisez les dates sous forme de chaînes ISO 8601 pour préserver les informations de fuseau horaire.
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>
);
}
Les chaînes ISO préservent le moment exact dans le temps, permettant au formatage côté client de les convertir avec précision vers n'importe quel fuseau horaire.