Reputation: 430
I am trying to add/subtract an integer to the element of array. my function is
var addToMonth = function (date, monthsToAdd) {
var tempDate = date.split("-");
tempDate[1] = parseInt(tempDate[1]) + monthsToAdd;
tempDate[1] = 0 + tempDate[1];
console.log("TempDate "+tempDate[1]);
tempDate = tempDate.join("-");
console.log("Added TempDate: "+tempDate);
return tempDate;
}
The acceptable date string is: date = "2016-04-05"
. If call the function as addToMonth(date,1)
. The output is correct that is 2016-05-05
. But when I call it as addToMonth(date, -1)
. It doesn't work. What is the correct way to do it?
Upvotes: 0
Views: 5014
Reputation: 7184
Original 2016
The selected answer is actually incorrect as the question asks how to add months, not days. The correct solution is:
function addToMonth( date, months ) {
var d = new Date( date || new Date() );
d.setMonth( d.getMonth() + (months || 0), d.getDate());
return d;
}
Show and then run the code snippet to view demo.
I've also up voted the question ... because it does show effort and dates are tricky to work with even for experienced coders (especially when time zones are involved). That's why there are libraries like monment.js and others. For more information on the Date object see: MDN Date
function addToMonth( date, months ) {
var d = new Date( date || new Date() );
d.setMonth( d.getMonth() + (months || 0), d.getDate());
return d;
}
// Test Data
var html = '', iso, step = 1;
[
'4/5/2016',
'4/5/2016 01:00 GMT',
'2016-04-05',
'2016-04-05T00:00:00',
'2016-04-05T23:59:59',
'2016-04-05T23:59:59Z',
'2016',
'4/5/2016',
undefined,
null,
0,
'',
(new Date())
].forEach(function(v,i) {
iso = addToMonth( v, -1).toISOString().split('T').shift();
html += '<tr><td>' + v + '</td><td>-1</td><td>' + iso + '</td></tr>';
iso = addToMonth( v, 1).toISOString().split('T').shift();
html += '<tr><td>' + v + '</td><td>+1</td><td>' + iso + '</td></tr>';
});
stdout.innerHTML = '<table>' + html + '</table>';
table {
border-collapse: collapse;
background-color: white;
}
td {
max-width: 10em;
min-width: 4em;
border: 1px lightgray solid;
padding: 2px;
overflow: hidden;
white-space: nowrap;
font-family: monospace;
}
tr:nth-child(odd) {
background-color: aliceblue;
}
<div id="stdout"></div>
Update 2023
A commenter noted the edge case where the day of the month is greater than the target maximum. In this case the function uses the default Date.setMonth behavior, which can spill over into the following month, e.g., 31 Jan + 1 month = 3 Mar rather than 28 Feb. Since the question doesn't specify how to handle these cases it seems reasonable to use the expected behavior and not try to guess what OP wants.
The commenter also noted that getDate
is redundant in
d.setMonth( d.getMonth() + (months || 0), d.getDate())
True, and it can be shortened to
d.setMonth( d.getMonth() + (months || 0))
Interestingly, this change didn't appear to make any difference in performance (Chrome 100k loops).
Alternative code that incorporates commenter suggestions:
function addToMonth( date, months ) {
let d = new Date( date || new Date() ), n = d.getDate();
d.setMonth( d.getMonth() + (months || 0));
if (d.getDate() < n) d.setMonth( d.getMonth(), 0);
return d;
}
Upvotes: 4
Reputation: 36703
Yours is not a right approach:
parseInt
should always use base 10 if working with decimals.addToMonth("2016-31-03", 1)
will give 2016-32-03. WRONG X.addToMonth("2016-01-03", -1)
will give 2016-00-03. WRONG X.0
is not right. (Find out why.)Use setDate
and getDate
functions on date instead.
var addToMonth = function (date, monthsToAdd) {
var d = new Date(date);
d.setDate(d.getDate()+monthsToAdd);
return d;
}
Upvotes: 1