Node.js 26 で Temporal がデフォルト有効化、JavaScript の Date を置き換える新しい日時 API の使い方

益子 竜与志
益子 竜与志
XThreads
最終更新日:2026年05月14日公開日:2026年05月14日

Node.js 26 で Temporal API がデフォルト有効化され、Chrome 144・Edge 144・Firefox 139 と合わせてフロントエンドとサーバサイドの両方で利用できる段階に入りました。Date の月0始まりや可変性、タイムゾーン非対応といった長年の課題を、PlainDate や ZonedDateTime、Duration などの新しいクラスがどう解決するのかを、コードサンプル付きで整理します。

2026 年 5 月にリリースされた Node.js 26 では、JavaScript の新しい日時 API である Temporal がデフォルトで有効化されました。フラグ追加も別パッケージのインストールも不要で、Temporal.Now.plainDateISO() がそのまま動きます。Firefox 139 では 2025 年 5 月から、Chrome 144 と Edge 144 でも 2026 年に既定で使えるようになっており、フロントエンドとサーバサイドの両方で利用環境が揃ってきました。本記事では、Temporal が解決する Date の課題、主要クラスの全体像、Date と Temporal を並べたコードサンプル、そして手元で動かす手順までを整理します。

Node.js 26 と Temporal が標準で使える時代の幕開け

Temporal は ECMAScript の新しい日時 API で、TC39 で長年議論されてきた提案です。Node.js 26.0.0 のリリースノートでは「Temporal API is now enabled by default」と明記されており、関連変更は SEMVER-MAJOR として扱われています。V8 エンジン側で実装が安定化したため、Node.js 側はフラグを外すだけで利用できるようになりました。

主要ランタイムでの対応状況は、Firefox 139 が 2025 年 5 月 27 日にリリースされ、主要ブラウザとして最初にデフォルト有効化を達成しています。Chrome 144 と Edge 144 では Chromium ベースで Temporal が有効化され、2026 年中に幅広いユーザー環境へ展開されました。Safari は 2026 年 5 月時点で Technology Preview 段階で、デフォルト有効化には至っていません。Node.js 26 が加わったことで、ブラウザ・サーバの両側で同じ Temporal コードを書ける土台が整いました。

Date が抱えていた 7 つの設計負債

Temporal が必要とされる背景には、1995 年の設計を引きずってきた Date の課題があります。代表的な落とし穴を 7 つ整理します。

  1. 月が 0 始まり。`new Date(2026, 0, 15)` は 2026 年 1 月 15 日です。配列インデックスと同じ感覚を強いられ、レビュー時の確認コストが発生します。
  2. 可変オブジェクトです。`setMonth` や `setFullYear` が元のインスタンスを書き換えるため、関数渡し後に値が変化していないかを常に意識する必要があります。
  3. タイムゾーンが UTC とローカルしか扱えない。`Asia/Tokyo` のような IANA 識別子を値として保持できず、サーバとブラウザで結果がずれる原因になります。
  4. 精度がミリ秒まで。高頻度トレースや金融、IoT 用途でナノ秒精度が欲しい場面では不足します。
  5. パース挙動が実装依存。`new Date('2026-5-1')` のような非 ISO 文字列は環境によって解釈が変わります。
  6. 暦がグレゴリオ暦固定。和暦やイスラム暦をネイティブには扱えません。
  7. 期間を表す標準型がない。「3 か月後」をミリ秒計算で代用する必要があります。

Temporal API の主要クラスを俯瞰する

Temporalの主要9クラスを本棚で整理するインフォグラフィック

Temporal は単一のクラスではなく、用途別に分かれたクラス群です。押さえておきたいのは次の 9 種類です。

クラス

役割

典型的なユースケース

Temporal.PlainDate

タイムゾーンなしの年月日

期限日、誕生日

Temporal.PlainTime

タイムゾーンなしの時刻

毎日のアラーム、シフト時刻

Temporal.PlainDateTime

タイムゾーンなしの日時

フォーム入力の素直な保持

Temporal.ZonedDateTime

IANA タイムゾーン付き日時

会議予約、国際イベント

Temporal.Instant

UNIX エポックからのナノ秒精度時点

サーバ間タイムスタンプ

Temporal.Duration

期間(年〜ナノ秒)

経過時間、SLA

Temporal.Now

現在時刻の取得

`now.instant()` 等

Temporal.PlainYearMonth

年月のみ

月次集計、給与計算

Temporal.PlainMonthDay

月日のみ

誕生日、記念日

この設計の肝は「タイムゾーンを伴う情報」と「伴わない情報」を型レベルで分けたことにあります。期限日のように「その地域の暦の上での日付」を扱いたいときは PlainDate、UTC 上の絶対的な瞬間を扱いたいときは Instant と、最初にどの軸の情報を扱うかを宣言します。これにより変換のたびにタイムゾーンを意識させ、暗黙の UTC 解釈を防げます。もう 1 つの大きな特徴はすべて不変であることです。`add` や `subtract`、`with` は常に新しいインスタンスを返し、元の値には触れません。

Date と Temporal を並べて書くコードサンプル

DateとTemporalの違いを月の0始まり、可変性、タイムゾーン、精度で対比したインフォグラフィック

言葉だけでは違いが伝わりにくいので、よくある 4 つのケースを Date と Temporal で並べてみます。

1. 月インデックスの違い

