Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get duration in weeks with Moment.js?

I use moment.js to format durations in human readable format.
For example (d is a Date object):

moment(d).subtract("days", 3).from(d)  // returns "3 days ago"

Now I would like to get "2 weeks ago" but the code below returns the durations in days

moment(d).subtract("weeks", 2).from(d) // returns "14 days ago" i/o "2 weeks ago"

How can I get "2 weeks ago" with moment.js?

like image 996
Michael Avatar asked Jul 12 '12 09:07

Michael


6 Answers

You can do this pretty easily with a custom callback function.

moment.relativeTime.dd = function (number) {
    // round to the closest number of weeks
    var weeks = Math.round(number / 7);
    if (number < 7) {
        // if less than a week, use days
        return number + " days";
    } else {
        // pluralize weeks
        return weeks + " week" + (weeks === 1 ? "" : "s"); 
    }
}

http://jsfiddle.net/timrwood/sWsXQ/

like image 52
timrwood Avatar answered Oct 28 '22 11:10

timrwood


Use the new updateLocale().

Moment.js has been updated again so the preferred method is the following:

moment.updateLocale('en', {

  relativeTime : {
    future: 'in %s',
    past:   '%s ago',
    s:      'a few seconds',
    m:      'a minute',
    mm:     '%d minutes',
    h:      'an hour',
    hh:     '%d hours',
    d:      'a day',
    dd:     function(number) {
              if (number < 7) {
                return number + ' days'; // Moment uses "d" when it's just 1 day.
              }
              else {
                var weeks = Math.round(number / 7);
                return weeks + ' ' + (weeks > 1 ? 'weeks' : 'week');
              }
            },
    M:      'a month',
    MM:     '%d months',
    y:      'a year',
    yy:     '%d years'
  }

});

Thanks to @timrwood and @gahen for their answers.

I'm in the works to get Moment updated so that you can override just a single relativeTime object, like dd, instead of having to provide all of the objects.

The GitHub Issue is here, so give it a thumbs up if you'd like to do something like this instead:

moment.updateLocale('en', {

  relativeTime : {
    dd: function(number) {
          if (number < 7) {
            return number + ' days'; // Moment uses "d" when it's just 1 day.
          }
          else {
            var weeks = Math.round(number / 7);
            return weeks + ' ' + (weeks > 1 ? 'weeks' : 'week');
          }
        }
  }

});
like image 44
Joshua Pinter Avatar answered Oct 28 '22 12:10

Joshua Pinter


I can't comment on the previous answer but I wanted to leave an updated answer (based on timrwood's)

moment.locale('en', {
  relativeTime : {
    future: "in %s",
    past:   "%s ago",
    s:  "seconds",
    m:  "a minute",
    mm: "%d minutes",
    h:  "an hour",
    hh: "%d hours",
    d:  "a day",
    dd: function (number) {
      var weeks = Math.round(number / 7);
      if (number < 7) {
        // if less than a week, use days
        return number + " days";
      } else {
        // pluralize weeks
        return weeks + " week" + (weeks === 1 ? "" : "s"); 
      }
    },
    M:  "a month",
    MM: "%d months",
    y:  "a year",
    yy: "%d years"
  }
});

$window.moment.relativeTimeThreshold('d', 340); // if you want weeks instead of months, otherwise put a 28 or so.
like image 28
gahen Avatar answered Oct 28 '22 11:10

gahen


improving on @vinjenzo's answer, when you need date diff in weeks, you will most likely encounter days returned:

var aPastDate = moment().subtract(5,'months');
var aPastDay = moment().subtract(6,'days');
var now = moment();

moment.fn.durationInWeeks = function(fromDate, toDate) {

    var days    = toDate.diff(fromDate, 'days');    
    var weeks   = toDate.diff(fromDate, 'weeks');

    if (weeks === 0) {
        return days + ' ' + (days > 1 ? 'days' : 'day');
    } else {
        return weeks + ' ' + (Math.round(days / 7) > 1 ? 'weeks' : 'week');
    }

}

moment().durationInWeeks(aPastDate,now); // 21 weeks
moment().durationInWeeks(aPastDay,now);  // 6 days
like image 45
cenk Avatar answered Oct 28 '22 11:10

cenk


The documentation lists the rules for creating those strings (under "Humanize time from another moment"). While you can modify the strings by changing moment.relativeTime, this is limited to the text that is displayed around the number, i.e. you can't change days to weeks.

You'll have to extend moment.js or write some custom code to implement this functionality.

like image 23
Lars Kotthoff Avatar answered Oct 28 '22 13:10

Lars Kotthoff


sharing and hoping still useful:

var aPastDate = moment().subtract(5,'months');
var now = moment();


moment.fn.durationInWeeks = function (fromDate, toDate) {

   var weeks =  toDate.diff( fromDate, 'weeks' );
   return weeks + ' weeks ago'; //your own format

}

moment().durationInWeeks(aPastDate,now);

//"21 weeks ago"
like image 39
vinjenzo Avatar answered Oct 28 '22 11:10

vinjenzo