Temporal APIの現在地(2025年9月時点)

に公開

祝、Firefox通常版でのTemporalリリース。といっても既に4ヶ月くらい経っていますが。

前回の記事:

https://zenn.dev/fabon/articles/e9d4610722b660

仕様

Temporalは現在stage 3です。仕様バグがちょこちょこ発覚して随時修正されているものの[1]、全体としては安定しています。今後APIのユーザー(一般の開発者)の対応を要する変更が入ることはないでしょう。

なお、Temporalの仕様本体(ECMA-262側)において、ISO8601以外の暦の動作は実装依存となっています。いくら実装依存とはいえ各々のエンジンの計算結果が食い違うと困るので、ECMA-402側の仕様としてサポートする暦やそれぞれの挙動が指定されることになっています。ちなみに、この仕様には「韓国天文研究院が計算・公開している太陰太陽暦と1900〜2050年の範囲で一致しなければならない」とか名指しで書かれていて、かなり面白いです。

https://github.com/tc39/proposal-intl-era-monthcode

2025年9月現在、こちらのIntl era and monthCode Proposalも現在stage 2.7で、仕様がほぼ定まっています。(READMEだとstage 2って書いてるけど2.7のはず……[2])

実装

JavaScriptエンジン

SpiderMonkey(Firefox)では、5月末リリースのv139でTemporal APIが正式にリリース(ship)されました。ただし、各種ヒジュラ暦(イスラム圏で使われる太陰暦)のうち一部(islamic-umalqura)のサポートは暫定的に無効化されています。

https://spidermonkey.dev/blog/2025/04/11/shipping-temporal.html
https://bugzilla.mozilla.org/show_bug.cgi?id=1912511

V8(Chrome)はかつて部分的にTemporalを実装していましたが、Boa(JSエンジン)のTemporal実装用ライブラリ(Rust製)とICU4Xを利用してTemporal全体を実装し直しました。今のところ、Chrome CanaryでTemporalを使うにはenable-javascript-harmonyフラグを有効にする必要があります。

https://groups.google.com/a/chromium.org/g/blink-dev/c/s58GKzoQZFg/m/iQ6OBGuLAAAJ
https://issues.chromium.org/issues/401065166
https://github.com/boa-dev/temporal

Chromeのv144(たぶん来年1月リリース)でTemporalがshipされる予定です。実装に必要なICU4Xのv2.1が10月下旬リリースで、そこからcanary→beta→stableと順番にリリースすることを考えると妥当な見積もりだと思います。

https://chromestatus.com/feature/5668291307634688

JavaScriptCore(Safari/WebKit)の実装も再開されています。実装自体よりもレビューにどうしても時間がかかってしまっているようですが……

https://bugs.webkit.org/show_bug.cgi?id=223166

余談ですが、最近jsvuというツールを知りました。V8やJavaScriptCoreやSpiderMonkeyといったJavaScriptエンジンの最新版をビルドなしでインストールできるので非常に便利です。

https://github.com/GoogleChromeLabs/jsvu

JavaScriptランタイム

V8本体にRustのコードが入ったわけではないものの、V8の実装で使われているライブラリはRust製です。Node.jsなどのV8を利用しているランタイムでは、依存関係のRustコードをビルドできるようにビルドパイプラインを調節する必要があります。

Node.jsでは対応作業中です。

https://github.com/nodejs/node/issues/58730

Denoではv2.5で新しいTemporal実装に対応しました。今まで--unstable-temporalフラグで一応使えていたTemporal実装はsegmentation faultが平気で起きるレベルで微妙だったのですが、今度こそ、まともなTemporal実装がネイティブで利用できるようになります。

https://deno.com/blog/v2.5

ただし、Deno v2.5が使っているV8のバージョンは8月21日にリリースされたv14.0で、この時点では仕様未準拠・未実装の箇所やバグがそこそこあります。未リリースの最新版ではISO8601以外の暦の問題を除いてほぼ全て[3]解消されているので、次のV8のバージョンアップを待ちましょう。

Deno v2.5の時点で通っていないtest262のテストケースは以下の通りです:

https://github.com/v8/v8/blob/14.0.365.4/test/test262/test262.status#L260-L581

polyfill

今のところ存在するpolyfillは2つとも最新の仕様におおよそ追従しています。メンテナが多忙なのか、どちらも仕様変更の反映などが滞っているのが若干不安要素ではありますが……

  • temporal-polyfill
  • @js-temporal/polyfill

バグの数では後者の方が少ないのですが、フロントエンドだとバンドルサイズの関係上前者しか選択肢がないことも多いと思います。非常に悩ましいところです。メンテナが多忙だとバグ修正も全然進まなくて……[6]

Temporal実装の混在リスク

