91 votes

Javascript horodatage en temps relatif

Je suis à la recherche d'un joli extrait de code JS pour convertir un horodatage (par exemple à partir de l'API Twitter) en un temps relatif convivial pour l'utilisateur (par exemple, il y a 2 secondes, il y a une semaine, etc).

Est-ce que quelqu'un serait prêt à partager certaines de ses méthodes préférées (de préférence sans utiliser de plugins) ?

0 votes

198voto

fearofawhackplanet Points 12147

Eh bien, c'est assez facile si vous ne vous souciez pas trop de l'exactitude. Qu'est-ce qui ne va pas avec la méthode triviale?

function timeDifference(current, previous) {

    var msPerMinute = 60 * 1000;
    var msPerHour = msPerMinute * 60;
    var msPerDay = msPerHour * 24;
    var msPerMonth = msPerDay * 30;
    var msPerYear = msPerDay * 365;

    var elapsed = current - previous;

    if (elapsed < msPerMinute) {
         return Math.round(elapsed/1000) + ' secondes auparavant';   
    }

    else if (elapsed < msPerHour) {
         return Math.round(elapsed/msPerMinute) + ' minutes auparavant';   
    }

    else if (elapsed < msPerDay ) {
         return Math.round(elapsed/msPerHour ) + ' heures auparavant';   
    }

    else if (elapsed < msPerMonth) {
        return 'environ ' + Math.round(elapsed/msPerDay) + ' jours auparavant';   
    }

    else if (elapsed < msPerYear) {
        return 'environ ' + Math.round(elapsed/msPerMonth) + ' mois auparavant';   
    }

    else {
        return 'environ ' + Math.round(elapsed/msPerYear ) + ' années auparavant';   
    }
}

Exemple de travail ici.

Vous pouvez ajuster pour gérer les valeurs singulières de manière plus efficace (par exemple, 1 jour au lieu de 1 jours) si cela vous dérange.

80voto

vsync Points 11280

Mise à jour 4 avril 2021:

J'ai converti le code ci-dessous en un package node. Voici le dépôt.


Intl.RelativeTimeFormat - API native

[✔] (Déc. 18) une proposition de stade 3, et déjà implémentée dans Chrome 71
[✔] (Oct. 20) au stade 4 (terminé), et prêt pour inclusion dans la norme ECMAScript formelle

// en millisecondes
var units = {
  year  : 24 * 60 * 60 * 1000 * 365,
  month : 24 * 60 * 60 * 1000 * 365/12,
  day   : 24 * 60 * 60 * 1000,
  hour  : 60 * 60 * 1000,
  minute: 60 * 1000,
  second: 1000
}

var rtf = new Intl.RelativeTimeFormat('en', { numeric: 'auto' })

var getRelativeTime = (d1, d2 = new Date()) => {
  var elapsed = d1 - d2

  // "Math.abs" tient compte des scénarios "passé" et "futur"
  for (var u in units) 
    if (Math.abs(elapsed) > units[u] || u == 'second') 
      return rtf.format(Math.round(elapsed/units[u]), u)
}

// liste de test de dates à comparer avec la date actuelle
[
  '20/10/1984',
  '20/10/2015',
  +new Date() - units.year,
  +new Date() - units.month,
  +new Date() - units.day,
  +new Date() - units.hour,
  +new Date() - units.minute,
  +new Date() + units.minute*2,
  +new Date() + units.day*7,
]
.forEach(d => console.log(   
  new Date(d).toLocaleDateString(),
  new Date(d).toLocaleTimeString(), 
  '(Relatif à maintenant) →',
  getRelativeTime(+new Date(d))
))

Intl.RelativeTimeFormat est disponible par défaut dans V8 v7.1.179 et Chrome 71. À mesure que cette API devient de plus en plus disponible, vous trouverez des bibliothèques telles que Moment.js, Globalize et date-fns abandonnant leur dépendance aux bases de données CLDR codées en dur au profit de la fonctionnalité native de formatage des temps relatifs, améliorant ainsi les performances de chargement, les performances d'analyse et de compilation, les performances d'exécution et l'utilisation de la mémoire.

33voto

Timur Carpeev Points 352

Voici l'exacte imitation du temps écoulé sur Twitter sans plugins:

