Sky Sanders
Sky Sanders

Reputation: 37074

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

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.

Upvotes: 380

Views: 341440

Answers (30)

Md Abdul Shahed
Md Abdul Shahed

Reputation: 99

Replying to @Stas Parshin answer, it is best answer here with less code, but it has bug when using with typescript, the .format function of Intl takes 2 inputs

  1. number,

  2. Units - i.e of type 'RelativeTimeFormatUnit' so if you pass a object key typescript will through error saying unit must be of type RelativeTimeFormatUnit and not of type string, so the work-around for this is to use the type to make another list of same type and rest you can have look at code... Happy coding.

    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],
     ] as const;
     const secondsElapsed = (date.getTime() - Date.now()) / 1000;
    
     for (const [rangeType, rangeVal] of ranges) {
       if (rangeVal < Math.abs(secondsElapsed)) {
         const delta = secondsElapsed / rangeVal;
         return formatter.format(Math.round(delta), rangeType);
       }
     }}
    
     console.log(timeAgo('2021-08-09T15:29:01+0000'));
    

Upvotes: 6

RJA
RJA

Reputation: 457

dayjs has a neat little one liner. Here is a function I pass a timestamp(ts) as a string. ts is in ISO format already.

export function nTimeAgo(ts: string){ 
  return `${dayjs().to(dayjs(ts), true)} ago`;
}

Link to docs here: https://day.js.org/docs/en/plugin/relative-time

Upvotes: 0

Vitim.us
Vitim.us

Reputation: 22128

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 YEAR = 365 * DAY;
    const MONTH = YEAR / 12;
    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 YEAR = 365 * DAY;
    const MONTH = YEAR / 12;
    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);
        }
    }
};

Upvotes: 27

Stas Parshin
Stas Parshin

Reputation: 1673

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

UPDATE For TypeScript usage please also consider the following answer https://stackoverflow.com/a/72817357/2619961

Upvotes: 44

Robert Coroianu
Robert Coroianu

Reputation: 426

I used an old answer by Possible 11 and I added Intl.RelativeTimeFormat for translations.

https://stackoverflow.com/a/73331658/673809

function timeAgo (value) {
    const seconds = Math.floor((new Date().getTime() - new Date(value).getTime()) / 1000)
    let interval = seconds / 31536000
    const rtf = new Intl.RelativeTimeFormat("en", { numeric: 'auto' })
    if (interval > 1) { return rtf.format(-Math.floor(interval), 'year') }
    interval = seconds / 2592000
    if (interval > 1) { return rtf.format(-Math.floor(interval), 'month') }
    interval = seconds / 86400
    if (interval > 1) { return rtf.format(-Math.floor(interval), 'day') }
    interval = seconds / 3600
    if (interval > 1) { return rtf.format(-Math.floor(interval), 'hour') }
    interval = seconds / 60
    if (interval > 1) { return rtf.format(-Math.floor(interval), 'minute') }
    return rtf.format(-Math.floor(interval), 'second')
}

console.log(timeAgo('2022-08-12 20:50:20'))

Upvotes: 4

Mirza Hayat
Mirza Hayat

Reputation: 402

    const timeHandler = (time: any) => {
      var a = moment(); //now
      var b = moment.utc(time);
      const sec = a.diff(b, 'seconds');
      const minuts = a.diff(b, 'minutes');
      const hours = a.diff(b, 'hours');
      const days = a.diff(b, 'days');
      const weeks = a.diff(b, 'weeks');
      return weeks == 0
        ? days == 0
          ? hours == 0
            ? minuts == 0
              ? sec >= 0 && `${sec}s ago`
              : `${minuts}m ago`
            : `${hours}h ago`
          : `${days}d ago`
        : `${weeks}w ago`;
    };

console.log(timeHandler('2022-11-11T12:11:06.6103808'))

Upvotes: 0

Fabiano Soriani
Fabiano Soriani

Reputation: 8562

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!

2022 addendum: Day.js is a newer library that's about 80% lighter than Luxon with similar capabilities.

Upvotes: 208

Possible 11
Possible 11

Reputation: 57

