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

JavascriptDate Formatting

Javascript Problem Overview


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

Javascript Solutions


Solution 1 - Javascript

function timeSince(date) {

  var seconds = Math.floor((new Date() - date) / 1000);

  var interval = seconds / 31536000;

  if (interval > 1) {
    return Math.floor(interval) + " years";
  }
  interval = seconds / 2592000;
  if (interval > 1) {
    return Math.floor(interval) + " months";
  }
  interval = seconds / 86400;
  if (interval > 1) {
    return Math.floor(interval) + " days";
  }
  interval = seconds / 3600;
  if (interval > 1) {
    return Math.floor(interval) + " hours";
  }
  interval = seconds / 60;
  if (interval > 1) {
    return Math.floor(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 - Javascript

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 - Javascript

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 4 - Javascript

I haven't checked (although it wouldn't be hard to), but I think that Stack Exchange sites use the [jquery.timeago plugin][1] 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.

[1]: http://timeago.yarp.com/ "jquery.timeago"

Solution 5 - Javascript

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 - Javascript

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: 1 }
];

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 7 - Javascript

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 8 - Javascript

An ES6 version of the code provided by @user1012181:

const epochs = [
    ['year', 31536000],
    ['month', 2592000],
    ['day', 86400],
    ['hour', 3600],
    ['minute', 60],
    ['second', 1]
];

const getDuration = (timeAgoInSeconds) => {
    for (let [name, seconds] of epochs) {
        const interval = Math.floor(timeAgoInSeconds / seconds);
        if (interval >= 1) {
            return {
                interval: interval,
                epoch: name
            };
        }
    }
};

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 9 - Javascript

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 10 - Javascript

So here is my version, it works both with dates in the past and in the future. It uses the Intl.RelativeTimeFormat to provide localized strings, instead of hardcoded strings. You can pass dates as timestamps, Date objects or parseable date strings.

/**
 * Human readable elapsed or remaining time (example: 3 minutes ago)
 * @param  {Date|Number|String} date A Date object, timestamp or string parsable with Date.parse()
 * @param  {Date|Number|String} [nowDate] A Date object, timestamp or string parsable with Date.parse()
 * @param  {Intl.RelativeTimeFormat} [trf] A Intl formater
 * @return {string} Human readable elapsed or remaining time
 * @author github.com/victornpb
 * @see https://stackoverflow.com/a/67338038/938822
 */
function fromNow(date, nowDate = Date.now(), rft = new Intl.RelativeTimeFormat(undefined, { numeric: "auto" })) {
    const SECOND = 1000;
    const MINUTE = 60 * SECOND;
    const HOUR = 60 * MINUTE;
    const DAY = 24 * HOUR;
    const WEEK = 7 * DAY;
    const MONTH = 30 * DAY;
    const YEAR = 365 * DAY;
    const intervals = [
        { ge: YEAR, divisor: YEAR, unit: 'year' },
        { ge: MONTH, divisor: MONTH, unit: 'month' },
        { ge: WEEK, divisor: WEEK, unit: 'week' },
        { ge: DAY, divisor: DAY, unit: 'day' },
        { ge: HOUR, divisor: HOUR, unit: 'hour' },
        { ge: MINUTE, divisor: MINUTE, unit: 'minute' },
        { ge: 30 * SECOND, divisor: SECOND, unit: 'seconds' },
        { ge: 0, divisor: 1, text: 'just now' },
    ];
    const now = typeof nowDate === 'object' ? nowDate.getTime() : new Date(nowDate).getTime();
    const diff = now - (typeof date === 'object' ? date : new Date(date)).getTime();
    const diffAbs = Math.abs(diff);
    for (const interval of intervals) {
        if (diffAbs >= interval.ge) {
            const x = Math.round(Math.abs(diff) / interval.divisor);
            const isFuture = diff < 0;
            return interval.unit ? rft.format(isFuture ? x : -x, interval.unit) : interval.text;
        }
    }
}

// examples
fromNow('2020-01-01') // 9 months ago
fromNow(161651684156) // 4 days ago
fromNow(new Date()-1) // just now
fromNow(30000 + Date.now()) // in 30 seconds
fromNow(Date.now() + (1000*60*60*24)) // in 1 day
fromNow(new Date('2029-12-01Z00:00:00.000')) // in 9 years

