Node 24のIntlは明治元年を1868年9月8日から始める|CLDR 47と48の差

和暦・西暦 変換 は、西暦の日付を令和・平成・昭和・大正・明治に変換するブラウザ内ツールである。改元日をまたぐ境目を日付単位で判定するために、改元日の表を自前で持っている。

一方 JavaScript には Intl.DateTimeFormat に ja-JP-u-ca-japanese を渡す方法があり、和暦の表示はこれで済むことが多い。では自前の表は要らないのか。両方を同じ日付で動かして比べたところ、明治の始まりだけが一致しなかった。

Intl の和暦は ICU と CLDR のデータで動く

Node.js の Intl は ICU(International Components for Unicode)で実装されていて、ICU の改元日は CLDR(Common Locale Data Repository)の calendarData から来る。手元の Node が持つ版は process.versions で分かる。

1
node v24.11.1 icu 77.1 cldr 47.0

CLDR 47 の calendarData.json(cldr-core/supplemental/calendarData.json・タグ 47.0.0)で、japanese の明治は次の値である。

1
"232": { "_code": "meiji", "_start": "1868-09-08" }

大正以降は 1912-07-30 / 1926-12-25 / 1989-01-08 / 2019-05-01 で、これは改元日の西暦(グレゴリオ暦)そのものだ。ところが明治の 1868-09-08 は西暦の日付ではない。

1868-09-08 は旧暦の日付をそのまま読んだ値

明治改元の詔は 慶応4年9月8日 に出た(国立公文書館「日本のあゆみ」)。この「9月8日」は当時の暦(天保暦・太陰太陽暦)での日付で、グレゴリオ暦に直すと 1868年10月23日 になる(Wikipedia「明治」)。

CLDR 47 の 1868-09-08 は、旧暦の「9月8日」を西暦の 9月8日として書いた値である。この件は CLDR のチケット CLDR-11375 として直され、CLDR 48 の同じファイル(main ブランチ)では次のようになっている。

1
"229": { "_code": "meiji", "_start": "1868-10-23" }

.NET 11 も同じ理由で JapaneseCalendar.MinSupportedDateTime を 1868-09-08 から 1868-10-23 に変更していて、Microsoft Learn の破壊的変更の記事が CLDR-11375 を理由として挙げている。

つまり 2026年10月時点の Node 24(CLDR 47)では、1868年9月8日から10月22日までの45日間が「明治」と表示されるが、歴史上はまだ慶応4年である。

もう1つの読み方: 慶応4年は年初に遡って明治元年

話はここで終わらない。明治改元の詔は「慶応四年を改めて明治元年と為す」と書いていて、改元の効力は 慶応4年の元日(グレゴリオ暦 1868年1月25日)に遡る。年の途中で呼び名が変わるのではなく、その年全体が明治元年になった(国立公文書館・Wikipedia とも同じ記述)。この遡及は明治だけで、大正・昭和・平成・令和は改元日の当日から切り替わる。

和暦ツールの表は、この遡及のほうを採っている。

1
2
3
4
5
6
7
var ERAS=[
{n:"令和",y:2019,m:5,d:1,max:null,next:null},
{n:"平成",y:1989,m:1,d:8,max:31,next:"令和"},
{n:"昭和",y:1926,m:12,d:25,max:64,next:"平成"},
{n:"大正",y:1912,m:7,d:30,max:15,next:"昭和"},
{n:"明治",y:1868,m:1,d:25,max:45,next:"大正"}
];

だから「1868年3月1日」は、ツールでは明治元年、Intl では慶応4年になる。どちらも根拠はあるが、何を聞かれているかで答えが変わる。書類の年号を書くなら「慶応4年の出来事は明治元年の出来事」で、改元の詔が出た瞬間を聞くなら 10月23日である。ツールが 1868-01-25 を採っているのは、書類の年号記入という用途に合わせたためだ。

実際に試す

