0

I'm trying to calculate a date based on another date by adding a certain period of time. Let's say if I want to add 3 months to a date, then the new date should be one day before the date after 3 months. Taking that example, below is the code that I came closest to for achieving what I want to do:

new Date(
    date
        .setMonth(date.getMonth() + 3)
        .setDate(date.getDate() - 1)
)

But this returns an error: TypeError: date.setMonth(...).setDate is not a function. I think the chaining of methods is not working, so I'll probably have to setDate in the next statement. Is there a way to do this in a single statement of code?

  • 2
    setMonth does not return the date object - you can't chain methods like that with Date methods – Jaromanda X Sep 28 '20 at 09:42
  • The [`Temporal` proposal](https://tc39.es/proposal-temporal/) (currently stage 2) will make [it easier](https://tc39.es/proposal-temporal/docs/cookbook.html). – Andreas Sep 28 '20 at 09:58

4 Answers4

1

Is there a way to set date and month on a date object in a single statement?

Yes. The following sets the month to January and the day to the first on one statement:

let d = new Date();
d.setMonth(0, 1);

…if I want to add 3 months to a date, then the new date should be one day before the date after 3 months

No, you can't do that in one statement because adding a month needs to consider the number of days in the month. E.g. adding one month to 31 Jan 2020 results in 31 Feb, and since there were only 29 days in Feb 2020, the date is set to 2 Mar 2020. Similarly, adding 1 month to 31 May gives 31 Jun which rolls over to 1 Jul. So you need to add months first (see Adding months to a Date in JavaScript), then subtract one day (see Add days to JavaScript Date).

RobG
  • 142,382
  • 31
  • 172
  • 209
  • Ah, I see the issue. I thought adding the dayValue parameter would solve the problem and hence posted it as answer, but cases with months having 28, 29, 30 days would still face this issue.I guess two statements would be better to avoid such issues. Thanks! – Chintan Dhandhusariya Sep 28 '20 at 10:29
  • The issue still remains even if I add the months first and then subtract the date. It still rolls over to 2 Mar in case of Feb ending. I even tried setting date first and then month. But that also has a similar issue. In that case it occurs when a starting date is entered. – Chintan Dhandhusariya Sep 28 '20 at 11:19
  • @ChintanDhandhusariya—not if you apply the linked answers. – RobG Sep 28 '20 at 11:56
  • I did. Here is the update to my example code: `oldDate // 30 Nov 2020` `let newDate = new Date(oldDate);` `newDate.setMonth(newDate.getMonth() + 3);` `newDate.setDate(newDate.getDate() - 1);` `console.log(newDate); // 1 March 2021` – Chintan Dhandhusariya Sep 28 '20 at 12:15
  • @ChintanDhandhusariya—that doesn't apply the algorithm in the [accepted answer](https://stackoverflow.com/a/12793246/257182), it just copies the erroneous simplistic solution. – RobG Sep 28 '20 at 21:47
  • I get it now. Thanks. But does the solution not work without `dateObj.getFullYear() * 12`? It seems pointless. Why not just get the difference from earlier month and updated month? Does it cover any edge case scenario? – Chintan Dhandhusariya Sep 29 '20 at 11:03
0

You could so something like

newDate = new Date(newDate.getFullYear(), newDate.getMonth() + 3, endDate.getDate() -1)
clanglai
  • 149
  • 1
  • 6
  • getYear() is deprecated now (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getYear) but I used getFullYear() instead and I think it works. Thanks. Testing for scenarios where year might change. – Chintan Dhandhusariya Sep 28 '20 at 10:04
  • Does that work if `newDate.getMonth()` returns e.g. 10? The Javadoc is not specific about that case... – Erich Kitzmueller Sep 28 '20 at 10:14
  • I guess you could use a modulo to ensure that month value will stay inside the 0 to 11 range – clanglai Sep 28 '20 at 10:25
  • @ErichKitzmueller It works in those cases, but it still has the issue mentioned in RobG's [answer](https://stackoverflow.com/a/64100148/7721183) – Chintan Dhandhusariya Sep 28 '20 at 10:46
  • @ChintanDhandhusariya Thanks. I just noticed that I confused the JavaScript `Date` class this question is about with the Java class `java.util.Date`, so my previous comment makes little sense ;-) – Erich Kitzmueller Sep 28 '20 at 11:26
  • @ErichKitzmueller By "this question is about with the Java class", do you mean your question in your comment or my question? Because my question actually _is_ about javascript date object (There is a #javascript tag in the question). – Chintan Dhandhusariya Sep 28 '20 at 11:36
  • @ChintanDhandhusariya I meant my first comment. For whatever reason I thought the original question was about Java, not JavaScript. Sorry for the confusion, the second comment was not any better. Needs more coffee ---> – Erich Kitzmueller Sep 28 '20 at 14:10
0

You could extend the Date Object and create your own methods which are chainable.

class MyDate extends Date {
  constructor() {
    super(...arguments)
  }
  
  changeMonth(amount) {
    return new MyDate(this.setMonth(this.getMonth() + amount));
  }
  
  changeDate(amount) {
    return new MyDate(this.setDate(this.getDate() + amount));
  }
};

const date = new MyDate();

console.log("Original:", date);
console.log("Changed :", date.changeMonth(3).changeDate(-5));
Reyno
  • 6,119
  • 18
  • 27
  • That isn't a good way to add months, see [Adding months to a Date in JavaScript](https://stackoverflow.com/questions/12793045/adding-months-to-a-date-in-javascript). Extending built–in objects isn't recommended. – RobG Sep 28 '20 at 10:14
0

Turns out there is a very simple solution. The setMonth() method allows us to pass an optional dayValue parameter (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/setMonth). Using which, the code simply becomes:

new Date(
    date.setMonth(
        date.getMonth() + 3,
        date.getDate() - 1
    )
)
  • This doesn't work where the start date is say 30 Nov and adding 3 months gives 30 Feb, which goes to 1 or 2 Mar, see see [Adding months to a Date in JavaScript](https://stackoverflow.com/questions/12793045/adding-months-to-a-date-in-javascript). – RobG Sep 28 '20 at 11:57