Alternative that doesn't use Intl.RelativeTimeFormat

/**
 * Human readable elapsed or remaining time (example: 3 minutes ago)
 * @param  {Date|Number|String} date A Date object, timestamp or string parsable with Date.parse()
 * @return {string} Human readable elapsed or remaining time
 * @author github.com/victornpb
 * @see https://stackoverflow.com/a/67338038/938822
 */
function fromNow(date) {
    const SECOND = 1000;
    const MINUTE = 60 * SECOND;
    const HOUR = 60 * MINUTE;
    const DAY = 24 * HOUR;
    const WEEK = 7 * DAY;
    const MONTH = 30 * DAY;
    const YEAR = 365 * DAY;
    const units = [
        { max: 30 * SECOND, divisor: 1, past1: 'just now', pastN: 'just now', future1: 'just now', futureN: 'just now' },
        { max: MINUTE, divisor: SECOND, past1: 'a second ago', pastN: '# seconds ago', future1: 'in a second', futureN: 'in # seconds' },
        { max: HOUR, divisor: MINUTE, past1: 'a minute ago', pastN: '# minutes ago', future1: 'in a minute', futureN: 'in # minutes' },
        { max: DAY, divisor: HOUR, past1: 'an hour ago', pastN: '# hours ago', future1: 'in an hour', futureN: 'in # hours' },
        { max: WEEK, divisor: DAY, past1: 'yesterday', pastN: '# days ago', future1: 'tomorrow', futureN: 'in # days' },
        { max: 4 * WEEK, divisor: WEEK, past1: 'last week', pastN: '# weeks ago', future1: 'in a week', futureN: 'in # weeks' },
        { max: YEAR, divisor: MONTH, past1: 'last month', pastN: '# months ago', future1: 'in a month', futureN: 'in # months' },
        { max: 100 * YEAR, divisor: YEAR, past1: 'last year', pastN: '# years ago', future1: 'in a year', futureN: 'in # years' },
        { max: 1000 * YEAR, divisor: 100 * YEAR, past1: 'last century', pastN: '# centuries ago', future1: 'in a century', futureN: 'in # centuries' },
        { max: Infinity, divisor: 1000 * YEAR, past1: 'last millennium', pastN: '# millennia ago', future1: 'in a millennium', futureN: 'in # millennia' },
    ];
    const diff = Date.now() - (typeof date === 'object' ? date : new Date(date)).getTime();
    const diffAbs = Math.abs(diff);
    for (const unit of units) {
        if (diffAbs < unit.max) {
            const isFuture = diff < 0;
            const x = Math.round(Math.abs(diff) / unit.divisor);
            if (x <= 1) return isFuture ? unit.future1 : unit.past1;
            return (isFuture ? unit.futureN : unit.pastN).replace('#', x);
        }
    }
};

Solution 11 - Javascript

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 12 - Javascript

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 13 - Javascript

This should properly handle any valid timestamp, including Date.now(), singular units, and future dates. I left out months, but those should be easy to add in. I tried to keep it readable as possible.

function getTimeInterval(date) {
  let seconds = Math.floor((Date.now() - date) / 1000);
  let unit = "second";
  let direction = "ago";
  if (seconds < 0) {
    seconds = -seconds;
    direction = "from now";
  }
  let value = seconds;
  if (seconds >= 31536000) {
    value = Math.floor(seconds / 31536000);
    unit = "year";
  } else if (seconds >= 86400) {
    value = Math.floor(seconds / 86400);
    unit = "day";
  } else if (seconds >= 3600) {
    value = Math.floor(seconds / 3600);
    unit = "hour";
  } else if (seconds >= 60) {
    value = Math.floor(seconds / 60);
    unit = "minute";
  }
  if (value != 1)
    unit = unit + "s";
  return value + " " + unit + " " + direction;
}

console.log(getTimeInterval(Date.now())); // 0 seconds ago
console.log(getTimeInterval(Date.now() + 1000)); // 1 second from now
console.log(getTimeInterval(Date.now() - 1000)); // 1 second ago
console.log(getTimeInterval(Date.now() + 60000)); // 1 minute from now
console.log(getTimeInterval(Date.now() - 120000)); // 2 minutes ago
console.log(getTimeInterval(Date.now() + 120000)); // 2 minutes from now
console.log(getTimeInterval(Date.now() + 3600000)); // 1 hour from now
console.log(getTimeInterval(Date.now() + 360000000000)); // 11 years from now
console.log(getTimeInterval(0)); // 49 years ago

