web-dev-qa-db-fra.com

Horodatage Javascript en temps relatif (par exemple il y a 2 secondes, une semaine, etc.), meilleures méthodes?

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

Quelqu'un souhaite-t-il partager certaines de ses méthodes préférées (de préférence sans plug-ins)?

42
wilsonpage

Eh bien, c'est assez facile si vous n'êtes pas trop préoccupé par la précision. Quel est le problème 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) + ' seconds ago';   
    }

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

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

    else if (elapsed < msPerMonth) {
        return 'approximately ' + Math.round(elapsed/msPerDay) + ' days ago';   
    }

    else if (elapsed < msPerYear) {
        return 'approximately ' + Math.round(elapsed/msPerMonth) + ' months ago';   
    }

    else {
        return 'approximately ' + Math.round(elapsed/msPerYear ) + ' years ago';   
    }
}

Exemple de travail ici

Vous voudrez peut-être le modifier pour mieux gérer les valeurs singulières (par exemple, 1 day au lieu de 1 days) si cela vous dérange.

82

Voici le mimique exact du temps Twitter il y a sans plugins:

  function timeSince(timeStamp) {
    var now = new Date(),
      secondsPast = (now.getTime() - timeStamp.getTime()) / 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;
    }
  }

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

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

J'espère que ça aide.

17
Timur Carpeev

Tada! Timeago: http://timeago.yarp.com/

Oh accrocher - sans plugins? Pourquoi ça alors? Je suppose que vous pourriez ouvrir le fichier de plugin et en couper les tripes.

6
James McCormack

Inspiré sur Diego Castillo awnser et dans le 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 = {};
  
  // Public Methods
  self.locales = {
    prefix: '',
    sufix:  'ago',
    
    seconds: 'less than a minute',
    minute:  'about a minute',
    minutes: '%d minutes',
    hour:    'about an hour',
    hours:   'about %d hours',
    day:     'a day',
    days:    '%d days',
    month:   'about a month',
    months:  '%d months',
    year:    'about a year',
    years:   '%d years'
  };
  
  self.inWords = function(timeAgo) {
    var seconds = Math.floor((new Date() - parseInt(timeAgo)) / 1000),
        separator = this.locales.separator || ' ',
        words = this.locales.prefix + separator,
        interval = 0,
        intervals = {
          year:   seconds / 31536000,
          month:  seconds / 2592000,
          day:    seconds / 86400,
          hour:   seconds / 3600,
          minute: seconds / 60
        };
    
    var distance = this.locales.seconds;
    
    for (var key in intervals) {
      interval = Math.floor(intervals[key]);
      
      if (interval > 1) {
        distance = this.locales[key + 's'];
        break;
      } else if (interval === 1) {
        distance = this.locales[key];
        break;
      }
    }
    
    distance = distance.replace(/%d/i, interval);
    words += distance + separator + this.locales.sufix;

    return words.trim();
  };
  
  return self;
}());


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

timeElement.innerText = TimeAgo.inWords(time.getTime());
<time datetime="2016-06-13"></time>

4
Caio Tarifa

Intl.RelativeTimeFormat - API native

Actuellement (18 décembre) a étape 3 proposition , et déjà implémentée dans Chrome 71

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

[
  [3.14 , 'second' ],
  [-15  , 'minute' ],
  [8    , 'hour'   ],
  [-1   , 'day'    ],
  [3    , 'week'   ],
  [-5   , 'month'  ],
  [2    , 'quarter'],
  [-42  , 'year'   ],
].forEach(d => console.log(   rtf.format(d[0], d[1])  ));

Intl.RelativeTimeFormat est disponible par défaut dans V8 v7.1.179 et Chrome 71. Au fur et à mesure que cette API sera plus largement disponible, vous découvrirez des bibliothèques telles que Moment.js , Globalize et date-fns en laissant tomber leur dépendance vis-à-vis des bases de données CLDR codées en dur au profit du parent natif fonctionnalité de formatage du temps, améliorant ainsi le temps de chargement performance, performances d'analyse et de compilation, exécution performances et utilisation de la mémoire.

2
vsync

Si vous avez besoin de plusieurs langues et que vous ne voulez pas ajouter une grande bibliothèque, par exemple. intl-relativeformat de Yahoo une solution intéressante.

