Tutorial :How to format time since xxx e.g. “4 minutes ago” similar to Stack Exchange sites



Question:

The question is how to format a JavaScript Date as a string stating the time elapsed similar to the way you see times displayed on Stack Overflow.

e.g.

  • 1 minute ago
  • 1 hour ago
  • 1 day ago
  • 1 month ago
  • 1 year ago


Solution:1

function timeSince(date) {      var seconds = Math.floor((new Date() - date) / 1000);      var interval = Math.floor(seconds / 31536000);      if (interval > 1) {      return interval + " years";    }    interval = Math.floor(seconds / 2592000);    if (interval > 1) {      return interval + " months";    }    interval = Math.floor(seconds / 86400);    if (interval > 1) {      return interval + " days";    }    interval = Math.floor(seconds / 3600);    if (interval > 1) {      return interval + " hours";    }    interval = Math.floor(seconds / 60);    if (interval > 1) {      return interval + " minutes";    }    return Math.floor(seconds) + " seconds";  }  var aDay = 24*60*60*1000  console.log(timeSince(new Date(Date.now()-aDay)));  console.log(timeSince(new Date(Date.now()-aDay*2)));


Solution:2

Might be an overkill in this case, but if the opportunity shows moment.js is just awesome!

Moment.js is a javascript datetime library, to use it for such scenario, you'd do:

moment(yourdate).fromNow()  

http://momentjs.com/docs/#/displaying/fromnow/

2018 addendum: Luxon is a new modern library and might be worth a look!


Solution:3

I haven't checked (although it wouldn't be hard to), but I think that Stack Exchange sites use the jquery.timeago plugin to create these time strings.


It's quite easy to use the plugin, and it's clean and updates automatically.

Here's a quick sample (from the plugin's home page):

First, load jQuery and the plugin:

<script src="jquery.min.js" type="text/javascript"></script> <script src="jquery.timeago.js" type="text/javascript"></script>

Now, let's attach it to your timestamps on DOM ready:

jQuery(document).ready(function() {
jQuery("abbr.timeago").timeago(); });

This will turn all abbr elements with a class of timeago and an ISO 8601 timestamp in the title: <abbr class="timeago" title="2008-07-17T09:24:17Z">July 17, 2008</abbr> into something like this: <abbr class="timeago" title="July 17, 2008">about a year ago</abbr> which yields: about a year ago. As time passes, the timestamps will automatically update.


Solution:4

This will show you past and previous time formats like '2 days ago' '10 minutes from now' and you can pass it either a Date object, a numeric timestamp or a date string