Solution 14 - Javascript

Yet another take on Intl.RelativeTimeFormat

  • Supports both past and future dates
  • Accepts both String and Date
  • Custom ranges are easy to add (edit ranges)
  • Can be easily translated Intl.RelativeTimeFormat('ua')

console.log(timeAgo('2021-08-09T15:29:01+0000'));

function timeAgo(input) {
  const date = (input instanceof Date) ? input : new Date(input);
  const formatter = new Intl.RelativeTimeFormat('en');
  const ranges = {
    years: 3600 * 24 * 365,
    months: 3600 * 24 * 30,
    weeks: 3600 * 24 * 7,
    days: 3600 * 24,
    hours: 3600,
    minutes: 60,
    seconds: 1
  };
  const secondsElapsed = (date.getTime() - Date.now()) / 1000;
  for (let key in ranges) {
    if (ranges[key] < Math.abs(secondsElapsed)) {
      const delta = secondsElapsed / ranges[key];
      return formatter.format(Math.round(delta), key);
    }
  }
}

https://jsfiddle.net/tv9701uf

Solution 15 - Javascript

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 Angular 6

Solution 16 - Javascript

Can also use the dayjs relativeTime plugin to solve this.

import * as dayjs from 'dayjs';
import * as relativeTime from 'dayjs/plugin/relativeTime';

dayjs.extend(relativeTime);
dayjs(dayjs('1990')).fromNow(); // x years ago

Solution 17 - Javascript

Simple and readable version:

const relativeTimePeriods = [
	[31536000, 'year'],
	[2419200, 'month'],
	[604800, 'week'],
	[86400, 'day'],
	[3600, 'hour'],
	[60, 'minute'],
	[1, 'second']
];

function relativeTime(date, isUtc=true) {
	if (!(date instanceof Date)) date = new Date(date * 1000);
	const seconds = (new Date() - date) / 1000;
	for (let [secondsPer, name] of relativeTimePeriods) {
		if (seconds >= secondsPer) {
			const amount = Math.floor(seconds / secondsPer);
			return `${amount} ${name}${amount ? 's' : ''}s ago`;
		}
	}
	return 'Just now';
}

Solution 18 - Javascript

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 19 - Javascript

function dateToHowManyAgo(stringDate){
	var currDate = new Date();
  	var diffMs=currDate.getTime() - new Date(stringDate).getTime();
  	var sec=diffMs/1000;
 	if(sec<60)
    	return parseInt(sec)+' second'+(parseInt(sec)>1?'s':'')+' ago';
	var min=sec/60;
	if(min<60)
	    return parseInt(min)+' minute'+(parseInt(min)>1?'s':'')+' ago';
	var h=min/60;
	if(h<24)
	    return parseInt(h)+' hour'+(parseInt(h)>1?'s':'')+' ago';
	var d=h/24;
	if(d<30)
	    return parseInt(d)+' day'+(parseInt(d)>1?'s':'')+' ago';
	var m=d/30;
	if(m<12)
	    return parseInt(m)+' month'+(parseInt(m)>1?'s':'')+' ago';
	var y=m/12;
	return parseInt(y)+' year'+(parseInt(y)>1?'s':'')+' ago';
}
console.log(dateToHowManyAgo('2019-11-07 19:17:06'));

Solution 20 - Javascript

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 21 - Javascript

My stab at this based on other answers.

function timeSince(date) {
    let minute = 60;
    let hour   = minute * 60;
    let day    = hour   * 24;
    let month  = day    * 30;
    let year   = day    * 365;

    let suffix = ' ago';

    let elapsed = Math.floor((Date.now() - date) / 1000);

    if (elapsed < minute) {
        return 'just now';
    }

    // get an array in the form of [number, string]
    let a = elapsed < hour  && [Math.floor(elapsed / minute), 'minute'] ||
            elapsed < day   && [Math.floor(elapsed / hour), 'hour']     ||
            elapsed < month && [Math.floor(elapsed / day), 'day']       ||
            elapsed < year  && [Math.floor(elapsed / month), 'month']   ||
            [Math.floor(elapsed / year), 'year'];

    // pluralise and append suffix
    return a[0] + ' ' + a[1] + (a[0] === 1 ? '' : 's') + suffix;
}

