If this seems similar to the other question "toLocaleTimeString() always showing leading zero", that’s because it is.
I want to format a time string to mm:ss
without a leading zero for minutes, like 9:09. However, I’m only getting 09:09 when using Date.toLocaleTimeString()
.
The difference with the question that I linked above is that I’m already using minute: "numeric"
in my DateTimeFormat
options:
const date = new Date(Date.now());
date.setMinutes(9,9); // so we're sure to catch leading zeros
const timeOptions = {
minute: "numeric", // without leading zero
second: "2-digit", // with leading zero
}
const dateString = date.toLocaleTimeString("en-US", timeOptions)
// ❌ I expect "9:09", I get "09:09"
console.log(dateString);
Interestingly, when changing options to get only numeric minutes (no seconds), it works as expected:
const date = new Date(Date.now());
date.setMinutes(9,9); // so we're sure to catch leading zeros
const timeOptions = {
minute: "numeric", // without leading zero
// second: "2-digit", // 👈 without seconds this time!
}
const dateString = date.toLocaleTimeString("en-US", timeOptions)
// ✅ I expect "9", I get "9"
console.log(dateString);
I’ve been through the full MDN docs on DateTimeFormat
and couldn’t find anything to explain this. I’ve also tried this on the latest Chrome and Firefox, with the same results.
So my question(s):
- is it just me? (e.g. could it be a localization issue? I’m explicitly setting the locale to
en-US
in my example to try to avoid this, but who knows) - how can I get this to work?
Thank you!
2
Answers
(Note: I'm accepting Kooilnc's answer since it was correct and shared a helpful library to help format dates in a more predictable way. This is meant to add some more detailed findings about and
Date
and localization.)DateTimeFormat
options work in mysterious waysThe first thing I missed when asking this question is that I misunderstood
DateTimeFormat
options. Theday
,hour
,minute
andsecond
options accept the following values (example for the day option):As a result, I assumed that to format minutes and seconds without a leading 0 for minutes, the following would work (snippet copied from the question):
This does not work, and that's because these properties (
day
,hour
,minute
,second
) don't behave consistently, especially when grouped in specific subsets.For example:
So as Kooilnc wrote, while this can seem inconsistent, this is just how
DateTimeFormat
options work.A side note about locale
When I stumbled on the similar SO question that I linked to, I was surprised to see that the accepted solution wasn't working for me:
I had missed a couple important things:
[]
asDate.toLocaleTimeString()
's first parameter, so the browser uses the default locale. I won't go into details here, but the tl;dr is: my browser's locale resolved toen-DE
(noten-US
), therefore I was seeing hours and minutes formatted differently. Iff you're interested, I did a few formatting experiments in a CodeSandbox.So: locale is an important factor for formatting hours and minutes, but it didn't affect my case of formatting minutes and seconds (although it might have, with yet other locales).
In closing (where do we go from here)
I've personally decided to not remove the leading zero from the formatted time after all. Attempting to force a localized time string to look a certain way seems at odds with the concept of localization itself.
My recommendation to others would be to treat the output of
Date.toLocaleDateTime()
like a random string (i.e. don't try to predict its format) and to trust the browser to format it in a way that makes the most sense for users. If you absolutely need to format aDate
in a specific way, you're probably better off using something likeDate.toISOString()
(which outputs a predictable ISO format), and transforming the result at will.I don’t think it’s the localization. It just works that way.
Maybe it’s overkill, but not long ago I created a small library to format dates using Intl.DateTimeFormat. It does the trick because it utilizes the parts of
formatToParts
, see snippet.To be more clear: here’s what
formatToParts
returns.Check some experiments with the library @Stackblitz.