JavaScript の Temporal API を実際に動かす - Date の footgun を捨てる

長年 JavaScript の日付処理は Date オブジェクトの「footgun」に悩まされてきた。月が 0 始まり、パースの挙動が実装依存、ミュータブルで setMonth が元オブジェクトを破壊する、タイムゾーンはローカルと UTC しか扱えない、といった問題だ。この積年の課題を根本から解決する Temporal API が、2026年についに標準の一部になった。

Temporal は 2026年3月11日に TC39 の Stage 4 に到達し、ES2026 仕様に組み込まれた。ブラウザでは Chrome 144+ / Firefox 139+ / Edge 144+ にネイティブ実装が入り、ランタイム側でも Deno 2.7(2026年2月25日リリース) が V8 14.5 への更新にあわせて Temporal を安定化し、--unstable-temporal フラグが不要になった。

この記事では Temporal が Date の何を直すのかを整理し、手元ですぐ動かせる形で挙動を確かめる。

Date の何が問題で、Temporal は何を変えるのか

Temporal の設計原則は主に 3 つ。

1. 不変(immutable)である。 すべての Temporal 型は不変で、addwithTimeZone などの操作は必ず新しいオブジェクトを返す。元のオブジェクトは変わらない。Date.prototype.setMonth のように既存の値を破壊してしまう事故が起きない。

2. 用途ごとに型が分かれている。 タイムゾーンを持たない日付だけの Temporal.PlainDate、日時の Temporal.PlainDateTime、タイムゾーン付きの Temporal.ZonedDateTime、絶対時刻の Temporal.Instant などがある。「これはローカル時刻なのか UTC なのか」が型で明示される。

3. タイムゾーンと暦を第一級で扱う。 IANA タイムゾーン名(America/New_York など)を直接指定でき、夏時間(DST)の切り替えも自動で処理される。

実際に試す

前提: Node.js 18 以上(動作確認は Node.js v20.17.0)。ネイティブ Temporal はまだ Node の安定版に入っていないため、ここでは仕様と同一 API を提供する公式系ポリフィル temporal-polyfill(動作確認は v1.0.1)を使う。これで任意の Node バージョンから、ブラウザ/Deno のネイティブ Temporal と同じコードを動かせる。

まず作業ディレクトリを用意してインストールする。

1
2
3
mkdir temporal-try && cd temporal-try
npm init -y
npm install temporal-polyfill

次に demo.mjs を作成する。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import { Temporal } from 'temporal-polyfill';

// 1. 現在日付(タイムゾーン付きの ISO 日付)
const today = Temporal.Now.plainDateISO();
console.log('today:', today.toString());

// 2. 不変な日付演算(元は変わらない)
const nextMonth = today.add({ months: 1 });
console.log('today after add:', today.toString());
console.log('nextMonth:', nextMonth.toString());

// 3. タイムゾーン変換(同一の瞬間を別の TZ で表示)
const meeting = Temporal.ZonedDateTime.from('2026-03-15T14:30[America/New_York]');
const inTokyo = meeting.withTimeZone('Asia/Tokyo');
console.log('NY :', meeting.toString());
console.log('JST:', inTokyo.toString());

// 4. 期間の差分
const a = Temporal.PlainDate.from('2026-07-10');
const b = Temporal.PlainDate.from('2026-12-25');
const diff = a.until(b, { largestUnit: 'month' });
console.log('until:', diff.toString(), '=>', `${diff.months}ヶ月${diff.days}日`);

// 5. DST(夏時間)をまたぐ加算
const before = Temporal.ZonedDateTime.from('2026-03-08T01:30[America/New_York]');
const after = before.add({ hours: 1 });
console.log('DST before:', before.toString());
console.log('DST after :', after.toString());

実行する。

1
node demo.mjs

期待される出力(today はこの記事の日付で実行した場合)。

1
2
3
4
5
6
7
8
today: 2026-07-10
today after add: 2026-07-10
nextMonth: 2026-08-10
NY : 2026-03-15T14:30:00-04:00[America/New_York]
JST: 2026-03-16T03:30:00+09:00[Asia/Tokyo]
until: P5M15D => 5ヶ月15日
DST before: 2026-03-08T01:30:00-05:00[America/New_York]
DST after : 2026-03-08T03:30:00-04:00[America/New_York]

出力から読み取れるポイントを補足する。

  • 不変性: today.add({ months: 1 }) を呼んだあとも today2026-07-10 のまま。加算結果は nextMonth として別に返る。DatesetMonth と違い、うっかり元の値を壊すことがない。
  • タイムゾーン変換: ニューヨークの 3/15 14:30(EDT, UTC-4)が、東京では 3/16 03:30(JST, UTC+9)になる。同一の瞬間を保ったまま表示だけが切り替わっている。オフセットも自動で付く。
  • 期間: until は ISO 8601 の期間表現 P5M15D(5ヶ月15日)を返す。largestUnit で最大単位を指定できる。
  • DST の自動処理: ここが Date では特に厄介だった部分だ。米国の夏時間は 2026年3月8日 02:00 に始まり、時計が 02:00 から 03:00 へ飛ぶ。そのため 01:30(EST, UTC-5)に 1 時間を足すと、存在しない 02:30 ではなく 03:30(EDT, UTC-4) になり、オフセットも -05:00 から -04:00 へ切り替わる。Temporal はこの「消える 1 時間」を自動で処理する。

ネイティブ環境で動かす場合

ポリフィルなしで動かせる環境なら、import を消して同じコードがそのまま動く。

  • ブラウザ: Chrome 144+ / Firefox 139+ / Edge 144+ では Temporal がグローバルに存在する。DevTools のコンソールに Temporal.Now.plainDateISO().toString() と打てば確認できる。
  • Deno 2.7 以降: フラグ不要で Temporal が使える。上記コードの import 行を削除し、deno run demo.js で実行できる。

Node.js の安定版にネイティブ実装が入るまでの間は、temporal-polyfill を使えばコードを一切変えずに移行できる。将来 Node がネイティブ対応したら import を外すだけでよい。

まとめ

Temporal は「9年越し」で JavaScript の日付処理を作り直した API で、2026年に ES2026 として正式に標準入りした。不変性・型による意図の明示・DST を含むタイムゾーンの自動処理という 3 点で、Date の代表的な落とし穴をまとめて解消する。ネイティブ対応が広がるまでもポリフィルで今日から書き始められるので、新規コードでは Date の代わりに Temporal を選ぶ価値がある。


JavaScript の Temporal API を実際に動かす - Date の footgun を捨てる
https://blog.hashito.biz/2026/07/10/try-temporal-api-javascript-dates-2026/
著者
hashito
作成日
2026年7月10日
著作権