Подтвердить что ты не робот

Javascript timestamp относительное время (например, 2 секунды назад, неделю назад и т.д.), Лучшие методы?

Я ищу хороший фрагмент JS для преобразования временной метки (например, из API Twitter) в удобное для пользователя относительное время (например, 2 секунды назад, неделю назад и т.д.).

Кто-нибудь хочет поделиться некоторыми из своих любимых методов (желательно, не используя плагины)?

4b9b3361

Ответ 1

Хорошо, это довольно легко, если вы не слишком озабочены точностью. Что не так с тривиальным методом?

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';   
    }
}

Рабочий пример здесь.

Вы можете настроить его, чтобы лучше обрабатывать особые значения (например, 1 day вместо 1 days), если это вас беспокоит.

Ответ 2

Вот точная мимика твиттера раз без плагинов:

  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/

Надеюсь, что это поможет.

Ответ 3

Тада! Timeago: http://timeago.yarp.com/

Ох подожди - без плагинов? Почему это тогда? Я думаю, вы могли бы открыть файл плагина и взломать его.

Ответ 4

Вдохновленный Diego Castillo awnser's и в timeago.js плагин, Для этого я написал свой собственный ванильный плагин.

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>

Ответ 5

Intl.RelativeTimeFormat - собственный API

В настоящее время (18 декабря) предложение стадии 3 и уже реализовано в Chrome 71

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

const millisecondsPerDay = 24 * 60 * 60 * 1000;

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

Ответ 6

Для всех, кого это интересует, я создал для этого помощника Handlebars. Использование:

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

Helper:

    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] +  ago';
                    else if (intervals[key] === 1) 
                        return intervals[key] + ' ' + times[key] + ' ago';
                }

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

Ответ 7

Плагины Datetime существуют, потому что это очень сложно сделать правильно. Этот видео, объясняющий несоответствия в отношении даты и времени, прояснит проблему.

Все вышеперечисленные решения без плагинов неверны.

Для работы с датами и временем с использованием плагина предпочтительнее. Из сотен плагинов, которые с ним связаны, мы используем Moment.js и выполняем эту работу.

Из twitter API dcumentation мы можем видеть их формат timestamp:

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

Мы можем проанализировать его с помощью 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');

Чтобы указать предпочтительную единицу времени для diff, мы можем использовать метод isSame. например:

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

В целом, создадим что-то вроде:

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

Обратитесь к документации по плагину для расчета относительного времени (т.е.: "Как давно?" ).

Ответ 8

Существует также sugar.js и relative для этой цели.

relative - выводит строку в единицах относительно текущей даты ( "назад" или "сейчас" ).

Ответ 9

Если вам нужен многоязычный язык и вы не хотите добавлять большую библиотеку, как момент. intl -lativeformat от Yahoo это хорошее решение.

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"

Ответ 10

Для этой цели можно использовать машинное время-дата. Это легко и понятно с помощью определенного API.

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
});

Ответ 11

Для пользователей Moment.js он имеет функцию fromNow(), которая возвращает "x days" или "x hours ago" из текущей даты/времени.

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