🍤

tc39/Temporalにまつわるいろんな変換

2023/06/11に公開

TC39でStage3となっているTemporalについて、使ってみるとそれぞれの変換周りが色々躓いたのでまとめる。

また、今回は@js-temporal/polyfillを利用している

今回の登場人物

Temporalについてはいくつかの種類があることを理解する必要がある。
今回はざっくりな説明に留めるので、詳細は下記を参照
https://tc39.es/proposal-temporal/docs/ja/index.html

  • 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が検討段階になっている

GitHubで編集を提案

Discussion