0

Why when I subtract these two dates do I get the wrong answer

var a = new Date("1990","0","1");
var b = new Date("1900","0","1");

var x = new Date(a - b);

console.log(x);

answer: Date {Thu Jan 01 1880 02:00:00 GMT+0200 (South Africa Standard Time)}

How do I make it return : 90 years and 0 days and 0 months

Hello-World
  • 9,277
  • 23
  • 88
  • 154

5 Answers5

2

Take a look at Moments.js

var start = moment([1990, 0, 1]);
var end = moment([1900, 0, 1]);

console.log(start.from(end));
console.log(start.from(end, true));
console.log(start.diff(end, "years"));

gives

in 90 years
90 years 
90

On jsfiddle

To get the exact format that you have requested will require a little more work though, something like this

var start = moment([1990, 0, 1]);
var end = moment([1900, 0, 2]);

var diff = start.diff(end, "years", true);

console.log(Math.floor(diff) + " years and " + Math.floor(30 * ((12 * (diff % 1)) % 1)) + " days and " + Math.floor(12 * (diff % 1)) + " months");

gives

89 years and 29 days and 11 months 

And my calculation above doesn't include leap year or any other differences, it's just rough, but you get the idea.

On jsfiddle

Xotic750
  • 22,914
  • 8
  • 57
  • 79
1

When you subtract two date objects, the result is the difference in milliseconds. It's equivalent to:

a.getTime() - b.getTime();

If you want the difference in years, months and days, that's a different proposition as you can't directly convert large millisecond values due to the difference in the length of days (may be 1hr longer or shorter over daylight saving changes), months (may be 28 to 31 days inclusive) and years (leap years and non–leap years).

The following script is meant for calculating age, but it can easily be adapted to your purpose:

// Given a date object, calcualte the number of
// days in the month
function daysInMonth(d) {
  return (new Date(d.getFullYear(), (d.getMonth() + 1), 0)).getDate();
}

/* For person born on birthDate, return their 
** age on datumDate.
**
** Don't modify original date objects
**
** tDate is used as adding and subtracting
** years, months and days from dates on 29 February 
** can affect the outcome, 
**
** e.g.
**
** 2000-02-29 + 1 year => 2001-03-01
** 2001-03-01 - 1 year => 2000-03-01 so not symetric
**
** Note: in some systems, a person born on 29-Feb
** will have an official birthday on 28-Feb, other 
** systems will have official birthday on 01-Mar.
*/
function getAge(birthDate, datumDate) {

  // Make sure birthDate is before datumDate
  if (birthDate - datumDate > 0) return null;

  var dob = new Date(+birthDate),
      now = new Date(+datumDate),
      tDate = new Date(+dob),
      dobY = dob.getFullYear(),
      nowY = now.getFullYear(),
      years, months, days;

  // Initial estimate of years
  years = nowY - dobY;
  dobY = (dobY + years);
  tDate.setYear(dobY);

  // Correct if too many
  if (now < tDate) {
    --years;
    --dobY;
  }
  dob.setYear(dobY);

  // Repair tDate
  tDate = new Date(+dob);

  // Initial month estimate
  months = now.getMonth() - tDate.getMonth();

  // Adjust if needed
  if (months < 0) {
    months = 12 + months;

  } else if (months == 0 && tDate.getDate() > now.getDate()) {
    months = 11;
  }
  tDate.setMonth(tDate.getMonth() + months);

  if (now < tDate) {
    --months;
    dob.setMonth(tDate.getMonth() - 1); 
  }

  // Repair tDate
  tDate = new Date(+dob);

  // Initial day estimate
  days = now.getDate() - tDate.getDate();

  // Adjust if needed 
  if (days < 0) {
    days = days + daysInMonth(tDate);
  }
  dob.setDate(dob.getDate() + days);

  if (now < dob) {
    --days;
  }

  return years + 'y ' + months + 'm ' + days + 'd';
}
RobG
  • 142,382
  • 31
  • 172
  • 209
1

The problem with your code is that x will contain the difference in milliseconds between those two dates. Next if you represent that as a new Date() it will simply subtract it from date 0 (1 jan 1970) giving you the answer you're seeing. Thus if you want to get the number of years you could do:

var x = a-b;
var years = x/1000/60/60/24/365.2425

Though that will be not be exact depending on the specific years in the range, however in most cases it will do. If on the other hand you want a precise answer or more versatile tool you can use a third party library or function as provided by the other answers. (As mentioned, moment.js is a good one)

David Mulder
  • 26,123
  • 9
  • 51
  • 114
0

This will give you the difference between 2 dates in years, months and days:

function dateDiff(a,b){
    var low = (a>b)?b:a,
    heigh = (a>b)?a:b,
    diff = {
        years:0,
        months:0,
        days:0
    },
    tmpMonth,
    lowDate=low.getDate();
    heighDate=heigh.getDate()
    while(lowDate!==heighDate){
        low.setDate(low.getDate()+1);
        diff.days++;
        if(low>heigh){
          low.setDate(low.getDate()-1);
          diff.days--;
          break;
        }
        lowDate=low.getDate();
    }
    if(low==heigh){return diff;}//a===b no difference
    diff.years=heigh.getFullYear()-low.getFullYear();
    low.setFullYear(low.getFullYear()+diff.years);
    if(low>heigh){
      low.setFullYear(low.getFullYear()-1);
      diff.years--;
    }
    tmpMonth=heigh.getMonth()-low.getMonth();
    diff.months=(tmpMonth<0)?tmpMonth+12:tmpMonth;
    low.setMonth(low.getMonth()+diff.months);
    if(low>heigh){
      low.setMonth(low.getMonth()-1);
      diff.months--;
    }
    return diff;
}


var a = new Date(2001,1,25);//Feb 25
var b = new Date(2001,2,3);
console.log(dateDiff(a,b));
var a = new Date(2000,1,25);//Feb 25
var b = new Date(2000,2,3);
console.log(dateDiff(a,b));
var a = new Date(2000,1,25);//Feb 25
var b = new Date(2001,2,3);
console.log(dateDiff(a,b));
HMR
  • 37,593
  • 24
  • 91
  • 160
-1

I don't think the - operator works with dates. Try

var x = new Date(a.getTime() - b.getTime());

According to @Quentin, the above is not correct.

Still, I don't think it would yield the result you expect... If you want a duration or a period to represent the difference in some time unit, check out moment.js instead.

Example:

var a = moment([1990, 1, 1]);
var b = moment([1900, 1, 1]);
b.from(a); // 90 years ago
NilsH
  • 13,705
  • 4
  • 41
  • 59