How to get difference between 2 Dates in Years, Months and days using moment.js? For example the difference between 4/5/2014 & 2/22/2013 should be calculated as 1 Year, 1 Month and 14 Days.
-
possible duplicate of [Get the time difference between two datetimes](http://stackoverflow.com/questions/18623783/get-the-time-difference-between-two-datetimes) – isherwood Sep 26 '14 at 16:16
-
2Actually, not a duplicate. The dup covers hours,minutes,seconds difference. It's a different problem when you're talking about calendar months. – Matt Johnson-Pint Sep 26 '14 at 17:25
-
1@Nawaf - Are the years correct in your question? They are both 2013. – Matt Johnson-Pint Sep 26 '14 at 17:25
-
You are correct Matt. I did fix the dates. – Nick Sep 26 '14 at 22:57
3 Answers
Moment.js can't handle this scenario directly. It does allow you to take the difference between two moments, but the result is an elapsed duration of time in milliseconds. Moment does have a Duration object, but it defines a month as a fixed unit of 30 days - which we know is not always the case.
Fortunately, there is a plugin already created for moment called "Precise Range", which does the right thing. Looking at the source, it does something similar to torazaburo's answer - but it properly accounts for the number of days in the month to adjust.
After including both moment.js and this plugin (readable-range.js) in your project, you can simply call it like this:
var m1 = moment('2/22/2013','M/D/YYYY');
var m2 = moment('4/5/2014','M/D/YYYY');
var diff = moment.preciseDiff(m1, m2);
console.log(diff);
The output is "1 year 1 month 14 days"

- 1
- 1

- 230,703
- 74
- 448
- 575
-
-
It's just another javascript file. Include it after you include moment.js. – Matt Johnson-Pint Sep 27 '14 at 00:10
-
This is really a great.. Currently it displayed **12 years 10 months 17 days 7 hours 9 minutes 23 seconds** but what if I just want to display the difference in Year and Month? I don't want days!! – Trimantra Software Solution May 15 '17 at 07:08
-
1@TrimantraSoftwareSolution Ask here: https://github.com/codebox/moment-precise-range/issues. Or maybe just use `startOf('month')` before you call `preciseDiff`. – Matt Johnson-Pint May 15 '17 at 15:48
-
Actually this was silly question, I got this by modifying the `moment-precise-range.js`. The return object was building a string, I just adjusted the string as per my need and it done. :-) – Trimantra Software Solution May 16 '17 at 05:10
You hardly need moment.
d1 = new Date(2014, 3, 5); // April 5, 2014
d2 = new Date(2013, 1, 22); // February 22, 2013
diff = new Date(
d1.getFullYear()-d2.getFullYear(),
d1.getMonth()-d2.getMonth(),
d1.getDate()-d2.getDate()
);
This takes advantage of the fact that the Date
constructor is smart about negative values. For instance, if the number of months is negative, it will take that into account and walk back the year.
console.log(diff.getYear(), "Year(s),",
diff.getMonth(), "Month(s), and",
diff.getDate(), "Days.");
>> 1 Year(s), 1 Month(s), and 11 Days.
Your calculation is wrong--it's not 14 days, it's six remaining days in February and the first five days of April, so it's 11 days, as the computer correctly computes.
Second try
This might work better given @MattJohnson's comment:
dy = d1.getYear() - d2.getYear();
dm = d1.getMonth() - d2.getMonth();
dd = d1.getDate() - d2.getDate();
if (dd < 0) { dm -= 1; dd += 30; }
if (dm < 0) { dy -= 1; dm += 12; }
console.log(dy, "Year(s),", dm, "Month(s), and", dd, "Days.");
-
2Nice thinking about reusing the `Date` object's ability to walk out of range. However, there's a few problems with his approach. 1) The `Date` object takes on DST behavior of the local time zone, which can skew certain results, and 2) It doesn't handle whole months well. Consider Jan 1 - July 1. Instead of "6 months", it returns "5 months and 30 days". 3) Even then, it doesn't work well with leap years. Jan 1 - Mar 1 always returns "1 month and 28 days", even if it was in a leap year - where technically it should be "1 month and 29 days". – Matt Johnson-Pint Sep 26 '14 at 16:56
-
-
Ideally, yes. I was just pointing out that the value your first pass returned wasn't accurate with regard to leap years. – Matt Johnson-Pint Sep 26 '14 at 17:20
-
1The second try code assumes all months are 30 days, which isn't true. Trust me, this problem is more difficult than it seems. :) moment has it covered by good understanding of calendar math. There is indeed a pure JS solution, but it's not simple. – Matt Johnson-Pint Sep 26 '14 at 17:22
-
Actually... As I'm browsing through the moment docs, I am realizing that moment *doesn't* have this operation covered... I will research more and post an answer later. Thx. – Matt Johnson-Pint Sep 26 '14 at 17:32
This worked for me. 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";
}

- 6,523
- 12
- 52
- 83