Solution 22 - Javascript

Answering 10 years old question to help the newcomers.

We can use this package for that javascript-time-ago

 
// Load locale-specific relative date/time formatting rules.
import en from 'javascript-time-ago/locale/en'
 
// Add locale-specific relative date/time formatting rules.
TimeAgo.addLocale(en)
 
// Create relative date/time formatter.
const timeAgo = new TimeAgo('en-US')
 
timeAgo.format(new Date())
// "just now"
 
timeAgo.format(Date.now() - 60 * 1000)
// "a minute ago"
 
timeAgo.format(Date.now() - 2 * 60 * 60 * 1000)
// "2 hours ago"
 
timeAgo.format(Date.now() - 24 * 60 * 60 * 1000)
// "a day ago"

Solution 23 - Javascript

const createdAt = moment(created_at).fromNow()

and a customized solution


        const duration = moment.duration(moment().diff(moment(created_at)))
        const createdAt = duration.as('week') >= 1
          ? `${Math.floor(duration.as('week'))} week(s)`
          : duration.as('day') >= 1
            ? `${Math.floor(duration.as('day'))} day(s)`
            : duration.as('hour') >= 1
              ? `${Math.floor(duration.as('hour'))} hour(s)`
              : `${Math.floor(duration.as('minute'))} minute(s)`

Solution 24 - Javascript

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 25 - Javascript

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

Solution 26 - Javascript

 I achieve this by following method

   timeAgo = (date) => {
            var ms = (new Date()).getTime() - date.getTime();
            var seconds = Math.floor(ms / 1000);
            var minutes = Math.floor(seconds / 60);
        var hours = Math.floor(minutes / 60);
        var days = Math.floor(hours / 24);
        var months = Math.floor(days / 30);
        var years = Math.floor(months / 12);
    
        if (ms === 0) {
            return 'Just now';
        } if (seconds < 60) {
            return seconds + ' seconds Ago';
        } if (minutes < 60) {
            return minutes + ' minutes Ago';
        } if (hours < 24) {
            return hours + ' hours Ago';
        } if (days < 30) {
            return days + ' days Ago';
        } if (months < 12) {
            return months + ' months Ago';
        } else {
            return years + ' years Ago';
        }
    
    }
    
        console.log(timeAgo(new Date()));
        console.log(timeAgo(new Date('Jun 27 2020 10:12:19')));
        console.log(timeAgo(new Date('Jun 27 2020 00:12:19')));
        console.log(timeAgo(new Date('May 28 2020 13:12:19')));
        console.log(timeAgo(new Date('May 28 2017 13:12:19')));

Solution 27 - Javascript

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 28 - Javascript

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 29 - Javascript

Here is a bit simplified version of @sky-sanders answer.

function timeSince(date) {

  var seconds = Math.floor((new Date() - date) / 1000);
  var divisors = [31536000, 2592000, 86400, 3600, 60, 1]
  var description = ["years", "months", "days", "hours", "minutes", "seconds"]
  var result = [];

  var interval = seconds;

  for (i = 0; i < divisors.length; i++) {
    interval = Math.floor(seconds / divisors[i])
    if (interval > 1) {
      result.push(interval + " " + description[i])
    }
    seconds -= interval * divisors[i]
  }

  return result.join(" ")
}

Solution 30 - Javascript

function calDateAgo(dString=null){
    //var dString = "2021-04-1 12:00:00";
     
    var d1 = new Date(dString);
    var d2 = new Date();
    var t2 = d2.getTime();
    var t1 = d1.getTime();
    var d1Y = d1.getFullYear();
    var d2Y = d2.getFullYear();
    var d1M = d1.getMonth();
    var d2M = d2.getMonth();
     
    var time_obj = {};
    time_obj.year = d2.getFullYear()-d1.getFullYear();
    time_obj.month = (d2M+12*d2Y)-(d1M+12*d1Y);
    time_obj.week = parseInt((t2-t1)/(24*3600*1000*7));
    time_obj.day = parseInt((t2-t1)/(24*3600*1000));
    time_obj.hour = parseInt((t2-t1)/(3600*1000));
    time_obj.minute = parseInt((t2-t1)/(60*1000));
    time_obj.second = parseInt((t2-t1)/(1000));

    for (const obj_key in time_obj) {
        if(time_obj[obj_key] == 0){
            delete time_obj[obj_key];
        }
    }
    var ago_text = 'just now';

    if(typeof Object.keys(time_obj)[0] != 'undefined'){
        var time_key = Object.keys(time_obj)[0];
        var time_val = time_obj[Object.keys(time_obj)[0]];
        time_key += (time_val > 1) ? 's':'';
        ago_text = time_val+' '+time_key+' ago'; 
    }
    
    return ago_text;
}