// Date は月が 0 始まり
const d1 = new Date(2026, 5, 15); // 6 月 15 日になる
console.log(d1.toISOString());

// Temporal は宣言通り
const t1 = Temporal.PlainDate.from({ year: 2026, month: 5, day: 15 });
console.log(t1.toString()); // "2026-05-15"

2. 可変と不変

// Date は元のインスタンスを書き換える
const d = new Date('2026-05-15T00:00:00Z');
d.setMonth(d.getMonth() + 3);
console.log(d.toISOString()); // 8 月になっている

// Temporal は新しいインスタンスを返す
const t = Temporal.PlainDate.from('2026-05-15');
const t2 = t.add({ months: 3 });
console.log(t.toString());  // "2026-05-15"
console.log(t2.toString()); // "2026-08-15"

3. タイムゾーン変換

// Date は IANA 識別子を値として保持できない
const d = new Date('2026-05-15T09:00:00');
console.log(d.toLocaleString('ja-JP', { timeZone: 'Asia/Tokyo' }));

// Temporal はタイムゾーンを値の一部として扱える
const nyc = Temporal.ZonedDateTime.from('2026-05-15T09:00:00[America/New_York]');
const tokyo = nyc.withTimeZone('Asia/Tokyo');
console.log(tokyo.toString());
// "2026-05-15T22:00:00+09:00[Asia/Tokyo]"

4. 期間(Duration)の扱い

// Date は引き算をミリ秒で受ける
const days = (new Date('2026-12-31') - new Date('2026-05-15')) / 86400000;
console.log(days); // 数値が返るだけ

// Temporal は Duration として返る
const start = Temporal.PlainDate.from('2026-05-15');
const end   = Temporal.PlainDate.from('2026-12-31');
const dur   = start.until(end, { largestUnit: 'months' });
console.log(dur.toString()); // "P7M16D"
console.log(dur.months, dur.days); // 7 16

とくにタイムゾーンと Duration の例は、これまで date-fns-tzluxon を呼び出して書いていた処理が、言語標準のままで自然に書けるようになる点が大きな価値です。

Node.js 26 で Temporal を有効化する手順とブラウザ対応

Node.js 26 では追加設定が一切要りません。`node -v` で v26 系であることを確認したら、そのまま使えます。

$ node -v
v26.0.0
$ node -e "console.log(Temporal.Now.zonedDateTimeISO('Asia/Tokyo').toString())"
2026-05-15T07:30:12.345678901+09:00[Asia/Tokyo]

ESM と CommonJS のどちらでもインポートは不要で、MathDate と同じくグローバル Temporal を直接参照できます。古い Node.js や Safari でも同じ書き方をしたい場合は、公式整備の @js-temporal/polyfill もしくは軽量な temporal-polyfill を併用します。

// temporal-polyfill を併用する例
import { Temporal } from 'temporal-polyfill';

const today = Temporal.Now.plainDateISO();
console.log(today.toString());

主要環境のサポート状況は次のとおりです。

環境

デフォルト有効化バージョン

備考

Node.js

26.0.0(2026 年 5 月)

フラグ不要、グローバル Temporal

Firefox

139(2025 年 5 月 27 日)

主要ブラウザで最初のデフォルト有効化

Chrome

144

Chromium 144 系で導入

Edge

144

Chromium ベースで追従

Safari

未対応

Technology Preview 段階、要ポリフィル

実務でどう取り入れるか、移行戦略と注意点

既存コードに Temporal を導入する場合、Date を全廃する必要はありません。境界面から徐々に置き換える戦略が現実的です。新規ロジックの内部表現を Temporal に統一しつつ、API レスポンスや DB へ書き戻すタイミングだけ ISO 8601 文字列に変換すれば、外部インターフェースは従来どおりに保てます。テストコードを Temporal で書き直すと、Date 依存の隠れた挙動(タイムゾーン、月跨ぎ、うるう年)が顕在化しやすくなる効果もあります。

API 設計の観点では、Temporal.ZonedDateTime をシリアライズすると 2026-05-15T22:00:00+09:00[Asia/Tokyo] の拡張 ISO 文字列になります。ユーザー入力の予約時刻はタイムゾーンも一緒に保存し、ログやイベントは UTC の Instant に統一する、といった使い分けが定石になりつつあります。Safari ユーザーが多いプロダクトでは、ブラウザ側にだけポリフィルをバンドルしてサーバとフロントで同じ書き方を維持するとよいでしょう。

注意点として、Temporal は TC39 で Stage 3 から Stage 4 への移行局面にあり、暦オブジェクトの取り扱いなど一部 API の細部は最終化の調整が続いています。本番投入では、利用しているランタイムのバージョンと MDN や Node.js のリリースノートを照合する運用にしておくと安心です。Date の不便さに毎回付き合ってきたチームほど、Temporal の導入効果は分かりやすく現れます。Node.js 26 と主要ブラウザが揃ったいまは、小さなユースケースから手を動かすのに最適なタイミングといえます。

AI-NATIVE WORKSPACE

Openclaw AX

いつもの業務がAIとの共同作業に変わる革新的AI製品

詳しく見る →
Openclaw AX

IT/DXプロジェクト推進するPMO・コンサル人材を提供しています

AI利活用×高生産性のリソースで、あらゆるIT/DXプロジェクトを一気通貫支援します

詳しく見る →
AI駆動型ITコンサルティング
Careerバナーconsultingバナー