39

I'm looking for a way to use momentjs to parse two dates, to show the difference.

I want to have it on the format: "X years, Y months, Z days".

For the years and months the moment library and modulo operator works nice. But for the days it's another tale as I don't want to handle leap years and all that by myself. So far the logic I have in my head is this:

var a = moment([2015, 11, 29]);
var b = moment([2007, 06, 27]);

var years = a.diff(b, 'years');
var months = a.diff(b, 'months') % 12;
var days = a.diff(b, 'days');
// Abit stuck here as leap years, and difference in number of days in months. 
// And a.diff(b, 'days') returns total number of days.
return years + '' + months + '' + days;
Josh Crozier
  • 233,099
  • 56
  • 391
  • 304

7 Answers7

77

You could get the difference in years and add that to the initial date; then get the difference in months and add that to the initial date again.

In doing so, you can now easily get the difference in days and avoid using the modulo operator as well.

Example Here

var a = moment([2015, 11, 29]);
var b = moment([2007, 06, 27]);

var years = a.diff(b, 'year');
b.add(years, 'years');

var months = a.diff(b, 'months');
b.add(months, 'months');

var days = a.diff(b, 'days');

console.log(years + ' years ' + months + ' months ' + days + ' days');
// 8 years 5 months 2 days

I'm not aware of a better, built-in way to achieve this, but this method seems to work well.

Josh Crozier
  • 233,099
  • 56
  • 391
  • 304
  • 2
    Thanks! This is exactly what i was looking for :) – Ole-Morten Heggertveit Nov 29 '15 at 22:02
  • 2
    Should adding one year to 29 February return 28 February or 1 March? Should 31 May plus one month be 30 June or 1 July? – RobG Nov 30 '15 at 07:17
  • 3
    This answer gives correct years, months, days when `b = moment([2007, 11, 29])`. (8 years 0 months 0 days) While @Kunal answer gave (8 years 0 months 1 days) – nattster Sep 12 '17 at 11:14
  • 1
    This is not return correct answers for who needs calendar months. var a = moment([2020, 03, 01]); var b = moment([2020, 01, 31]); returns "0 years 0 months 30 days" But actually it should be 1 month & 2 days – Sadee May 13 '20 at 23:46
39

Moment.js also has duration object. A moment is defined as single point in time, whereas duration is defined as a length of time which is basically what you want.

var a = moment([2015, 11, 29]);
var b = moment([2007, 06, 27]);

var diffDuration = moment.duration(a.diff(b));

console.log(diffDuration.years()); // 8 years
console.log(diffDuration.months()); // 5 months
console.log(diffDuration.days()); // 2 days

What @Josh suggest may work, but is definitely not the right way of calculating difference in 2 moments.

Kunal Kapadia
  • 3,223
  • 2
  • 28
  • 36
  • 8
    Wrong answer for difference between `01/01/2013` and `01/01/2016`. It gives `2y 11m 29d` while Josh's answer gives `3y`. – Shreevardhan Apr 21 '18 at 13:44
3

I just converted @Josh Crozier's answer into a function and added hours, minutes and seconds too.

 function diffYMDHMS(date1, date2) {

    let years = date1.diff(date2, 'year');
    date2.add(years, 'years');

    let months = date1.diff(date2, 'months');
    date2.add(months, 'months');

    let days = date1.diff(date2, 'days');
    date2.add(days, 'days');

    let hours = date1.diff(date2, 'hours');
    date2.add(hours, 'hours');

    let minutes = date1.diff(date2, 'minutes');
    date2.add(minutes, 'minutes');

    let seconds = date1.diff(date2, 'seconds');

    console.log(years + ' years ' + months + ' months ' + days + ' days ' + hours + ' 
    hours ' + minutes + ' minutes ' + seconds + ' seconds'); 

    return { years, months, days, hours, minutes, seconds};
}
Muneeb
  • 1,469
  • 16
  • 24
  • To make it a function, I suggest `clone()`ing arguments before calling `add()` because `date2` is mutated. Otherwise, there will be some unwanted cases with the passed moment instances in the client code (e.g. calling the function twice with same moment instances gives different results). – Tomoyuki Aota Sep 29 '22 at 17:15
2

Above solution is not working with momentjs 2.19.1

Then with reference of Date of Joining calculation not working with moment 2.19.1 I have implemented new solution with latest solution for momentjs 2.19.1.

Required npm packages:

"moment": "^2.19.4",

"moment-duration-format": "^1.3.0",

"react-moment": "^0.6.8",

import following in reactjs:

 import moment from "moment";
 import Moment from "react-moment";
 import momentDurationFormatSetup from "moment-duration-format";

var DOJ = moment([work_data.joining_date]).format("YYYY,MM,DD");      
var today = moment().format("YYYY,MM,DD");      
var totalMonths =  parseInt(moment(today).diff(moment(DOJ), 'months'));      
var totalDuration = moment.duration(totalMonths, "months").format();      
if(totalDuration.search('1y') > -1) {
   totalDuration = totalDuration.replace("1y", "1 Year,");
} else {
   totalDuration = totalDuration.replace("y", " Years,");
}

if(totalDuration.search('1m') > -1){
  totalDuration = totalDuration.replace("1m", "1 Month");
} else {
  totalDuration = totalDuration.replace("m", " Months");
}

console.log(totalDuration);
Chandresh
  • 277
  • 2
  • 14
1

All the solutions presented here are failing for some of the test cases. So I made some changes to the accepted answer.

function getYMD(date1, date2) {
    const a = moment(date1);
    const b = moment(date2);
    var years = a.diff(b, 'year');
    b.add(years, 'years');

    const noOfDaysInb = b.daysInMonth();
    const noOfDaysIna = a.daysInMonth();
    let months = 0;
    if (noOfDaysInb > noOfDaysIna) {
        months = b.diff(a, "months");
        a.add(months, "months");
    } else {
        months = a.diff(b, 'months');
        b.add(months, 'months');
    }
    var days = a.diff(b, 'days');
    return {
        years: Math.abs(years),
        months: Math.abs(months),
        days: Math.abs(days),
    }
}

This is the best answer I can come up with.

-1

This is another answer. Verified with Age Calculator

function calculateAge(){
    ageText = jQuery("#dob").closest(".form-group").find(".age-text");
    ageText.text("");
    level2.dob = jQuery("#dob").val();
    if(!level2.dob) return;
    level2.mdob= moment(level2.dob, 'DD-MM-YYYY');
    if(!level2.mdob.isValid()){
        alert("Invalid date format");
        return;
    }
    level2.targetDate = moment();//TODO: Fill in the target date
    level2.months = level2.targetDate.diff(level2.mdob, 'months'); // Calculate the months
    let years = parseInt(level2.months/12); // A year has 12 months irrespective or leap year or not
    let balanceMonths = level2.months%12; // The balance gives the number of months 
    let days;
    if(!balanceMonths){ // If no balance months, then the date selected lies in the same month
        months = 0; // so months = 0
        days = level2.targetDate.diff(level2.mdob, 'days'); // only the days difference
    }else{
    months = balanceMonths;
    dob_date = level2.mdob.date();
    target_month = level2.targetDate.month();
    construct_date = moment().month(target_month).date(dob_date);
    days = level2.targetDate.diff(construct_date, 'days')+1; // There might be one day missed out. Not sure on UTC
}

ageText = years +" years " + months+ " months " + days +" days";
}
Alaksandar Jesus Gene
  • 6,523
  • 12
  • 52
  • 83
-1

Use this

  var totalDays = endDate.diff(startDate, "days");
Abdus Salam Azad
  • 5,087
  • 46
  • 35