web-dev-qa-db-ja.com

相対時間(2秒前、1週間前など)に対するJavascriptタイムスタンプ、最良の方法

タイムスタンプ(たとえば、Twitter APIから)をユーザーにとって使いやすい相対時間(たとえば、2秒前、1週間前など)に変換するNice JSスニペットを探しています。

お気に入りのメソッドを共有したい人はいますか(プラグインを使用しないことが望ましい)。

57
wilsonpage

精度に過度に関心がなければ、それは非常に簡単です。些細な方法の何が問題になっていますか?

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)それが気になる場合。

102

以下は、プラグインを使用しない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;
    }
  }

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

フィドル http://jsfiddle.net/qE8Lu/1/

それが役に立てば幸い。

20
Timur Carpeev

Intl.RelativeTimeFormat -ネイティブAPI

現在(Dec '18)a Stage 3 Proposal 、および既に実装済み 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])  ));

Intl.RelativeTimeFormatは、デフォルトでV8 v7.1.179および=で利用可能ですChrome71。このAPIがより広く利用可能になると、 Momentなどのライブラリが見つかります。 .jsGlobalize 、および date-fns ネイティブの相対時間フォーマット機能を優先して、ハードコーディングされたCLDRデータベースへの依存関係を削除、それにより、ロード時のパフォーマンス、解析時とコンパイル時のパフォーマンス、実行時のパフォーマンス、およびメモリ使用量が向上します。

6
vsync

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

ちょっと待って-プラグインなしで?それはなぜですか?プラグインファイルを開いて、その中身をハックできると思います。

5
James McCormack

Diego Castillo awnser'stimeago.js プラグインに触発され、私はこのために独自のVanillaプラグインを作成しました。

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
Caio Tarifa

多言語が必要で、瞬間のような大きなライブラリを追加したくない場合。 intl-relativeformat 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"
1
abumalick

日時プラグインが存在するのは、正しくするのが非常に難しいためです。この 日付と時刻の不一致を説明するビデオ は、この問題を明らかにします。

プラグインなしの上記のソリューションはすべて間違っています。

日付と時刻を操作するには、プラグインを使用することをお勧めします。それを処理する数百のプラグインのうち、 Moment.js を使用し、ジョブを実行しています。

Twitter APIドキュメント から、タイムスタンプ形式を確認できます。

"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`;

相対時間(つまり、「どのくらい前ですか?」)計算の処理については、プラグインのドキュメントを参照してください。

1
Art Knipe

興味がある人のために、私はこれを行うためにHandlebarsヘルパーを作成することになりました。使用法:

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

ヘルパー:

    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

この目的のための sugar.js および relative 関数もあります。

relative-現在の日付(「ago」または「from now」)に相対的な単位で文字列を出力します。

1
user8171823

Moment.jsユーザーの場合、現在の日付/時刻から「x日」または「x時間前」を返すfromNow()関数があります。

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

この目的のためにmachinepack-datetimeを使用できます。定義された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
});
0
Piyush P