Why is date formatting so hard in vanilla JS?

Suppose you want to deal with some dates while building a website. You don't want to roll your own input parsing, so you use new Date(inputDateString); and you want to output datestrings in a format that's clear, readable[^1], and (while we're making a wish list) sorts the same both lexically and chronologically. That is: you want YYYY-MM-DD. Surely that is built in, right?

wrong

Oh. Wait, really? Ugh, fine. Just npm install date-fns or dayjs or moment or

you're seriously going to make every user download a whole library just to create one(1) common date format with no time zone logic.

FINE. Fine. No.

At first, I was tempted to cast the date to a predictable, standardized format and then reach for ~good~ old-fashioned string manipulation:

const datestamp = date => new Date(date).toISOString().slice(0, 10)

But verifying the correctness of that function entails

  1. remembering/inferring/guessing that Date.prototype.toISOString returns an ISO-8601-formatted date;
  2. remembering that ISO 8601 dates start YYYY-MM-DD;
  3. remembering that the ISO 8601 format zero-pads single-digit month and day fields; and
  4. walking through a date string counting characters on your fingers like a neanderthal.

Dear reader, you deserve better than that. You deserve a built-in strftime-style formatting utility! But since you can't have that, here's a reasonably robust, flexible pattern you can use to extract named, semantically-meaningful parts of the date you can slep into whatever template string you want:

const datestamp = date => {
  const { year, month, day } = new Intl.DateTimeFormat(undefined, {
    year: "numeric",
    month: "2-digit",
    day: "2-digit",
  })
    .formatToParts(new Date(date))
    .filter(part => part.type !== "literal")
    .reduce((acc, part) => {
      acc[part.type] = part.value
      return acc
    }, {})

  return `${year}-${month}-${day}`
}

[^1]: What's more, you want people the world over to be able to unambiguously parse your output as the same date, even if happens to be before the 13th day of its month.