Home > Software design >  Why does Javascript's Date.getDate() .setDate() behave so unpredictably?
Why does Javascript's Date.getDate() .setDate() behave so unpredictably?

Time:06-24

Hobbyist coder here, and this problem is above my pay grade. I'm trying to build a dynamic html / css calendar, where the cells are filled in based on today's date. I get today's date, and then try to add days to fill in another 13 days (looping thru html elements.innerHTML).

If I try to setDate(30 2) and then getDate(). The code works fine. Javascript figures out that June ends at the 30th day, and the result is 2 as desired (July 2nd)

But this only works if there's only one call, if I have a loop, or call this code multiple times, then the result is different. Is there some async stuff gumming up the works? Here's code: If you leave the "result2" call and comment the others, works great, but multiple calls, things break and numbers get repeated. Please help!

const theDate = new Date();
    const todaysDate = 30;
    
    theDate.setDate(todaysDate   1);
    let result1 = theDate.getDate();
    
    theDate.setDate(todaysDate   2);
    let result2 = theDate.getDate();
    
    theDate.setDate(todaysDate   3);
    let result3 = theDate.getDate();
    
    theDate.setDate(todaysDate   4);
    let result4 = theDate.getDate();
    
    console.log(result1);
    console.log(result2);
    console.log(result3);
    console.log(result4);

CodePudding user response:

June has 30 days but July has 31 days.

When you set the date to 32 for the first time, you are setting it to the 32nd of June and the dates after June 30 push it to July 2nd. (32-30=2)

When you set to 32 again, it is already July so the dates after July 31 push it to August 1st (32-31=1).

CodePudding user response:

In answer to your question, the setDate() function is behaving so strangely for you because each time you are setting the date you are setting it relative to the previous setting, so incrementing each time by 31, 32, or 33 days instead of by 1, 2, or 3. See the brilliant answer by @Quentin for more information, this finding was entirely his and I just wanted to mention the root cause in my answer as well as my own fix to your problem.


An alternative solution if you just want to generate the dates:

const dayOfMonth = 30;
const date = new Date();
date.setDate(dayOfMonth);
console.log("Date:", date);

let timestamp = Date.parse(date);

for (let i = 1; i <= 14; i  ) {
  const newTimestamp = timestamp   i * (1000 * 60 * 60 * 24);
  const newDate = new Date(newTimestamp);
  console.log("New date:", newDate);
}

This method will manipulate the timestamp and generate new dates for each of the timestamps added to the number of milliseconds in a day.

You could use your date logic within the loop to populate the calendar as you mentioned.

CodePudding user response:

If you use the Date() constructor on each iteration, you don't have to worry about the varying days of a particular month.

Details are commented in example

/**
 * @desc - return a range of dates starting today (or a given
 *         date) and a given number of days (including start)
 * @param {number} range - The number of days
 * @param {string<date>} start - The date to start the range
 *        if not defined @default is today
 * @return {array<date>} An array of dates
 */
function dayRange(range, start) {
  // If undefined default is today
  let now = start ? new Date(start) : new Date();
  // Create an array of empty slots - .length === range
  let rng = [...new Array(range)];

  /*
  .map() through array rng
  If it's the first iteration add today's date...
  ... otherwise get tommorow's date...
  and return it in local format
  */
  return rng.map((_, i) => {
    if (i === 0) {
      return now.toLocaleDateString();
    }
    let day = now.getDate()   1;
    now.setDate(day);
    return now.toLocaleDateString();
  });
}

console.log("Pass the first parameter if the start day is today");
console.log(JSON.stringify(dayRange(14)));

console.log("Pass a properly formatted date string as the second parameter if you want to start on a date other than today");
console.log(JSON.stringify(dayRange(10, '05/12/2020')));

  • Related