2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

1人フロントエンドAdvent Calendar 2024

Day 14

Intl.RelativeTimeFormat()を使って日本語で相対時刻を取得する

Last updated at Posted at 2024-12-14

JavaScriptの標準組み込みオブジェクトにIntlオブジェクトがあります。国際化APIの名前空間で、localeに依存した数値のフォーマットや分かち書きを行うプロパティを持ちます。

この記事ではそんなプロパティの1つであるRelativeTimeFormatについて解説します。

RelativeTimeFormat

RelativeTimeFormatは相対時刻をlocaleに応じて扱うためのオブジェクトです。

const rtf = new Intl.RelativeTimeFormat('ja-JP');

// 2 日後
console.log(rtf.format(2, 'day'));

// 9 か月前
console.log(rtf.format(-9, 'month'));

RelativeTimeFormatを初期化するタイミングで扱いたいlocaleを指定します。

const rtf = new Intl.RelativeTimeFormat('ja-JP');

RelativeTimeFormatには第2引数でオプションをオブジェクトとして渡せます。

const rtf = new Intl.RelativeTimeFormat(
  'ja-JP',
  {
    localeMatcher: 'lookup',
    numeric: 'auto',
    style: 'short',
  },
);

オプションはlocaleMatchernumericstyleの3つです。

localeMathcerは第一引数のlocaleが配列で複数渡ってきた時の優先順位の付け方を決めます。デフォルトではbest fitで他にlookupを指定できます。
best fitはリクエストやランタイムを用いて最適なlocaleを決定し、lookupを指定した場合はLookupのアルゴリズムによって決定されます。

numericはメッセージを表示する形式を指定できます。デフォルトはalwaysでどのような数値であっても一貫した形式でフォーマットするのですが、autoにすると明日や昨日のように特定の数値を別の一般的な言い方に置き換えます。

const rtf1 = new Intl.RelativeTimeFormat('ja-JP');
const rtf2 = new Intl.RelativeTimeFormat(
  'ja-JP',
  {
    numeric: 'auto',
  },
);

// 2 日後
console.log(rtf1.format(2, 'day'));

// 明後日
console.log(rtf2.format(2, 'day'));

styleは単位の長さを指定します。デフォルトはlongshortnarrowが存在します。
localeja-JPの場合はlongshortに違いがありません(例えばlocaleenの場合はlongではmonthshortではmoのように表示されます)。narrowは数値と単位の間の空白を埋めた形で出力します。

const rtf1 = new Intl.RelativeTimeFormat('ja-JP');
const rtf2 = new Intl.RelativeTimeFormat(
  'ja-JP',
  {
    style: 'short',
  },
);
const rtf3 = new Intl.RelativeTimeFormat(
  'ja-JP',
  {
    style: 'narrow',
  },
);

// 2 日後
console.log(rtf1.format(2, 'day'));

// 2 日後
console.log(rtf2.format(2, 'day'));

// 2日後
console.log(rtf3.format(2, 'day'));

このように作成されたRelativeTimeFormatformatメソッドを用いて相対時刻を表示します。第1引数に相対日付の数値を、第2引数には単位を渡します。

第1引数の数値は正であれば未来との相対時刻を、負であれば過去との相対日付と判断します。

const rtf = new Intl.RelativeTimeFormat('ja-JP');

// 1 年後
console.log(rtf.format(1, 'year'));

// 1 年前
console.log(rtf.format(-1, 'year'));

第2引数はyearquartermonthweekdayhourminutesecondとその複数形を渡します。それぞれその名の通りのフォーマットをしてくれます。

const rtf = new Intl.RelativeTimeFormat('ja-JP');

// 1 年後
console.log(rtf.format(1, 'year'));

// 1 四半期後
console.log(rtf.format(1, 'quarter'));

// 1 か月後
console.log(rtf.format(1, 'month'));

// 1 週間後
console.log(rtf.format(1, 'week'));

// 1 日後
console.log(rtf.format(1, 'day'));

// 1 時間後
console.log(rtf.format(1, 'hour'));

// 1 分後
console.log(rtf.format(1, 'minute'));

// 1 秒後
console.log(rtf.format(1, 'second'));

部品単位で相対時刻を取得する

RelatveTimeFormatオブジェクトのformatToPartsメソッドを使えば数値と単位を配列の要素に分けて表示できます。

const rtf = new Intl.RelativeTimeFormat('ja-JP');

/**
 * [
 *   {
 *     type: 'integer',
 *     unit: 'day',
 *     value: 2,
 *   },
 *   {
 *     type: 'literal',
 *     value: ' 日後',
 *   },
 * ]
 */
console.log(rtf.formatToParts(2, 'day'));

/**
 * [
 *   {
 *     type: 'integer',
 *     unit: 'day',
 *     value: 9,
 *   },
 *   {
 *     type: 'literal',
 *     value: ' か月前',
 *   },
 * ]
 */
console.log(rtf.formatToParts(-9, 'month'));

引数はformatメソッドと同じです。単位には空白が含まれていることに注意です。

localeが対応していることを確認する

RelativeTimeFormatオブジェクトに渡すlocaleは静的メソッドであるsupportedLocalesOfを用いて確認できます。引数はRelativeTimeFormatオブジェクトのコンストラクタと同じです。

// ['ja', 'ja-JP']
console.log(
  Intl.RelativeTimeFormat.supportedLocalesOf(
    ['ja', 'JP', 'ja-JP']
  )
);

有効なオプションを確認する

resolvedOptionsRelativeTimeFormatオブジェクトを作成したときに有効となった設定を表示します。

// {locale: 'ja', style: 'long', numeric: 'always', numberingSystem: 'latn'}
console.log((new Intl.RelativeTimeFormat('ja')).resolvedOptions());

// {locale: 'ja-JP', style: 'long', numeric: 'always', numberingSystem: 'latn'}
console.log((new Intl.RelativeTimeFormat(['ja-JP', 'en'])).resolvedOptions());

const rtf = new Intl.RelativeTimeFormat(
  'ja-JP',
  {
    localeMatcher: 'lookup',
    numeric: 'auto',
    style: 'short',
  },
);
// {locale: 'ja-JP', style: 'short', numeric: 'auto', numberingSystem: 'latn'}
console.log(rtf.resolvedOptions());

localeMatcherはおそらくlocaleの決定後は使われないことから表示されません。
numberingSystemだけ見慣れませんが、これはlocaleに依存する命数法を渡しています。

const locale = new Intl.Locale(
  'ja-JP',
  { numberingSystem: 'arab' }
);
// ['arab']
console.log(locale.getNumberingSystems());

// {locale: 'ja-JP-u-nu-arab', style: 'long', numeric: 'always', numberingSystem: 'arab'}
console.log((new Intl.RelativeTimeFormat(locale)).resolvedOptions())
2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?