Temporal とは
JavaScript で日付を扱うための新しい API。
ポリフィルが 2 つあって、1 つはブラウザでポリフィルが試せる。
現在のステータスは stage 3 なので、普通はいくつかのランタイムで実装されれば stage 4 になり、晴れて ECMA Script の仕様として標準化される。
しかし、この提案はそうはいかない(後述)。
なぜ Temporal が必要なのか
JavaScript では日時を扱うのに Date オブジェクトを使用している。
一部では有名な話だが、JavaScript の Date は Java 1.0 の Date を参考にして作られたが、本家 Java では時期バージョンの 1.1 でほとんどのメソッドが非推奨になっている。 しかし JavaScript では使い続けている。
故に落とし穴が多く、わかりやすいところでは月だけが 0-indexed になっていたり、タイムゾーンが存在しなかったりする。 そういった不便を解消するために、これまでは Moment.js や date-fns を始めとしたライブラリを使用してきた。
しかし、そもそも JavaScript の API を直すべきだという発想の元、Temporal が提案された。
とてもざっくり言うと、Temporal は「正確で」「タイムゾーンや別のカレンダーも扱えて」「使いやすい」を目指している。
仕様について
Temporal の仕様を見ていく。 日本語のドキュメントがあるのでそれをベースに、不足しているところは英語のドキュメントを見つつ。
概要
ドキュメントにあるこの図がわかりやすそう。
日時の表現ができるいくつかのオブジェクトが追加される。
年月日を表す PlainDate
、加えて時間も表す PlainDateTime
、日時に関するすべての情報を詰め込める ZonedDateTime
など。
分類
一部のオブジェクトには分類名がついている。 ここは特に解釈が間違ってるかも。
- Exact Time
- 「カレンダーや場所によらない特定の時点での時刻」
- Unix Time に変換できる
2020-08-05T20:06:13+09:00
というデータ- 場所というパラメーター(
[Asia/Tokyo]
など)やカレンダー([u-ca=japanese]
など)がない - 一方で、オフセットはついているので Unix Time での表現が可能
- 場所というパラメーター(
- Calendar Date / Wall-Clock Time
- Calendar Date は「カレンダー上の日付」、Wall-Clock Time は「壁掛け時計の時間」
- つまり現地時間のこと
2020-08-05T20:06:13
というデータ- 「Exact Time とは対象的に、タイムゾーンによるオフセットが加味された時刻」
- すでに加味されているので、オフセットはデータ上存在しない
- オブジェクトには
Plain
という名前がついている(ZonedDateTime
を除く)
- Calendar Date は「カレンダー上の日付」、Wall-Clock Time は「壁掛け時計の時間」
追加されるオブジェクト一覧
文字列表現は toString()
を呼んだときの値。
一部を除いて、日時の文字列表現において標準となっている ISO 8601 形式。
名前 | 文字列表現 | 分類 |
---|---|---|
PlainYearMonth |
2020-08 |
Calendar Date / Wall-Clock Time |
PlainMonthDay |
08-05 |
Calendar Date / Wall-Clock Time |
PlainDate |
2020-08-05 |
Calendar Date / Wall-Clock Time |
PlainTime |
20:06:13 |
Calendar Date / Wall-Clock Time |
PlainDateTime |
2020-08-05T20:06:13 |
Calendar Date / Wall-Clock Time |
Instant |
2020-08-05T20:06:13+09:00 |
Exact Time |
TimeZone |
[Asia/Tokyo] |
- |
Calendar |
[u-ca=japanese] |
- |
ZonedDateTime |
2020-08-05T20:06:13+09:00[Asia/Tokyo][u-ca=japanese] |
Exact Time, Calendar Date / Wall-Clock Time |
Duration |
P1Y2M3W4DT5H6M7.987654321S |
- |
分類についてはドキュメントの図を見たほうが圧倒的にわかりやすい。
できること
簡単に言えば、そのオブジェクトができるかぎりの時刻表現の保持、ISO 8601 形式文字列の解釈、加減算などの操作。 ちなみにすべてイミュータブル。
詳しくはドキュメントを参照。
「一部を除いて」?
ISO 8601 形式は、簡単に言うと yyyy-MM-ddThh:mm:ssZ
みたいな形で日時を表す。
期間(Duration)は P1Y2M3W4DT5H6M7.987654321S
という形式で表す。
ただし、上の表に載っているが ISO 8601 で認められていない形式が 3 つある。
- タイムゾーン名
[Asia/Tokyo]
等
mm-dd
形式- カレンダー
[u-ca=japanese]
等
これらは重要なユースケースであるにも関わらず標準化されていないため、標準化に向けて動いている。 この記事の執筆時点では、IETF に草案を提出し、IESG(Internet Engineering Steering Group)のレビューを待っているところだそう。
stage 4 に上がるには、これが標準化された上で、通常通り 2 つの JavaScript エンジンが実装する必要がある。 標準化を待つので時間がかかりそうな雰囲気。
補足
ISO 8601 / RFC 3339 準拠とか言っておきながら、yyyy-MM-dd hh:mm:ss
のように年月日と時刻の間をスペースで区切ってもパースできる。
これは HTML の time タグに準拠している。
https://developer.mozilla.org/ja/docs/Web/HTML/Element/time
ちなみに time タグも MM-dd
を受け入れるので、標準化が進んだら HTML 側にもメリットがありそう。ないかも、わからない。
逆に ISO 8601 全部受け入れるようにしようみたいな動きになって大変かも。知らない。
Temporal 仕様超まとめ
- 日時を厳密に表せるようになる
- 厳密性がいらない場合は、それに合わせたオブジェクトを使える
- 日時の計算が簡単に出来るようになる
- ISO 8601 / RFC 3339 形式文字列のパース・出力はできるが、任意の形式で文字列出力はできない
自分の見解
- 内部で正しく扱いたい
- 正しく計算したい
ときは Temporal が使える。
- 日付を特定のフォーマットで表示する
ときは引き続きライブラリを使用することになる。
現状では(そもそも使えないというのは置いといて)、フロントエンドでは表示が主なので Day.js なり date-fns なりを引き続き使うのがよさそう。 基本は Temporal で扱って表示だけをやってくれるライブラリみたいなのが出てきたら、そちらに乗り換えるのがいいかも。
お気持ち
Temporal
とか Instant
とかの名前、どうにかならなかったものか……
最後に
Temporal、超期待。 日付に苦しめられることが減りそう。
フロントエンドでの表示系は今ひとつなので、そこら辺は今後に期待かな。 別 API になりそう。
また、今回 Temporal について調べてみたら(おそらく)理解できたので、怖がらずに調べてみるのが大切だと感じた。 知らないことを知らないままにしておかなくてよかった。
これで「結局どうしたらいいのか」の判断ができるようになったのは大きな収穫だった。