Difference between two dates in years, months, day

2019-01-01 05:58发布

问题:

I\'ve been searching for 4 hours now, and have not found a solution to get the difference between two dates in years, months, and days in JavaScript, like: 10th of April 2010 was 3 years, x month and y days ago.

There are lots of solutions, but they only offer the difference in the format of either days OR months OR years, or they are not correct (meaning not taking care of actual number of days in a month or leap years, etc). Is it really that difficult to do that?

I\'ve had a look at:

  • http://momentjs.com/ -> can only output the difference in either years, months, OR days
  • http://www.javascriptkit.com/javatutors/datedifference.shtml
  • http://www.javascriptkit.com/jsref/date.shtml
  • http://timeago.yarp.com/
  • www.stackoverflow.com -> Search function

In php it is easy, but unfortunately I can only use client-side script on that project. Any library or framework that can do it would be fine, too.

Here are a list of expected outputs for date differences:

//Expected output should be: \"1 year, 5 months\".
diffDate(new Date(\'2014-05-10\'), new Date(\'2015-10-10\'));

//Expected output should be: \"1 year, 4 months, 29 days\".
diffDate(new Date(\'2014-05-10\'), new Date(\'2015-10-09\'));

//Expected output should be: \"1 year, 3 months, 30 days\".
diffDate(new Date(\'2014-05-10\'), new Date(\'2015-09-09\'));

//Expected output should be: \"9 months, 27 days\".
diffDate(new Date(\'2014-05-10\'), new Date(\'2015-03-09\'));

//Expected output should be: \"1 year, 9 months, 28 days\".
diffDate(new Date(\'2014-05-10\'), new Date(\'2016-03-09\'));

//Expected output should be: \"1 year, 10 months, 1 days\".
diffDate(new Date(\'2014-05-10\'), new Date(\'2016-03-11\'));

回答1:

How precise do you need to be? If you do need to take into account common years and leap years, and the exact difference in days between months then you\'ll have to write something more advanced but for a basic and rough calculation this should do the trick:

today = new Date()
past = new Date(2010,05,01) // remember this is equivalent to 06 01 2010
//dates in js are counted from 0, so 05 is june

function calcDate(date1,date2) {
    var diff = Math.floor(date1.getTime() - date2.getTime());
    var day = 1000 * 60 * 60 * 24;

    var days = Math.floor(diff/day);
    var months = Math.floor(days/31);
    var years = Math.floor(months/12);

    var message = date2.toDateString();
    message += \" was \"
    message += days + \" days \" 
    message += months + \" months \"
    message += years + \" years ago \\n\"

    return message
    }


a = calcDate(today,past)
console.log(a) // returns Tue Jun 01 2010 was 1143 days 36 months 3 years ago

Keep in mind that this is imprecise, in order to calculate the date with full precision one would have to have a calendar and know if a year is a leap year or not, also the way I\'m calculating the number of months is only approximate.

But you can improve it easily.



回答2:

I used this simple code to get difference in Years, Months, days with current date.

var sdt = new Date(\'1972-11-30\');
var difdt = new Date(new Date() - sdt);
alert((difdt.toISOString().slice(0, 4) - 1970) + \"Y \" + (difdt.getMonth()+1) + \"M \" + difdt.getDate() + \"D\");


回答3:

Actually, there\'s a solution with a moment.js plugin and it\'s very easy.

You might use moment.js

Don\'t reinvent the wheel again.

Just plug Moment.js Date Range Plugin.


Example:

var starts = moment(\'2014-02-03 12:53:12\');
var ends   = moment();

var duration = moment.duration(ends.diff(starts));

// with ###moment precise date range plugin###
// it will tell you the difference in human terms

var diff = moment.preciseDiff(starts, ends, true); 
// example: { \"years\": 2, \"months\": 7, \"days\": 0, \"hours\": 6, \"minutes\": 29, \"seconds\": 17, \"firstDateWasLater\":  false }


// or as string:
var diffHuman = moment.preciseDiff(starts, ends);
// example: 2 years 7 months 6 hours 29 minutes 17 seconds

document.getElementById(\'output1\').innerHTML = JSON.stringify(diff)
document.getElementById(\'output2\').innerHTML = diffHuman
<html>
<head>

  <script src=\"https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.14.1/moment.min.js\"></script>

  <script src=\"https://raw.githubusercontent.com/codebox/moment-precise-range/master/moment-precise-range.js\"></script>

</head>
<body>
  
  <h2>Difference between \"NOW and 2014-02-03 12:53:12\"</h2>
  <span id=\"output1\"></span>
  <br />
  <span id=\"output2\"></span>
  
</body>
</html>



回答4:

For quick and easy use I wrote this function some time ago. It returns the diff between two dates in a nice format. Feel free to use it (tested on webkit).

/**
 * Function to print date diffs.
 * 
 * @param {Date} fromDate: The valid start date
 * @param {Date} toDate: The end date. Can be null (if so the function uses \"now\").
 * @param {Number} levels: The number of details you want to get out (1=\"in 2 Months\",2=\"in 2 Months, 20 Days\",...)
 * @param {Boolean} prefix: adds \"in\" or \"ago\" to the return string
 * @return {String} Diffrence between the two dates.
 */
function getNiceTime(fromDate, toDate, levels, prefix){
    var lang = {
            \"date.past\": \"{0} ago\",
            \"date.future\": \"in {0}\",
            \"date.now\": \"now\",
            \"date.year\": \"{0} year\",
            \"date.years\": \"{0} years\",
            \"date.years.prefixed\": \"{0} years\",
            \"date.month\": \"{0} month\",
            \"date.months\": \"{0} months\",
            \"date.months.prefixed\": \"{0} months\",
            \"date.day\": \"{0} day\",
            \"date.days\": \"{0} days\",
            \"date.days.prefixed\": \"{0} days\",
            \"date.hour\": \"{0} hour\",
            \"date.hours\": \"{0} hours\",
            \"date.hours.prefixed\": \"{0} hours\",
            \"date.minute\": \"{0} minute\",
            \"date.minutes\": \"{0} minutes\",
            \"date.minutes.prefixed\": \"{0} minutes\",
            \"date.second\": \"{0} second\",
            \"date.seconds\": \"{0} seconds\",
            \"date.seconds.prefixed\": \"{0} seconds\",
        },
        langFn = function(id,params){
            var returnValue = lang[id] || \"\";
            if(params){
                for(var i=0;i<params.length;i++){
                    returnValue = returnValue.replace(\"{\"+i+\"}\",params[i]);
                }
            }
            return returnValue;
        },
        toDate = toDate ? toDate : new Date(),
        diff = fromDate - toDate,
        past = diff < 0 ? true : false,
        diff = diff < 0 ? diff * -1 : diff,
        date = new Date(new Date(1970,0,1,0).getTime()+diff),
        returnString = \'\',
        count = 0,
        years = (date.getFullYear() - 1970);
    if(years > 0){
        var langSingle = \"date.year\" + (prefix ? \"\" : \"\"),
            langMultiple = \"date.years\" + (prefix ? \".prefixed\" : \"\");
        returnString += (count > 0 ?  \', \' : \'\') + (years > 1 ? langFn(langMultiple,[years]) : langFn(langSingle,[years]));
        count ++;
    }
    var months = date.getMonth();
    if(count < levels && months > 0){
        var langSingle = \"date.month\" + (prefix ? \"\" : \"\"),
            langMultiple = \"date.months\" + (prefix ? \".prefixed\" : \"\");
        returnString += (count > 0 ?  \', \' : \'\') + (months > 1 ? langFn(langMultiple,[months]) : langFn(langSingle,[months]));
        count ++;
    } else {
        if(count > 0)
            count = 99;
    }
    var days = date.getDate() - 1;
    if(count < levels && days > 0){
        var langSingle = \"date.day\" + (prefix ? \"\" : \"\"),
            langMultiple = \"date.days\" + (prefix ? \".prefixed\" : \"\");
        returnString += (count > 0 ?  \', \' : \'\') + (days > 1 ? langFn(langMultiple,[days]) : langFn(langSingle,[days]));
        count ++;
    } else {
        if(count > 0)
            count = 99;
    }
    var hours = date.getHours();
    if(count < levels && hours > 0){
        var langSingle = \"date.hour\" + (prefix ? \"\" : \"\"),
            langMultiple = \"date.hours\" + (prefix ? \".prefixed\" : \"\");
        returnString += (count > 0 ?  \', \' : \'\') + (hours > 1 ? langFn(langMultiple,[hours]) : langFn(langSingle,[hours]));
        count ++;
    } else {
        if(count > 0)
            count = 99;
    }
    var minutes = date.getMinutes();
    if(count < levels && minutes > 0){
        var langSingle = \"date.minute\" + (prefix ? \"\" : \"\"),
            langMultiple = \"date.minutes\" + (prefix ? \".prefixed\" : \"\");
        returnString += (count > 0 ?  \', \' : \'\') + (minutes > 1 ? langFn(langMultiple,[minutes]) : langFn(langSingle,[minutes]));
        count ++;
    } else {
        if(count > 0)
            count = 99;
    }
    var seconds = date.getSeconds();
    if(count < levels && seconds > 0){
        var langSingle = \"date.second\" + (prefix ? \"\" : \"\"),
            langMultiple = \"date.seconds\" + (prefix ? \".prefixed\" : \"\");
        returnString += (count > 0 ?  \', \' : \'\') + (seconds > 1 ? langFn(langMultiple,[seconds]) : langFn(langSingle,[seconds]));
        count ++;
    } else {
        if(count > 0)
            count = 99;
    }
    if(prefix){
        if(returnString == \"\"){
            returnString = langFn(\"date.now\");
        } else if(past)
            returnString = langFn(\"date.past\",[returnString]);
        else
            returnString = langFn(\"date.future\",[returnString]);
    }
    return returnString;
}


回答5:

I think you are looking for the same thing that I wanted. I tried to do this using the difference in milliseconds that javascript provides, but those results do not work in the real world of dates. If you want the difference between Feb 1, 2016 and January 31, 2017 the result I would want is 1 year, 0 months, and 0 days. Exactly one year (assuming you count the last day as a full day, like in a lease for an apartment). However, the millisecond approach would give you 1 year 0 months and 1 day, since the date range includes a leap year. So here is the code I used in javascript for my adobe form (you can name the fields): (edited, there was an error that I corrected)

var f1 = this.getField(\"LeaseExpiration\");
var g1 = this.getField(\"LeaseStart\");


var end = f1.value
var begin = g1.value
var e = new Date(end);
var b = new Date(begin);
var bMonth = b.getMonth();
var bYear = b.getFullYear();
var eYear = e.getFullYear();
var eMonth = e.getMonth();
var bDay = b.getDate();
var eDay = e.getDate() + 1;

if ((eMonth == 0)||(eMonth == 2)||(eMonth == 4)|| (eMonth == 6) || (eMonth == 7) ||(eMonth == 9)||(eMonth == 11))

{
var eDays =  31;
}

if ((eMonth == 3)||(eMonth == 5)||(eMonth == 8)|| (eMonth == 10))

{
var eDays = 30;
}

if (eMonth == 1&&((eYear % 4 == 0) && (eYear % 100 != 0)) || (eYear % 400 == 0))
{
var eDays = 29;
}

if (eMonth == 1&&((eYear % 4 != 0) || (eYear % 100 == 0)))
{
var eDays = 28;
}


if ((bMonth == 0)||(bMonth == 2)||(bMonth == 4)|| (bMonth == 6) || (bMonth == 7) ||(bMonth == 9)||(bMonth == 11))

{
var bDays =  31;
}

if ((bMonth == 3)||(bMonth == 5)||(bMonth == 8)|| (bMonth == 10))

{
var bDays = 30;
}

if (bMonth == 1&&((bYear % 4 == 0) && (bYear % 100 != 0)) || (bYear % 400 == 0))
{
var bDays = 29;
}

if (bMonth == 1&&((bYear % 4 != 0) || (bYear % 100 == 0)))
{
var bDays = 28;
}


var FirstMonthDiff = bDays - bDay + 1;


if (eDay - bDay < 0)
{

eMonth = eMonth - 1;
eDay = eDay + eDays;

}

var daysDiff = eDay - bDay;

if(eMonth - bMonth < 0)
{
eYear = eYear - 1;
eMonth = eMonth + 12;
}

var monthDiff = eMonth - bMonth;

var yearDiff = eYear - bYear;

if (daysDiff == eDays)
{
daysDiff = 0;
monthDiff = monthDiff + 1;

if (monthDiff == 12)
{
monthDiff = 0;
yearDiff = yearDiff + 1;
}

}

if ((FirstMonthDiff != bDays)&&(eDay - 1 == eDays))

{
daysDiff = FirstMonthDiff;

}
event.value = yearDiff + \" Year(s)\" + \" \" + monthDiff + \" month(s) \" + daysDiff + \" days(s)\"


回答6:

Some math is in order.

You can subtract one Date object from another in Javascript, and you\'ll get the difference between them in milisseconds. From this result you can extract the other parts you want (days, months etc.)

For example:

var a = new Date(2010, 10, 1);
var b = new Date(2010, 9, 1);

var c = a - b; // c equals 2674800000,
               // the amount of milisseconds between September 1, 2010
               // and August 1, 2010.

Now you can get any part you want. For example, how many days have elapsed between the two dates:

var days = (a - b) / (60 * 60 * 24 * 1000);
// 60 * 60 * 24 * 1000 is the amount of milisseconds in a day.
// the variable days now equals 30.958333333333332.

That\'s almost 31 days. You can then round down for 30 days, and use whatever remained to get the amounts of hours, minutes etc.



回答7:

Yet another solution, based on some PHP code. The strtotime function, also based on PHP, can be found here: http://phpjs.org/functions/strtotime/.

Date.dateDiff = function(d1, d2) {
    d1 /= 1000;
    d2 /= 1000;
    if (d1 > d2) d2 = [d1, d1 = d2][0];

    var diffs = {
        year: 0,
        month: 0,
        day: 0,
        hour: 0,
        minute: 0,
        second: 0
    }

    $.each(diffs, function(interval) {
        while (d2 >= (d3 = Date.strtotime(\'+1 \'+interval, d1))) {
            d1 = d3;
            ++diffs[interval];
        }
    });

    return diffs;
};

Usage:

> d1 = new Date(2000, 0, 1)
Sat Jan 01 2000 00:00:00 GMT+0100 (CET)

> d2 = new Date(2013, 9, 6)
Sun Oct 06 2013 00:00:00 GMT+0200 (CEST)

> Date.dateDiff(d1, d2)
Object {
  day: 5
  hour: 0
  minute: 0
  month: 9
  second: 0
  year: 13
}


回答8:

I have created, yet another one, function for this purpose:

function dateDiff(date) {
    date = date.split(\'-\');
    var today = new Date();
    var year = today.getFullYear();
    var month = today.getMonth() + 1;
    var day = today.getDate();
    var yy = parseInt(date[0]);
    var mm = parseInt(date[1]);
    var dd = parseInt(date[2]);
    var years, months, days;
    // months
    months = month - mm;
    if (day < dd) {
        months = months - 1;
    }
    // years
    years = year - yy;
    if (month * 100 + day < mm * 100 + dd) {
        years = years - 1;
        months = months + 12;
    }
    // days
    days = Math.floor((today.getTime() - (new Date(yy + years, mm + months - 1, dd)).getTime()) / (24 * 60 * 60 * 1000));
    //
    return {years: years, months: months, days: days};
}

Doesn\'t require any 3rd party libraries. Takes one argument -- date in YYYY-MM-DD format.

https://gist.github.com/lemmon/d27c2d4a783b1cf72d1d1cc243458d56



回答9:

@RajeevPNadig\'s answer was what I was looking for, but the code returns incorrect values as written.

My edit to his answer got rejected and I was told to post it as my own answer. This can return some results that feel a little weird, but aren\'t technically incorrect.

// startDate must be a
function dateAgo(date) {
    var startDate = new Date(date);
    var diffDate = new Date(new Date() - startDate);
    return ((diffDate.toISOString().slice(0, 4) - 1970) + \"Y \" +
        diffDate.getMonth() + \"M \" + (diffDate.getDate()-1) + \"D\");
}

Then you can use it like this:

// based on a current date of 2018-03-09
dateAgo(\'1972-11-30\'); // \"45Y 3M 9D\"
dateAgo(\'2017-03-09\'); // \"1Y 0M 0D\"
dateAgo(\'2018-01-09\'); // \"0Y 2M 0D\"
dateAgo(\'2018-02-09\'); // \"0Y 0M 28D\" -- a little odd, but not wrong
dateAgo(\'2018-02-01\'); // \"0Y 1M 5D\" -- definitely \"feels\" wrong
dateAgo(\'2018-03-09\'); // \"0Y 0M 0D\"

Things can get a little weird if you call dateAgo with the current date and aren\'t using an YYYY-MM-DD string, i.e.:

oneMinuteAgo = Date.now() - 60000;
dateAgo(oneMinuteAgo); // \"0Y 11M 30D\" -- ???

If your use case is just date strings, then this should work pretty well for most people.



回答10:

   let startDate = moment(new Date(\'2017-05-12\')); // yyyy-MM-dd
   let endDate = moment(new Date(\'2018-09-14\')); // yyyy-MM-dd

   let Years = newDate.diff(date, \'years\');
   let months = newDate.diff(date, \'months\');
   let days = newDate.diff(date, \'days\');

console.log(\"Year: \" + Years, \", Month: \" months-(Years*12), \", Days: \" days-(Years*365.25)-((365.25*(days- (Years*12)))/12));

Above snippet will print: Year: 1, Month: 4, Days: 2



回答11:

This link has the best answer http://forums.asp.net/t/1610039.aspx?How+to+calculate+difference+between+two+dates+in+years

You only need to add a validation for the days, somthing like:

if ( firstDate.getDate() <= now.getDate() )



回答12:

I would personally use http://www.datejs.com/, really handy. Specifically, look at the time.js file: http://code.google.com/p/datejs/source/browse/trunk/src/time.js



回答13:

Time span in full Days, Hours, Minutes, Seconds, Milliseconds:

// Extension for Date
Date.difference = function (dateFrom, dateTo) {
  var diff = { TotalMs: dateTo - dateFrom };
  diff.Days = Math.floor(diff.TotalMs / 86400000);

  var remHrs = diff.TotalMs % 86400000;
  var remMin = remHrs % 3600000;
  var remS   = remMin % 60000;

  diff.Hours        = Math.floor(remHrs / 3600000);
  diff.Minutes      = Math.floor(remMin / 60000);
  diff.Seconds      = Math.floor(remS   / 1000);
  diff.Milliseconds = Math.floor(remS % 1000);
  return diff;
};

// Usage
var a = new Date(2014, 05, 12, 00, 5, 45, 30); //a: Thu Jun 12 2014 00:05:45 GMT+0400 
var b = new Date(2014, 02, 12, 00, 0, 25, 0);  //b: Wed Mar 12 2014 00:00:25 GMT+0400
var diff = Date.difference(b, a);
/* diff: {
  Days: 92
  Hours: 0
  Minutes: 5
  Seconds: 20
  Milliseconds: 30
  TotalMs: 7949120030
} */


回答14:

Neither of the codes work for me, so I use this instead for months and days:

function monthDiff(d2, d1) {
    var months;
    months = (d2.getFullYear() - d1.getFullYear()) * 12;
    months -= d1.getMonth() + 1;
    months += d2.getMonth() + 1;
    return months <= 0 ? 0 : months;
}

function daysInMonth(date) {
    return new Date(date.getYear(), date.getMonth() + 1, 0).getDate();
}    

function diffDate(date1, date2) {
    if (date2 && date2.getTime() && !isNaN(date2.getTime())) {
        var months = monthDiff(date1, date2);
        var days = 0;

        if (date1.getUTCDate() >= date2.getUTCDate()) {
            days = date1.getUTCDate() - date2.getUTCDate();
        }
        else {
            months--;
            days = date1.getUTCDate() - date2.getUTCDate() + daysInMonth(date2);
        }

        // Use the variables months and days how you need them.
    }
}


回答15:

The following is an algorithm which gives correct but not totally precise since it does not take into account leap year. It also assumes 30 days in a month. A good usage for example is if someone lives in an address from 12/11/2010 to 11/10/2011, it can quickly tells that the person lives there for 10 months and 29 days. From 12/11/2010 to 11/12/2011 is 11 months and 1 day. For certain types of applications, that kind of precision is sufficient. This is for those types of applications because it aims for simplicity:

var datediff = function(start, end) {
  var diff = { years: 0, months: 0, days: 0 };
  var timeDiff = end - start;

  if (timeDiff > 0) {
    diff.years = end.getFullYear() - start.getFullYear();
    diff.months = end.getMonth() - start.getMonth();
    diff.days = end.getDate() - start.getDate();

    if (diff.months < 0) {
      diff.years--;
      diff.months += 12;
    }

    if (diff.days < 0) {
      diff.months = Math.max(0, diff.months - 1);
      diff.days += 30;
    }
  }

  return diff;
};

Unit tests



回答16:

To calculate the difference between two dates in Years, Months, Days, Minutes, Seconds, Milliseconds using TypeScript/ JavaScript

dateDifference(actualDate) {
            // Calculate time between two dates:
            const date1 = actualDate; // the date you already commented/ posted
            const date2: any = new Date(); // today

            let r = {}; // object for clarity
            let message: string;

            const diffInSeconds = Math.abs(date2 - date1) / 1000;
            const days = Math.floor(diffInSeconds / 60 / 60 / 24);
            const hours = Math.floor(diffInSeconds / 60 / 60 % 24);
            const minutes = Math.floor(diffInSeconds / 60 % 60);
            const seconds = Math.floor(diffInSeconds % 60);
            const milliseconds = 
           Math.round((diffInSeconds - Math.floor(diffInSeconds)) * 1000);

            const months = Math.floor(days / 31);
            const years = Math.floor(months / 12);

            // the below object is just optional 
            // if you want to return an object instead of a message
            r = {
                years: years,
                months: months,
                days: days,
                hours: hours,
                minutes: minutes,
                seconds: seconds,
                milliseconds: milliseconds
            };

            // check if difference is in years or months
            if (years === 0 && months === 0) {
                // show in days if no years / months
                if (days > 0) {
                    if (days === 1) {
                        message = days + \' day\';
                    } else { message = days + \' days\'; }
                }  else if (hours > 0) {
                    if (hours === 1) {
                        message = hours + \' hour\';
                    } else {
                        message = hours + \' hours\';
                    }
                } else {
                    // show in minutes if no years / months / days
                    if (minutes === 1) {
                        message = minutes + \' minute\';
                    } else {message = minutes + \' minutes\';}  
                }
            } else if (years === 0 && months > 0) {
                // show in months if no years
                if (months === 1) {
                    message = months + \' month\';
                } else {message = months + \' months\';}
            } else if (years > 0) {
                // show in years if years exist
                if (years === 1) {
                    message = years + \' year\';
                } else {message = years + \' years\';}
            }

            return \'Posted \' + message + \' ago\'; 
     // this is the message a user see in the view
        }

However, you can update the above logic for the message to show seconds and milliseconds too or else use the object \'r\' to format the message whatever way you want.

If you want to directly copy the code, you can view my gist with the above code here



回答17:

I know it is an old thread, but I\'d like to put my 2 cents based on the answer by @Pawel Miech.

It is true that you need to convert the difference into milliseconds, then you need to make some math. But notice that, you need to do the math in backward manner, i.e. you need to calculate years, months, days, hours then minutes.

I used to do some thing like this:

    var mins;
    var hours;
    var days;
    var months;
    var years;

    var diff = new Date() - new Date(yourOldDate);  
// yourOldDate may be is coming from DB, for example, but it should be in the correct format (\"MM/dd/yyyy hh:mm:ss:fff tt\")

    years = Math.floor((diff) / (1000 * 60 * 60 * 24 * 365));
    diff = Math.floor((diff) % (1000 * 60 * 60 * 24 * 365));
    months = Math.floor((diff) / (1000 * 60 * 60 * 24 * 30));
    diff = Math.floor((diff) % (1000 * 60 * 60 * 24 * 30));
    days = Math.floor((diff) / (1000 * 60 * 60 * 24));
    diff = Math.floor((diff) % (1000 * 60 * 60 * 24));
    hours = Math.floor((diff) / (1000 * 60 * 60));
    diff = Math.floor((diff) % (1000 * 60 * 60));
    mins = Math.floor((diff) / (1000 * 60));

But, of course, this is not precise because it assumes that all years have 365 days and all months have 30 days, which is not true in all cases.



回答18:

Very old thread, I know, but here\'s my contribution, as the thread is not solved yet.

It takes leap years into consideration and does not asume any fixed number of days per month or year.

It might be flawed in border cases as I haven\'t tested it thoroughly, but it works for all the dates provided in the original question, thus I\'m confident.

function calculate() {
  var fromDate = document.getElementById(\'fromDate\').value;
  var toDate = document.getElementById(\'toDate\').value;

  try {
    document.getElementById(\'result\').innerHTML = \'\';

    var result = getDateDifference(new Date(fromDate), new Date(toDate));

    if (result && !isNaN(result.years)) {
      document.getElementById(\'result\').innerHTML =
        result.years + \' year\' + (result.years == 1 ? \' \' : \'s \') +
        result.months + \' month\' + (result.months == 1 ? \' \' : \'s \') + \'and \' +
        result.days + \' day\' + (result.days == 1 ? \'\' : \'s\');
    }
  } catch (e) {
    console.error(e);
  }
}

function getDateDifference(startDate, endDate) {
  if (startDate > endDate) {
    console.error(\'Start date must be before end date\');
    return null;
  }
  var startYear = startDate.getFullYear();
  var startMonth = startDate.getMonth();
  var startDay = startDate.getDate();

  var endYear = endDate.getFullYear();
  var endMonth = endDate.getMonth();
  var endDay = endDate.getDate();

  // We calculate February based on end year as it might be a leep year which might influence the number of days.
  var february = (endYear % 4 == 0 && endYear % 100 != 0) || endYear % 400 == 0 ? 29 : 28;
  var daysOfMonth = [31, february, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];

  var startDateNotPassedInEndYear = (endMonth < startMonth) || endMonth == startMonth && endDay < startDay;
  var years = endYear - startYear - (startDateNotPassedInEndYear ? 1 : 0);

  var months = (12 + endMonth - startMonth - (endDay < startDay ? 1 : 0)) % 12;

  // (12 + ...) % 12 makes sure index is always between 0 and 11
  var days = startDay <= endDay ? endDay - startDay : daysOfMonth[(12 + endMonth - 1) % 12] - startDay + endDay;

  return {
    years: years,
    months: months,
    days: days
  };
}
<p><input type=\"text\" name=\"fromDate\" id=\"fromDate\" placeholder=\"yyyy-mm-dd\" value=\"1999-02-28\" /></p>
<p><input type=\"text\" name=\"toDate\" id=\"toDate\" placeholder=\"yyyy-mm-dd\" value=\"2000-03-01\" /></p>
<p><input type=\"button\" name=\"calculate\" value=\"Calculate\" onclick=\"javascript:calculate();\" /></p>
<p />
<p id=\"result\"></p>