Subtracting 1 month to 2015-12-31 gives 2015-12-01

2019-01-20 13:39发布

问题:

I'm trying to subtract one month from 2015-12-31 but it gives me 2015-12-01 instead of 2015-11-30. Why ?

Code:

var date1 = new Date('2015-12-31');
var date2 = new Date(date1);

date2.setMonth(date1.getMonth() - 1);
console.log(date1);
console.log(date2);

Output:

Thu Dec 31 2015 01:00:00 GMT+0100 (CET)
Tue Dec 01 2015 01:00:00 GMT+0100 (CET)

Any workaround?

回答1:

Try this

var date1 = new Date('2015-12-31');
var date2 = new Date(date1);
date2.setDate(date2.getDate()-date1.getDate()); 
alert(date2)


回答2:

When subtracting months, you can check whether the day of the adjusted Date is different to the day of the initial Date. If it is, then it must have rolled over to the next month, so set the day of the adjusted Date to 0, so it goes to the last day of the previous month, e.g.

function subtractMonths(date, months) {
  var day = date.getDate();
  date.setMonth(date.getMonth() - months);
  if (date.getDate() != day) date.setDate(0);
  return date;
}

// 31 Mar 2016 - 1 month = 29 Feb 2015
[[new Date(2016,2,31), 1],

 // 29 Feb 2016 - 12 months = 28 Feb 2015
 [new Date(2016,1,29), 12],

 // 15 Feb 2016 - 3 months = 15 Nov 2015
 [new Date(2016,1,15), 3]].forEach(function(arr){
  document.write('<br>' + subtractMonths(arr[0], arr[1]));
})

The same algorithm can be used for adding months. Note that this is why date arithmetic is not symmetric, e.g.

31 May + 1 month  => 30 June
30 June - 1 month => 30 May

i.e. If A + B = C, then C - B = A may or may not be true (and vice versa).



回答3:

Per the setMonth documentation, ‘If you do not specify the [optional] dayValue parameter, the value returned from the getDate() method is used’. Since you’re not specifying the optional parameter, your code tries to set the date to 2015-11-31, which isn’t valid. JavaScript resolves this situation by setting the date to one day after 2015-11-30, which is 2015-12-01.

As for a workaround, it depends on what you’re actually trying to do. Are you trying to go 31 days back from 31 December? Or are you trying to get the last day of the month before December? Date semantics are extremely complicated; what are you going to do when the inevitable edge cases arise?



回答4:

It is producing the requested result, which is subtracting 1 month from the date given. But remember a month is a variable amount of time. November 31 is actually December 1 (just like November 55th would actually be December 25, Christmas). To get the last day of the previous month you could do something like this:

var date = new Date('2015-12-31');
date.setDate(-1)