javascript toLocaleTimeString(),“数字”分钟始终显示前导零

oxcyiej7  于 2023-03-21  发布在  Java
关注(0)|答案(2)|浏览(108)

如果这看起来与另一个问题“toLocaleTimeString() always showing leading zero”相似,那是因为它是。
我想将一个时间字符串格式化为mm:ss,分钟不带前导零,例如9:09,但是,使用Date.toLocaleTimeString()时,我只能得到09:09
与我上面链接的问题不同的是,我已经在DateTimeFormat选项中使用了minute: "numeric"

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);

有趣的是,当更改选项以获取 only 数字分钟(没有秒)时,它按预期工作:

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);

我看过DateTimeFormat上完整的MDN文档,找不到任何解释,我也在最新的Chrome和Firefox上试过,结果也一样。
我的问题(S):

  • 只是我吗?(例如,可能是本地化问题吗?我在示例中显式地将区域设置为en-US以避免这种情况,但谁知道呢)
  • 我怎么才能让这个工作?

谢谢大家!

d4so4syb

d4so4syb1#

只是我吗?(例如,可能是本地化问题吗?我在示例中显式地将locale设置为en-US以避免这种情况,但谁知道呢)
我不认为是本地化的问题。它就是这样工作的。
我怎么才能让这个工作?
也许这有点夸张,但不久前我创建了一个small library来使用Intl.DateTimeFormat化日期。它之所以能做到这一点,是因为它利用了formatToParts的一部分,请参阅片段。

<script type="module">
  const dtFormat = (await 
    import(`//cdn.jsdelivr.net/npm/intl-dateformatter@latest/index.min.js`))
    .default;
  const date2Format = new Date();
  date2Format.setHours(9);
  date2Format.setMinutes(9);
  console.log( dtFormat(date2Format, `h:mmi`, `l:en-US`) );
</script>

更明确地说:下面是formatToParts返回的内容。

const now = new Date();
now.setHours(9);
now.setMinutes(9);
const opts = {hour: `numeric`, minute: `2-digit`};
const formatter = new Intl.DateTimeFormat('en-US', opts);
console.log(formatter.formatToParts(now));

使用库@Stackblitz检查一些实验。

rqdpfwrv

rqdpfwrv2#

  • (注意:我接受Kooilnc's answer,因为它是正确的,并分享了一个有用的库,以帮助以更可预测的方式格式化日期。这意味着添加一些关于Date和本地化的更详细的发现。)*

DateTimeFormat选项的工作方式很神秘

问这个问题时,我错过的第一件事是我误解了DateTimeFormat选项。dayhourminutesecond选项接受以下值(例如日期选项):
day
日的表示形式。可能的值为:

  • "numeric"(例如,1)
  • "2-digit"(例如,01)

因此,我假设要格式化分钟和秒,并且分钟不带前导0,可以使用以下代码(从问题中复制的代码片段):

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);

这不起作用,这是因为这些属性(dayhourminutesecond)的行为并不一致,特别是当分组在特定子集中时。
例如:

const date = new Date(Date.now());
date.setHours(9,9,9); // so we're sure to catch leading zeros

// consistent options
const minuteAndSecond = {
  minute: "numeric",
  second: "2-digit",
}
const hourAndMinute = {
  hour: "numeric",
  minute: "2-digit",
}

// inconsistent formatting (even in the same locale)
console.log(date.toLocaleTimeString("en-US", minuteAndSecond)); // 👉 09:09
console.log(date.toLocaleTimeString("en-US", hourAndMinute)); // 👉 9:09 AM

因此,作为Kooilnc wrote,虽然这看起来不一致,但这正是DateTimeFormat选项的工作方式。

关于locale的一点小提示

当我偶然发现我链接到的similar SO question时,我惊讶地发现公认的解决方案并不适合我:

const date = new Date(Date.now());
date.setHours(9,9); // so we're sure to catch leading zeros

const timeOptions = {
  hour: "numeric", // without leading zero
  minute: "2-digit", // with leading zero
}

const dateString = date.toLocaleTimeString([], timeOptions)

// 🤔 the question said this would be "9:09 AM", I was getting "09:09"
console.log(dateString);

我错过了几件重要的事情:

  • 首先,如上所述,格式化小时和分钟的选项的行为与格式化分钟和秒的选项不同。因此,其他问题的解决方案不适用于我的问题
  • 在另一个问题的例子中,我得到一个前导零的原因确实是因为locale。代码片段将[]作为Date.toLocaleTimeString()的第一个参数传递,因此浏览器使用默认的locale。dr* is:我的浏览器的区域设置解析为en-DE(不是en-US),因此我看到的小时和分钟格式不同。如果你感兴趣,我在a CodeSandbox中做了一些格式化实验。

所以:locale is 是格式化小时和分钟的一个重要因素,但它并没有影响我格式化分钟和秒的情况(尽管它可能会影响其他地区)。

最后(我们将何去何从)

我个人决定不从格式化的时间中删除前导零。试图强制本地化的时间字符串以某种方式看起来似乎与本地化本身的概念不一致。
我对其他人的建议是将Date.toLocaleDateTime()的输出视为随机字符串(即不要试图预测其格式),并信任浏览器以对用户最有意义的方式格式化它。如果您 * 绝对 * 需要以特定方式格式化Date,你可能最好使用像Date.toISOString()这样的东西(它输出一个可预测的ISO格式),并随意转换结果。

相关问题