365

I want to add months to a date in JavaScript.

For example: I am inserting date 06/01/2011 (format mm/dd/yyyy) and now I want to add 8 months to this date. I want the result to be 02/01/2012.

So when adding months, the year may also increase.

Simon Johnson
  • 7,802
  • 5
  • 37
  • 49
Kanak Vaghela
  • 7,750
  • 10
  • 32
  • 37
  • If, you add 8 months to the date 06/01/2011 how it will be changed to 02/01/2011, Please can you make it some what clear – Sai Kalyan Kumar Akshinthala Apr 13 '11 at 06:07
  • 1
    this is a hard problem to get right - what happens if you're on the 31st of a month and the target month doesn't have 31 days? Even worse, what if the target month is February? – Alnitak Apr 13 '11 at 06:08
  • @kalyan : if I add 8 months to the date 06/01/2011(mm/dd/yyyy) then it will be 02/01/2012 because if we add 06+08 = 14 and we have only 12 months so it will change the year and give the result as 02/01/2012. – Kanak Vaghela Apr 13 '11 at 06:12
  • @Alnitak : No dear it will only start with 1st date of month. – Kanak Vaghela Apr 13 '11 at 06:13
  • then you should have said so.... – Alnitak Apr 13 '11 at 06:15
  • I suggest adding days instead of months. if you add one month to 30.01.2011 what would the result be? 30.02.2011 ? 02.03.2011 ? – Özgür Kaplan Apr 13 '11 at 06:27
  • @Alnitak : I have already maintain that in the my question... – Kanak Vaghela Apr 13 '11 at 07:05
  • no, you didn't. The fact that the dates in your question are all the 1st would be taken by most as an _example_, and not a _constraint_. You even said so: "For example:". – Alnitak Apr 13 '11 at 08:59
  • var month = new Date(someDate).getMonth() + 1; – Jnr Nov 07 '18 at 06:09
  • Just encountered this issue today, in case the day of the date is between 1 - 28 (where we know for sure the next month has these days) you can just use `setMonth(currentMonth + 1)`, else use Luxon or any other `Date` replacement because it won't work otherwise (unless you do parsing on the backend, because JS zero-month based dates is going to screw you) – late1 Apr 27 '22 at 08:40

3 Answers3

471

Corrected as of 25.06.2019:

var newDate = new Date(date.setMonth(date.getMonth()+8));

Old From here:

