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