function timeSince(timeStamp) {
  var now = new Date(),
    secondsPast = (now.getTime() - timeStamp) / 1000;
  if (secondsPast < 60) {
    return parseInt(secondsPast) + 's';
  }
  if (secondsPast < 3600) {
    return parseInt(secondsPast / 60) + 'm';
  }
  if (secondsPast <= 86400) {
    return parseInt(secondsPast / 3600) + 'h';
  }
  if (secondsPast > 86400) {
    day = timeStamp.getDate();
    month = timeStamp.toDateString().match(/ [a-zA-Z]*/)[0].replace(" ", "");
    year = timeStamp.getFullYear() == now.getFullYear() ? "" : " " + timeStamp.getFullYear();
    return day + " " + month + year;
  }
}

const currentTimeStamp = new Date().getTime();

console.log(timeSince(currentTimeStamp));

Gist https://gist.github.com/timuric/11386129

Fiddle http://jsfiddle.net/qE8Lu/1/

J'espère que cela vous aidera.

11voto

User Rebo Points 40

Typescript et Intl.RelativeTimeFormat (2020)

Implémentation combinée de Typescript basée sur les approches de @vsync et @kigiri en utilisant l'API Web RelativeTimeFormat.

const units: {unit: Intl.RelativeTimeFormatUnit; ms: number}[] = [
    {unit: "year", ms: 31536000000},
    {unit: "month", ms: 2628000000},
    {unit: "day", ms: 86400000},
    {unit: "hour", ms: 3600000},
    {unit: "minute", ms: 60000},
    {unit: "second", ms: 1000},
];
const rtf = new Intl.RelativeTimeFormat("en", {numeric: "auto"});

/**
 * Obtenir un message de temps relatif adapté à la langue à partir de Dates.
 * @param relative - la dateTime relative, généralement dans le passé ou le futur
 * @param pivot - la dateTime de référence, généralement l'heure actuelle
 */
export function relativeTimeFromDates(relative: Date | null, pivot: Date = new Date()): string {
    if (!relative) return "";
    const elapsed = relative.getTime() - pivot.getTime();
    return relativeTimeFromElapsed(elapsed);
}

/**
 * Obtenir un message de temps relatif adapté à la langue à partir du temps écoulé.
 * @param elapsed - le temps écoulé en millisecondes
 */
export function relativeTimeFromElapsed(elapsed: number): string {
    for (const {unit, ms} of units) {
        if (Math.abs(elapsed) >= ms || unit === "second") {
            return rtf.format(Math.round(elapsed / ms), unit);
        }
    }
    return "";
}

7voto

Caio Tarifa Points 1604

Inpiré de la réponse de Diego Castillo et du plugin timeago.js, j'ai écrit mon propre plugin vanilla pour cela.

var timeElement = document.querySelector('time'),
    time = new Date(timeElement.getAttribute('datetime'));

timeElement.innerText = TimeAgo.inWords(time.getTime());

var TimeAgo = (function() {
  var self = {};

  // Méthodes publiques
  self.locales = {
    prefixe: '',
    suffixe:  'il y a',

    seconds: 'moins d\'une minute',
    minute:  'environ une minute',
    minutes: '%d minutes',
    hour:    'environ une heure',
    hours:   'environ %d heures',
    day:     'un jour',
    days:    '%d jours',
    month:   'environ un mois',
    months:  '%d mois',
    year:    'environ un an',
    years:   '%d ans'
  };

  self.inWords = function(timeAgo) {
    var seconds = Math.floor((new Date() - parseInt(timeAgo)) / 1000),
        separateur = this.locales.separateur || ' ',
        mots = this.locales.prefixe + separateur,
        intervalle = 0,
        intervalles = {
          year:   seconds / 31536000,
          month:  seconds / 2592000,
          day:    seconds / 86400,
          hour:   seconds / 3600,
          minute: seconds / 60
        };

    var distance = this.locales.seconds;

    for (var cle in intervalles) {
      intervalle = Math.floor(intervalles[cle]);

      if (intervalle > 1) {
        distance = this.locales[cle + 's'];
        break;
      } else if (intervalle === 1) {
        distance = this.locales[cle];
        break;
      }
    }

    distance = distance.replace(/%d/i, intervalle);
    mots += distance + separateur + this.locales.suffixe;

    return mots.trim();
  };

  return self;
}());

// UTILISATION
var timeElement = document.querySelector('time'),
    time = new Date(timeElement.getAttribute('datetime'));

timeElement.innerText = TimeAgo.inWords(time.getTime());

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X