The 2-digit option in the Intl.DateTimeFormat API doesn't always do what you might expect. In particular, this piece of code doesn't produce a 2-digit number:

const dt = Date.parse('2000-01-02T03:04:05');

new Intl.DateTimeFormat('en-US', {minute: '2-digit'}).format(dt) === "4" // doesn't this look like it should be "04"?

However, it turns out this is not strictly a bug.

Internally, this is looking for a "best fit" pattern from the locale data. Apparently, patterns are only available for commonly used date formats, so for example "year/month/day" or "hour:minute", and when it can't find one for, in this case, "only the month value", it doesn't actually format the month with 2 digits. Why it still returns the single digit is, to me, a mystery.

So, a possible solution could be using the formatToParts method, which returns each part of the formatted date string in a data structure we can use:

// Config includes values for a full date/time format, using a 24-hour value
const formatter = new Intl.DateTimeFormat('en-US', {
  year: 'numeric', month: '2-digit', day: '2-digit',
  hour: '2-digit', minute: '2-digit', second: '2-digit',
  hour12: false,
});

const dt = Date.parse('2000-01-02T03:04:05');

// This looks like: [{"type":"month","value":"01"}, {"type":"literal","value":"/"}, {"type":"day","value":"02"}...]
const parts = formatter.formatToParts(dt);

// Some "reduce" magic to extract the parts
const {year, month, day, hour, minute, second} = parts.reduce((acc, cur) => {acc[cur.type] = cur.value; return acc;}, {});

// Let's render it however we want now! three guesses as to what file format this is part of.
`${year}/${month}/${day}/${hour}:${minute}:${second}` === "2000/01/02/03:04:05"
Final thoughts

And then they wonder why we use Moment.js...

Previous on JavaScript
Mastodon Mastodon