There multiple ways to count months and days. Without further restrictions all correct of them are correct even though the results might differ.
For example from September 27 to November 1 could be either
- 1 month and 5 days or
- 4 days and 1 month.
This is one possible solution.
// swap dates if difference would be negative
if (firstDate.getTime() > secondDate.getTime()) {
var tmp = firstDate;
firstDate = secondDate;
secondDate = tmp;
}
var years = secondDate.getFullYear() - firstDate.getFullYear();
var months = secondDate.getMonth() - firstDate.getMonth();
var days = secondDate.getDate() - firstDate.getDate();
// prevent negative amount of days by breaking up months
for (var i = 0; days < 0; ++i) {
// while the day difference is negative
// we break up months into days, starting with the first
months -= 1;
days += new Date(
firstDate.getFullYear(),
firstDate.getMonth() + 1 + i,
0, 0, 0, 0, 0
).getDate();
}
// prevent negative amount of months by breaking up years
if (months < 0) {
years += Math.floor(months / 12);
months = (months % 12 + 12) % 12;
}
// print the result
console.log([
{amount: days, unit: 'day'},
{amount: months, unit: 'month'},
{amount: years, unit: 'year'},
].filter(value => value.amount).map(value =>
value.amount === 1 ?
`${value.amount} ${value.unit}` :
`${value.amount} ${value.unit}s`
).reduce((result, part, index, parts) =>
index > 0 ? index === parts.length - 1 ?
`${result} and ${part}` :
`${result}, ${part}` :
`${part}`,
`0 days`
));
Examples:
- 02/12 to 02/22: 10 days
- 09/27 to 11/01: 4 days and 1 month // instead of 1 month and 5 days
- 12/31 to 03/01: 1 day and 2 months // instead of 1 month and 29 days
- 05/31 to 06/30: 30 days
- 01/31 to 03/30: 30 days and 1 month // instead of 1 month and 27 days
- 10/27/2010 to 08/26/2014: 30 days, 9 months and 3 years