function time_ago(time) {      switch (typeof time) {      case 'number':        break;      case 'string':        time = +new Date(time);        break;      case 'object':        if (time.constructor === Date) time = time.getTime();        break;      default:        time = +new Date();    }    var time_formats = [      [60, 'seconds', 1], // 60      [120, '1 minute ago', '1 minute from now'], // 60*2      [3600, 'minutes', 60], // 60*60, 60      [7200, '1 hour ago', '1 hour from now'], // 60*60*2      [86400, 'hours', 3600], // 60*60*24, 60*60      [172800, 'Yesterday', 'Tomorrow'], // 60*60*24*2      [604800, 'days', 86400], // 60*60*24*7, 60*60*24      [1209600, 'Last week', 'Next week'], // 60*60*24*7*4*2      [2419200, 'weeks', 604800], // 60*60*24*7*4, 60*60*24*7      [4838400, 'Last month', 'Next month'], // 60*60*24*7*4*2      [29030400, 'months', 2419200], // 60*60*24*7*4*12, 60*60*24*7*4      [58060800, 'Last year', 'Next year'], // 60*60*24*7*4*12*2      [2903040000, 'years', 29030400], // 60*60*24*7*4*12*100, 60*60*24*7*4*12      [5806080000, 'Last century', 'Next century'], // 60*60*24*7*4*12*100*2      [58060800000, 'centuries', 2903040000] // 60*60*24*7*4*12*100*20, 60*60*24*7*4*12*100    ];    var seconds = (+new Date() - time) / 1000,      token = 'ago',      list_choice = 1;      if (seconds == 0) {      return 'Just now'    }    if (seconds < 0) {      seconds = Math.abs(seconds);      token = 'from now';      list_choice = 2;    }    var i = 0,      format;    while (format = time_formats[i++])      if (seconds < format[0]) {        if (typeof format[2] == 'string')          return format[list_choice];        else          return Math.floor(seconds / format[2]) + ' ' + format[1] + ' ' + token;      }    return time;  }    var aDay = 24 * 60 * 60 * 1000;  console.log(time_ago(new Date(Date.now() - aDay)));  console.log(time_ago(new Date(Date.now() - aDay * 2)));


Solution:5

Here is a slight modification on Sky Sander's solution that allows the date to be input as a string and is capable of displaying spans like "1 minute" instead of "73 seconds"

var timeSince = function(date) {    if (typeof date !== 'object') {      date = new Date(date);    }      var seconds = Math.floor((new Date() - date) / 1000);    var intervalType;      var interval = Math.floor(seconds / 31536000);    if (interval >= 1) {      intervalType = 'year';    } else {      interval = Math.floor(seconds / 2592000);      if (interval >= 1) {        intervalType = 'month';      } else {        interval = Math.floor(seconds / 86400);        if (interval >= 1) {          intervalType = 'day';        } else {          interval = Math.floor(seconds / 3600);          if (interval >= 1) {            intervalType = "hour";          } else {            interval = Math.floor(seconds / 60);            if (interval >= 1) {              intervalType = "minute";            } else {              interval = seconds;              intervalType = "second";            }          }        }      }    }      if (interval > 1 || interval === 0) {      intervalType += 's';    }      return interval + ' ' + intervalType;  };  var aDay = 24 * 60 * 60 * 1000;  console.log(timeSince(new Date(Date.now() - aDay)));  console.log(timeSince(new Date(Date.now() - aDay * 2)));


Solution:6

You might want to look at humanized_time_span: https://github.com/layam/js_humanized_time_span

It's framework agnostic and fully customizable.

Just download / include the script and then you can do this:

humanized_time_span("2011-05-11 12:00:00")       => '3 hours ago'    humanized_time_span("2011-05-11 12:00:00", "2011-05-11 16:00:00)       => '4 hours ago'  

or even this:

var custom_date_formats = {    past: [      { ceiling: 60, text: "less than a minute ago" },      { ceiling: 86400, text: "$hours hours, $minutes minutes and $seconds seconds ago" },      { ceiling: null, text: "$years years ago" }    ],    future: [      { ceiling: 60, text: "in less than a minute" },      { ceiling: 86400, text: "in $hours hours, $minutes minutes and $seconds seconds time" },      { ceiling: null, text: "in $years years" }    ]  }    humanized_time_span("2010/09/10 10:00:00", "2010/09/10 10:00:05", custom_date_formats)     => "less than a minute ago"  

Read the docs for more info.


Solution:7

Changed the function above to

function timeSince(date) {        var seconds = Math.floor(((new Date().getTime()/1000) - date)),      interval = Math.floor(seconds / 31536000);        if (interval > 1) return interval + "y";        interval = Math.floor(seconds / 2592000);      if (interval > 1) return interval + "m";        interval = Math.floor(seconds / 86400);      if (interval >= 1) return interval + "d";        interval = Math.floor(seconds / 3600);      if (interval >= 1) return interval + "h";        interval = Math.floor(seconds / 60);      if (interval > 1) return interval + "m ";        return Math.floor(seconds) + "s";  }  

Otherwise it would show things like "75 minutes" (between 1 and 2 hours). It also now assumes input date is a Unix timestamp.


Solution:8

Much readable and cross browser compatible code:

As given by @Travis

var DURATION_IN_SECONDS = {    epochs: ['year', 'month', 'day', 'hour', 'minute'],    year: 31536000,    month: 2592000,    day: 86400,    hour: 3600,    minute: 60  };    function getDuration(seconds) {    var epoch, interval;      for (var i = 0; i < DURATION_IN_SECONDS.epochs.length; i++) {      epoch = DURATION_IN_SECONDS.epochs[i];      interval = Math.floor(seconds / DURATION_IN_SECONDS[epoch]);      if (interval >= 1) {        return {          interval: interval,          epoch: epoch        };      }    }    };    function timeSince(date) {    var seconds = Math.floor((new Date() - new Date(date)) / 1000);    var duration = getDuration(seconds);    var suffix = (duration.interval > 1 || duration.interval === 0) ? 's' : '';    return duration.interval + ' ' + duration.epoch + suffix;  };    alert(timeSince('2015-09-17T18:53:23'));


Solution:9

from now, unix timestamp param,

function timeSince(ts){      now = new Date();      ts = new Date(ts*1000);      var delta = now.getTime() - ts.getTime();        delta = delta/1000; //us to s        var ps, pm, ph, pd, min, hou, sec, days;        if(delta<=59){          ps = (delta>1) ? "s": "";          return delta+" second"+ps      }        if(delta>=60 && delta<=3599){          min = Math.floor(delta/60);          sec = delta-(min*60);          pm = (min>1) ? "s": "";          ps = (sec>1) ? "s": "";          return min+" minute"+pm+" "+sec+" second"+ps;      }        if(delta>=3600 && delta<=86399){          hou = Math.floor(delta/3600);          min = Math.floor((delta-(hou*3600))/60);          ph = (hou>1) ? "s": "";          pm = (min>1) ? "s": "";          return hou+" hour"+ph+" "+min+" minute"+pm;      }         if(delta>=86400){          days = Math.floor(delta/86400);          hou =  Math.floor((delta-(days*86400))/60/60);          pd = (days>1) ? "s": "";          ph = (hou>1) ? "s": "";          return days+" day"+pd+" "+hou+" hour"+ph;      }    }  


Solution:10

A shorter version as used by Lokely:

const intervals = [    { label: 'year', seconds: 31536000 },    { label: 'month', seconds: 2592000 },    { label: 'day', seconds: 86400 },    { label: 'hour', seconds: 3600 },    { label: 'minute', seconds: 60 },    { label: 'second', seconds: 0 }  ];    function timeSince(date) {    const seconds = Math.floor((Date.now() - date.getTime()) / 1000);    const interval = intervals.find(i => i.seconds < seconds);    const count = Math.floor(seconds / interval.seconds);    return `${count} ${interval.label}${count !== 1 ? 's' : ''} ago`;  }  


Solution:11

An ES6 version of the code provided by @user1012181

// Epochs  const epochs = [      ['year', 31536000],      ['month', 2592000],      ['day', 86400],      ['hour', 3600],      ['minute', 60],      ['second', 1]  ];      // Get duration  const getDuration = (timeAgoInSeconds) => {      for (let [name, seconds] of epochs) {          const interval = Math.floor(timeAgoInSeconds / seconds);            if (interval >= 1) {              return {                  interval: interval,                  epoch: name              };          }      }  };      // Calculate  const timeAgo = (date) => {      const timeAgoInSeconds = Math.floor((new Date() - new Date(date)) / 1000);      const {interval, epoch} = getDuration(timeAgoInSeconds);      const suffix = interval === 1 ? '' : 's';        return `${interval} ${epoch}${suffix} ago`;  };  

Edited with @ibe-vanmeenen suggestions. (Thanks !)


Solution:12

I write one with js and python, used in two projects, very nice and simple: a simple library (less then 2kb) used to format date with *** time ago statement.

simple, small, easy used, and well tested.

  1. npm install timeago.js

  2. import timeago from 'timeago.js'; // or use script tag

  3. use api format.

Sample:

var timeagoIns  = timeago();  timeagoIns .format('2016-06-12');  

Also you can render in real-time.

var timeagoIns = timeago();  timeagoIns.render(document.querySelectorAll('time'));  


Solution:13

Simple and readable version:

const NOW = new Date()  const times = [["second", 1], ["minute", 60], ["hour", 3600], ["day", 86400], ["week", 604800], ["month", 2592000], ["year", 31536000]]    function timeAgo(date) {      var diff = Math.round((NOW - date) / 1000)      for (var t = 0; t < times.length; t++) {          if (diff < times[t][1]) {              if (t == 0) {                  return "Just now"              } else {                  diff = Math.round(diff / times[t - 1][1])                  return diff + " " + times[t - 1][0] + (diff == 1?" ago":"s ago")              }          }      }  }  


Solution:14

I have modified Sky Sanders' version. The Math.floor(...) operations are evaluated in the if block

       var timeSince = function(date) {              var seconds = Math.floor((new Date() - date) / 1000);              var months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];              if (seconds < 5){                  return "just now";              }else if (seconds < 60){                  return seconds + " seconds ago";              }              else if (seconds < 3600) {                  minutes = Math.floor(seconds/60)                  if(minutes > 1)                      return minutes + " minutes ago";                  else                      return "1 minute ago";              }              else if (seconds < 86400) {                  hours = Math.floor(seconds/3600)                  if(hours > 1)                      return hours + " hours ago";                  else                      return "1 hour ago";              }              //2 days and no more              else if (seconds < 172800) {                  days = Math.floor(seconds/86400)                  if(days > 1)                      return days + " days ago";                  else                      return "1 day ago";              }              else{                    //return new Date(time).toLocaleDateString();                  return date.getDate().toString() + " " + months[date.getMonth()] + ", " + date.getFullYear();              }          }  


Solution:15

function timeago(date) {      var seconds = Math.floor((new Date() - date) / 1000);      if(Math.round(seconds/(60*60*24*365.25)) >= 2) return Math.round(seconds/(60*60*24*365.25)) + " years ago";      else if(Math.round(seconds/(60*60*24*365.25)) >= 1) return "1 year ago";      else if(Math.round(seconds/(60*60*24*30.4)) >= 2) return Math.round(seconds/(60*60*24*30.4)) + " months ago";      else if(Math.round(seconds/(60*60*24*30.4)) >= 1) return "1 month ago";      else if(Math.round(seconds/(60*60*24*7)) >= 2) return Math.round(seconds/(60*60*24*7)) + " weeks ago";      else if(Math.round(seconds/(60*60*24*7)) >= 1) return "1 week ago";      else if(Math.round(seconds/(60*60*24)) >= 2) return Math.round(seconds/(60*60*24)) + " days ago";      else if(Math.round(seconds/(60*60*24)) >= 1) return "1 day ago";      else if(Math.round(seconds/(60*60)) >= 2) return Math.round(seconds/(60*60)) + " hours ago";      else if(Math.round(seconds/(60*60)) >= 1) return "1 hour ago";      else if(Math.round(seconds/60) >= 2) return Math.round(seconds/60) + " minutes ago";      else if(Math.round(seconds/60) >= 1) return "1 minute ago";      else if(seconds >= 2)return seconds + " seconds ago";      else return seconds + "1 second ago";  }  


Solution:16

Although the question was asked quite long time ago, writing this answer with hope it will help somebody.

Pass the date you want to start to count from. Using moment().fromNow() of momentjs: (See more information here)

getRelativeTime(date) {      const d = new Date(date * 1000);      return moment(d).fromNow();  }  

If you want to change information provided for dates fromNow you write your custom relative time for moment.

For example, in my own case I wanted to print 'one month ago' instead of 'a month ago' (provided by moment(d).fromNow()). In this case, you can write something given below.

moment.updateLocale('en', {      relativeTime: {          future: 'in %s',          past: '%s ago',          s: 'a few seconds',          ss: '%d seconds',          m: '1 m',          mm: '%d minutes',          h: '1 h',          hh: '%d hours',          d: '1 d',          dd: '%d days',          M: '1 month',          MM: '%d months',          y: '1 y',          yy: '%d years'      }  });  

NOTE: I wrote my code for project in Agular 6


Solution:17

I was looking for an answer to this and almost implemented one of these solutions, but a colleague reminded me to check the react-intl library since we were already using it.

So adding to the solutions...in the case you are using the react-intl library, they have a <FormattedRelative> component for this.

https://github.com/yahoo/react-intl/wiki/Components#formattedrelative


Solution:18

Here's what I did (the object returns the unit of time along with its value):

function timeSince(post_date, reference)  {  	var reference = reference ? new Date(reference) : new Date(),  		diff = reference - new Date(post_date + ' GMT-0000'),  		date = new Date(diff),  		object = { unit: null, value: null };  	  	if (diff < 86400000)  	{  		var secs  = date.getSeconds(),  			mins  = date.getMinutes(),  			hours = date.getHours(),  			array = [ ['second', secs], ['minute', mins], ['hour', hours] ];  	}  	else  	{  		var days   = date.getDate(),  			weeks  = Math.floor(days / 7),  			months = date.getMonth(),  			years  = date.getFullYear() - 1970,  			array  = [ ['day', days], ['week', weeks], ['month', months], ['year', years] ];  	}    	for (var i = 0; i < array.length; i++)  	{  		array[i][0] += array[i][1] != 1 ? 's' : '';    		object.unit  = array[i][1] >= 1 ? array[i][0] : object.unit;  		object.value = array[i][1] >= 1 ? array[i][1] : object.value;  	}    	return object;  }


Solution:19

My solution..

(function(global){              const SECOND   = 1;              const MINUTE   = 60;              const HOUR     = 3600;              const DAY      = 86400;              const MONTH    = 2629746;              const YEAR     = 31556952;              const DECADE   = 315569520;                global.timeAgo = function(date){                  var now = new Date();                  var diff = Math.round(( now - date ) / 1000);                    var unit = '';                  var num = 0;                  var plural = false;                    switch(true){                      case diff <= 0:                          return 'just now';                      break;                        case diff < MINUTE:                          num = Math.round(diff / SECOND);                          unit = 'sec';                          plural = num > 1;                      break;                        case diff < HOUR:                          num = Math.round(diff / MINUTE);                          unit = 'min';                          plural = num > 1;                      break;                        case diff < DAY:                          num = Math.round(diff / HOUR);                          unit = 'hour';                          plural = num > 1;                      break;                        case diff < MONTH:                          num = Math.round(diff / DAY);                          unit = 'day';                          plural = num > 1;                      break;                        case diff < YEAR:                          num = Math.round(diff / MONTH);                          unit = 'month';                          plural = num > 1;                      break;                        case diff < DECADE:                          num = Math.round(diff / YEAR);                          unit = 'year';                          plural = num > 1;                      break;                        default:                          num = Math.round(diff / YEAR);                          unit = 'year';                          plural = num > 1;                  }                    var str = '';                  if(num){                      str += `${num} `;                  }                    str += `${unit}`;                    if(plural){                      str += 's';                  }                    str += ' ago';                    return str;              }          })(window);            console.log(timeAgo(new Date()));          console.log(timeAgo(new Date('Jun 03 2018 15:12:19 GMT+0300 (FLE Daylight Time)')));          console.log(timeAgo(new Date('Jun 03 2018 13:12:19 GMT+0300 (FLE Daylight Time)')));          console.log(timeAgo(new Date('May 28 2018 13:12:19 GMT+0300 (FLE Daylight Time)')));          console.log(timeAgo(new Date('May 28 2017 13:12:19 GMT+0300 (FLE Daylight Time)')));          console.log(timeAgo(new Date('May 28 2000 13:12:19 GMT+0300 (FLE Daylight Time)')));          console.log(timeAgo(new Date('Sep 10 1994 13:12:19 GMT+0300 (FLE Daylight Time)')));  

Note:If u also have question or solution just comment us below or mail us on toontricks1994@gmail.com
Previous
Next Post »