【JavaScript】外部ライブラリに頼らないdateフォーマット【Intl.DateTimeFormat】

#この記事について
new Intl.DateTimeFormatを使えば外部ライブラリを使わずに、ある程度自由に日付の書式を設定できます。
また、formatToParts()を使えば設定した値を項目ごとに(例えば秒だけ）取り出すことができて便利です。

この記事ではDateオブジェクト(`2019-12-31T21:05:00.000Z`)から0パディング時間(`06時05分`)を取得する方法を例に、上記関数の使い方を紹介します。
何らかの事情で、moment.jsなどのライブラリを使えない方の助けになれれば嬉しいです。

#結論
Dateオブジェクトから `06時05分` という出力を得ます。

```javascript
const time = new Date(2020, 0, 1, 6, 5)
const dateTimeFormat = new Intl.DateTimeFormat('jp', { hour: '2-digit', minute: '2-digit'});
const [{ value: hour }, , { value: minute }] = dateTimeFormat.formatToParts(time);
console.log(`${hour}時${minute}分`); // → 06時05分
```

#解説
上記のコードを一行一行解説します。

## 1行目:
### `const time = new Date(2020, 0, 1, 6, 5)`

- new Dateを使って、Dateオブジェクトを作成します。（例: 2020年1月1日 6時5分）
- new Dateを使う時、月は1月なら`0`、2月なら`1`というように、番号が一つずれます。（詳細は[こちら](http://cly7796.net/wp/javascript/how-to-use-new-date/)）

## 2行目:
### `const dateTimeFormat = new Intl.DateTimeFormat('jp', { hour: '2-digit', minute: '2-digit' });`

- new Intl.DateTimeFormatを使ってフォーマッタを定義します。(詳細は[こちら]())
- 引数の `{ hour: '2-digit', minute: '2-digit' }` はoptionsと呼ばれます。
このoptionsで時間と分の書式を2桁に設定します。

- 例えば日付を出力したければ、` { month: 'short', day: '2-digit' }` と定義します。（詳細は[こちら](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat))

## 3行目:
### `const [{ value: hour }, , { value: minute }] = dateTimeFormat.formatToParts(time);`

- DateTimeFormat.prototype.formatToParts()を使って、時間と分を別々に取得しています。
- この中身をconsole.logで確認すると以下のようになっています。

```javascript:
console.log(dateTimeFormat.formatToParts(time));

// 出力結果
[
  { type: 'hour', value: '06' },
  { type: 'literal', value: ':' },
  { type: 'minute', value: '05' }
]
```
このように、2行目で設定した`hour`や`minute`はオブジェクトに格納されているので、各値を個々に取り出すことが可能です。(詳細は[こちら](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/formatToParts))

- ちなみに変数の代入には分割代入を使用しています。
　`{オブジェクトのキー名 : 任意の変数名} = オブジェクト`とすることで、該当キーの値がその変数名で定義されます。(詳細は[こちら](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment))

- オブジェクトで個々に取り出す必要がない場合は`format()`を使って以下のように書くこともできます。

```javascript
const time = new Date(2020, 0, 1, 6, 5);
const dateTimeFormat = new Intl.DateTimeFormat('jp', { hour: '2-digit', minute: '2-digit' });
console.log(dateTimeFormat.format(time));
// 06:05
```

## 4行目:
### ``console.log(`${hour}時${minute}分`)``

- テンプレートリテラルを使って、値と`'時'`、`'分'`を結合し、`06時05分`を出力しています。



# 落とし穴

## 1. minuteは0サプレスされない

0パディングとは逆の0サプレスをしたい場合、optionsで`('jp', { hour: 'numeric', minute: 'numeric' })`を設定すれば良さそうですが、`minute`は0サプレスされません。
理由は不明。調べましたが、できないことをメモしている記事しか見つけられませんでした。

[リファレンス メモ new Intl.DateTimeFormat()【コンストラクタ】](https://cercopes-z.com/JavaScript/Object-Intl-DateTimeFormat-new-js.html)

## 2. localeによって書式が設定されないことがある
`Intl.DateTimeFormat`のoptionsで`{ weekday: 'long' })`を指定すると、MDNの説明によれば`Wednesday`が出力されるはずです。
しかし以下のコードでは、`Wed`と表示されてしまいます。

```javascript
const time = new Date(2020, 0, 1, 6, 5);
const dateTimeFormat = new Intl.DateTimeFormat('jp', { weekday: 'long' });
console.log(dateTimeFormat.format(time))
// Wed
```

これは`Intl.DateTimeFormat`のlocaleが`jp`になっているのが原因です。
このようにlocaleによっては書式設定が適用されないこともあるので注意が必要です。
今回の場合は`('en', { weekday: 'long' })`とすれば期待通りになります。

```javascript
const time = new Date(2020, 0, 1, 6, 5);
const dateTimeFormat = new Intl.DateTimeFormat('en', { weekday: 'long' }); // jp → enに修正
console.log(dateTimeFormat.format(time))
// Wednesday
```

#　まとめ

optionsと`formatToParts()`を使えば自由に日時を取得できるので便利です。
日付の扱いや日本語表記についても、いつかまとめて記事にしておきたいです。