Javascript时间戳到相对时间(例如2秒前,一周前等),最佳方法?

wil*_*age 59 javascript time datetime relative-date

我正在寻找一个很好的JS片段来将时间戳(例如从Twitter API)转换为友好的用户友好相对时间(例如2秒前,一周前等).

有人愿意分享一些他们喜欢的方法(最好不要使用插件)吗?

fea*_*net 111

如果你不过分关注准确性,这很容易.这个琐碎的方法有什么问题?

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';   
    }
}
Run Code Online (Sandbox Code Playgroud)

这里的工作示例.

您可能想要调整它以更好地处理奇异值(例如,1 day而不是1 days),如果这困扰你.

  • 我注意到,由于四舍五入,这有一个小怪癖,例如,如果小于 24 小时,但更接近 24 而不是 23,它会说“24 小时前”而不是“1 天前”。而不是 Math.round 应该可以解决问题。 (3认同)

Tim*_*eev 22

这里是没有插件的twitter时间的精确模仿:

  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;
    }
  }
Run Code Online (Sandbox Code Playgroud)

要点https://gist.github.com/timuric/11386129

小提琴http://jsfiddle.net/qE8Lu/1/

希望能帮助到你.

  • 这不应该是一个答案。你的脚本输出“9 Sep 2001”,他要求的是“XX分钟/秒/小时/天”前 (3认同)

Use*_*ebo 11

Typescript 和 Intl.RelativeTimeFormat (2020)

使用 Web APIrelativeTimeFormat组合Typescript实现 @vsync 和 @kigiri 方法。

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

/**
 * Get language-sensitive relative time message from Dates.
 * @param relative  - the relative dateTime, generally is in the past or future
 * @param pivot     - the dateTime of reference, generally is the current time
 */
export function relativeTimeFromDates(relative: Date | null, pivot: Date = new Date()): string {
    if (!relative) return "";
    const elapsed = relative.getTime() - pivot.getTime();
    return relativeTimeFromElapsed(elapsed);
}

/**
 * Get language-sensitive relative time message from elapsed time.
 * @param elapsed   - the elapsed time in milliseconds
 */
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 "";
}
Run Code Online (Sandbox Code Playgroud)


vsy*_*ync 8

Intl.RelativeTimeFormat - Native API

Currently (Dec' 18) a Stage 3 proposal, and already implemented in 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])  ));
Run Code Online (Sandbox Code Playgroud)

Intl.RelativeTimeFormat is available by default in V8 v7.1.179 and Chrome 71. As this API becomes more widely available, you’ll find libraries such as Moment.js, Globalize, and date-fns dropping their dependency on hardcoded CLDR databases in favor of the native relative time formatting functionality, thereby improving load-time performance, parse- and compile-time performance, run-time performance, and memory usage.

  • @Dayd-用** days **的示例更新了答案,但如果要以可靠的方式比较日期,则必须首先创建两个日期之间的比较方法,并了解边距是否以“小时”,“天”为单位`,`years`等。然后,就像将结果传递给Intl.RelativeTimeFormat`方法一样简单。您要问的是一个完全不同的话题 (2认同)

Jam*_*ack 5

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

哦,坚持 - 没有插件?那为什么呢?我想你可以打开插件文件并破解其中的内容.


Cai*_*ifa 5

Diego Castillo遮篷timeago.js插件的启发下,我为此编写了自己的香草插件。

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

timeElement.innerText = TimeAgo.inWords(time.getTime());
Run Code Online (Sandbox Code Playgroud)

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());
Run Code Online (Sandbox Code Playgroud)
<time datetime="2016-06-13"></time>
Run Code Online (Sandbox Code Playgroud)


kig*_*iri 5

const units = [
  ['year', 31536000000],
  ['month', 2628000000],
  ['day', 86400000],
  ['hour', 3600000],
  ['minute', 60000],
  ['second', 1000],
]

const rtf = new Intl.RelativeTimeFormat('en', { style:'narrow'})
const relatime = elapsed => {
  for (const [unit, amount] of units) {
    if (Math.abs(elapsed) > amount || unit === 'second') {
      return rtf.format(Math.round(elapsed/amount), unit)
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

打高尔夫球玩得很开心192b呵呵

const relatime = e=>{for(let[u,a]of Object.entries({year:31536e6,month:2628e6,day:864e5,hour:36e5,minute:6e4,second:1e3})){if(Math.abs(e)>a||a===1e3){return new Intl.RelativeTimeFormat('en',{style:'narrow'}).format(~~(e/a),u)}}}
Run Code Online (Sandbox Code Playgroud)

我还在打高尔夫球时测试了一个功能版本:

const rtf = new Intl.RelativeTimeFormat('en', { style:'narrow'})
const relatime = Object.entries({year:31536e6,month:2628e6,day:864e5,hour:36e5,minute:6e4,second:1e3})
  .reduce((f, [unit, amount]) => amount === 1e3
    ? f(elapsed => rtf.format(Math.round(elapsed/amount), unit))
    : next => f(e => Math.abs(e) < amount
      ? next(elapsed)
      : rtf.format(Math.round(elapsed/amount), unit)), _=>_)
Run Code Online (Sandbox Code Playgroud)

好吧,我现在真的得回去工作了……

  • 这可能是编写尽可能短的代码的一个有趣的练习,但任何阅读本文的人都应该避免复制粘贴这个答案;这不是可维护的代码。 (2认同)