JavaScript の日付処理が変わる — Temporal API が Chrome 137 で使えるようになった

new Date() の後継として10年かけて設計された Temporal API が Chrome 137 に入った。タイムゾーン処理・日付計算・フォーマットが根本的に改善される。

JavaScript で日付を扱うとき、一度はこういうコードを書いたことがあるはずだ。

const date = new Date();
date.getMonth(); // 6 と返ってきたら 7月

そう、getMonth() は 0-indexed。1月が 0、12月が 11。初めてこれを踏んだときの「は?」という感覚は、たぶん誰もが覚えている。

これだけじゃない。new Date() には長年の問題が山積している。タイムゾーン処理が難しい、日付の加算に便利なメソッドがない、immutable じゃないので破壊的変更のバグを踏みやすい……。だから date-fnsdayjs みたいなライブラリが生まれた。

Temporal API は、その new Date() をまるごと置き換えるために 10 年かけて設計された新しい API だ。Chrome 137 でフラグなしで使えるようになった。

一番変わった設計思想: 型で日付を区別する

Temporal の本質は「日付の種類を型で区別する」設計にある。

new Date() はすべてを UTC ミリ秒で管理していた。「日付だけ」「時刻だけ」を表現するのに苦労した。Temporal はそれを最初から分けている。

何を表すか使いどころ
Temporal.PlainDate日付のみ(時刻なし)誕生日、予約日
Temporal.PlainTime時刻のみ(日付なし)営業時間、アラーム
Temporal.PlainDateTime日付+時刻(タイムゾーンなし)ローカルの予定
Temporal.ZonedDateTimeタイムゾーン付き日時会議の招待、ログ
Temporal.InstantUTC の絶対時刻DB の timestamp

「誕生日」を new Date() で表すのは本来おかしかった。誕生日にタイムゾーンは関係ない。Temporal.PlainDate を使えば意味が正確になる。

日付計算が素直になる

new Date() で「3ヶ月後」を計算するとこうなる。

const d = new Date();
d.setMonth(d.getMonth() + 3); // 破壊的変更。元の d が変わる

setMonth を呼んだ瞬間に元の値が書き換わる。「変更前の日付も使いたい」となったとき、事前にコピーを作っておかなかったことを後悔する。

Temporal ならこう書ける。

const today = Temporal.Now.plainDateISO();
const threeMonthsLater = today.add({ months: 3 });
// today は変わらない。threeMonthsLater が新しいオブジェクト

immutable なので破壊的変更のバグが起きない。.add() .subtract() .with() が使いやすい。「2つの日付の差」もシンプルだ。

const start = Temporal.PlainDate.from('2026-01-01');
const end = Temporal.PlainDate.from('2026-07-06');

const diff = start.until(end, { largestUnit: 'month' });
console.log(`${diff.months}ヶ月 ${diff.days}日`); // 6ヶ月 5日

new Date() でやるとミリ秒計算になるやつだ。

タイムゾーン処理がようやくまともになる

Temporal の最大の強みはタイムゾーン処理にある。

const tokyoNow = Temporal.Now.zonedDateTimeISO('Asia/Tokyo');
const nyNow = tokyoNow.withTimeZone('America/New_York');

console.log(tokyoNow.toString());
// 2026-07-06T10:00:00+09:00[Asia/Tokyo]

console.log(nyNow.toString());
// 2026-07-05T21:00:00-04:00[America/New_York]

タイムゾーン名が型に含まれるので、「UTC で管理していたつもりがローカル時刻だった」問題が起きにくい。文字列を見れば、その値がどのタイムゾーンのものかが一目でわかる。

今すぐ使えるか?

Chrome 137 でフラグなし対応。Firefox は 139 で対応。Safari はまだ技術プレビューの段階。

ポリフィルがあるので、本番に入れること自体は可能だ。

npm install @js-temporal/polyfill
import { Temporal } from '@js-temporal/polyfill';

新規プロジェクトでライブラリを入れずに日付処理をするなら、Temporal が第一候補になりつつある。既存プロジェクトで date-fnsdayjs が入っているなら、急いで移行する必要はない。

ただ「なぜ Date ライブラリが必要なのか」という問いへの答えが、ブラウザの標準機能として届くようになった。それはそれで、大事な変化だと思う。

元ネタ: https://tc39.es/proposal-temporal/docs/