ネイティブ実装や違う種類のpolyfill、あるいはdual package hazardなどでTemporalの実体が複数存在してしまうと、全てがバグります。以下のコードを実行するとバグっている様子を観察できます。

import { Temporal as Temporal1 } from 'temporal-polyfill';
import { Temporal as Temporal2 } from '@js-temporal/polyfill';
// 本来エラーにならないはずが、エラーになる
Temporal1.Now.zonedDateTimeISO().since(Temporal2.Now.zonedDateTimeISO());

「さすがにこんなアホなことはしないよ」と言われそうですが、実は意外とハマる可能性があると思います。たとえば以下のようなパターンがあり得るでしょう。

  • 使っているライブラリが内部で読み込んでいるpolyfillと自分のコードで使っているpolyfillが違う種類だった
  • グローバルにpolyfillを読み込まずimport経由でTemporalを利用していたが、1ファイルでだけimportを忘れてしまいネイティブのTemporalを使ってしまった

とにかく注意しましょう。

エコシステム

ライブラリ

Temporalは基本的な日時の計算や比較、文字列との相互変換、丸め処理といった基本機能を提供します。あくまで基本機能であり、Luxonやdayjsやdate-fnsといったライブラリと違って「あったら便利」レベルのものは入っていません。さすがにそれはJSの標準ライブラリでやることではないので。

今のところ有力なTemporal対応ライブラリはなさそうです。半年前の記事に引き続き手前味噌で恐縮ですが私の自作ライブラリをオススメしておきます。date-fnsインスパイアのTemporal対応ライブラリです。

https://github.com/fabon-f/vremel

  • 勝手にpolyfillを読み込まないしglobalThis.Temporalも参照しない
    • どのpolyfillを使っても、polyfillをグローバルに読み込まなくても、JSエンジンのネイティブ実装を使ってもちゃんと動く
  • 先述の実装混在リスクが発生しない
  • Temporalの各クラスに対応している
  • タイムゾーンや暦のエッジケースをちゃんと考慮した実装になっている
  • そこそこ機能が揃っている

テスト関連

Vitest v3.2.0でTemporalオブジェクト同士をtoEqualで比較できるようになりました。もちろん違うクラスのオブジェクト(たとえばTemporal.PlainDateTemporal.PlainDateTime)は等しくないと判定されます。

expect(Temporal.PlainDate.from("2025-08-01")).toEqual(
	Temporal.PlainDate.from("2025-08-01"),
); // OK
expect(Temporal.PlainDate.from("2025-08-01")).toEqual(
	Temporal.PlainDateTime.from("2025-08-01"),
); // NG

https://github.com/vitest-dev/vitest/pull/8007

chaiでも結構前からサポートされているので(Temporal.Durationのサポートはちょっとバグってますが)、Vitestのassert系のAPIでもTemporalをテストできます。

まとめ

Temporal APIは実装によって準拠している仕様が古かったりバグが直っていなかったりと、今の段階では過渡期ゆえの混乱が多いです。仕様は固まっているので、クリティカルでない部分であれば、過渡期であることを覚悟した上で一応実戦投入できる段階にあります。みんなで人柱になりましょう。

ただし、ISO8601以外の暦(中韓の旧暦とか日本の元号とか)の操作に関しては、仕様と実装が安定するまで待つことを強く推奨します。

脚注
  1. ちなみに仕様バグの1つは私が報告しました。https://github.com/tc39/proposal-temporal/issues/3099 ↩︎

  2. 2025年9月のTC39ミーティングのアジェンダに"Intl Era Month Code Stage 2.7 Update"と書かれている。 ↩︎

  3. 厳密にはDuration.prototype.totalと浮動小数点数の精度の問題が残っていますが、このAPIの結果が10のマイナス15乗くらいズレたところで現実的には誰も困らないでしょう。 ↩︎

  4. 「じゃあ自分で修正プルリク送れば?」と言われそうですが、temporal-polyfillのコードはめちゃくちゃ癖が強く、癖の強い設計のまま手を入れるのは難しいけど勝手に設計を変えるわけにもいかないというジレンマがあります。一応、私も可能な限りcontributeするよう努めてはいるのですが。 ↩︎

  5. 「じゃあ自分で反映させてプルリク送れば?」と言われそうですが、あの作業(rebase)は慣れているメンテナしか無理だと思います…… ↩︎

  6. 実は私もpolyfillをフルスクラッチで実装中で、完成すれば大手を振って「これ使ってください」と言えるのですが(https://github.com/fabon-f/temporal-polyfill-lite)、Temporalの仕様がデカすぎて全然終わりそうにありません。コツコツ実装を進めていくつもりではありますが、あまり期待しないでください。 ↩︎

Discussion