The above answers are good for old java scripts. But it's not working well on new EC6 JavaScript or TypeScript. Below is a very short and simple function for the latest JavaScript, TypeScript, AngularJs, ReactJs, and NodeJs to return the time ago as per the given date and time.

  public timeAgo(date) {
    var seconds = Math.floor((new Date().getTime() - new Date(date).getTime()) / 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";
  }

console.log(timeAgo('2022-08-12 20:50:20'));
// 2 hours ago, as per the given date time string.

Upvotes: 0

Chase Sandmann
Chase Sandmann

Reputation: 5005

If you're already using date-fns, you can use the built-in formatDistance (previously distanceInWords):

const date1 = new Date(2014, 6, 2);
const date2 = new Date(2015, 0, 1);
const options = { addSuffix: true }
const result = formatDistance(date1, date2, options);
//=> '6 months ago'

Upvotes: 1

Jeremy Bernier
Jeremy Bernier

Reputation: 2202

Most of these answers fail to account for plurals (eg. "1 minutes ago" when we want "1 minute ago")

const MINUTE = 60;
const HOUR = MINUTE * 60;
const DAY = HOUR * 24;
const WEEK = DAY * 7;
const MONTH = DAY * 30;
const YEAR = DAY * 365;

function getTimeAgo(date) {
  const secondsAgo = Math.round((Date.now() - Number(date)) / 1000);

  if (secondsAgo < MINUTE) {
    return secondsAgo + ` second${secondsAgo !== 1 ? "s" : ""} ago`;
  }

  let divisor;
  let unit = "";

  if (secondsAgo < HOUR) {
    [divisor, unit] = [MINUTE, "minute"];
  } else if (secondsAgo < DAY) {
    [divisor, unit] = [HOUR, "hour"];
  } else if (secondsAgo < WEEK) {
    [divisor, unit] = [DAY, "day"];
  } else if (secondsAgo < MONTH) {
    [divisor, unit] = [WEEK, "week"];
  } else if (secondsAgo < YEAR) {
    [divisor, unit] = [MONTH, "month"];
  } else {
    [divisor, unit] = [YEAR, "year"];
  }

  const count = Math.floor(secondsAgo / divisor);
  return `${count} ${unit}${count > 1 ? "s" : ""} ago`;
}

Then you can use it like so:

const date = new Date();
console.log(getTimeAgo(date));
// 1 second ago
// 2 seconds ago
// 1 minute ago
// 2 minutes ago
// ...

Upvotes: 4

Jackie Santana
Jackie Santana

Reputation: 1458

to use this, just LITERALLY COPY ALL of this code & just import it in your component or where ever & just place in your ISOstring() date inside: showTimeAgo("2022-06-20T13:42:29-05:00") & you will get automatic time updates for every scenario.

sidenote: I made an npm package for this https://www.npmjs.com/package/showtimeago

export const showTimeAgo = () => {
    const MONTH_NAMES = [
        'January',
        'February',
        'March',
        'April',
        'May',
        'June',
        'July',
        'August',
        'September',
        'October',
        'November',
        'December',
    ];

    function getOrdinalNum() {
        return (
            n +
            (n > 0
                ? ['th', 'st', 'nd', 'rd'][
                      (n > 3 && n < 21) || n % 10 > 3 ? 0 : n % 10
                  ]
                : '')
        );
    }

    function getFormattedDate(
        date,
        preformattedDate = false,
        hideYear = false
    ) {
        const day = date.getDate();
        const month = MONTH_NAMES[date.getMonth()];
        const year = date.getFullYear();
        let hours = date.getHours();
        let minutes = date.getMinutes();

        let ampm = hours >= 12 ? 'pm' : 'am';

        switch(true){
            case (hours > 12):
                hours = hours - 12;
                break;
            case (hours === 0):
                hours = 12;
                break;
            case(minutes < 10):
                minutes = `0${minutes}`;
                break;
            case(preformattedDate):
            // Today at 10:20am
            // Yesterday at 10:20am
                return `${preformattedDate} at ${hours}:${minutes} ${ampm}`;

            case(hideYear):
                // January 10th at 10:20pm
                return `${month} ${getOrdinalNum(
                    day
                )}, at ${hours}:${minutes} ${ampm}`;
            default:
                // January 10th 2022 at 10:20pm
                return `${month} ${getOrdinalNum(
                    day
                )}, ${year} at ${hours}:${minutes} ${ampm}`;
        }
        
    }

    // --- Main function
    function timeAgo(dateParam) {
        if (!dateParam) {
            return null;
        }

        const date =
            typeof dateParam === 'object' ? dateParam : new Date(dateParam);
        const DAY_IN_MS = 86400000; // 24 * 60 * 60 * 1000
        const today = new Date();

        const yesterday = new Date(today - DAY_IN_MS);

        const seconds = Math.round((today - date) / 1000);
        const minutes = Math.round(seconds / 60);
        const hour = Math.round(seconds / 3600);
        const day = Math.round(seconds / 86400);
        const month = Math.round(seconds / 2629800);
        const year = Math.floor(seconds / 31536000);
        const isToday = today.toDateString() === date.toDateString();
        const isYesterday =
            yesterday.toDateString() === date.toDateString();
        const isThisYear = today.getFullYear() === date.getFullYear();

        switch(true){
            case (seconds < 5):
                return 'now';
            case (seconds < 60):
                return `${seconds} seconds ago`;
            case (seconds < 90):
                return 'about a minute ago';
            case (minutes < 60):
                return `${minutes} minutes ago`;
            case (hour === 1 && hour < 2):
                return `${hour} hour ago`; // 1 hour ago
            case (hour > 1 && hour <= 12):
                return `${hour} hours ago`; // 2 hours ago
            case (isToday):
                return getFormattedDate(date, 'Today'); // Today at 10:20am
            case (isYesterday): 
                return getFormattedDate(date, 'Yesterday'); // Yesterday at 10:20am
            case(day > 1 && day <= 30):
                return `${day} days ago`; // 2 days ago
            case (isThisYear):
                return getFormattedDate(date, false, true); // January 10th at 10:20pm 
            case (day > 30 && month <= 1):
                return `${hour} month ago`; // 1 month ago
            case (month > 1 && month <= 12):
                return `${month} months ago`; // 2 months ago
            case (year === 1):
                return `${year} year ago`; // 1 year ago
            case (year > 1):
                return `${year} years ago`; // 2 years ago
            default:
                return getFormattedDate(date); // January 10th 2022 at 10:20pm
        }
    }

    return timeAgo(date);
};

console.log(showTimeAgo("2022-06-20T13:42:29-05:00"));-05:00"))

Upvotes: 0

Yilmaz
Yilmaz

Reputation: 49263

I use this package: javascript-time-ago

  • set TimeAgo

     import TimeAgo from 'javascript-time-ago'
     import en from 'javascript-time-ago/locale/en.json'
    
     TimeAgo.addDefaultLocale(en)
    
  • write a function // twitter-now is twitter style. check docs for more options

    const clockToDateString = (timestamp) =>
      timeAgo.format(new Date(timestamp.toNumber() * 1000), 'twitter-now')
    
  • use it in dom

       <div >
          {clockToDateString(post.postTime)}
        </div>
    

Upvotes: 0

Lars Flieger
Lars Flieger

Reputation: 2544

You can use Luxon:

DateTime.toRelative()

https://moment.github.io/luxon/api-docs/index.html#datetimetorelative

Here are some more examples:

const DateTime = luxon.DateTime;

// toRelative
console.log(DateTime.now().minus({ seconds: 1 }).toRelative()) // 1 second ago
console.log(DateTime.now().minus({ seconds: 10 }).toRelative()) // 10 seconds ago
console.log(DateTime.now().minus({ days: 2 }).toRelative())
console.log(DateTime.now().minus({ years: 3 }).toRelative())
console.log(DateTime.now().plus({ years: 3 }).toRelative())
console.log(DateTime.now().plus({ days: 2 }).toRelative())
console.log(DateTime.now().plus({ seconds: 1 }).toRelative())
console.log(DateTime.now().plus({ seconds: 10 }).toRelative())

// toRelativeCalendar
console.log(DateTime.now().minus({ seconds: 1 }).toRelativeCalendar()) // today
console.log(DateTime.now().minus({ seconds: 10 }).toRelativeCalendar()) // today
console.log(DateTime.now().minus({ days: 2 }).toRelativeCalendar())
console.log(DateTime.now().minus({ years: 3 }).toRelativeCalendar())
console.log(DateTime.now().plus({ years: 3 }).toRelativeCalendar())
console.log(DateTime.now().plus({ days: 2 }).toRelativeCalendar())
console.log(DateTime.now().plus({ seconds: 1 }).toRelativeCalendar())
console.log(DateTime.now().plus({ seconds: 10 }).toRelativeCalendar())
<script src="https://moment.github.io/luxon/global/luxon.min.js"></script>

Upvotes: 0

jcrs
jcrs

Reputation: 509

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

Upvotes: 10

Weilory
Weilory

Reputation: 3101

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

Upvotes: 0

Hamid Shoja
Hamid Shoja

Reputation: 4768

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)`

Upvotes: 2

Sam
Sam

Reputation: 201

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

Upvotes: 20

Dinesh Sah
Dinesh Sah

Reputation: 311

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

Upvotes: 0

Kishor V
Kishor V

Reputation: 441

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

Upvotes: 1

Geoffroy Warin
Geoffroy Warin

Reputation: 647

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!)

Upvotes: 15

Maksim Ivanov
Maksim Ivanov

Reputation: 4311

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

Upvotes: 2

Nodira
Nodira

Reputation: 666

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

Upvotes: 6

Dinindu Kanchana
Dinindu Kanchana

Reputation: 353

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"

Upvotes: 2

Sky Sanders
Sky Sanders

Reputation: 37074

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

Upvotes: 489

Tanzeem Bhatti
Tanzeem Bhatti

Reputation: 219

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

Upvotes: 1

Will
Will

Reputation: 354

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

Upvotes: 7

Boumeziane Marouane
Boumeziane Marouane

Reputation: 89

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

Upvotes: 4

jjbskir
jjbskir

Reputation: 10617

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

Upvotes: 6

nikksan
nikksan

Reputation: 3471

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

Upvotes: 1

user1012181
user1012181

Reputation: 8726

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

Upvotes: 11

Related Questions