修复 NodeJS Intl.DateTimeFormat 不能正确格式化区域设置

症状:

NodeJS 从 v9.x 版本开始支持 ES6 Intl.DateTimeFormat

当你在 ’en-US’ 区域设置中使用它时,它正常工作并打印 "August 13, 2018"

example-en.js
const df = new Intl.DateTimeFormat('en-US', {day: 'numeric', month: 'long', year: 'numeric', timeZone: 'UTC'});
console.log(df.format(new Date("2018-08-13T04:00:00.000Z")));

但是,使用不同的区域设置会失败:

example-de.js
const df = new Intl.DateTimeFormat('de', {day: 'numeric', month: 'long', year: 'numeric', timeZone: 'UTC'});
console.log(df.format(new Date("2018-08-13T04:00:00.000Z")));

虽然你期望这会打印 "13. August 2018",但它会打印 "2018 M08 13"

原因:

默认情况下,NodeJS 仅构建了 small-icu 支持,因此仅安装了 en-US 区域设置以减少安装文件大小

解决方案 1(首选):

你可以使用 intl polyfill 模块完全替换 NodeJS 的 intl 实现:

安装:

install-intl.sh
npm i --save intl

用法:

使用-intl-polyfill.js
// 用 polyfill 替换 Intl
Intl = require("intl")

const df = new Intl.DateTimeFormat('de', {day: 'numeric', month: 'long', year: 'numeric', timeZone: 'UTC'});
console.log(df.format(new Date("2018-08-13T04:00:00.000Z")));

这将按预期打印 13. August 2018

解决方案 2(替代):

你可以使用 full-icu 包继续使用 NodeJS ICU 实现(即不用 polyfill),但只安装 ICU 数据。

虽然这减少了总安装文件大小,但安装速度慢,确切方法取决于 NodeJS 版本,并且比仅使用 intl polyfill 需要更多工作。

要安装,使用

install-full-icu.sh
npm i --save full-icu

这将需要一些时间来编译数据,然后会打印类似这样的说明:

full-icu-instructions.txt
 √ icudt62l.dat (link)
Node will 使用 this ICU datafile if the environment variable NODE_ICU_DATA is set to “node_modules/full-icu”
or with node --icu-data-dir=node_modules/full-icu YOURAPP.js
 For package.json:
{"scripts":{"start":"node --icu-data-dir=node_modules/full-icu YOURAPP.js"}}

By the way, if you have full data, running this in node:
> new Intl.DateTimeFormat('es',{month:'long'}).format(new Date(9E8));
... will show “enero”. If it shows “January” you don't have full data.
News: Please see https://github.com/icu-project/full-icu-npm/issues/6

为了实际使用 full-icu,你每次运行 node 时都需要使用 --icu-data-dir=node_modules/full-icu 参数。要以交互方式运行 node,使用

node-with-icu.sh
node --icu-data-dir=node_modules/full-icu

如果你在应用程序中使用脚本(例如 start 脚本,即运行 npm start 时执行的内容),你需要调整 package.json 中的配置:

而不是

package.start.json
// [...]
"scripts": {
    "start": "node --icu-data-dir=node_modules/full-icu index.js"
}
// [...]

使用

package.json
// [...]
"scripts": {
    "start": "node --icu-data-dir=node_modules/full-icu index.js"
}
// [...]

Depending on your application, you might need to 使用 a different script name than index.js - common names include server.js and start.js


Check out similar posts by category: Allgemein, Javascript, NodeJS