はじめに
Temporalは現状 TC39 proposal stage 3 のものを使用しています
今後APIが変わる可能性もあるのでご注意ください
TC39 proposalのTemporalをいじってみて、以下2つのような記事を書いたのですが、和暦の扱い方についてピックアップしてまとめます。
暦について
Temporalでは和暦のようなグレゴリオ暦以外の暦も扱うことができます。こちらについては別記事で説明しています。
和暦への変換
例えば、2022年3月6日の和暦の年号を表示したいということもあるかと思います。
このときに、グレゴリオ暦と和暦の対応表を作って、何月何日から何月何日は和暦だといくつみたいなかなりめんどくさい実装をしたり、年が変わったり年号が変わって、令和対応をしたという方もいるのではないかと思います。
Temporalでは複数の暦を扱うことができ、これの変換も機能として備わっているので、楽に変換ができそうです。
(正確にはIntl.Locale.prototype.calendarにあるようにTemporal外でも暦を扱うことができます)
やりかた
Intl.DateTimeFormat
を使うと楽に和暦の表示ができます。
これはTemporalの機能ではないので、Dateでも使うことができますが、TemporalでPlainMonthDate等を使う場合はインスタンスにも暦の設定が必要になります。 (詳しくはこちら)
const date = Temporal.Now.plainDate()
console.log(
new Intl.DateTimeFormat([], {
calendar: 'japanese',
year: 'numeric',
}).format(date)
)
// -> 令和4年
const date = new Date()
console.log(
new Intl.DateTimeFormat([], {
calendar: 'japanese',
year: 'numeric',
}).format(date)
)
// -> 令和4年
DateTimeFormat
の第1引数はlocales
で、空配列を指定するとブラウザーのロケールを使用します。
特定の言語に固定したい場合は、明示してあげます。
const date = Temporal.Now.plainDate('japanese')
console.log(
new Intl.DateTimeFormat('en', {
calendar: 'japanese',
year: 'numeric',
}).format(date)
)
// -> 4 Reiwa
注意点としては、第1引数のlocale
と、第2引数のオプションのcalendar: 'japanese'
の意味は異なり、calendarは和暦を表しています。
詳しくはこちらで説明してあります。
和暦の計算
和暦の計算といっても、Temporalは内部的にはISO8601カレンダーを使用しているので、日付の計算をして、表示の部分で和暦に変換を行います。
const date = Temporal.Now.plainDate('japanese').subtract({ years: 3 }) // 3年前 (2019/3/6)
console.log(
new Intl.DateTimeFormat([], {
calendar: 'japanese',
dateStyle: 'long',
}).format(date)
)
// -> 平成31年3月6日
おまけ (Intl.DateTimeFormat
のオプションについて)
TypeScriptのlib.es2020.intl.d.ts
の型定義ファイルに以下のように定義されています。
Temporalのpolyfillでは一部拡張されている部分はありますが、基本的にこのあたりを使用することができます。
interface DateTimeFormatOptions {
calendar?: string | undefined;
dayPeriod?: "narrow" | "short" | "long" | undefined;
numberingSystem?: string | undefined;
dateStyle?: "full" | "long" | "medium" | "short" | undefined;
timeStyle?: "full" | "long" | "medium" | "short" | undefined;
hourCycle?: "h11" | "h12" | "h23" | "h24" | undefined;
}
ただ、full, long, medium, shortなど、どういう結果になるのか分かりづらいので、それぞれ試してみます。
full
const dateTime = Temporal.Now.plainDateTimeISO()
const locale = 'ja'
const option = {
dateStyle: 'full',
timeStyle: 'full',
} as const
new TemporalIntl.DateTimeFormat(locale, option).format(dateTime)
// 2022年3月6日日曜日 23時27分04秒 日本標準時
long
const option = {
dateStyle: 'long',
timeStyle: 'long',
}
// 2022年3月6日 23:28:11 JST
medium
const option = {
dateStyle: 'medium',
timeStyle: 'medium',
}
// 2022/03/06 23:31:25
short
const option = {
dateStyle: 'short',
timeStyle: 'short',
}
// 2022/03/06 23:32
hourCycle
const option = {
timeStyle: 'short',
hourCycle: 'h11'
}
// 午後11:35
dayPeriod
const option = {
dayPeriod: 'long',
hourCycle: 'h12'
}
// 夜中
formatMatcher
その他、細かく指定することもできます。
今回はlocale: 'en'で実行してみます。
const dateTime = Temporal.Now.instant()
const locale = 'en'
const option = {
era: 'short',
year: 'numeric',
month: 'short',
day: '2-digit',
timeZoneName: 'long',
hour: 'numeric',
minute: '2-digit',
second: 'numeric',
hourCycle: 'h12',
} as const
const formatter = new TemporalIntl.DateTimeFormat(locale, option)
console.log(formatter.format(dateTime))
// Mar 06, 2022 AD, 11:46:40 at night Japan Standard Time
このようにformatterを定義してあげることで柔軟に表示させることができます。