1月25日、Mozillaが「JavaScript Temporal is coming」と題した記事を公開した。この記事では、JavaScriptの新たな日時処理APIであるTemporalについて詳しく紹介されている。
以下に、その内容を紹介する。
Temporalとは何か?
従来のJavaScriptにおいては、日時を扱うための標準手段としてDate
オブジェクトが用意されてきた。しかし、Date
は以下のような問題点を抱えていたため、柔軟かつ正確な日時操作を実現することが難しかった。
- コンストラクタの引数や各種メソッドでタイムゾーンが混在しやすく、扱いが直感的でない
- 自動的にUTCやローカルタイムに変換される挙動が複雑で、思わぬバグが発生する
- 月や日など、一部の値がゼロ始まりであるなどAPIの仕様が分かりにくい
- サマータイムや閏年などの複雑な計算を開発者側で行う必要があり、ミスを引き起こしやすい
こうした問題を解決するために導入されるのが、今回の記事で紹介されているTemporal
である。柔軟なタイムゾーン指定やカレンダーシステムの選択、各種計算メソッドの充実などにより、複雑な日時処理を簡潔かつ正確に記述できるようになっている点が特徴だ。以下では記事内で言及されている主なコードサンプルを抜粋する。
Temporalのコード例
/**
* システムのタイムゾーンで現在の日付を取得
*/
const dateTime = Temporal.Now.plainDateTimeISO();
console.log(dateTime); // 例: 2025-01-22T11:46:36.144
/**
* "America/New_York" タイムゾーンで現在の日付を取得
*/
const dateTimeInNewYork = Temporal.Now.plainDateTimeISO("America/New_York");
console.log(dateTimeInNewYork);
// 例: 2025-01-22T05:47:02.555
従来のDateオブジェクトでは、UTCやローカルタイムへの変換ロジックを開発者が直接扱わなければならない場面が多かった。Temporalでは、上のようにメソッド呼び出し時にタイムゾーンを指定して直接取得できるため、複雑なタイムゾーン計算を回避できる。
さらに、異なるカレンダーシステムでの日時を取り扱うのも簡単である。次の例では、中国暦を使用して旧正月の日付を求める。
/**
* 中国暦で旧正月は毎年1月1日 (monthCode: "M01", day: 1) にあたる
*/
const chineseNewYear = Temporal.PlainMonthDay.from({
monthCode: "M01",
day: 1,
calendar: "chinese",
});
const currentYear = Temporal.Now.plainDateISO().withCalendar("chinese").year;
let nextCNY = chineseNewYear.toPlainDate({ year: currentYear });
// もし現在日付よりも旧正月日が過ぎていれば、翌年を取得
if (Temporal.PlainDate.compare(nextCNY, Temporal.Now.plainDateISO()) <= 0) {
nextCNY = nextCNY.add({ years: 1 });
}
console.log(
`The next Chinese New Year is on ${nextCNY.withCalendar("iso8601").toLocaleString()}`,
);
// 実行時点では "The next Chinese New Year is on 1/29/2025" のように表示される
異なるカレンダーを用いる処理はDate
オブジェクトでは標準サポートされていなかったが、Temporalを利用すれば複数のカレンダー切り替えも直感的に行える。Unixタイムスタンプ(エポックミリ秒)を扱う場合も同様に容易である。
/**
* 1851222399924ミリ秒を表すUnixタイムスタンプ
*/
const launch = Temporal.Instant.fromEpochMilliseconds(1851222399924);
const now = Temporal.Now.instant();
const duration = now.until(launch, { smallestUnit: "hour" });
console.log(`It will be ${duration.toLocaleString("en-US")} until the launch`);
// polyfill使用時: "It will be 31,600 hr until the launch"
// Firefox Nightly使用時: "It will be PT31600H until the launch"
ここで使用しているtoLocaleString
は、Firefoxではまだロケール感知の文字列を返さず、ISO 8601形式(例: PT31600H
)が出力される仕様になっている。しかし、これは技術的な制限というよりも設計上の方針によるものであり、将来的にはポリフィル版と同様のフォーマットに統一される可能性がある。
日時オブジェクトを比較・ソートする処理も、Temporalによりシンプルに記述できる。下記の例では、Duration.compare()
を用いて配列を昇順に並べ替えている。
const durations = [
Temporal.Duration.from({ hours: 1 }),
Temporal.Duration.from({ hours: 2 }),
Temporal.Duration.from({ hours: 1, minutes: 30 }),
Temporal.Duration.from({ hours: 1, minutes: 45 }),
];
durations.sort(Temporal.Duration.compare);
console.log(durations.map((d) => d.toString()));
// [ 'PT1H', 'PT1H30M', 'PT1H45M', 'PT2H' ]
このように、Date
では煩雑だった日時操作をより正確かつ柔軟に行えるのがTemporal
の大きな利点である。タイムゾーンやカレンダーなどをオブジェクト同士の組み合わせで自在に管理できる仕組みは、将来的にさまざまな場面で標準APIとして活用されることが期待されている。
Temporalを試してみよう!
各ブラウザーでのサポートは徐々に進んでおり、Firefoxでは、Nightly版でjavascript.options.experimental.temporal
という設定を有効にすることで試すことができる。対応状況の詳細は(非常にボリュームのある)Temporal object Browser Compatibility sectionを参照するとよい。
以下に各ブラウザーのTemporal実装を追跡している主要なバグレポートを示す。
- Firefox: Build temporal in Nightly by default
- Safari: [JSC] Implement Temporal
- Chrome: Implement the Temporal proposal
さらに、https://tc39.es/proposal-temporal/docs/では@js-temporal/polyfill
が用意されているため、TC39ドキュメントのページ上で開発者ツールを開き、フラグや設定を切り替えなくてもサンプルコードを試すことが可能である。
実験的な実装が進む中、JavaScriptで日付と時刻を扱うモダンなアプローチとなるTemporalを今のうちに試してみるのは有益といえるだろう。
詳細は[JavaScript Temporal is coming」を参照していただきたい。