tc39/Temporalにまつわるいろんな変換
TC39でStage3となっているTemporalについて、使ってみるとそれぞれの変換周りが色々躓いたのでまとめる。
また、今回は@js-temporal/polyfill
を利用している
今回の登場人物
Temporalについてはいくつかの種類があることを理解する必要がある。
今回はざっくりな説明に留めるので、詳細は下記を参照
-
Temporal.PlainDateTime
- Timezoneを持たない日付の状態
- ユーザーに向けた表記などで利用しやすい。
- 同じ仲間に
PlainDate
,PlainTime
,PlainYearMonth
,PlainMonthDay
がある
-
Temporal.Instant
- Unixtimeのような、場所や環境によらない値
-
ZonedDateTime
にだけ変換可能
-
Temporal.ZonedDateTime
- 日付からタイムゾーンまで持った状態
- 一番情報量が多い。
基礎編: Temporalの中での変換
Temporal.ZonedDateTime -> それぞれへの変換
まず、ZonedDateTime
からそれぞれの形式へ変換する方法。
これらはそれぞれわかりやすいtoXXX()
のような関数が用意されてるので、特に考えることもない
const zoned = Temporal.Now.zonedDateTimeISO()
const plainDate = zoned.toPlainDate()
const instant = zoned.toInstant()
Temporal.PlainDateTime -> Temporal.ZonedDateTime
PlainDateTime
からZonedDateTime
へ変換する場合は、timezoneの指定が必要になる。
Timezoneが稼働環境のもので良ければTemporal.Now.zonedDateTimeISO
から取り出す事ができるので、これが利用できる
const datetime = Temporal.PlainDateTime.from("2021-01-01T09:10:11")
// 現時刻からTimezoneIdを取得する
const timezoneId = Temporal.Now.zonedDateTimeISO().timeZoneId
const zoned = datetime.toZonedDateTime(timezoneId)
Temporal.Instant -> Temporal.ZonedDateTime
Instant
からの場合もTimzoneの指定は同じとなる。
const instant = Temporal.Now.instant()
const timezoneId = Temporal.Now.zonedDateTimeISO().timeZoneId
const zoned = instant.toZonedDateTimeISO(timezoneId)
応用編: Temporal以外との変換
Date -> Temporal への変換
DateからTemporalへ変換する場合は、Instant
へ一度変換するのが妥当。
Date.getTime
がミリ秒となるので、これをInstant.fromEpochMilliseconds
にわたす
const targetDate = new Date('2021-01-01T00:00:00')
const instantDate = Temporal.Instant.fromEpochMilliseconds(targetDate.getTime())
Temporal -> Dateへの変換
TemporalからDate型へ戻したい場合は、ここまでの組み合わせとなる。
最終的にinstant
に変換してepochMillisecondから変換するのが無難だろう
const plainDate = Temporal.PlainDateTime.from("2021-01-01T09:10:11")
// instantへ変換。Timezoneがずれる可能性があることに注意
const timezoneId = Temporal.Now.zonedDateTimeISO().timeZoneId
const zoned = plainDate.toZonedDateTime(timezoneId)
const instant = zoned.toInstant()
const date = new Date(instant.epochMilliseconds)
Temporal -> 文字列への変換
Temporalから文字列に変換する場合は、PlainDateTime
にするのが良いだろう。
例えばInstant
から変換する場合を考える
const instant = Temporal.Instant.fromEpochSeconds(1672498800)
const timezoneId = Temporal.Now.zonedDateTimeISO().timeZoneId
const plainDate = instant.toZonedDateTimeISO(timezoneId).toPlainDateTime()
const dateMinutes = plainDate.toString()
// => 2023-01-01T00:00:00
「秒は不要」などの場合はsmallestUnit
を指定すると良い
const dateMinutes = plainDate.toString({ smallestUnit: "minutes" })
// => 2023-01-01T00:00
toLocaleString
も利用できる
const locale = plainDate.toLocaleString("ja-JP")
// => 2023/1/1 0:00:00
文字列 -> Temporal への変換
文字列の場合からは、フォーマットによるが、例えば普通の日付であればPlainDateTime.from
からの変換が可能だ。
const targetTime = '2021-01-01T00:00:00'
const datetime = Temporal.PlainDateTime.from(targetTime)
年月だけでよければYearMonth
などが使える
const yearMonth = Temporal.PlainYearMonth.from('2021-01-01T00:00:00')
// yearMonth.toString() -> '2021-01'
ただし、整形された文字列でしか現状は変換ができない。
複雑なものからのパースはTemporal.parse
が検討段階になっている
Discussion