0

I'm trying to build a custom datepicker. I am struggling in my understanding of JS Date, I need help to identify the gap however. I have some weirdness happening while trying to create dates using a for loop!

Basically I create a date, grab the # of days in the month, and create Date objects using a valid date string for display/processing using that number.

For some months (month # > 9 based on my testing), the 9th day is repeated, so the integer 10 doesn't make it into the date. The rest of the date is created 1 behind.

Code:

export const MinimalDatepicker = () => {
  // grab an arbitrary date for further use
  const today = new Date('2022-11-01');
  console.log('Month:', today.getMonth() + 1);
  const daysInCurrentMonth = getDaysInMonth(today);
  const daysToShow: Date[] = [];
  Array.from(Array(daysInCurrentMonth).keys()).map((day) => {
    const date = new Date(`${today.getFullYear()}-${today.getMonth() + 1}-${day + 1}`);
    daysToShow.push(date);
  });
  console.log(daysToShow.map((d) => d.getDate()))

  return (
    <div>stuff</div>
  );
};

The outputted log for month # > 9 - note the duplicate 9 -- last day should be 31, not 30:

Month: 10
[1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30]

If we roll back the month to 10, we see the issue no longer happens:

Month: 9
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30]

More confusion

I understand that in JS Date, month index starts at zero, so I use date.getMonth() + 1 to "accurately" represent my current month, but I'm not sure how accurate it is.

In my date string example of 2022-11-01, when I call .getMonth(), I actually receive a date that is 2 integers behind the number used in the string; in the logs above, 2022-11-01 yields a month of 9 + 1 in the logs, such that 2022-01-01 actually yields a December date.

ChumiestBucket
  • 868
  • 4
  • 22
  • 51
  • 1
    The date string format you use is ambiguous, and different engines may interpret it differently. One will interpret it as a date in UTC, while others will interpret it as date in local time zone. As you use Date methods that work on local time zone, you can get into trouble when the clock is set back due to day light saving. In the northern hemisphere this happens typically in September - October. – trincot Mar 30 '22 at 16:51
  • 1
    I don't see how that would account for the issue being asked – Abraham Labkovsky Mar 30 '22 at 16:57
  • @trincot i don't think this is timezone related, as using UTC functions does not change the outcome. – ChumiestBucket Mar 30 '22 at 17:13
  • To be fair, I could not reproduce the issue *at all*. Could you create a runnable snippet that reproduces the issue, using the toolbar in the editor? – trincot Mar 30 '22 at 17:18
  • 1
    '2022-11-01' will be parsed as UTC, but the timestamps are generated using local methods so there will be a ±1 day shift around the local offfset of midnight. See [*Why does Date.parse give incorrect results?*](https://stackoverflow.com/questions/2587345/why-does-date-parse-give-incorrect-results) – RobG Mar 30 '22 at 20:37

1 Answers1

2

I believe the issue you are facing is the result of malformed date strings (or at least it very well might be). getMonth and day are both numbers which means that when they are less than 10, they will be a single character string. 2022-1-1 is not a valid date for JS to parse. padStart can help format it correctly.

Try:

const date = new Date(`${today.getFullYear()}-${String(today.getMonth() + 1).padStart(2, "0")}-${String(day + 1).padStart(2, "0")}`);
Abraham Labkovsky
  • 1,771
  • 6
  • 12