JavaScript Intl.DateTimeFormat.format与Date.toLocaleString的区别

34
我想打印一个代表日期的字符串,使用特定的时区、语言环境和显示选项。
这些选项中哪一个应该使用?
  1. Intl.DateTimeFormat.prototype.format
  2. Date.prototype.toLocaleString()

看起来它们返回相同的结果。

const event = new Date(1521065710000);

const options = {
  day: 'numeric',
  month: 'long',
  weekday: 'short',
  hour: 'numeric',
  minute: 'numeric',
  timeZoneName: 'short',
  timeZone: 'America/Los_Angeles',
};

console.log(event.toLocaleString('en-US', options));
// "Wed, March 14, 3:15 PM PDT"

console.log(new Intl.DateTimeFormat('en-US', options).format(event));
// "Wed, March 14, 3:15 PM PDT"


就实际目的而言,它们是相同的。toLocaleString 最初完全依赖于实现,但现在它也支持与 Intl 对象相同的选项,两者都基于 ECMA-402 国际化 API。请注意,ECMA-402 并未指定格式,它仅要求符合区域或文化偏好,即使对于相同的语言和地区,在不同的实现中可能会有所不同。因此,您可能无法获得完全一致的结果(但非常接近)。 - RobG
@RobG 当然,是打错了...而我所记得的关于性能的内容可能只是MDN中的注释 - Kaiido
@Kaiido - 没问题。;-) - RobG
4个回答

24

这个问题与基于个人意见的离题很接近,但我还是会尝试回答。

我应该使用哪一个?

Date.prototype.toLocaleString 最初仅仅依赖于实现,不同浏览器之间存在较大的差异。ECMAScript 2015(第6版)增加了对 Intl 对象的支持,允许 toLocaleString 支持相同的选项。虽然 ECMA-262 没有强制要求支持,但目前可能所有的实现都支持它。

需要注意的是,这并没有消除允许的实现差异,只是提供了一些基于语言、地区和方言的格式化选项(以及基于IANA时区数据库标识符和值的时区选项)。

Intl 对象(因此也包括toLocaleString)基于ECMA-402,它没有严格指定格式,因此实现之间仍有一些差异。最大的差异在于时区名称(没有标准)和逗号、空格等的位置。

然而,对于大多数实际目的而言,无论是使用 Intl 对象还是 toLocaleString 都取决于你自己,我认为没有任何技术上的理由倾向于其中一个。虽然对于某个实现来说两者的结果应该是相同的,但不要期望所得到的字符串在各个实现之间是完全相同的,也不要期望它符合给定的BCP 47语言标记的特定格式。


谢谢,这就是我感兴趣的信息。我很高兴编辑我的问题,以避免离题。也许可以改为“使用这两种方法有什么优缺点?”或者“为什么存在两种实现方式?”或者“这两种方法的历史是什么?”或其他建议。 - mark

6
除了其他人提到的要点外,我注意到与默认格式(选项)有所不同:

const event = new Date(1521065710000)

//const o = options

console.log(event.toLocaleString('en-US' /*, o*/))  // "3/15/2018, 1:45:10 AM"

console.log(new Intl.DateTimeFormat('en-US' /*, o*/).format(event))  // "3/15/2018"

在Chrome v72 - v85 / Node v14上进行过测试。


是的,日期AI有一种简单明了的方式来指定应包含哪些组件,即toLocaleDateString() vs toLocaleTimeString() vs toLocalString()。使用Intl API时,似乎可以从选项中推断出这一点。 - Tom

4

如果您多次重复使用相同的格式,从性能角度考虑,重新使用Intl.DateTimeFormat对象似乎更好。

const format =  {
    weekday: 'long',
    month: 'long',
    day: '2-digit',
};
const dateTimeFormat = new Intl.DateTimeFormat('en', format);
const start1 = performance.now();
for (let i = 0; i < 10000; i++) dateTimeFormat.format(new Date());
console.log('re-use Intl.DateTimeFormat', performance.now() - start1);

const start2 = performance.now();
for (let i = 0; i < 10000; i++) new Date().toLocaleString('en', format);
console.log('use toLocaleString', performance.now() - start2);

当我在Chrome 105中运行这段代码时,它给出了以下结果:

re-use Intl.DateTimeFormat 17.299999952316284
use toLocaleString 876.0999999046326

3

目前并非所有浏览器都支持国际化API(链接1),尤其是IE10及以下版本和安卓11.8版UC浏览器。如果您想要支持这些浏览器,请使用ToLocaleString。(但是,如果不支持国际化API,则ToLocalString返回的内容取决于实现。)

Intl.DateTimeFormat.prototype.format旨在用于格式化大量日期,而不是每次设置语言环境和选项,您只需设置一次,然后从那时起使用生成的格式化函数即可。


目前,Intl.DateTimeFormat.prototype.format已经在主流浏览器中得到支持。 - IliasT
@IliasT 尽管我非常希望停止支持IE10,但我仍有付费客户在使用IE8,尽管我向他们展示了所有的“拜托不要再用IE8”的横幅。 “所有主流浏览器”并不等同于“我的客户使用的浏览器”。 - Sora2455
1
哈哈,说得对。是的,“主要浏览器”并不等同于“所有浏览器”。 - IliasT

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接