Node.js: Format dates and numbers with toLocaleString()

With Node.js 13+, it should just work. With earlier Node.js versions, you need to install and use the full-icu package.

Table of contents

The problem

Using Node.js version 12 or ealier, Date.prototype.toLocaleString() and Number.prototype.toLocaleString() don't always produce correct results, at least with non-English (or non-default) locales. For example:

const date = new Date('2021-11-22')

//=> Actual/expected: 11/22/2021, 2:00:00 AM (🆗)

//=> Actual: 2021-11-22 2:00:00 (❗)
//=> Expected: 22.11.2021 klo 2.00.00

const number = 1234.56

console.log(number.toLocaleString('en', { style: 'currency', currency: 'USD' }))
//=> Actual/expected: $1,234.56 (🆗)

console.log(number.toLocaleString('fi', { style: 'currency', currency: 'USD' }))
//=> Actual: US$ 1,234.56 (❗)
//=> Expected: 1 234,56 $

The solution

The results depend on the ICU data (= localization data) used by Node.js.

Node.js 13+

Starting from version 13.0.0, Node.js comes with full ICU support by default, so toLocaleString() should produce correct results.

From version 13.0.0 changelog:

Node.js releases are now built with default full-icu support. This means that all locales supported by ICU are now included and Intl-related APIs may return different values than before (Richard Lau) #29887.

Node.js 12 and earlier

You need to install and enable full ICU data manually:

  1. Run npm install full-icu cross-env to install the following packages:

    • full-icu: the full ICU data
    • cross-env: needed by Windows users to set the environment variable in the next step.
  2. Update the scripts section of package.json to set the environment variable NODE_ICU_DATA. For example:

    "scripts": {
    // Before
    "start": "index.js",
    "test": "react-scripts test",

    // After
    "start": "cross-env NODE_ICU_DATA=node_modules/full-icu index.js",
    "test": "cross-env NODE_ICU_DATA=node_modules/full-icu react-scripts test"

Now when you run npm start or npm test, Node.js will load the full ICU data from node_modules/full-icu, and toLocaleString() should produce correct results.

Further resources

More info in my Stack Overflow answer