1

I am calculating date in JavaScript based on date, frequency and period. When I am calculating date for one month then It is working perfectly but when I am trying to calculate date three monthly or six monthly then below code is not working fine.

CurrentDate value is 01-Feb-2023 and value of X is 3

When I am giving value of x = 1 then below code is giving 1-Mar-2023 which is correct but when I am giving value of x = 3 then it is giving 1-Feb-2024 instead of 1-May-2023.

var x = 3;
CurrentDate = "01-Feb-2023"
var d = new Date(CurrentDate);
console.log(d);
d.setMonth(d.getMonth() + x);
console.log(d);
var lastDate = moment(d.toISOString().slice(0, 10)).format("DD-MMM-YYYY");
console.log(lastDate)
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.4/moment.min.js"></script>
RobG
  • 142,382
  • 31
  • 172
  • 209
Moin Khan
  • 674
  • 2
  • 9
  • 27

1 Answers1

1

You have a timezone issue

Also you are wasting moment by not using it to add the month

Note that this date format makes moment complain: '01-Feb-2023'

var x = 3;
var currentDate = moment('01-Feb-2023'); // not a great value for moment
var lastDate = moment(currentDate).add(x, 'M').format("DD-MMM-YYYY");

console.log(lastDate)
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.4/moment.min.js"></script>

Better: Strict mode is set by passing true as the third parameter to the moment function.

moment('02/01/2023', 'MM/DD/YYYY', true);

var x = 3;
var currentDate = moment('02/01/2023', 'MM/DD/YYYY', true); // better
var lastDate = moment(currentDate).add(x, 'M').format("DD-MMM-YYYY");

console.log(lastDate)
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.4/moment.min.js"></script>

Without moment - note the new Date(dateString); is STILL not a good idea with "01-Feb-2023" due to Why does Date.parse give incorrect results?

But if you can live with this, then here is a version

const dateTimeFormat = new Intl.DateTimeFormat('en-US', { year: 'numeric', month: 'short', day: 'numeric' });

const addToDate = (dateString, offset) => {
  const currentDate = new Date(dateString); // using the Date.parse. Moment warned it would use this
  currentDate.setHours(15, 0, 0, 0) // normalise
  currentDate.setMonth(currentDate.getMonth() + offset); // add the month
  const [month, sp1, day, comma, year] = dateTimeFormat.formatToParts(currentDate);
  return `${day.value}-${month.value}-${year.value}`; // There is no DD-MMM-YYYY in INTL so we make our own
}

let x = 3;
const lastDate = addToDate("01-Feb-2023", x);
console.log("01-Feb-2023 plus",x,"months:",lastDate)
mplungjan
  • 169,008
  • 28
  • 173
  • 236
  • 1
    `new Date("01-Feb-2023")` is not a good idea, see [*Why does Date.parse give incorrect results?*](https://stackoverflow.com/questions/2587345/why-does-date-parse-give-incorrect-results) If using moment.js, there's no need to change the format of the input timestamp, just use the right tokens: "DD-MMM-YYYY". – RobG Feb 01 '23 at 14:17
  • @RobG Note the warning we get in first example: `Deprecation warning: value provided is not in a recognized RFC2822 or ISO format. moment construction falls back to js Date(), which is not reliable across all browsers and versions. Non RFC2822/ISO date formats are discouraged. Please refer to http://momentjs.com/guides/#/warnings/js-date/ for more info.` – mplungjan Feb 01 '23 at 14:52
  • Sure, but parsing using `moment(dateString, 'DD-MMM-YYYY')` solves the issue up front. ;-) – RobG Feb 01 '23 at 22:33
  • As I do in the second example.. I am not sure why that is not enough information. It is basically what I say in my answer. – mplungjan Feb 02 '23 at 06:45