Solution 31 - Javascript

function mdiv(dividend, divisor) {
    return [ Math.floor(dividend/divisor), dividend % divisor ];
}
// pass in milliseconds, gained by Date1.getTime() - Date2.getTime()
// if max_units is two, the result will be, for example
// 2years 12months ago, or 2hours 38minutes ago
// return formated period

function readable_period(ms, max_units=2){
    let [yy, yr] = mdiv(ms, 3.154e10);
    let [mm, mr] = mdiv(yr, 2.628e9);
    let [dd, dr] = mdiv(mr, 8.64e7);
    let [hh, hr] = mdiv(dr, 3.6e6);
    let [tt, ss] = mdiv(hr, 6e4);

    var ymdht = ['year', 'month', 'day', 'hour', 'minute'];
    let res = [];
    [yy, mm, dd, hh, tt].forEach((tis, ii)=>{
        if(res.length === max_units){return};
        if(tis !== 0){
            res.push(tis === 1 ? `${tis}${ymdht[ii]}` : `${tis}${ymdht[ii]}s`);
        }
    });
    return res.length === 0 ? '' : res.join(' ') + ' ago';
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionSky SandersView Question on Stackoverflow
Solution 1 - JavascriptSky SandersView Answer on Stackoverflow
Solution 2 - JavascriptFabiano SorianiView Answer on Stackoverflow
Solution 3 - JavascriptTheBrainView Answer on Stackoverflow
Solution 4 - JavascriptMaxim ZaslavskyView Answer on Stackoverflow
Solution 5 - JavascriptrobView Answer on Stackoverflow
Solution 6 - JavascriptSamView Answer on Stackoverflow
Solution 7 - JavascriptWill TomlinsView Answer on Stackoverflow
Solution 8 - JavascriptGeoffroy WarinView Answer on Stackoverflow
Solution 9 - JavascriptPanManView Answer on Stackoverflow
Solution 10 - JavascriptVitim.usView Answer on Stackoverflow
Solution 11 - Javascriptuser1012181View Answer on Stackoverflow
Solution 12 - JavascriptpkarcView Answer on Stackoverflow
Solution 13 - JavascriptWillView Answer on Stackoverflow
Solution 14 - JavascriptStas ParshinView Answer on Stackoverflow
Solution 15 - JavascriptNodiraView Answer on Stackoverflow
Solution 16 - JavascriptjjbskirView Answer on Stackoverflow
Solution 17 - JavascriptjcrsView Answer on Stackoverflow
Solution 18 - JavascriptatoolView Answer on Stackoverflow
Solution 19 - JavascriptBoumeziane MarouaneView Answer on Stackoverflow
Solution 20 - JavascriptMoses KoledoyeView Answer on Stackoverflow
Solution 21 - JavascriptMaksim IvanovView Answer on Stackoverflow
Solution 22 - JavascriptDinindu KanchanaView Answer on Stackoverflow
Solution 23 - JavascriptHamid ShojaView Answer on Stackoverflow
Solution 24 - JavascriptUygarView Answer on Stackoverflow
Solution 25 - JavascriptnikksanView Answer on Stackoverflow
Solution 26 - JavascriptTanzeem BhattiView Answer on Stackoverflow
Solution 27 - JavascriptewHView Answer on Stackoverflow
Solution 28 - JavascriptnateclonchView Answer on Stackoverflow
Solution 29 - JavascriptKishor VView Answer on Stackoverflow
Solution 30 - JavascriptDinesh SahView Answer on Stackoverflow
Solution 31 - JavascriptWeiloryView Answer on Stackoverflow