DateTimeFormat.prototype.formatToParts()

Intl.DateTimeFormat.prototype.formatToParts() メソッドは、ロケールを意識した DateTimeFormat フォーマッターが生成する文字列のロケールを考慮した書式化を可能にします。

構文

dateTimeFormat.formatToParts(date)

引数

date 省略可
書式化する日付。

返値

書式化された日付のパーツを含むオブジェクトの Array です。

解説

formatToParts() メソッドは、日付文字列のフォーマットをカスタマイズするときに役立ちます。これは、ロケール特有の部分を保持しながら、カスタム文字列を構築できるロケール特有のトークンを含むオブジェクトの Array を返します。formatToParts() メソッドが返却する構造は、このようになります。

[
  { type: 'day', value: '17' },
  { type: 'weekday', value: 'Monday' }
]

渡される可能性がある type は以下のとおりです。

day
日付として使用される文字列。たとえば、 "17"。
dayPeriod
日付期間として使用される文字列。たとえば、 "AM", "PM", "in the morning", "noon" など。
era
時代として使用される文字列。たとえば、"BC" や "AD"。
fractionalSecond
小数点以下の秒として使用される文字列です。例えば "0" や "00" や "000" です。
hour
時刻として使用される文字列。たとえば "3" や "03"。
literal
日付や時刻の区切りとして使用される文字列。たとえば "/"、","、"o'clock"、"de"。
minute
分として使用される文字列。たとえば、"00"。
month
月として使用される文字列。たとえば、"12"。
relatedYear
カレンダーの表現が year ではなくyearNameである場合、関連する4桁のグレゴリオ暦の年に使用される文字列です。例えば "2019" です。
second
秒として使用される文字列。たとえば、"07" や "42"。
timeZoneName
タイムゾーン名として使用される文字列。たとえば、"UTC"。
weekday
曜日として使用される文字列。たとえば、"M" や "Monday"、"Montag"。
year
年として使用される文字列。たとえば、"2012" や "96"。
yearName
関連するコンテキストで yearName に使用される文字列、例えば "geng-zi" など。

ポリフィル

この機能のポリフィルは、提案リポジトリから利用できます。

DateTimeFormat は、直接操作できないローカライズされた透過的でない文字列を出力します。

var date = Date.UTC(2012, 11, 17, 3, 0, 42);

var formatter = new Intl.DateTimeFormat('en-us', {
  weekday: 'long',
  year: 'numeric',
  month: 'numeric',
  day: 'numeric',
  hour: 'numeric',
  minute: 'numeric',
  second: 'numeric',
  fractionalSecondDigits: 3,
  hour12: true,
  timeZone: 'UTC'
});

formatter.format(date);
// "Monday, 12/17/2012, 3:00:42.000 AM"

しかし、多くのユーザーインターフェイスでは、この文字列の書式をカスタマイズしたいという要望があります。 formatToParts メソッドは、文字列を部品単位で提供することで、 DateTimeFormat フォーマッターによって生成された文字列のロケールを意識した書式設定ができるようになります。

formatter.formatToParts(date);

// return value:
[
  { type: 'weekday',   value: 'Monday' },
  { type: 'literal',   value: ', '     },
  { type: 'month',     value: '12'     },
  { type: 'literal',   value: '/'      },
  { type: 'day',       value: '17'     },
  { type: 'literal',   value: '/'      },
  { type: 'year',      value: '2012'   },
  { type: 'literal',   value: ', '     },
  { type: 'hour',      value: '3'      },
  { type: 'literal',   value: ':'      },
  { type: 'minute',    value: '00'     },
  { type: 'literal',   value: ':'      },
  { type: 'second',    value: '42'     },
  { type: 'fractionalSecond', value: '000' },
  { type: 'literal',   value: ' '      },
  { type: 'dayPeriod', value: 'AM'     }
]

これで情報は個別に利用可能になり、カスタマイズされた方法で再び書式化して連結することができます。例えば、Array.prototype.map()アロー関数switch 文テンプレートリテラルArray.prototype.reduce() などを使用しています。

var dateString = formatter.formatToParts(date).map(({type, value}) => {
  switch (type) {
    case 'dayPeriod': return `<b>${value}</b>`;
    default : return value;
  }
}).reduce((string, part) => string + part);

これにより、 formatToParts() メソッドを使用する際に、日の部分が太字になります。

console.log(formatter.format(date));
// "Monday, 12/17/2012, 3:00:42.000 AM"

console.log(dateString);
// "Monday, 12/17/2012, 3:00:42.000 <b>AM</b>"

名前付きの年と混合カレンダー

いくつかのケースでは、暦は名前付きの年を使用しています。 例えば、中国やチベットの暦では、60年周期の干支を使用しています。これらの年は、グレゴリオ暦の年と関連付けて識別されます。このような場合、 formatToParts() の結果は、通常は年が存在するはずなのに、年の項目ではなく、4桁のグレゴリオ暦の年を含む relatedYear のエントリを含むことになります。バッグの中の項目を (任意の値で) year に設定すると、年と yearName グレゴリオ暦の relatedYear の両方が得られます。

let opts = { year: "numeric", month: "numeric", day: "numeric" };
let df = new Intl.DateTimeFormat("zh-u-ca-chinese", opts);
df.formatToParts(Date.UTC(2012, 11, 17, 3, 0, 42));

// return value
[
  { type: 'relatedYear', value: '2012' },
  { type: 'literal', value: '年' },
  { type: 'month', value: '十一月' },
  { type: 'day', value: '4' }
]

year オプションがバッグ内で設定されていない場合 (任意の値に設定されている場合)、結果には relatedYear のみが含まれます。

let df = new Intl.DateTimeFormat("zh-u-ca-chinese");
df.formatToParts(Date.UTC(2012, 11, 17, 3, 0, 42));

// 返値
[
   { type: 'relatedYear', value: '2012' },
   { type: 'literal', value: '年' },
   { type: 'month', value: '十一月' },
   { type: 'day', value: '4' }
]

year を出力したい場合は、 .format() は一般的にこれらを並べて表示することができます。

let df = new Intl.DateTimeFormat("zh-u-ca-chinese", {year: "numeric"});
df.format(Date.UTC(2012, 11, 17, 3, 0, 42));

// 返値
2012壬辰年

これにより、ロケールとカレンダーを両方の format で混在させることも可能になります。

let df = new Intl.DateTimeFormat("en-u-ca-chinese", {year: "numeric"});
let date = Date.UTC(2012, 11, 17, 3, 0, 42);
df.format(date);

// 返値
2012(ren-chen)

および formatToParts の場合

let opts = {month: 'numeric', day: 'numeric', year: "numeric"};
let df = new Intl.DateTimeFormat("en-u-ca-chinese", opts);
let date = Date.UTC(2012, 11, 17, 3);
df.formatToParts(date)

// 返値
[
  { type: 'month', value: '11' },
  { type: 'literal', value: '/' },
  { type: 'day', value: '4' },
  { type: 'literal', value: '/' },
  { type: 'relatedYear', value: '2012' }
]

仕様書

仕様書
ECMAScript Internationalization API (ECMA-402)
Intl.DateTimeFormat.prototype.formatToParts の定義

ブラウザーの互換性

BCD tables only load in the browser

関連情報