Comment formater les temps relatifs comme il y a 3 jours ou dans 2 heures ?
Utilisez Intl.RelativeTimeFormat pour afficher des temps comme il y a 3 jours ou dans 2 heures dans n'importe quelle langue avec pluralisation et localisation automatiques
Introduction
Les fils d'actualité des réseaux sociaux, les sections de commentaires et les journaux d'activité affichent des horodatages comme "il y a 5 minutes", "il y a 2 heures" ou "dans 3 jours". Ces horodatages relatifs aident les utilisateurs à comprendre rapidement quand quelque chose s'est produit sans avoir besoin d'analyser une date absolue.
Lorsque vous codez en dur ces chaînes en anglais, vous supposez que tous les utilisateurs parlent anglais et suivent les règles grammaticales anglaises. Différentes langues ont différentes façons d'exprimer le temps relatif. L'espagnol dit "hace 3 días" au lieu de "3 days ago". Le japonais utilise "3日前" avec une structure complètement différente. Chaque langue a également des règles de pluralisation uniques qui déterminent quand utiliser les formes singulières ou plurielles.
JavaScript fournit l'API Intl.RelativeTimeFormat pour gérer automatiquement le formatage du temps relatif. Cette leçon explique comment formater correctement les temps relatifs pour n'importe quelle langue en utilisant cette API intégrée.
Pourquoi le formatage du temps relatif nécessite l'internationalisation
Différentes langues expriment le temps relatif de différentes manières. L'anglais place l'unité de temps avant "ago" pour les temps passés et après "in" pour les temps futurs. D'autres langues utilisent des ordres de mots différents, des prépositions différentes ou des structures grammaticales entièrement différentes.
const rtfEnglish = new Intl.RelativeTimeFormat('en');
console.log(rtfEnglish.format(-3, 'day'));
// "3 days ago"
const rtfSpanish = new Intl.RelativeTimeFormat('es');
console.log(rtfSpanish.format(-3, 'day'));
// "hace 3 días"
const rtfJapanese = new Intl.RelativeTimeFormat('ja');
console.log(rtfJapanese.format(-3, 'day'));
// "3 日前"
Chaque langue produit un résultat naturel qui suit ses propres conventions. Vous n'avez pas besoin de connaître ces conventions ni de maintenir des fichiers de traduction. L'API gère automatiquement tous les détails de formatage.
Les règles de pluralisation varient également considérablement d'une langue à l'autre. L'anglais distingue "1 day" et "2 days". L'arabe a six formes plurielles différentes selon le nombre. Le japonais utilise la même forme quel que soit la quantité. L'API Intl.RelativeTimeFormat applique les règles de pluralisation correctes pour chaque langue.
L'API Intl.RelativeTimeFormat
Le constructeur Intl.RelativeTimeFormat crée un formateur qui convertit des valeurs numériques et des unités de temps en chaînes localisées. Vous passez un identifiant de locale comme premier argument, puis appelez la méthode format() avec une valeur et une unité.
const rtf = new Intl.RelativeTimeFormat('en-US');
console.log(rtf.format(-1, 'day'));
// "1 day ago"
console.log(rtf.format(2, 'hour'));
// "in 2 hours"
La méthode format() prend deux paramètres. Le premier est un nombre représentant la quantité de temps. Le second est une chaîne spécifiant l'unité de temps.
Les nombres négatifs indiquent des temps passés, tandis que les nombres positifs indiquent des temps futurs. Cette convention rend l'API intuitive à utiliser une fois que vous comprenez la convention des signes.
Formatage des temps passés et futurs
Le signe de la valeur détermine si le temps est dans le passé ou le futur. Les valeurs négatives produisent des temps passés, tandis que les valeurs positives produisent des temps futurs.
const rtf = new Intl.RelativeTimeFormat('en-US');
console.log(rtf.format(-5, 'minute'));
// "5 minutes ago"
console.log(rtf.format(5, 'minute'));
// "in 5 minutes"
console.log(rtf.format(-2, 'week'));
// "2 weeks ago"
console.log(rtf.format(2, 'week'));
// "in 2 weeks"
Ce modèle fonctionne de manière cohérente pour toutes les unités de temps et toutes les langues. L'API sélectionne automatiquement la structure grammaticale correcte selon que la valeur est positive ou négative.
Unités de temps disponibles
L'API prend en charge huit unités de temps qui couvrent la plupart des besoins de formatage de temps relatif. Vous pouvez utiliser des formes singulières ou plurielles, et les deux fonctionnent de manière identique.
const rtf = new Intl.RelativeTimeFormat('en-US');
console.log(rtf.format(-30, 'second'));
// "30 seconds ago"
console.log(rtf.format(-15, 'minute'));
// "15 minutes ago"
console.log(rtf.format(-6, 'hour'));
// "6 hours ago"
console.log(rtf.format(-3, 'day'));
// "3 days ago"
console.log(rtf.format(-2, 'week'));
// "2 weeks ago"
console.log(rtf.format(-4, 'month'));
// "4 months ago"
console.log(rtf.format(-1, 'quarter'));
// "1 quarter ago"
console.log(rtf.format(-2, 'year'));
// "2 years ago"
L'API accepte à la fois les formes singulières comme day et les formes plurielles comme days. Les deux produisent un résultat identique. L'unité trimestre est utile pour les applications métier qui travaillent avec des périodes fiscales.
Utilisation du langage naturel avec numeric auto
L'option numeric contrôle si le formateur utilise des nombres ou des alternatives en langage naturel. La valeur par défaut est always, qui affiche toujours des nombres.
const rtfAlways = new Intl.RelativeTimeFormat('en-US', {
numeric: 'always'
});
console.log(rtfAlways.format(-1, 'day'));
// "1 day ago"
console.log(rtfAlways.format(0, 'day'));
// "in 0 days"
console.log(rtfAlways.format(1, 'day'));
// "in 1 day"
Définir numeric sur auto produit des formulations plus naturelles pour certaines valeurs.
const rtfAuto = new Intl.RelativeTimeFormat('en-US', {
numeric: 'auto'
});
console.log(rtfAuto.format(-1, 'day'));
// "yesterday"
console.log(rtfAuto.format(0, 'day'));
// "today"
console.log(rtfAuto.format(1, 'day'));
// "tomorrow"
Cette option rend les interfaces plus conversationnelles. Les utilisateurs voient « hier » au lieu de « il y a 1 jour », ce qui se lit plus naturellement. L'option auto fonctionne pour toutes les unités de temps et toutes les langues, chaque langue fournissant ses propres alternatives idiomatiques.
Choisir un style de formatage
L'option style contrôle la verbosité de la sortie. Les trois styles disponibles sont long, short et narrow.
const rtfLong = new Intl.RelativeTimeFormat('en-US', {
style: 'long'
});
console.log(rtfLong.format(-2, 'hour'));
// "2 hours ago"
const rtfShort = new Intl.RelativeTimeFormat('en-US', {
style: 'short'
});
console.log(rtfShort.format(-2, 'hour'));
// "2 hr. ago"
const rtfNarrow = new Intl.RelativeTimeFormat('en-US', {
style: 'narrow'
});
console.log(rtfNarrow.format(-2, 'hour'));
// "2h ago"
Le style long est le style par défaut et fonctionne bien pour la plupart des interfaces. Le style short économise de l'espace dans les mises en page mobiles ou les tableaux. Le style narrow produit la sortie la plus compacte pour les designs extrêmement contraints en espace.
Calculer les différences de temps
L'API Intl.RelativeTimeFormat formate les valeurs mais ne les calcule pas. Vous devez calculer vous-même la différence de temps, puis transmettre le résultat au formateur.
Pour calculer une différence de temps, soustrayez la date cible de la date actuelle, puis convertissez le résultat de millisecondes vers l'unité souhaitée.
const rtf = new Intl.RelativeTimeFormat('en-US', { numeric: 'auto' });
function formatDaysAgo(date) {
const now = new Date();
const diffInMs = date - now;
const diffInDays = Math.round(diffInMs / (1000 * 60 * 60 * 24));
return rtf.format(diffInDays, 'day');
}
const yesterday = new Date();
yesterday.setDate(yesterday.getDate() - 1);
console.log(formatDaysAgo(yesterday));
// "yesterday"
const tomorrow = new Date();
tomorrow.setDate(tomorrow.getDate() + 1);
console.log(formatDaysAgo(tomorrow));
// "tomorrow"
Cette fonction calcule la différence en jours entre la date cible et maintenant. Le calcul divise les millisecondes par le nombre de millisecondes dans un jour, puis arrondit au nombre entier le plus proche.
La soustraction date - now produit une valeur négative pour les dates passées et une valeur positive pour les dates futures. Cela correspond à la convention de signe attendue par la méthode format().
Créer une fonction utilitaire complète
Pour un formateur de temps relatif à usage général, vous devez sélectionner l'unité de temps la plus appropriée en fonction de l'amplitude de la différence de temps.
const rtf = new Intl.RelativeTimeFormat('en-US', { numeric: 'auto' });
const units = {
year: 24 * 60 * 60 * 1000 * 365,
month: 24 * 60 * 60 * 1000 * 365 / 12,
week: 24 * 60 * 60 * 1000 * 7,
day: 24 * 60 * 60 * 1000,
hour: 60 * 60 * 1000,
minute: 60 * 1000,
second: 1000
};
function formatRelativeTime(date) {
const now = new Date();
const diffInMs = date - now;
const absDiff = Math.abs(diffInMs);
for (const [unit, msValue] of Object.entries(units)) {
if (absDiff >= msValue || unit === 'second') {
const value = Math.round(diffInMs / msValue);
return rtf.format(value, unit);
}
}
}
const fiveMinutesAgo = new Date(Date.now() - 5 * 60 * 1000);
console.log(formatRelativeTime(fiveMinutesAgo));
// "5 minutes ago"
const threeDaysAgo = new Date(Date.now() - 3 * 24 * 60 * 60 * 1000);
console.log(formatRelativeTime(threeDaysAgo));
// "3 days ago"
const tomorrow = new Date(Date.now() + 24 * 60 * 60 * 1000);
console.log(formatRelativeTime(tomorrow));
// "tomorrow"
Cette fonction itère à travers les unités de temps de la plus grande à la plus petite, en sélectionnant la première unité où la différence absolue dépasse la valeur en millisecondes de l'unité. Le repli sur les secondes garantit que la fonction retourne toujours un résultat.
Les définitions d'unités utilisent des valeurs approximatives. Les mois sont calculés comme 1/12 d'une année plutôt que de tenir compte des différentes longueurs de mois. Cette approximation fonctionne bien pour les affichages de temps relatif où les valeurs approximatives sont plus utiles que la précision exacte.
Formater selon la locale de l'utilisateur
Au lieu de coder en dur une locale spécifique, vous pouvez utiliser la langue préférée de l'utilisateur depuis le navigateur.
const userLocale = navigator.language;
const rtf = new Intl.RelativeTimeFormat(userLocale, { numeric: 'auto' });
const yesterday = new Date(Date.now() - 24 * 60 * 60 * 1000);
console.log(rtf.format(-1, 'day'));
// Output varies by user's locale
// For en-US: "yesterday"
// For es-ES: "ayer"
// For fr-FR: "hier"
// For de-DE: "gestern"
Cette approche affiche les temps relatifs selon les préférences linguistiques de chaque utilisateur sans nécessiter de sélection manuelle de locale. Le navigateur fournit la préférence linguistique, et l'API applique les conventions de formatage appropriées.
Voir le même temps dans différentes langues
La même valeur de temps relatif produit un résultat différent pour différentes locales. Chaque langue suit ses propres conventions pour l'ordre des mots, la grammaire et la pluralisation.
const threeDaysAgo = -3;
const rtfEnglish = new Intl.RelativeTimeFormat('en-US');
console.log(rtfEnglish.format(threeDaysAgo, 'day'));
// "3 days ago"
const rtfSpanish = new Intl.RelativeTimeFormat('es-ES');
console.log(rtfSpanish.format(threeDaysAgo, 'day'));
// "hace 3 días"
const rtfFrench = new Intl.RelativeTimeFormat('fr-FR');
console.log(rtfFrench.format(threeDaysAgo, 'day'));
// "il y a 3 jours"
const rtfGerman = new Intl.RelativeTimeFormat('de-DE');
console.log(rtfGerman.format(threeDaysAgo, 'day'));
// "vor 3 Tagen"
const rtfJapanese = new Intl.RelativeTimeFormat('ja-JP');
console.log(rtfJapanese.format(threeDaysAgo, 'day'));
// "3 日前"
const rtfArabic = new Intl.RelativeTimeFormat('ar-SA');
console.log(rtfArabic.format(threeDaysAgo, 'day'));
// "قبل 3 أيام"
Chaque langue produit un résultat naturel que les locuteurs natifs utiliseraient dans une conversation. L'API gère toute la complexité des différentes structures grammaticales, des différents systèmes d'écriture et des différentes directions de texte.
Réutiliser les formateurs pour les performances
Créer une instance Intl.RelativeTimeFormat implique le chargement de données de locale et le traitement d'options. Lors du formatage de plusieurs horodatages, créez le formateur une fois et réutilisez-le.
const rtf = new Intl.RelativeTimeFormat('en-US', { numeric: 'auto' });
const timestamps = [
new Date(Date.now() - 5 * 60 * 1000), // 5 minutes ago
new Date(Date.now() - 2 * 60 * 60 * 1000), // 2 hours ago
new Date(Date.now() - 24 * 60 * 60 * 1000) // 1 day ago
];
timestamps.forEach(date => {
const diffInMs = date - new Date();
const diffInMinutes = Math.round(diffInMs / (60 * 1000));
console.log(rtf.format(diffInMinutes, 'minute'));
});
Cette approche est plus efficace que de créer un nouveau formateur pour chaque horodatage. La différence de performance devient significative lors du formatage de centaines ou de milliers d'horodatages dans les fils d'actualité ou les fils de commentaires.
Utilisation des temps relatifs dans les interfaces
Vous pouvez utiliser le formatage de temps relatif partout où vous affichez des horodatages aux utilisateurs. Cela inclut les fils de médias sociaux, les sections de commentaires, les journaux d'activité, les systèmes de notification et toute interface où afficher depuis combien de temps quelque chose s'est produit aide les utilisateurs à comprendre le contexte.
const rtf = new Intl.RelativeTimeFormat(navigator.language, {
numeric: 'auto'
});
function updateTimestamp(element, date) {
const now = new Date();
const diffInMs = date - now;
const diffInMinutes = Math.round(diffInMs / (60 * 1000));
element.textContent = rtf.format(diffInMinutes, 'minute');
}
const commentDate = new Date('2025-10-15T14:30:00');
const timestampElement = document.getElementById('comment-timestamp');
updateTimestamp(timestampElement, commentDate);
Les chaînes formatées fonctionnent comme n'importe quelle autre valeur de chaîne. Vous pouvez les insérer dans du contenu texte, des attributs ou tout autre contexte où vous affichez des informations aux utilisateurs.