クラス間/Dateとの相互変換はどうなっている?
Temporalは多種のクラスを揃えるので、それぞれの間の変換、そしてDateオブジェクトとの変換も気になるところです。
Temporalは各クラスがtoXxxxメソッドを備える
Temporalでは、各クラスがtoXxxxメソッド(XxxxはPlainDate、Instantなど)を備えるので、相互の変換が極めて容易になっています。以下のリストは、ZonedDateTimeからPlainDateTime、PlainDate、PlainTime、Instantへの変換を試す例です。
const str = "2026-06-02T12:34:56.789000000+09:00[Asia/Tokyo]";
const zdt = Temporal.ZonedDateTime.from(str);
console.log(zdt.toString()); // 2026-06-02T12:34:56.789+09:00[Asia/Tokyo]
const pdt = zdt.toPlainDateTime();
console.log(pdt.toString()); // 2026-06-02T12:34:56.789
const dt = pdt.toPlainDate();
console.log(dt.toString()); // 2026-06-02
const time = pdt.toPlainTime();
console.log(time.toString()); // 12:34:56.789
const instant = zdt.toInstant();
console.log(instant.toString()); // 2026-06-02T03:34:56.789Z
const zdt2 = instant.toZonedDateTimeISO("Asia/Tokyo");
console.log(zdt2.toString()); // 2026-06-02T12:34:56.789+09:00[Asia/Tokyo]
InstantからZonedDateTimeに戻すにはtoZonedDateTimeISOメソッドを使いますが、引数にタイムゾーン情報を指定する必要があります。これにより絶対的な時間からタイムゾーンに基づく時間を安全に得ることができます。
代表的なクラスの変換メソッドを挙げておきます。
- Instant:toZonedDateTimeISO
- ZonedDateTime:toInstant、toPlainDate、toPlainDateTime、toPlainTime
- PlainDateTime:toPlainDate、toPlainTime、toZonedDateTime
- PlainDate:toPlainDateTime、toPlainMonthDay、toPlainYearMonth、toZonedDateTime
- PlainTime:なし
DateオブジェクトからはInstantを生成する
Temporalの実装によって、DateにtoTemporalInstantメソッドが追加されました。これを使うと、DateオブジェクトをTemporal.Instantに変換し、さらにZonedDateTimeなどへの変換が可能です。
const date = new Date(2026, 5, 2, 12, 34, 56, 789);
const instant = date.toTemporalInstant();
console.log(instant.toString()); // 2026-06-02T03:34:56.789Z
const zdt2 = instant.toZonedDateTimeISO("Asia/Tokyo");
console.log(zdt2.toString()); // 2026-06-02T12:34:56.789+09:00[Asia/Tokyo]
ローカルタイムゾーンに基づき生成されたDateオブジェクトをInstantに変換するとUTCとなります。これをtoZonedDateTimeメソッドで変換すると、タイムゾーンAsia/Tokyoに基づく日時とすることができるわけです。
【補足】Dateがダメなら替わりの機能を使えばいいじゃない
このようにさまざまな問題を抱えるDateですが、それに対応する動きが湧き上がりました。それらが、国際化対応のためのIntlと、Moment.js、Days.js、Luxon、date-fnsなどのライブラリです。
国際化対応のIntlで出力における問題点は解消される
Intl名前空間のDateTimeFormatクラスを使うと、そのformatメソッドでDateオブジェクトをさまざまな書式で文字列化できます。
たとえば、timeZoneオプションに"Asia/Tokyo""America/New_York"を指定すると、Dateオブジェクトはそのタイムゾーンとして文字列化されます。
const date = new Date(2026, 5, 2, 12, 34, 56);
const jstString = new Intl.DateTimeFormat('ja-JP', {
timeZone: 'Asia/Tokyo',
dateStyle: 'full',
timeStyle: 'long',
}).format(date);
console.log(jstString); // 2026年6月2日火曜日 12:34:56 JST
const edtString = new Intl.DateTimeFormat('en-US', {
timeZone: 'America/New_York',
dateStyle: 'full',
timeStyle: 'long',
}).format(date);
console.log(edtString); // Monday, June 1, 2026 at 11:34:56 PM EDT
DateTimeFormatクラスにより、少なくとも出力に関する問題はある程度解消されたのではないでしょうか。
Dateの穴を埋める多彩なライブラリが利用できる
外部ライブラリの先駆けであるMoment.jsは、長い間Dateの代替として使われてきましたが、2020年に開発を終了してメンテナンスモードに移行しています。現時点では、残る3つのライブラリが適材適所で使われています。
| ライブラリ | 特徴 | バンドルサイズ |
|---|---|---|
| Day.js | Moment.jsを代替する軽量ライブラリ。Moment.jsとほぼ同じAPIで扱いやすく、極めて軽量 | 約2KB |
| date-fns | 関数型処理が可能。必要な関数だけをインポートできるため、コードサイズを抑えられる | 軽量(ツリーシェイキング対応) |
| Luxon | 公式がMoment.jsの後継として推奨。タイムゾーンや期間の計算、複雑なフォーマット処理に対応 | 中規模(標準機能が豊富) |
特にdate-fnsではオブジェクトの取り扱いは基本的に不変であり、演算処理の結果は新しいオブジェクトとして得られるので、ことオブジェクトの変更については強い設計となっています。LuxonではDateの弱点である演算機能やフォーマットなどの機能を持ちあわせます。
これらのライブラリは、現時点でもDateの代替/補完として広く使われていますが、果たしてTemporalの普及でどう変化していくのか、興味深いところです。
まとめ
今回は、前回に引き続き、改めてDateの問題点を示し、それに対するTemporalのアプローチを紹介しました。Temporalが以下に配慮の行き届いた設計で、使いやすく実装されているかをお伝えできたのではないかと思います。
次回は、配列メソッドの罠とその処方箋として、Iteratorによる反復処理を紹介します。
