Getting the last day of the month or year in JavaScript
It’s easy to get the first day of a month but what about the last day of a month? Looking on Stack Overflow this is quite a common ask but it’s not something I’d ever encountered and the solution is quite interesting so I thought I’d describe it here.
It turns out the way to get the last day of a month is to ask for the day before the first day of the following month! I particularly like that phrasing because it’s both a description for humans and an explanation of the code. Here’s an example:
const month = 5 // June.
const startOfMonth = new Date(2019, month, 1)
// Sat Jun 01 2019...
const endOfMonth = new Date(2019, month + 1, 0)
// Sun Jun 30 2019...
Obviously zero is the day before the first day of a month?! And zero isn’t a special case, you can continue to count back:
new Date(2019, 6, 1)
// Mon Jul 01 2019...
new Date(2019, 6, 0)
// Sun Jun 30 2019...
new Date(2019, 6, -1)
// Sat Jun 29 2019...
// Keep going...
new Date(2019, 6, -364)
// Sun Jul 01 2018...
It works with months too, and across years:
new Date(2019, 11)
// Sun Dec 01 2019...
new Date(2019, 12) // ¿December + 1?
// Wed Jan 01 2020...
The two can be combined to get the last day of the year by asking for the zeroeth day of the thirteenth month (remembering it’s zero-indexed, so month number 12):
new Date(2019, 12, 0)
// Tue Dec 31 2019...
Or the final second before the new year:
new Date(2019, 12, 0, 24, 0, -1)
// Tue Dec 31 2019 23:59:59 GMT+0000 (Greenwich Mean Time)
And it’s the same behaviour when you mutate a date object — it does the cleverness on write so it reads back normally.
const date = new Date(2019, 6)
// Mon Jul 01 2019...
date.setMonth(12)
// Wed Jan 01 2020...
date.getFullYear()
// 2020
date.getMonth()
// 0
It seems a bit weird at first but behaves entirely consistently — as described in the specs (even the first one from 1997) — and is unusually developer friendly (particularly compared to the zero-indexed month debacle), I can’t believe I didn’t know this already.