var jan312009 = new Date(2009, 0, 31);
var eightMonthsFromJan312009  = jan312009.setMonth(jan312009.getMonth()+8);
Daniel Protopopov
  • 6,778
  • 3
  • 23
  • 39
  • 70
    that's not a typo - the Date constructor uses 0 for January, not 1. – Alnitak Apr 13 '11 at 06:19
  • 1
    What if for example you add 1 instead of 8? It would display February 31st 2009 would it not? – Will Sampson May 31 '13 at 23:05
  • 2
    @Sampson. No, it will display March 3rd 2009 :) – Cristian Ciocău Aug 22 '13 at 14:10
  • 9
    Check this solution for last days in month ;) – Szorstki May 27 '14 at 12:39
  • 2
    Why do you have to do `new Date` on `jan3120091` twice? Couldn't the second line be `var eight.... = jan312009.setMonth(jan312009.getMonth()+8);`? – Kellen Stuart Jul 13 '16 at 21:33
  • 22
    the setMonth() method mutates the date it's called on so surely you need to do the following to not change jan312009 var jan312009 = new Date(2009, 0, 31); var eightMonthsFromJan312009 = new Date(jan312009.getTime()); eightMonthsFromJan312009.setMonth(jan312009.getMonth()+8); – tazmaniax Jul 04 '17 at 16:27
  • running this code in a REPL sets `eightMonthsFromJan312009` to a number, not a valid date. Calling `jan312009.setMonth(jan312009.getMonth()+8);` changes the variable `jan312009` rather than returning the expected value. – gudatcomputers Sep 06 '17 at 14:42
  • To run it in REPL one needs to remove var before the declaration of variables. – Daniel Protopopov Sep 06 '17 at 16:33
  • no you don't.. if you use http://repl.it it just takes pure Javascript like what you've pasted. Try it.. see the results. – gudatcomputers Sep 06 '17 at 19:50
  • This is really not a reusable solution since setMonth can only accept values from 0-11. So you can't add 8 month to April. – Vinayak Thatte Nov 06 '18 at 09:56
  • OP, please change your answer : as @tazmaniax and other people said, the `setMonth()` method does not return a `Date` object, it returns a `Number` representative of the unix timestamp (https://www.w3schools.com/jsref/jsref_setmonth.asp) Therefore, the acceptable answers would be to either remove the new var assignation, or instance a new Date object using the returned timestamp : `var newDate = new Date(date.setMonth(date.getMonth()+8))` – Ghis Jun 25 '19 at 13:34
  • 20
    It's important to emphasize that both `date` and `newDate` will contain the same date after this code is run. IOW `date` is modified by this code. – Roger Feb 13 '20 at 14:34
  • 1
    @VinayakThatte it seems that it accepts more than that, please check the [docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/setMonth). monthValue: A zero-based integer representing the month of the year offset from the start of the year. So, 0 represents January, 11 represents December, -1 represents December of the previous year, and 12 represents January of the following year. – MhdSyrwan Mar 16 '20 at 09:17
  • error "date" as shown in lowercase is nothing in JS – Devmyselz Aug 03 '22 at 12:03
  • 1
    adding 1 month to 31 of January dives you 3 March is it OK? – serge Oct 19 '22 at 07:33
  • Gives Invalid date error when the added months sum to > 12 – Yee Nov 26 '22 at 02:41
129

I took a look at the datejs and stripped out the code necessary to add months to a date handling edge cases (leap year, shorter months, etc):

Date.isLeapYear = function (year) { 
    return (((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0)); 
};

Date.getDaysInMonth = function (year, month) {
    return [31, (Date.isLeapYear(year) ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month];
};

Date.prototype.isLeapYear = function () { 
    return Date.isLeapYear(this.getFullYear()); 
};

Date.prototype.getDaysInMonth = function () { 
    return Date.getDaysInMonth(this.getFullYear(), this.getMonth());
};

Date.prototype.addMonths = function (value) {
    var n = this.getDate();
    this.setDate(1);
    this.setMonth(this.getMonth() + value);
    this.setDate(Math.min(n, this.getDaysInMonth()));
    return this;
};

This will add "addMonths()" function to any javascript date object that should handle edge cases. Thanks to Coolite Inc!

Use:

var myDate = new Date("01/31/2012");
var result1 = myDate.addMonths(1);

var myDate2 = new Date("01/31/2011");
var result2 = myDate2.addMonths(1);

->> newDate.addMonths -> mydate.addMonths

result1 = "Feb 29 2012"

result2 = "Feb 28 2011"

Jazaret
  • 3,655
  • 3
  • 17
  • 15
  • 8
    Is this the only solution that considers for example this: Oct 31 2011 + 1 ? – chris Sep 26 '13 at 07:11
  • 1
    easier IMHO finding days in month is return new Date(year, month+1, 0).getDate(); So also the need for isLeapYear() falls. Also not clear the need for not-Prototype-Methods – Daniel Nov 14 '14 at 09:43
  • Interesting Daniel that you can put a 0 day to get the previous month. – Jazaret Nov 14 '14 at 17:15
  • 2
    There is a problem with this solution: https://jsfiddle.net/nikoudel/mdzaddeh/ Suppose initial date is "2011-03-11T00:00:00Z" and local timezone is Helsinki (GMT+2). When adding six months, an hour gets lost because of daylight savings time: Sat, 10 Sep 2011 23:00:00 GMT. – Nikolai Koudelia Mar 31 '16 at 10:40
  • See [this response](http://stackoverflow.com/a/36331522/513570) when a non extending prototype solution is needed, as discussed in http://stackoverflow.com/questions/14034180/why-is-extending-native-objects-a-bad-practice – Miquel Mar 31 '16 at 11:03
18

I would highly recommend taking a look at datejs. With it's api, it becomes drop dead simple to add a month (and lots of other date functionality):

var one_month_from_your_date = your_date_object.add(1).month();

What's nice about datejs is that it handles edge cases, because technically you can do this using the native Date object and it's attached methods. But you end up pulling your hair out over edge cases, which datejs has taken care of for you.

Plus it's open source!

Alex
  • 64,178
  • 48
  • 151
  • 180