Node.js 24.11.1(ICU 77.1・CLDR 47.0)で確認した。ツールの表による判定と、Intl の判定を同じ日付で並べる。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
const ERAS = [
{ n: "令和", y: 2019, m: 5, d: 1 },
{ n: "平成", y: 1989, m: 1, d: 8 },
{ n: "昭和", y: 1926, m: 12, d: 25 },
{ n: "大正", y: 1912, m: 7, d: 30 },
{ n: "明治", y: 1868, m: 1, d: 25 }
];
function toWareki(y, mo, d) {
for (const e of ERAS) {
const ok = (y > e.y) || (y === e.y && (mo > e.m || (mo === e.m && d >= e.d)));
if (ok) return e.n + (y - e.y + 1) + "年";
}
return "(明治より前)";
}
const icu = new Intl.DateTimeFormat("ja-JP-u-ca-japanese",
{ era: "long", year: "numeric", month: "numeric", day: "numeric", timeZone: "Asia/Tokyo" });
console.log("node", process.version, "icu", process.versions.icu, "cldr", process.versions.cldr);
for (const s of ["1868-01-24", "1868-01-25", "1868-09-07", "1868-09-08", "1868-10-22", "1868-10-23",
"1912-07-30", "1989-01-07", "1989-01-08", "2019-04-30", "2019-05-01"]) {
const [y, m, d] = s.split("-").map(Number);
const dt = new Date(s + "T12:00:00+09:00");
console.log(s, "| Intl:", icu.format(dt).padEnd(14), "| table:", toWareki(y, m, d));
}

実行結果:

1
2
3
4
5
6
7
8
9
10
11
12
node v24.11.1 icu 77.1 cldr 47.0
1868-01-24 | Intl: 慶応4/1/24 | table: (明治より前)
1868-01-25 | Intl: 慶応4/1/25 | table: 明治1年
1868-09-07 | Intl: 慶応4/9/7 | table: 明治1年
1868-09-08 | Intl: 明治1/9/8 | table: 明治1年
1868-10-22 | Intl: 明治1/10/22 | table: 明治1年
1868-10-23 | Intl: 明治1/10/23 | table: 明治1年
1912-07-30 | Intl: 大正1/7/30 | table: 大正1年
1989-01-07 | Intl: 昭和64/1/7 | table: 昭和64年
1989-01-08 | Intl: 平成1/1/8 | table: 平成1年
2019-04-30 | Intl: 平成31/4/30 | table: 平成31年
2019-05-01 | Intl: 令和1/5/1 | table: 令和1年
  • 大正・昭和・平成・令和の境目は両者で一致する。
  • Intl が明治に切り替わるのは 1868-09-08。CLDR 48 を積んだ ICU なら 1868-10-23 になるはずで、process.versions.cldr が 48 以上の Node で同じコードを流せば確かめられる。
  • 1868-01-25 から 1868-09-07 の区間は、ツールは明治元年、Intl は慶応4年を返す。

なお year: "numeric" でも Intl は元年を 1 で出す(month: "long" を指定したときは 令和元年 と出た)。元年表記が要るなら formatToParts で year の値を見て自分で置き換える。

「和暦を Intl に任せる」と決めるときの確認点

  1. process.versions.cldr を記録する。 明治の境目は CLDR 47 と 48 で違う。同じコードがサーバとブラウザで別の答えを出し得る。
  2. 明治元年の扱いを決める。 1868年1月25日から10月22日までを明治と呼ぶかどうかは、データではなく用途の判断である。年号記入なら遡及(表)、歴史上の呼称なら改元日(CLDR 48)。
  3. 令和以前の境目は Intl で問題ない。 平成31年4月30日と令和元年5月1日、昭和64年1月7日と平成元年1月8日は、どちらの方法でも一致した。

参照: CLDR calendarData.json(47.0.0) / CLDR calendarData.json(main・CLDR 48) / .NET 11 破壊的変更: Japanese Calendar minimum supported date corrected / 国立公文書館 日本のあゆみ: 改元の詔となる / 和暦・西暦 変換(hashitosystem)


Node 24のIntlは明治元年を1868年9月8日から始める|CLDR 47と48の差
https://blog.hashito.biz/2026/10/05/intl-japanese-calendar-meiji-start-cldr-47-48-node-24/
著者
hashito
作成日
2026年10月5日
著作権