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

Temporal は単一のクラスではなく、用途別に分かれたクラス群です。押さえておきたいのは次の 9 種類です。
クラス | 役割 | 典型的なユースケース |
|---|---|---|
| タイムゾーンなしの年月日 | 期限日、誕生日 |
| タイムゾーンなしの時刻 | 毎日のアラーム、シフト時刻 |
| タイムゾーンなしの日時 | フォーム入力の素直な保持 |
| IANA タイムゾーン付き日時 | 会議予約、国際イベント |
| UNIX エポックからのナノ秒精度時点 | サーバ間タイムスタンプ |
| 期間(年〜ナノ秒) | 経過時間、SLA |
| 現在時刻の取得 | `now.instant()` 等 |
| 年月のみ | 月次集計、給与計算 |
| 月日のみ | 誕生日、記念日 |
この設計の肝は「タイムゾーンを伴う情報」と「伴わない情報」を型レベルで分けたことにあります。期限日のように「その地域の暦の上での日付」を扱いたいときは PlainDate、UTC 上の絶対的な瞬間を扱いたいときは Instant と、最初にどの軸の情報を扱うかを宣言します。これにより変換のたびにタイムゾーンを意識させ、暗黙の UTC 解釈を防げます。もう 1 つの大きな特徴はすべて不変であることです。`add` や `subtract`、`with` は常に新しいインスタンスを返し、元の値には触れません。
Date と Temporal を並べて書くコードサンプル

言葉だけでは違いが伝わりにくいので、よくある 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-tz や luxon を呼び出して書いていた処理が、言語標準のままで自然に書けるようになる点が大きな価値です。
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 のどちらでもインポートは不要で、Math や Date と同じくグローバル 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 月) | フラグ不要、グローバル |
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 と主要ブラウザが揃ったいまは、小さなユースケースから手を動かすのに最適なタイミングといえます。

















