- JavaScript
JavaScript Intlの使い方|数値・通貨・日付フォーマット逆引き一覧
JavaScriptの Intl とは、数値・通貨・日付・相対時間・リスト・並べ替え・文字分割などを、ロケール(言語と地域の指定)に合わせて書式化するための組み込みオブジェクト(国際化API)です。 (1234567).toLocaleString("ja-JP") の裏側で動いているのも Intl.NumberFormat で、オプションを渡すだけで「¥1,234,568」「1235万」「令和8年10月1日」「3 日前」のような表示が、自前の文字列処理なしで作れます。
この記事は「やりたいこと → コード → 出力」の逆引き一覧が中心です。118個のレシピを Node.js 22.22(ICU 78.2)と Chromium 141(Playwright)で同じコードで実行して出力を並べ、環境で異なる点(Intl.DurationFormat の有無、¥ と ¥、空白の種類)、インスタンスを使い回したときの速度差(Node で約60倍)、toLocaleString との関係、実際のエラー文つきのつまずきポイントまでまとめました。表の出力はすべて実行結果です。
Intl 逆引き早見表(やりたいこと → コード → 出力)
数値・通貨(Intl.NumberFormat)
ロケールは "ja-JP"、コード欄の { ... } は new Intl.NumberFormat("ja-JP", { ... }).format(値) の省略形です。
| やりたいこと | コード | 出力(Node 22 / Chromium 141 とも) |
|---|---|---|
| 3桁区切り | new Intl.NumberFormat("ja-JP").format(1234567.891) |
1,234,567.891 |
| 区切りなし | { useGrouping: false } → 1234567 |
1234567 |
| 円(JPY) | { style: "currency", currency: "JPY" } → 1234567.5 |
¥1,234,568 |
| 「円」を付ける | { style: "currency", currency: "JPY", currencyDisplay: "name" } |
1,234,567円 |
| 通貨コードで | { ..., currencyDisplay: "code" } |
JPY 1,234,567 |
| ドル(USD) | { style: "currency", currency: "USD" } → 1234567.891 |
$1,234,567.89 |
| ドルを言葉で | { ..., currency: "USD", currencyDisplay: "name" } |
1,234,567.89米ドル |
| 負数を括弧で(会計) | new Intl.NumberFormat("en-US", { style: "currency", currency: "USD", currencySign: "accounting" }).format(-1234.5) |
($1,234.50) |
| 万・億 | { notation: "compact" } → 12345678 |
1235万 |
| 万・億 小数1桁 | { notation: "compact", maximumFractionDigits: 1 } |
1234.6万 |
| 億 | { notation: "compact" } → 123456789 |
1.2億 |
| 円 + 万・億 | { style: "currency", currency: "JPY", notation: "compact" } |
¥1235万 |
| 英語の K / M | new Intl.NumberFormat("en-US", { notation: "compact" }).format(12345678) |
12M |
| 英語の million | { notation: "compact", compactDisplay: "long" }(en-US) |
12 million |
| パーセント | { style: "percent" } → 0.2567 |
26% |
| パーセント 小数1桁 | { style: "percent", maximumFractionDigits: 1 } → 0.2567 |
25.7% |
| 単位 km | { style: "unit", unit: "kilometer" } → 12.5 |
12.5 km |
| 単位を言葉で | { style: "unit", unit: "kilometer", unitDisplay: "long" } |
12.5 キロメートル |
| 単位 kg / GB | unit: "kilogram" → 3.2 / unit: "gigabyte" → 256 |
3.2 kg / 256 GB |
| 単位 時間 | { style: "unit", unit: "hour", unitDisplay: "long" } → 3 |
3 時間 |
| 単位 km/h・℃ | unit: "kilometer-per-hour" → 60 / unit: "celsius" → 36.5 |
60 km/h / 36.5°C |
| 小数2桁固定 | { minimumFractionDigits: 2, maximumFractionDigits: 2 } → 1234.5 |
1,234.50 |
| 小数の既定(最大3桁) | {} → 3.14159265 |
3.142 |
| 有効桁3桁 | { maximumSignificantDigits: 3 } → 1234567 / 0.00123456 |
1,230,000 / 0.00123 |
| ゼロ埋め | { minimumIntegerDigits: 3, useGrouping: false } → 7 |
007 |
| 符号を常に付ける | { signDisplay: "always" } → 1234 |
+1,234 |
| 0以外に符号 | { signDisplay: "exceptZero" } → 0 / 5 / -5 |
0 / +5 / -5 |
| 切り捨て | { maximumFractionDigits: 0, roundingMode: "trunc" } → 2.9 |
2 |
| 整数なら小数を消す | { minimumFractionDigits: 2, trailingZeroDisplay: "stripIfInteger" } → 100 |
100 |
| 範囲(〜) | new Intl.NumberFormat("ja-JP", { style: "currency", currency: "JPY" }).formatRange(1000, 2500) |
¥1,000 ~ ¥2,500 |
| 部品に分解 | .formatToParts(-1234)(JPY) |
minusSign:- currency:¥ integer:1 group:, integer:234 |
| 指数表記 | new Intl.NumberFormat("en-US", { notation: "scientific" }).format(123456) |
1.235E5 |
| BigInt | .format(12345678901234567890n) |
12,345,678,901,234,567,890 |
| 文字列の数値(精度維持) | { maximumFractionDigits: 20 } → "0.1234567890123456789" |
0.1234567890123456789 |
| 漢数字 | new Intl.NumberFormat("ja-JP-u-nu-hanidec").format(2026) |
二,〇二六 |
日付・時刻(Intl.DateTimeFormat)
D = new Date("2026-10-01T00:00:00Z")(日本時間 2026/10/1 9:00)、D2 は同日 10:30、D3 は 10/3 です。すべて timeZone: "Asia/Tokyo" を付けています(理由は後述)。
| やりたいこと | コード(new Intl.DateTimeFormat("ja-JP", { timeZone: "Asia/Tokyo", ... }).format(D)) |
出力 |
|---|---|---|
| 標準の日付 | オプションなし | 2026/10/1 |
| ゼロ埋めの日付 | { dateStyle: "medium" } |
2026/10/01 |
| yyyy/MM/dd(個別指定) | { year: "numeric", month: "2-digit", day: "2-digit" } |
2026/10/01 |
| yyyy-MM-dd | new Intl.DateTimeFormat("sv-SE", { timeZone: "Asia/Tokyo" }) |
2026-10-01 |
| yyyy-MM-dd HH:mm:ss | "sv-SE" + { dateStyle: "short", timeStyle: "medium" } → D2 |
2026-10-01 10:30:00 |
| 日本語の日付 | { dateStyle: "long" } |
2026年10月1日 |
| 曜日つき | { dateStyle: "full" } |
2026年10月1日木曜日 |
| 曜日だけ | { weekday: "short" } / { weekday: "long" } |
木 / 木曜日 |
| 月日と曜日 | { month: "long", day: "numeric", weekday: "short" } |
10月1日(木) |
| 時刻 | { timeStyle: "short" } / "medium" / "long" / "full" |
9:00 / 9:00:00 / 9:00:00 JST / 9時00分00秒 日本標準時 |
| 日時 | { dateStyle: "medium", timeStyle: "short" } |
2026/10/01 9:00 |
| 24時間・2桁 | { hour: "2-digit", minute: "2-digit", hourCycle: "h23" } |
09:00 |
| 午前・午後 | { hour: "numeric", minute: "2-digit", hour12: true }(15:05) |
午後3:05 |
| 英語の日時 | "en-US" + { dateStyle: "full", timeStyle: "short" } |
Thursday, October 1, 2026 at 9:00 AM |
| 和暦 | "ja-JP-u-ca-japanese" + { dateStyle: "long" } |
令和8年10月1日 |
| 和暦(短い) | "ja-JP-u-ca-japanese"、オプションなし |
R8/10/1 |
| 和暦(オプション指定) | { calendar: "japanese", era: "long", year: "numeric", month: "long", day: "numeric" } |
令和8年10月1日 |
| 元年 | 和暦 + dateStyle: "long" → 2019-05-01 |
令和元年5月1日 |
| タイムゾーン名 | { hour: "2-digit", minute: "2-digit", timeZoneName: "longOffset" } |
09:00 GMT+09:00 |
| 別のタイムゾーン | { timeZone: "America/New_York", dateStyle: "medium", timeStyle: "long" } |
2026/09/30 20:00:00 GMT-4 |
| 時間の範囲 | { dateStyle: "medium", timeStyle: "short" } → .formatRange(D, D2) |
2026/10/01 9時00分~10時30分 |
| 日付の範囲 | { dateStyle: "long" } → .formatRange(D, D3) |
2026/10/01~2026/10/03 |
| 英語の範囲 | "en-US" + { dateStyle: "medium" } → .formatRange(D, D3) |
Oct 1 – 3, 2026 |
| ミリ秒 | { minute: "2-digit", second: "2-digit", fractionalSecondDigits: 3 } |
00:05.123 |
| 部品に分解 | { dateStyle: "medium" } → .formatToParts(D) |
year:2026 literal:/ month:10 literal:/ day:01 |
相対時間・リスト・複数形・並べ替え・分割・期間・表示名
| やりたいこと | コード | 出力 |
|---|---|---|
| 「昨日」 | new Intl.RelativeTimeFormat("ja", { numeric: "auto" }).format(-1, "day") |
昨日 |
| 「3 日前」 | new Intl.RelativeTimeFormat("ja").format(-3, "day") |
3 日前 |
| 「2 時間後」「来月」 | .format(2, "hour") / { numeric: "auto" } + .format(1, "month") |
2 時間後 / 来月 |
| 英語の相対時間 | new Intl.RelativeTimeFormat("en", { numeric: "auto" }).format(-1, "day") |
yesterday |
| 「A、B、C」 | new Intl.ListFormat("ja").format(["りんご", "みかん", "バナナ"]) |
りんご、みかん、バナナ |
| 「AまたはB」 | new Intl.ListFormat("ja", { type: "disjunction" }).format([...]) |
りんご、みかん、またはバナナ |
| 英語の and / or | new Intl.ListFormat("en").format(["apples", "oranges", "bananas"]) |
apples, oranges, and bananas |
| 複数形の判定 | new Intl.PluralRules("en").select(1) / .select(2) |
one / other |
| 序数(1st, 2nd) | new Intl.PluralRules("en", { type: "ordinal" }).select(3) |
few(→ 3rd) |
| 日本語の並べ替え | ["みかん", "りんご", "バナナ", "いちご"].sort(new Intl.Collator("ja").compare) |
いちご, バナナ, みかん, りんご |
| 数値順に並べる | ["item10", "item2", "item1"].sort(new Intl.Collator("ja", { numeric: true }).compare) |
item1, item2, item10 |
| 大小・アクセント無視 | new Intl.Collator("en", { sensitivity: "base" }).compare("a", "Á") |
0(等しい) |
| 見た目の文字数 | [...new Intl.Segmenter("ja", { granularity: "grapheme" }).segment("👨👩👧👦です")].length |
3(.length は 13) |
| 単語に分割 | new Intl.Segmenter("ja", { granularity: "word" }) + isWordLike |
今日, は, 良い, 天気, です, ね |
| 文に分割 | new Intl.Segmenter("ja", { granularity: "sentence" }) |
今日は晴れ。 / 明日は雨です。 |
| 期間(1時間30分5秒) | new Intl.DurationFormat("ja", { style: "long" }).format({ hours: 1, minutes: 30, seconds: 5 }) |
1 時間 30 分 5 秒(Chromium 141。Node 22 は未対応) |
| 期間(digital) | new Intl.DurationFormat("ja", { style: "digital" }).format({ ... }) |
1:30:05 |
| 国名 | new Intl.DisplayNames(["ja"], { type: "region" }).of("US") |
アメリカ合衆国 |
| 言語名 | new Intl.DisplayNames(["ja"], { type: "language" }).of("en-GB") |
イギリス英語 |
| 通貨名・文字体系 | { type: "currency" } → .of("USD") / { type: "script" } → .of("Hira") |
米ドル / ひらがな |
| ロケールの分解 | new Intl.Locale("ja-JP-u-ca-japanese") → .language / .region / .calendar |
ja / JP / japanese |
| 対応している値の一覧 | Intl.supportedValuesOf("currency").length / ("timeZone").length |
162(Node)・159(Chromium)/ 418 |
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「JavaScript Intlの使い方|数値・通貨・日付フォーマット逆引き一覧」
検証環境と Intl の全体像
この記事の出力は、Node.js v22.22.2(V8 12.4、ICU 78.2、CLDR 48、tz 2025c)と Chromium 141.0.7390.37(Playwright 1.56)で同じコードを実行して得たものです。 Intl の各クラスは「ロケール + オプションでインスタンスを作り、format() に値を渡す」という同じ形をしています。
flowchart LR
A[やりたいこと] --> B{種類は?}
B -->|数値・通貨・単位・%| N["Intl.NumberFormat"]
B -->|日付・時刻・和暦・TZ| D["Intl.DateTimeFormat"]
B -->|3日前・来月| R["Intl.RelativeTimeFormat"]
B -->|A、B、C| L["Intl.ListFormat"]
B -->|1時間30分| U["Intl.DurationFormat"]
B -->|並べ替え| C["Intl.Collator"]
B -->|文字数・単語| S["Intl.Segmenter"]
B -->|国名・言語名| G["Intl.DisplayNames"]
N & D & R & L & U --> F["format / formatToParts / formatRange"]
| クラス | 役割 | Chrome | Firefox | Safari | Node.js |
|---|---|---|---|---|---|
Intl.NumberFormat |
数値・通貨・単位・% | 24 | 29 | 10 | 0.12 |
同 v3(formatRange・roundingMode・trailingZeroDisplay 等) |
範囲・丸めの細かい制御 | 106 | 116 | 15.4 | 19 |
Intl.DateTimeFormat |
日付・時刻・和暦・タイムゾーン | 24 | 29 | 10 | 0.12 |
同 formatRange |
日時の範囲 | 76 | 91 | 14.1 | 12.9 |
Intl.RelativeTimeFormat |
「3 日前」 | 71 | 65 | 14 | 12 |
Intl.ListFormat |
「A、B、C」 | 72 | 78 | 14.1 | 12 |
Intl.PluralRules |
複数形・序数の判定 | 63 | 58 | 13 | 10 |
Intl.Collator |
言語に合わせた並べ替え | 24 | 29 | 10 | 0.12 |
Intl.Segmenter |
文字・単語・文の分割 | 87 | 125 | 14.1 | 16 |
Intl.DisplayNames |
国名・言語名・通貨名 | 81 | 86 | 14.1 | 14 |
Intl.DurationFormat |
期間(1時間30分) | 129 | 136 | 16.4 | 23 |
Intl.Locale |
ロケールの分解・正規化 | 74 | 75 | 14 | 12 |
Intl.supportedValuesOf() |
対応値の一覧 | 99 | 93 | 15.4 | 18 |
対応バージョンは MDN の互換性データ(@mdn/browser-compat-data 8.1.3、2026-09-24)から取りました。Intl.DurationFormat 以外は、現在サポートされている主要ブラウザと Node.js 18 以降でそのまま使えます。
ロケールは BCP 47 形式("ja-JP"、"en-US")で指定し、-u- 以降に拡張キーを付けると暦(ca-japanese)や数字の体系(nu-hanidec)、数値順の並べ替え(kn-true)を切り替えられます。配列で ["xx-YY", "ja-JP"] のように渡すと、使える最初のものが選ばれます(検証では ja-JP が選ばれました)。"ja_JP" のようにアンダースコアで書くと RangeError: Incorrect locale information provided になるので、ハイフンに直して渡します("ja-jp" と小文字で書いた場合は ja-JP に正規化されます)。
数値の書式(Intl.NumberFormat)
3桁区切り・小数桁・有効桁
既定では小数は最大3桁(maximumFractionDigits: 3)で四捨五入され、3桁区切りが付きます。 桁数を固定したいときは minimumFractionDigits と maximumFractionDigits を同じ値にし、「意味のある桁」で丸めたいときは maximumSignificantDigits を使います(1234567 → 1,230,000、0.00123456 → 0.00123)。ロケールを de-DE にすると区切り記号が入れ替わり 1.234.567,891 になります。
適用された既定値は new Intl.NumberFormat("ja-JP").resolvedOptions() で確認でき、Node 22・Chromium 141 とも minimumFractionDigits: 0、maximumFractionDigits: 3、useGrouping: "auto"、roundingMode: "halfExpand"、signDisplay: "auto" でした。
通貨(JPY / USD と currencyDisplay)
style: "currency" では小数桁の既定が通貨ごとに決まり、JPY は0桁、USD は2桁です。 そのため 1234.56 円は ¥1,235 と丸められます(resolvedOptions() で JPY は [0, 0]、USD は [2, 2] でした)。記号の出し方は currencyDisplay で切り替えます。
const yen = (opt) => new Intl.NumberFormat("ja-JP", { style: "currency", currency: "JPY", ...opt });
console.log(yen().format(1234567.5)); // ¥1,234,568
console.log(yen({ currencyDisplay: "name" }).format(1234567)); // 1,234,567円
console.log(yen({ minimumFractionDigits: 2 }).format(1234.5)); // ¥1,234.50
console.log(new Intl.NumberFormat("en-US", { style: "currency", currency: "JPY" }).format(1234567.5)); // ¥1,234,568
console.log(new Intl.NumberFormat("de-DE", { style: "currency", currency: "EUR" }).format(1234567.891)); // 1.234.567,89 €
currencyDisplay |
JPY(ja-JP) | USD(ja-JP) | 用途 |
|---|---|---|---|
"symbol"(既定) |
¥1,234,567 |
$1,234,567.89 |
一般的な表示 |
"narrowSymbol" |
¥1,234,567 |
$1,234,567.89 |
地域を省いた短い記号(CA$ → $ など) |
"code" |
JPY 1,234,567 |
USD 1,234,567.89 |
複数通貨が混ざる一覧 |
"name" |
1,234,567円 |
1,234,567.89米ドル |
日本語の文章中 |
JPY の記号は、ロケール ja-JP では全角の ¥(U+FFE5)、en-US では半角の ¥(U+00A5)になります。 半角で統一したいときは formatToParts で currency 部分を差し替えるか、currencyDisplay: "name" で「円」を付ける方法があります。通貨コードは3文字なら何でも受け付けられ、currency: "YEN" のような存在しないコードでもエラーにならず YEN 1.00 と出ます(コードの綴りはテストで確認しておくと安心です)。
万・億の compact 表記
notation: "compact" を ja-JP で使うと「万」「億」単位になります。 既定の丸めは「小数0桁」と「有効桁2桁」のうち精度が高いほう(roundingPriority: "morePrecision")なので、12345678 は 1235万、123456789 は 1.2億 と、桁によって小数の有無が変わります。小数桁をそろえたいときは maximumFractionDigits を明示します。
const compact = (opt) => new Intl.NumberFormat("ja-JP", { notation: "compact", ...opt });
console.log([1000, 9999, 10000, 15000, 12345678, 123456789].map((n) => compact().format(n)));
// [ '1000', '9999', '1万', '1.5万', '1235万', '1.2億' ]
console.log(compact({ maximumFractionDigits: 1 }).format(12345678)); // 1234.6万
console.log(compact({ style: "currency", currency: "JPY" }).format(12345678)); // ¥1235万
console.log(new Intl.NumberFormat("en-US", { notation: "compact" }).format(12345678)); // 12M
console.log(new Intl.NumberFormat("en-US", { notation: "compact", compactDisplay: "long" }).format(12345678)); // 12 million
パーセントと単位
style: "percent" は「割合(0.256)」を受け取って100倍します。 すでに百分率になった 25.6 を渡すと 2,560% になります。単位は style: "unit" と unit で指定し、unit には "km" ではなく CLDR の名前("kilometer")を使います。使える名前は Intl.supportedValuesOf("unit") で一覧できます(-per- でつなぐと kilometer-per-hour のような合成単位になります)。
よく使う unit |
short(既定) | long(ja-JP) |
|---|---|---|
kilometer / meter / centimeter |
12.5 km |
12.5 キロメートル |
kilogram / gram |
3.2 kg |
3.2 キログラム |
byte / kilobyte / megabyte / gigabyte / terabyte |
256 GB |
256 ギガバイト |
second / minute / hour / day |
5 秒 / 3 時間 / 5 日(ja-JP は short でも漢字) |
3 時間 |
kilometer-per-hour(-per- で合成) |
60 km/h |
時速 60 キロメートル |
celsius / percent |
36.5°C |
摂氏 36.5 度 |
符号・丸め・末尾ゼロ
roundingMode の既定は "halfExpand"(いわゆる四捨五入)で、Intl は数値を最短の10進表現として丸めます。 そのため (1.005).toFixed(2) は2進数の誤差で 1.00 になりますが、Intl では 1.01 になります(検証済み。文字列 "1.005" を渡しても 1.01)。
const nf = (opt) => new Intl.NumberFormat("ja-JP", opt);
console.log([0, 5, -5].map((n) => nf({ signDisplay: "exceptZero" }).format(n))); // [ '0', '+5', '-5' ]
console.log(nf({ maximumFractionDigits: 0, roundingMode: "trunc" }).format(2.9)); // 2
console.log((1.005).toFixed(2), new Intl.NumberFormat("en-US", { maximumFractionDigits: 2 }).format(1.005)); // 1.00 1.01
console.log([NaN, Infinity, -0].map((n) => nf().format(n))); // [ 'NaN', '∞', '-0' ]
| オプション | 取りうる値 | 既定 |
|---|---|---|
signDisplay |
auto / always / exceptZero / negative / never |
auto |
roundingMode |
ceil / floor / expand / trunc / halfCeil / halfFloor / halfExpand / halfTrunc / halfEven |
halfExpand |
roundingIncrement |
1 / 2 / 5 / 10 / 20 / 25 / 50 / 100 ...(maximumFractionDigits と併用) |
1 |
roundingPriority |
auto / morePrecision / lessPrecision |
auto(compact は morePrecision) |
trailingZeroDisplay |
auto / stripIfInteger |
auto |
範囲(formatRange)と部品(formatToParts)
formatRange(a, b) は「¥1,000 ~ ¥2,500」のような範囲を、formatToParts() は記号・整数・区切りなどの部品を返します。 部品に分けると、通貨記号だけ小さく表示する、¥ を ¥ に置き換える、といった加工が文字列操作なしでできます。
const yen = new Intl.NumberFormat("ja-JP", { style: "currency", currency: "JPY" });
console.log(yen.formatRange(1000, 2500)); // ¥1,000 ~ ¥2,500(~ は U+FF5E、前後は半角空白)
console.log(yen.formatRange(1000, 1000)); // 約¥1,000(同じ値は「約」になる)
console.log(new Intl.NumberFormat("en-US", { style: "currency", currency: "USD" }).formatRange(3, 5)); // $3.00 – $5.00(– は U+2013)
console.log(yen.formatToParts(-1234));
// [ { type: 'minusSign', value: '-' }, { type: 'currency', value: '¥' },
// { type: 'integer', value: '1' }, { type: 'group', value: ',' }, { type: 'integer', value: '234' } ]
// 通貨記号を半角にし、<small> で囲む例
const html = yen.formatToParts(1234567)
.map((p) => (p.type === "currency" ? `<small>¥</small>` : p.value)).join("");
console.log(html); // <small>¥</small>1,234,567
NumberFormat オプション早見表
| オプション | 主な値 | 既定 | 用途 |
|---|---|---|---|
style |
decimal / currency / percent / unit |
decimal |
書式の種類 |
currency |
ISO 4217 コード(JPY、USD) |
なし(currency スタイルでは必須) |
通貨 |
currencyDisplay |
symbol / narrowSymbol / code / name |
symbol |
記号の出し方 |
currencySign |
standard / accounting |
standard |
負数を括弧に |
unit / unitDisplay |
CLDR 単位名 / short / narrow / long |
なし / short |
単位 |
notation |
standard / scientific / engineering / compact |
standard |
万・億、指数 |
compactDisplay |
short / long |
short |
12M / 12 million |
useGrouping |
always / auto / min2 / true / false |
auto |
3桁区切り |
minimumIntegerDigits |
1〜21 | 1 |
ゼロ埋め |
minimumFractionDigits / maximumFractionDigits |
0〜100 | 0 / 3(通貨は通貨ごと) |
小数桁 |
minimumSignificantDigits / maximumSignificantDigits |
1〜21 | 指定時 1 / 21 |
有効桁 |
numberingSystem |
latn / hanidec / arab など |
ロケール依存 | 数字の体系 |
日付・時刻の書式(Intl.DateTimeFormat)
dateStyle / timeStyle の一覧
よく使う形は dateStyle と timeStyle の組み合わせで作れます。 4段階(full / long / medium / short)の出力を ja-JP でそろえました。
| 指定 | ja-JP の出力(2026-10-01 9:00 JST) |
en-US の出力 |
|---|---|---|
dateStyle: "full" |
2026年10月1日木曜日 |
Thursday, October 1, 2026 |
dateStyle: "long" |
2026年10月1日 |
October 1, 2026 |
dateStyle: "medium" |
2026/10/01 |
Oct 1, 2026 |
dateStyle: "short" |
2026/10/01 |
10/1/26 |
timeStyle: "full" |
9時00分00秒 日本標準時 |
9:00:00 AM Japan Standard Time |
timeStyle: "long" |
9:00:00 JST |
9:00:00 AM GMT+9 |
timeStyle: "medium" |
9:00:00 |
9:00:00 AM |
timeStyle: "short" |
9:00 |
9:00 AM |
dateStyle: "medium", timeStyle: "short" |
2026/10/01 9:00 |
Oct 1, 2026, 9:00 AM |
個別指定(yyyy/MM/dd・曜日・24時間)
year / month / day / weekday / hour / minute / second を個別に指定すると、必要な要素だけを出せます。 dateStyle と個別指定を同時に渡すと TypeError: Invalid option : option になるので、どちらか一方にします。"sv-SE"(スウェーデン語)ロケールは yyyy-MM-dd の形になるため、ISO 風の日付が欲しいときの定番です。
const D = new Date("2026-10-01T00:00:00Z");
const ja = (opt) => new Intl.DateTimeFormat("ja-JP", { timeZone: "Asia/Tokyo", ...opt }).format(D);
console.log(ja({ year: "numeric", month: "2-digit", day: "2-digit" })); // 2026/10/01
console.log(ja({ month: "long", day: "numeric", weekday: "short" })); // 10月1日(木)
console.log(ja({ hour: "2-digit", minute: "2-digit", hourCycle: "h23" })); // 09:00
console.log(new Intl.DateTimeFormat("sv-SE", { dateStyle: "short", timeStyle: "medium", timeZone: "Asia/Tokyo" })
.format(new Date("2026-10-01T01:30:00Z"))); // 2026-10-01 10:30:00
hourCycle は "h23"(0〜23時)を使います。"h24" にすると深夜0時が 24:00 になります(検証済み)。hour12: false も 00:00 になりました。
和暦(ja-JP-u-ca-japanese)
和暦はロケールに -u-ca-japanese を付けるか、calendar: "japanese" を渡すだけで出せます。 改元の境目も ICU のデータで正しく切り替わります。
const w = (d, opt = {}) => new Intl.DateTimeFormat("ja-JP-u-ca-japanese", { timeZone: "Asia/Tokyo", ...opt }).format(d);
console.log(w(new Date("2026-10-01T00:00:00Z"))); // R8/10/1
console.log(w(new Date("2026-10-01T00:00:00Z"), { dateStyle: "long" })); // 令和8年10月1日
console.log(w(new Date("2019-05-01T00:00:00Z"), { dateStyle: "long" })); // 令和元年5月1日
console.log(w(new Date("2019-04-30T00:00:00Z"), { dateStyle: "long" })); // 平成31年4月30日
era を個別指定すると "long" で 令和8年10月1日、"short" で 令和8/10/1、"narrow" で R8/10/1 になります。
タイムゾーン
timeZone を省略すると実行環境のタイムゾーンが使われます。 サーバー(多くは UTC)とブラウザ(JST)で日付がずれる原因になるため、表示用のフォーマッタには timeZone: "Asia/Tokyo" を付けておくと安心です。名前の出し方は timeZoneName で6種類(short / long / shortOffset / longOffset / shortGeneric / longGeneric)あり、IANA 名の一覧は Intl.supportedValuesOf("timeZone") で取れます(検証環境では418件)。
const D = new Date("2026-10-01T00:00:00Z");
for (const z of ["short", "long", "shortOffset", "longOffset"]) {
console.log(z, new Intl.DateTimeFormat("ja-JP", { hour: "numeric", timeZoneName: z, timeZone: "Asia/Tokyo" }).format(D));
}
// short 9時 JST / long 9時 日本標準時 / shortOffset 9時 GMT+9 / longOffset 9時 GMT+09:00
console.log(new Intl.DateTimeFormat("ja-JP", { dateStyle: "medium", timeStyle: "long", timeZone: "America/New_York" }).format(D));
// 2026/09/30 20:00:00 GMT-4
日時の範囲(formatRange)
formatRange(from, to) は、同じ日なら日付を1回だけ出し、時刻だけを「~」でつなぎます。 自前で「開始 ~ 終了」を組むと日付の重複やロケールごとの記号に悩みますが、formatRange ならロケールに合った形になります。
const D = new Date("2026-10-01T00:00:00Z"), D2 = new Date("2026-10-01T01:30:00Z"), D3 = new Date("2026-10-03T00:00:00Z");
console.log(new Intl.DateTimeFormat("ja-JP", { dateStyle: "medium", timeStyle: "short", timeZone: "Asia/Tokyo" }).formatRange(D, D2));
// 2026/10/01 9時00分~10時30分
console.log(new Intl.DateTimeFormat("ja-JP", { dateStyle: "long", timeZone: "Asia/Tokyo" }).formatRange(D, D3));
// 2026/10/01~2026/10/03
console.log(new Intl.DateTimeFormat("en-US", { dateStyle: "medium", timeZone: "Asia/Tokyo" }).formatRange(D, D3));
// Oct 1 – 3, 2026
DateTimeFormat オプション早見表
| オプション | 主な値 | 既定 | 用途 |
|---|---|---|---|
dateStyle / timeStyle |
full / long / medium / short |
なし | まとめて指定(個別指定と併用不可) |
year |
numeric / 2-digit |
個別指定なしのとき numeric |
年 |
month |
numeric / 2-digit / long / short / narrow |
numeric |
月(long で「10月」「October」) |
day |
numeric / 2-digit |
numeric |
日 |
weekday |
long / short / narrow |
なし | 曜日 |
era |
long / short / narrow |
なし | 元号・紀元 |
hour / minute / second |
numeric / 2-digit |
なし(timeStyle 指定時は自動) |
時刻 |
fractionalSecondDigits |
1〜3 | なし | ミリ秒 |
hourCycle / hour12 |
h11 / h12 / h23 / h24 / true / false |
ロケール依存 | 12時間・24時間 |
timeZone |
IANA 名(Asia/Tokyo、UTC) |
実行環境の値 | タイムゾーン |
timeZoneName |
short / long / shortOffset / longOffset / shortGeneric / longGeneric |
なし | JST / GMT+9 など |
calendar |
gregory / japanese / buddhist など18種 |
gregory |
暦 |
numberingSystem |
latn / hanidec など |
latn |
数字の体系 |
相対時間・リスト・複数形
「3 日前」「来月」を出す(Intl.RelativeTimeFormat)
RelativeTimeFormat は「数値と単位」から相対表現を作ります。 numeric: "auto" にすると -1 day が「昨日」、1 month が「来月」のような言葉になり、既定("always")では「1 日前」のように常に数字で出ます。単位は second / minute / hour / day / week / month / quarter / year(複数形 days なども可)で、それ以外は RangeError: Invalid unit argument for Intl.RelativeTimeFormat.prototype.format() 'days ago' になります。
const rtf = new Intl.RelativeTimeFormat("ja", { numeric: "auto" });
console.log(rtf.format(-1, "day"), rtf.format(-3, "day"), rtf.format(1, "month")); // 昨日 3 日前 来月
console.log(new Intl.RelativeTimeFormat("ja").format(-1, "day")); // 1 日前(numeric: "always" が既定)
console.log(rtf.formatToParts(-3, "day"));
// [ { type: 'integer', value: '3', unit: 'day' }, { type: 'literal', value: ' 日前' } ]
差の大きさから単位を自動で選ぶ関数は、次の「使い回しヘルパー」に入れています(30 秒前 / 5 分前 / 3 時間前 / 昨日 / 3 日前 / 2 週間後 / 2 か月前 / 来年 を確認済み)。
「A、B、C」「AまたはB」(Intl.ListFormat)
ListFormat は配列を、言語ごとの読点や「and / or」でつなぎます。 引数は文字列の配列(または Set などの反復可能オブジェクト)で、文字列をそのまま渡すと1文字ずつ分解され a、,、b のようになります。
console.log(new Intl.ListFormat("ja").format(["りんご", "みかん", "バナナ"])); // りんご、みかん、バナナ
console.log(new Intl.ListFormat("ja", { type: "disjunction" }).format(["りんご", "みかん", "バナナ"])); // りんご、みかん、またはバナナ
console.log(new Intl.ListFormat("ja").format(new Set(["a", "b"]))); // a、b
type |
意味 | ja |
en |
|---|---|---|---|
conjunction(既定) |
AとB | りんご、みかん、バナナ |
apples, oranges, and bananas |
disjunction |
AまたはB | りんご、みかん、またはバナナ |
apples, oranges, or bananas |
unit |
単位の列挙 | 3 ft 7 in(narrow) |
3 ft, 7 in(long) |
複数形と序数(Intl.PluralRules)
PluralRules は「1 item / 2 items」のような複数形の分岐と、「1st / 2nd / 3rd」の序数の分岐を言語ごとに判定します。 日本語の分類は other だけなので(resolvedOptions().pluralCategories は ["other"])、主に英語など複数形がある言語の文言で使います。
const ord = new Intl.PluralRules("en", { type: "ordinal" });
const suffix = { one: "st", two: "nd", few: "rd", other: "th" };
console.log([1, 2, 3, 4, 11, 22].map((n) => n + suffix[ord.select(n)]).join(", ")); // 1st, 2nd, 3rd, 4th, 11th, 22nd
const items = (n) => `${n} ${new Intl.PluralRules("en").select(n) === "one" ? "item" : "items"}`;
console.log(items(1), items(2)); // 1 item 2 items
並べ替え・文字分割・表示名
日本語の並べ替えと数値順(Intl.Collator)
Array.prototype.sort() は引数なしだと文字コード順なので、日本語は Intl.Collator("ja").compare を渡します。 numeric: true で「item2 → item10」の数値順、sensitivity で大小やアクセントの扱いを変えられます。localeCompare も内部では同じ比較ですが、大量に並べるときは Collator を1つ作って渡すほうが効率的です。
console.log(["みかん", "りんご", "バナナ", "いちご"].sort()); // [ 'いちご', 'みかん', 'りんご', 'バナナ' ](コード順)
console.log(["みかん", "りんご", "バナナ", "いちご"].sort(new Intl.Collator("ja").compare)); // [ 'いちご', 'バナナ', 'みかん', 'りんご' ]
console.log(["item10", "item2", "item1"].sort(new Intl.Collator("ja", { numeric: true }).compare)); // [ 'item1', 'item2', 'item10' ]
console.log(new Intl.Collator("ja").compare("あ", "ア")); // 0(既定ではひらがなとカタカナを同じ扱い)
sensitivity |
区別するもの | "a" と "A" |
"a" と "á" |
|---|---|---|---|
base |
文字の基本形だけ | 等しい | 等しい |
accent |
アクセント | 等しい | 異なる |
case |
大小 | 異なる | 等しい |
variant(既定) |
すべて | 異なる | 異なる |
文字数・単語・文の分割(Intl.Segmenter)
絵文字や結合文字を含む文字列の「見た目の文字数」は Segmenter で数えます。 granularity を "grapheme" にすると "👨👩👧👦です" は 3(.length は 13)、"word" にすると 今日は良い天気ですね。 が 今日 / は / 良い / 天気 / です / ね に分かれ(isWordLike が true のものだけ)、"sentence" にすると 今日は晴れ。 / 明日は雨です。 のように文で分かれます。英語でも "It's 3.5 km." を It's / 3.5 / km のように単語単位で切り出せます。
国名・言語名・通貨名(Intl.DisplayNames)
DisplayNames はコードから各言語の名前を引けます。 対応している type は region / language / currency / script / calendar / dateTimeField です。コードの形式が合わないと RangeError: invalid_argument になります("japan" のような綴りではなく "JP")。
console.log(new Intl.DisplayNames(["ja"], { type: "region" }).of("US")); // アメリカ合衆国
console.log(new Intl.DisplayNames(["ja"], { type: "language" }).of("en-GB")); // イギリス英語
console.log(new Intl.DisplayNames(["ja"], { type: "calendar" }).of("japanese")); // 和暦
console.log(["year", "month", "weekOfYear", "day"].map((f) => new Intl.DisplayNames(["ja"], { type: "dateTimeField" }).of(f))); // [ '年', '月', '週', '日' ]
期間の書式(Intl.DurationFormat)と対応状況
Intl.DurationFormat は { hours: 1, minutes: 30 } のような期間オブジェクトを「1 時間 30 分」「1:30:05」に書式化します。 MDN では 2025年3月に Baseline(主要ブラウザで利用可)となり、対応は Chrome 129 / Edge 129 / Firefox 136 / Safari 16.4 / Node.js 23 / Deno 1.46 からです。検証した Node 22 では typeof Intl.DurationFormat が undefined(呼ぶと TypeError: Intl.DurationFormat is not a constructor)で、Chromium 141 では function でした。Chromium 141 の出力は style: "long" で 1 時間 30 分 5 秒、"digital" で 1:30:05、英語の "long" で 1 hour, 30 minutes, 5 seconds、"narrow" で 2d 3h です。
未対応環境では、NumberFormat の unit と ListFormat の type: "unit" を組み合わせると同じ出力が作れます。 次の関数は Node 22 でも Chromium 141 でも同じ結果になりました。
// Intl.DurationFormat があれば使い、なければ NumberFormat(unit) + ListFormat で組み立てる
function formatDuration(duration, locale = "ja", style = "long") {
if (typeof Intl.DurationFormat === "function") {
return new Intl.DurationFormat(locale, { style }).format(duration);
}
const parts = Object.entries(duration)
.filter(([, v]) => v !== 0)
.map(([unit, v]) => new Intl.NumberFormat(locale, {
style: "unit", unit: unit.replace(/s$/, ""), unitDisplay: style,
}).format(v));
return new Intl.ListFormat(locale, { style, type: "unit" }).format(parts);
}
console.log(formatDuration({ hours: 1, minutes: 30, seconds: 5 })); // 1 時間 30 分 5 秒
console.log(formatDuration({ hours: 1, minutes: 30, seconds: 5 }, "en")); // 1 hour, 30 minutes, 5 seconds
console.log(formatDuration({ days: 2, hours: 3 }, "en", "narrow")); // 2d 3h
style は long / short / narrow / digital で、{ hours: "numeric", minutes: "2-digit" } のように単位ごとの表示や fractionalDigits も指定できます。期間オブジェクトのキーは years / months / weeks / days / hours / minutes / seconds / milliseconds / microseconds / nanoseconds です。
Node 22 と Chromium 141 で同じコードを動かした結果
118個のレシピのうち112個は Node 22 と Chromium 141 で完全に同じ出力で、違ったのは Intl.DurationFormat に関する5個と Intl.supportedValuesOf("currency") の件数(162 と 159)だけでした。 どちらも V8 + ICU で動いているため書式はほぼ一致しますが、V8 の版(Node 22 は 12.4、Chromium 141 はより新しい)と ICU/CLDR の版は別々に更新されます。Node.js は 22.x の途中でも ICU を更新する(今回の 22.22 は ICU 78.2)ので、「同じ Node 22 でもパッチ版で文字列が変わる」ことがあります。 テストで日時や通貨の文字列を固定値と比べるときは、この前提を知っておくと原因が追いやすくなります。
Chromium 側は Playwright の page.evaluate() に同じ式の文字列を渡して評価し、locale / timezoneId を指定しない既定のコンテキストで実行しました。
記号と空白の違い(文字コードで確認)
見た目が同じでも、通貨記号や空白の文字コードがロケールや書式で異なります。 文字列比較のテストが「一致しない」ときは、まずここを疑うと早く解決します([...s].map((c) => c.codePointAt(0).toString(16)) で確認できます)。
| 書式 | 出力 | 注目する文字 |
|---|---|---|
JPY(ja-JP) |
¥1 |
¥ は U+FFE5(全角) |
JPY(en-US) |
¥1 |
¥ は U+00A5(半角) |
currencyDisplay: "code" |
JPY 1,234,567 |
コードと数字の間は U+00A0(改行しない空白) |
EUR(de-DE) |
1.234,50 € |
€ の前は U+00A0 |
3桁区切り(fr-FR) |
1 234 567,891 |
区切りは U+202F(狭い改行しない空白) |
単位(ja-JP) |
12.5 km |
通常の空白 U+0020 |
範囲(ja-JP) |
¥1,000 ~ ¥2,500 |
~ は U+FF5E、前後は U+0020 |
範囲(en-US) |
$3.00 – $5.00 |
– は U+2013(en ダッシュ) |
時刻(en-US) |
9:00 AM |
この環境では U+0020。ICU の版によっては U+202F が使われていたことがある |
テストでは、formatToParts() で部品ごとに比べる、あるいは s.replace(/\s+/g, " ") のように空白を正規化してから比べると、ICU の版が変わっても安定します(JavaScript の \s は U+00A0 や U+202F にも一致します)。
ロケールとタイムゾーンを省略すると環境で結果が変わる
ロケールを省略すると Node.js は環境変数 LANG(または LC_ALL)、ブラウザは利用者の言語設定で既定ロケールが決まり、タイムゾーンは TZ 環境変数や OS 設定に従います。 同じコードを環境変数だけ変えて実行した結果です。
| 実行方法 | 既定ロケール | 既定 TZ | D.toLocaleString() |
(1234567.891).toLocaleString() |
|---|---|---|---|---|
TZ=Asia/Tokyo node(検証環境の既定) |
en-US |
Asia/Tokyo |
10/1/2026, 9:00:00 AM |
1,234,567.891 |
TZ=UTC node |
en-US |
UTC |
10/1/2026, 12:00:00 AM |
1,234,567.891 |
TZ=America/New_York node |
en-US |
America/New_York |
9/30/2026, 8:00:00 PM |
1,234,567.891 |
LANG=ja_JP.UTF-8 node |
ja-JP |
Asia/Tokyo |
2026/10/1 9:00:00 |
1,234,567.891 |
LANG=de_DE.UTF-8 TZ=Europe/Berlin node |
de-DE |
Europe/Berlin |
1.10.2026, 02:00:00 |
1.234.567,891 |
| Chromium(既定のコンテキスト) | en-US |
Asia/Tokyo |
10/1/2026, 9:00:00 AM |
1,234,567.891 |
Chromium(locale: "ja-JP", timezoneId: "Asia/Tokyo") |
ja-JP |
Asia/Tokyo |
2026/10/1 9:00:00 |
1,234,567.891 |
同じ D が「10/1」にも「9/30」にもなっています。表示用のフォーマッタには、ロケールと timeZone を必ず明示するのがいちばん簡単な対策です。Playwright では browser.newContext({ locale: "ja-JP", timezoneId: "Asia/Tokyo" }) でブラウザ側の既定を固定できます。
インスタンスを使い回すと何倍速いか
new Intl.NumberFormat(...) の生成は、format() の呼び出しよりはるかに重い処理です。 同じ書式を1万〜10万回使う場合の計測結果です(performance.now() で計測、単位はミリ秒。環境により値は変わります)。
| 処理 | Node 22(10万回) | Node 22(1万回) | Chromium 141(1万回) |
|---|---|---|---|
NumberFormat を毎回 new して format |
3,130 | 317 | 246 |
n.toLocaleString("ja-JP", opt) を毎回 |
2,988 | 302 | 233 |
NumberFormat を1つ作って format を使い回す |
52 | 6 | 5 |
DateTimeFormat を毎回 new して format |
6,718 | 658 | 615 |
d.toLocaleString("ja-JP", opt) を毎回 |
6,579 | 629 | 593 |
DateTimeFormat を1つ作って使い回す |
306 | 14 | 14 |
Node 22 の10万回では、NumberFormat で約60倍、DateTimeFormat で約22倍の差になりました。toLocaleString は呼ぶたびに内部でフォーマッタを作るのと同じコストなので、一覧表示やループの中では Intl のインスタンスを使い回します(計測は performance.now() で、for ループ内で毎回 new する版と、ループ外で1つ作る版を同じ入力配列で比べました)。
コピペ用:キャッシュ付きフォーマッタ(fmt.mjs)
ロケールとオプションをキーにして Map に保存しておけば、どこから呼んでもインスタンスが使い回されます。 相対時間の単位を自動で選ぶ relative() も入れています。
// fmt.mjs — Intl のインスタンスをキャッシュして使い回すヘルパー(Node 22 / ブラウザ共通)
const cache = new Map();
/** 同じロケール・オプションなら同じインスタンスを返す */
function get(Ctor, locale, options = {}) {
const key = `${Ctor.name}|${locale}|${JSON.stringify(options)}`;
let f = cache.get(key);
if (!f) {
f = new Ctor(locale, options);
cache.set(key, f);
}
return f;
}
export const num = (n, options, locale = "ja-JP") =>
get(Intl.NumberFormat, locale, options).format(n);
export const yen = (n) => num(n, { style: "currency", currency: "JPY" });
export const compact = (n) => num(n, { notation: "compact", maximumFractionDigits: 1 });
const TZ = "Asia/Tokyo";
export const dateTime = (d, options = { dateStyle: "medium", timeStyle: "short" }, locale = "ja-JP") =>
get(Intl.DateTimeFormat, locale, { timeZone: TZ, ...options }).format(d);
export const wareki = (d) => dateTime(d, { dateStyle: "long" }, "ja-JP-u-ca-japanese");
export const dateRange = (from, to) =>
get(Intl.DateTimeFormat, "ja-JP", { timeZone: TZ, dateStyle: "medium", timeStyle: "short" }).formatRange(from, to);
/** 「3 日前」「来月」など、差の大きさから単位を自動で選ぶ */
export function relative(target, now = new Date(), locale = "ja") {
const rtf = get(Intl.RelativeTimeFormat, locale, { numeric: "auto" });
const diffSec = Math.round((target - now) / 1000);
const units = [["year", 31536000], ["month", 2592000], ["week", 604800],
["day", 86400], ["hour", 3600], ["minute", 60], ["second", 1]];
for (const [unitName, sec] of units) {
if (Math.abs(diffSec) >= sec || unitName === "second") {
return rtf.format(Math.round(diffSec / sec), unitName);
}
}
}
export const list = (items, type = "conjunction", locale = "ja") =>
get(Intl.ListFormat, locale, { type }).format(items);
export const sortJa = (arr) => [...arr].sort(get(Intl.Collator, "ja", { numeric: true }).compare);
// 使い方(node で実行した出力をコメントに記載)
import { yen, compact, wareki, dateRange, relative, list, sortJa } from "./fmt.mjs";
const now = new Date("2026-10-01T00:00:00Z"); // 日本時間 2026/10/01 9:00
console.log(yen(1234567.5), compact(12345678), wareki(now)); // ¥1,234,568 1234.6万 令和8年10月1日
console.log(dateRange(now, new Date("2026-10-01T01:30:00Z"))); // 2026/10/01 9時00分~10時30分
for (const t of [-30, -5 * 60, -3 * 3600, -86400, -3 * 86400, 14 * 86400, -60 * 86400, 400 * 86400]) {
console.log(relative(new Date(now.getTime() + t * 1000), now));
}
// 30 秒前 / 5 分前 / 3 時間前 / 昨日 / 3 日前 / 2 週間後 / 2 か月前 / 来年
console.log(list(["りんご", "みかん"], "disjunction"), sortJa(["item10", "りんご", "item2", "いちご"]));
// りんごまたはみかん [ 'item2', 'item10', 'いちご', 'りんご' ]
toLocaleString との関係とオプション早見表
toLocaleString() 系のメソッドは、内部で対応する Intl クラスを作って format() を呼ぶのと同じ結果になります。 引数も同じ (locales, options) なので、Intl のオプション表はそのまま toLocaleString に使えます。検証では (1234.5).toLocaleString("ja-JP", opt) === new Intl.NumberFormat("ja-JP", opt).format(1234.5) が true でした。
| メソッド | 同じ結果になる Intl | 既定で出る要素 |
|---|---|---|
number.toLocaleString(loc, opt) |
new Intl.NumberFormat(loc, opt).format(number) |
3桁区切り、小数最大3桁 |
bigint.toLocaleString(loc, opt) |
new Intl.NumberFormat(loc, opt).format(bigint) |
同上 |
date.toLocaleString(loc, opt) |
new Intl.DateTimeFormat(loc, opt).format(date) |
年月日 + 時分秒(2026/10/1 9:00:00) |
date.toLocaleDateString(loc, opt) |
同上(日付の既定) | 年月日(2026/10/1) |
date.toLocaleTimeString(loc, opt) |
同上(時刻の既定) | 時分秒(9:00:00) |
array.toLocaleString(loc, opt) |
各要素の toLocaleString を , でつなぐ |
1,234.5,2026/10/1 9:00:00 |
string.localeCompare(other, loc, opt) |
new Intl.Collator(loc, opt).compare(string, other) |
言語に合わせた比較 |
string.toLocaleUpperCase(loc) |
(対応する Intl クラスはなし。言語ごとの大小変換) | トルコ語の i など |
Temporal.*.toLocaleString(loc, opt) |
new Intl.DateTimeFormat(loc, opt).format(temporalObject) |
型に応じた日付・時刻 |
| 使い分け | 選ぶもの | 理由 |
|---|---|---|
| 1回だけ、画面の1か所 | toLocaleString |
短く書ける |
| ループ・一覧・サーバーの大量処理 | Intl のインスタンスを使い回す |
生成コストを払うのが1回で済む(上の計測で約20〜60倍) |
範囲(formatRange)や部品(formatToParts)が必要 |
Intl |
toLocaleString にはない |
| 適用された既定値を知りたい | Intl の resolvedOptions() |
toLocaleString にはない |
よくあるつまずきと直し方
つまずきの多くは「省略した指定が環境依存になる」か「オプション名・値の形式が違う」のどちらかです。 実際のエラー文と合わせてまとめます。
| 症状 | 原因 | 直し方 |
|---|---|---|
| サーバーとブラウザで日付が1日ずれる | timeZone 未指定で実行環境の TZ(UTC など)が使われる |
timeZone: "Asia/Tokyo" を付ける |
本番だけ 10/1/2026 と英語形式になる |
ロケール未指定で LANG やブラウザ設定に従う |
第1引数に "ja-JP" を必ず渡す |
3.14159 が 3.142 になる |
maximumFractionDigits の既定が 3 |
maximumFractionDigits を指定する |
¥1,235 と小数が消える |
JPY の既定は小数0桁 | minimumFractionDigits: 2 などを指定 |
RangeError: maximumFractionDigits value is out of range. |
minimumFractionDigits: 3, maximumFractionDigits: 1 のように最小 > 最大 |
最小 ≤ 最大にする |
TypeError: Currency code is required with currency style. |
style: "currency" で currency 未指定 |
currency: "JPY" を付ける |
YEN 1.00 のような表示 |
存在しない通貨コードはエラーにならない | ISO 4217 のコード(JPY)を使う |
RangeError: Invalid unit argument for Intl.NumberFormat() 'km' |
単位は CLDR 名 | unit: "kilometer" |
2,560% になる |
percent は割合を100倍する |
0.256 を渡す |
RangeError: Invalid time zone specified: Asia/Tokio |
IANA 名の綴り | Asia/Tokyo(Intl.supportedValuesOf("timeZone") で確認) |
TypeError: Invalid option : option |
dateStyle と year などの併用 |
どちらか一方にする |
RangeError: Invalid time value |
Invalid Date を渡した |
Number.isNaN(d.getTime()) で先に確認 |
RangeError: Incorrect locale information provided |
"ja_JP" のようなアンダースコア |
"ja-JP" |
RangeError: Invalid unit argument ... 'days ago' |
RelativeTimeFormat の単位に余計な語 |
"day" または "days" |
a、,、b と1文字ずつ区切られる |
ListFormat に文字列を渡した |
配列を渡す |
テストで "9:00 AM" が一致しない |
空白が U+00A0 や U+202F の場合がある | formatToParts で比べる、または空白を正規化 |
1235万 と 1.2億 で小数の有無が違う |
compact の既定は「小数0桁」と「有効2桁」の精度が高いほう | maximumFractionDigits: 1 をそろえる |
// 直す前:環境に依存する
const before = (d) => d.toLocaleDateString(); // TZ=UTC のサーバーでは前日になることがある
// 直した後:ロケール・タイムゾーン・桁数を明示し、インスタンスを使い回す
const dateFmt = new Intl.DateTimeFormat("ja-JP", { dateStyle: "medium", timeZone: "Asia/Tokyo" });
const after = (d) => (Number.isNaN(d.getTime()) ? "-" : dateFmt.format(d));
console.log(after(new Date("2026-10-01T00:00:00Z")), after(new Date("2026-13-01"))); // 2026/10/01 -
よくある質問
Q. toLocaleString と Intl.NumberFormat、どちらを使えばよいですか?
A. 結果は同じなので、1回だけなら toLocaleString、一覧やループでは Intl.NumberFormat のインスタンスを使い回す、と使い分けます。10万回の計測では、毎回 toLocaleString を呼ぶより使い回すほうが約60倍速くなりました。範囲(formatRange)や部品(formatToParts)が必要なときも Intl を使います。
Q. 「1,234円」のように数字と「円」を別々に装飾したいです。
A. currencyDisplay: "name" で 1,234円 にするか、formatToParts() で integer / group / currency などの部品に分けて、必要な部分だけタグで囲みます。この記事の「範囲と部品」の例では currency 部分を <small>¥</small> に置き換えました。
Q. Node.js で Intl.DurationFormat が undefined になります。
A. Intl.DurationFormat は Node.js 23 以降(ブラウザは Chrome 129 / Firefox 136 / Safari 16.4 以降)で使えます。Node 22 では NumberFormat の unit と ListFormat の type: "unit" を組み合わせた関数で同じ出力(1 時間 30 分 5 秒)が作れます。本文の formatDuration() をそのまま使えます。
Q. ブラウザとサーバーで表示が違うのはなぜですか?
A. 主な原因は3つです。(1)ロケールやタイムゾーンを省略して環境の既定が使われている、(2)ICU/CLDR の版が違い記号や空白の文字が異なる、(3)Intl.DurationFormat のように対応していないクラスがある。ロケールと timeZone を明示し、テストでは formatToParts や空白の正規化で比べると安定します。
まとめ
Intlは「ロケール + オプションでインスタンスを作り、format()に値を渡す」という同じ形で、数値・通貨・日付・相対時間・リスト・期間・並べ替え・分割・表示名を扱える- 3桁区切りは
NumberFormat("ja-JP")、円はstyle: "currency", currency: "JPY"、万・億はnotation: "compact"、単位はstyle: "unit" - 日付は
dateStyle/timeStyleか個別指定、和暦は"ja-JP-u-ca-japanese"、範囲はformatRange、部品はformatToParts - ロケールと
timeZoneは必ず明示する。省略するとLANG/TZ/ ブラウザ設定で結果が変わる(検証では同じ日時が10/1にも9/30にもなった) - インスタンスを使い回すと Node 22 で約20〜60倍速い。
toLocaleStringは毎回フォーマッタを作るのと同じコスト - Node 22 と Chromium 141 の出力は118個中112個が一致。違いは
Intl.DurationFormatの有無(Node 23 以降で対応)と通貨一覧の件数だけ ¥(U+FFE5)と¥(U+00A5)、U+00A0 / U+202F の空白はテストで一致しない原因になるので、formatToPartsや正規化で比べる
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「JavaScript Intlの使い方|数値・通貨・日付フォーマット逆引き一覧」
株式会社RJCでは、標準APIの細かな挙動を実際に動かして確かめ、プロジェクトの中で仲間と学び合っています。こうした知識を共有しながら、日々技術を磨いています。
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。