JavaScript Dates: Building a Date Selector

Mike Pottebaum
Level Up Coding
Published in
4 min readSep 4, 2020

--

This week, I had to construct a date selector form in React that looks like this:

As you can see, the user interface includes the surrounding month and date options in addition to the selected date. This means that I need to not only keep track of the current date, but I also need a way to conveniently figure out how many days are in the selected month and which months come before and after that selected month.

When I first looked at this design, I thought I was going to have to write a bunch of helper functions for this. But I didn’t have a lot of time, so I decided to see what JavaScript’s Date object could do for me in this situation.

It turns out, the Date object is well suited to solve this problem. I started out by just playing around with it in my browser console. I was surprised to find that the Date object’s constructor method behaves in exactly the way I needed it to in order to easily get the required information.

The constructor method can be used in a few different ways. For this task, I created a date like so:

new Date(year, monthIndex, day)

The monthIndex is the month’s order number starting from 0 instead of 1.

To make it easier on myself, I created a hook and some setter functions to create new Date objects each time the date changed:

const dateObj = new Date(2000, 0, 1);
const [date, setDate] = useState(dateObj);
const setMonth = month => {
const newDate = new Date(
date.getFullYear(),
month,
date.getDate()
);
setDate(newDate);
};
const setDay = day => {
const newDate = new Date(
date.getFullYear(),
date.getMonth(),
day
);
setDate(newDate);
};
const setYear = year => {
const newDate = new Date(
year,
date.getMonth(),
date.getDate()
);
setDate(newDate);
};

Now that I have a way to create a date and change it, I need to figure out how to 1) translate the month index into a three-letter month name and 2) display the months and days that come before and after the selected month and day.

Solving the first problem is simple. I just created an array with the abbreviations. Then, to display the before/after months, I added some conditional statements to adjust the index if it’s invalid.

That way, to display the month name that comes two months before the selected date’s month — in the image at the top, this would be ‘FEB’ — I would just need to pass selectedMonthIndex — 2 in and the function will do the rest:

const getMonth = index => {
let newMonthIndex = index;
if (index < 0) newMonthIndex += 12;
else if (index > 11) newMonthIndex -= 12;
const monthList = [ ‘JAN’, ‘FEB’, ‘MAR’, ‘APR’, ‘MAY’, ‘JUN’, ‘JUL’, ‘AUG’, ‘SEP’, ‘OCT’, ‘NOV’, ‘DEC’, ]; return monthList[newMonthIndex];
};

That takes care of the months. Now on to the days.

To figure out which days to display, I need to calculate how many days are in the currently selected month. Building this from scratch would take a lot of work. Luckily, there’s a little bit of JavaScript magic already built in to take care of this.

The cool part about the Date object’s constructor method is that it corrects any mistakes you make in a way that is pretty convenient. For example, if you paste this code in your console:

new Date(2020, 0, 32)

The returned date will be February 1, 2020. The Date object knows January 2020 had 31 days. Therefore, in JavaScript, January 32 is the same as February 1. Conversely, February 0 is the same as January 31.

So, given a month index, you can calculate how many days are in that month by doing this:

const maxDay = new Date(year, monthIndex + 1, 0)

The zeroth day of the next month is the last day of the current month. Using that, I can write a function similar to the above getMonth() to calculate my before/after days:

const getDay = dayNum => {
const fullMaxDate = new Date(
date.getFullYear(),
date.getMonth() + 1,
0
);
const maxDay = fullMaxDate.getDate();
if (dayNum < 1) return maxDay - dayNum;
if (dayNum > maxDay) return dayNum - maxDay;
return dayNum;
};

Just as before, I can simply pass selectedDay — 2 into this function, and it will do the rest of the work calculating the correct day to display.

Ultimately, I need to format this date as YYYY-MM-DD when I send it over to the back end. The Date object doesn’t have a built-in method for this, but it does provide a toISOString() method that contains this format at the beginning of the returned string. To correctly format my date, I just sliced off those first 10 characters:

const format = () => date.toISOString().slice(0, 10);

And that was all I needed to build the UI component shown at the top of this article. Using JavaScript’s built-in Date object, I let JavaScript do all the tricky date calculations and wrapped its API in my own, easy-to-use functions.

The great thing about this is that, on top of making the calculations simple, the date selector will account for leap years without any extra work.

--

--