はじめに
システム開発において、切っても切り離せないのが「日時操作」ですよね。
これまでは皆さんJavaScript標準の Date を使用していたと思います。慣れれば問題なかったのですが、他言語の日付操作と違ってオブジェクトの若干の使い勝手の悪さに頭を悩ませた人もいるのではないでしょうか。
しかし、先日(2026/05/05)リリースされた Node.js 26 正式版 にて「Temporal」がデフォルトで有効になりました。
今回、Node.jsがTemporalをデフォルトで有効化したことにより、Safariを除く主要なWebブラウザとサーバサイドJavaScriptランタイムで安心してTemporalが利用可能になりました。
今回は、ピュアなJavaScriptでこの新しい機能を触ってみた感想を共有したいと思います。
※この記事は、現時点での「ブラウザ実装がまだ揃っていない段階」の検証記事です。
なぜ Date ではダメだったのか
これまで私たちが使ってきた Date には、いくつかの大きな課題がありました。
- ミュータブル(可変)である: オブジェクトを操作すると元の値が変わってしまう。
- タイムゾーンの扱いが複雑: 基本的にローカルかUTCしかなく、特定の場所の時間を扱うのが困難。
-
月(Month)が0から始まる:
0が1月という仕様が直感的ではなく、バグの温床になりやすい。
これらを解決するために生まれたのが Temporal です。
ブラウザでの検証
今回はピュアなJavaScriptで動作を確認するため、最新のブラウザのコンソールで動かしてみます。
実際にコードで比較
1. 現在時刻の取得
まずは基本となる現在時刻の取得です。
// 【Date】
const dateNow = new Date();
console.log("Date:", dateNow.toString());
// 【Temporal】
const temporalNow = Temporal.Now.zonedDateTimeISO();
console.log("Temporal:", temporalNow.toString());
Date: Fri May 15 2026 08:00:11 GMT+0900 (GMT+09:00)
Temporal: 2026-05-15T08:00:11.896530029+09:00[Etc/GMT-9]
2. 日付の加算操作
// 【Date】
const date = new Date(2026, 4, 15); // 2026年5月15日
console.log("計算前:", date.toDateString());
// 7日後を計算。新しい変数に代入したつもり
const result = date.setDate(date.getDate() + 7);
// 戻り値が日付オブジェクトではなく「数値(タイムスタンプ)」になる(初めてだと焦る)
console.log("計算結果:", result); // 1779375600000
// そして元の「date」変数の中身が勝手に書き換わっている。
console.log("計算後の元の変数:", date.toDateString()); // Fri May 22 2026
// ↑これが意図せず過去のデータが消える例
計算前: Fri May 15 2026
計算結果: 1779375600000
計算後の元の変数: Fri May 22 2026
// 【Temporal】
const temporal = Temporal.PlainDate.from({ year: 2026, month: 5, day: 15 });
console.log("計算前:", temporal.toString()); // "2026-05-15"
// 7日後を計算。
const nextWeek = temporal.add({ days: 7 });
// 戻り値がちゃんと日付オブジェクトになる
console.log("計算結果:", nextWeek.toString()); // "2026-05-22"
// 元の「temporal」変数はそのまま保持される。
console.log("計算後の元の変数:", temporal.toString()); // "2026-05-15"
// これが「イミュータブル(不変)」。意図しないバグが入り込むリスクが低い。
計算前: 2026-05-15
計算結果: 2026-05-22
計算後の元の変数: 2026-05-15
ここが一番の感動ポイントでした。
Temporal は イミュータブル(不変) であるため、メソッドを呼ぶと新しいオブジェクトが返ってきます。これにより、意図しない値の書き換えを防ぐことができ、安全な実装が出来ると感じています。
上記コードのDateの日付加算はよく見るバグの例です。
実際は下記のようにコピーして安全に使います。
const date = new Date(2026, 4, 15);
const next = new Date(date); // コピー
next.setDate(next.getDate() + 7);
3. 月の指定が直感的
Date の最大の罠、0始まりの月から解放されます。
// 【Date】
// Dateは 4 = 5月
const dateBad = new Date(2026, 4, 15);
// 【Temporal】
// Temporalは 5 = 5月
const temporalGood = Temporal.PlainDate.from({ year: 2026, month: 5, day: 15 });
これだけでも、バグリスクが下がります。
4.タイムゾーンのサポート
これまでは「実行環境のタイムゾーン」に振り回されていましたが、Temporal ではタイムゾーンを明示的に、かつ簡単に扱えます。
// 【Date】
const d = new Date();
// 実行環境(サーバーなど)がUTCだと、JST(日本標準時)にならない
console.log("Date (そのまま):", d.toString());
// タイムゾーンを指定して取得しようとすると、文字列になってしまう
const tokyoString = d.toLocaleString("ja-JP", { timeZone: "Asia/Tokyo" });
console.log("Date (東京・文字列):", tokyoString);
// 文字列になってしまうので、ここから「1時間後」を計算したい場合、
// またDateオブジェクトに戻すなどのパースが必要。
Date (そのまま): Fri May 15 2026 08:25:41 GMT+0900 (GMT+09:00)
Date (東京・文字列): 2026/5/15 8:25:41
// 【Temporal】
// タイムゾーンを指定して、即座にオブジェクトとして取得。
const tokyoNow = Temporal.Now.zonedDateTimeISO('Asia/Tokyo');
console.log("Temporal (東京):", tokyoNow.toString());
// オブジェクトなので、そのままスムーズに計算に移れる。
const afterTwoHours = tokyoNow.add({ hours: 2 });
console.log("2時間後:", afterTwoHours.toString());
Temporal (東京): 2026-05-15T08:25:41.62275+09:00[Asia/Tokyo]
2時間後: 2026-05-15T10:25:41.62275+09:00[Asia/Tokyo]
5. 比較が簡単
日付同士の前後関係を調べる際、Date のように数値に変換(getTime())して比較する手間がなくなります。
const d1 = Temporal.PlainDate.from('2026-05-15');
const d2 = Temporal.PlainDate.from('2026-12-25');
// 【Date】
// if (date1.getTime() > date2.getTime()) ... と書く必要があった。
// 【Temporal】
// 比較専用の compare メソッドが用意されている。
const result = Temporal.PlainDate.compare(d1, d2);
if (result < 0) console.log("d1の方が前です");
if (result > 0) console.log("d1の方が後です");
if (result === 0) console.log("同じ日です");
// 配列のソートもこれだけで完結します
const sorted = [d2, d1].sort(Temporal.PlainDate.compare);
d1の方が前です
Temporalを触って感じたメリット
私が実際に触ってみて、特にメリットだと感じたのは以下の5点です。
-
メソッド名が自己説明的:
PlainDate(日付のみ)、PlainTime(時間のみ)など、何を扱っているかが一目でわかる。 -
計算が非常に楽:
addやsubtractメソッドが直感的。 - タイムゾーンのサポート: 日本時間を指定しての計算が標準でスムーズ。
-
比較が簡単:
Temporal.PlainDate.compare(d1, d2)で簡単にソートや比較ができる。 - 標準機能であること: ライブラリの選定や、プロジェクトごとの書き方の揺れに悩まなくて済む。
さいごに
今回は、Node.jsへの標準実装で注目されている Temporal をピュアな環境で触ってみました。
Temporalが標準として定着すれば、私たちのコードはより安全で読みやすいものになるはずです。
今回記事で触れませんでしたがDateのメリット、Temporalのデメリットもあると思います。
しかし、Temporalのメリットが多いのは事実なので皆さんもぜひ、一度「Temporal」を体験してみてください。
(・・・早くSafariでも実装して欲しい)