var rf = new IntlRelativeFormat('en-US');

var posts = [
    {
        id   : 1,
        title: 'Some Blog Post',
        date : new Date(1426271670524)
    },
    {
        id   : 2,
        title: 'Another Blog Post',
        date : new Date(1426278870524)
    }
];

posts.forEach(function (post) {
    console.log(rf.format(post.date));
});
// => "3 hours ago"
// => "1 hour ago"
1
abumalick

Les plugins Datetime existent parce qu'il est très difficile de bien faire les choses. Cette vidéo expliquant les incohérences date-heure jettera un peu de lumière sur le problème.

_ {Toutes les solutions ci-dessus sans plug-in sont incorrectes.

Pour travailler avec les dates et les heures l’utilisation d’un plugin est préférable. Parmi les centaines de plug-ins qui traitent ce problème, nous utilisons Moment.js et il fait le travail.

Depuis la documentation de l'API Twitter nous pouvons voir leur format d'horodatage:

"created_at":"Wed Aug 27 13:08:45 +0000 2008"

Nous pouvons l'analyser avec Moment.js

const postDatetime = moment(
  "Wed Aug 27 13:08:45 +0000 2008",
  "dddd, MMMM Do, h:mm:ss a, YYYY"
);
const now = moment();
const timeAgo = now.diff(postDatetime, 'seconds');

Pour spécifier l'unité de temps préférée pour la variable diff, nous pouvons utiliser la méthode isSame. par exemple:

if (now.isSame(postDatetime, 'day')) {
  const timeUnit = 'days';
}

Globalement, construire quelque chose comme:

`Posted ${timeAgo} ${timeUnit} ago`;

Reportez-vous à la documentation de votre plugin pour la gestion des calculs de temps relatif («il y a combien de temps?»).

1
Art Knipe

Pour ceux que ça intéresse, j'ai fini par créer un assistant de guidon pour le faire .

    {{#beautify_date}}
        {{timestamp_ms}}
    {{/beautify_date}}

Assistant:

    Handlebars.registerHelper('beautify_date', function(options) {
        var timeAgo = new Date(parseInt(options.fn(this)));

        if (Object.prototype.toString.call(timeAgo) === "[object Date]") {
            if (isNaN(timeAgo.getTime())) {
                return 'Not Valid';
            } else {
                var seconds = Math.floor((new Date() - timeAgo) / 1000),
                intervals = [
                    Math.floor(seconds / 31536000),
                    Math.floor(seconds / 2592000),
                    Math.floor(seconds / 86400),
                    Math.floor(seconds / 3600),
                    Math.floor(seconds / 60)
                ],
                times = [
                    'year',
                    'month',
                    'day',
                    'hour',
                    'minute'
                ];

                var key;
                for(key in intervals) {
                    if (intervals[key] > 1)  
                        return intervals[key] + ' ' + times[key] + 's ago';
                    else if (intervals[key] === 1) 
                        return intervals[key] + ' ' + times[key] + ' ago';
                }

                return Math.floor(seconds) + ' seconds ago';
            }
        } else {
            return 'Not Valid';
        }
    });
1
Diego Castillo

Il existe également une fonction sugar.js et relative à cet effet.

relative - Affiche une chaîne en unités par rapport à la date actuelle ("il y a" ou "à partir de maintenant").

1
user8171823

Pour les utilisateurs de Moment.js, il a la fonction fromNow () qui renvoie "x jours" ou "x heures auparavant" à partir de la date/heure actuelle.

moment([2007, 0, 29]).fromNow();     // 4 years ago
moment([2007, 0, 29]).fromNow(true); // 4 years
0
Nitin Jadhav

Vous pouvez utiliser machinepack-datetime à cette fin. C'est facile et clair avec son API définie.

tutorialSchema.virtual('createdOn').get(function () {
    const DateTime = require('machinepack-datetime');
    let timeAgoString = "";
    try {
        timeAgoString = DateTime.timeFrom({
            toWhen: DateTime.parse({
                datetime: this.createdAt
            }).execSync(),
            fromWhen: new Date().getTime()
        }).execSync();
    } catch(err) {
        console.log('error getting createdon', err);
    }
    return timeAgoString; // a second ago
});
0
Piyush P