【JavaScript】日付型（Date 型）と文字列型の相互変換についてのまとめ

以下、JavaScript における「日付型から文字列型への変換」および「文字列型から日付型への変換」についてまとめておきます。

[1. Date オブジェクトの生成（前置き）](#1-date-オブジェクトの生成前置き)
[2. 日付型から文字列型に変換する](#2-日付型から文字列型に変換する)
[3. 文字列型から日付型に変換する](#3-文字列型から日付型に変換する)

## 1. Date オブジェクトの生成（前置き）

2022年5月5日6時35分20.333秒を指定して Date オブジェクトを生成する場合は、次のように指定します。

```sample.ts
// 2022年5月5日6時35分20.333秒を設定
const date = new Date(2022, 5 - 1, 5, 6, 35, 20, 333);

// 格納されている値は9時間前の日時
console.log(date); // 2022-05-04T21:35:20.333Z (注)協定世界時で出力される
```

**月は 0 〜 11 の数値で指定する**
月の指定は `0` が起点となるため <font color="red">0 〜 11 の数値で指定</font>します（指定したい月から 1 引いた数値で指定）。

**データは協定世界時（UTC）で格納される**
Date オブジェクトは、ホストシステムのタイムゾーンに基づき、常に世界標準時（[協定世界時: UTC](https://ja.wikipedia.org/wiki/%E5%8D%94%E5%AE%9A%E4%B8%96%E7%95%8C%E6%99%82)）に変換して値を格納しています。
そのため、console.log() でそのまま出力すると指定時刻の９時間前の値が表示されます（日本のシステム設定の場合）。

ただし、メソッドを使用して出力する際には、基本的に日本標準時に変換されて出力されるので、あまり難しく考えなくとも大丈夫なようになっています。

## 2. 日付型から文字列型に変換する

### 2-1. 一括で文字列に変換 （日本標準時で取得）

以下のメソッドを使用することで、日本標準時で出力されます（出力値はコメント部分に記載のとおり）。
決まった形式の文字列で出力されるため、使用の際の自由度は低いです。

```sample.ts
const date = new Date(2022, 5 - 1, 5, 6, 35, 20, 333); // 2022年5月5日6時35分20.333秒を設定

// 文字列として出力
console.log(date.toString()); // Thu May 05 2022 06:35:20 GMT+0900 (日本標準時)
console.log(date.toDateString()); // Thu May 05 2022
console.log(date.toTimeString()); // 06:35:20 GMT+0900 (日本標準時)

// システム設定に基づいて地域性を考慮した表現で出力
console.log(date.toLocaleString()); // 2022/5/5 6:35:20
console.log(date.toLocaleDateString()); // 2022/5/5
console.log(date.toLocaleTimeString()); // 6:35:20
```

前者の３つのメソッドは、あまり使用しない形式だと思います。
後者の toLocale から始まる３つのメソッドは、場合によってはそのまま使用できると思います。

|メソッド名|戻り値の型|表示例（全て日本標準時）|
|---|---|---|
|toString()|string|Thu May 05 2022 06:35:20 GMT+0900 (日本標準時)|
|toDateString()|string|Thu May 05 2022|
|toTimeString()|string|06:35:20 GMT+0900 (日本標準時)|
|toLocaleString()|string|2022/5/5 6:35:20|
|toLocaleDateString()|string|2022/5/5|
|toLocaleTimeString()|string|6:35:20|

### 2-2. 年・月・日・時・分・秒・曜日で個別に値を取得する （日本標準時で取得）

以下のメソッドを使用することで、年・月・日・時・分・秒・ミリ秒・曜日の値を個別に取得できます（出力値はコメント部分に記載のとおり）。

```sample.ts
const date = new Date(2022, 5 - 1, 5, 6, 35, 20, 333); // 2022年5月5日6時35分20.333秒を設定

console.log(date.getFullYear()); // 2022
console.log(date.getMonth()); // 4 (注)取得値に1を足して5月となる
console.log(date.getDate()); // 5
console.log(date.getHours()); // 6
console.log(date.getMinutes()); // 35
console.log(date.getSeconds()); // 20
console.log(date.getMilliseconds()); // 333
console.log(date.getDay()); // 4 (注)曜日を数値で取得している（4は木曜日）
```

|メソッド名|戻り値の型|取得内容（全て日本標準時）|表示例|
|---|---|---|---|
|getFullYear()|number|年を取得|2022|
|getMonth()|number|月を取得（0 起点）|4|
|getDate()|number|日を取得|5|
|getHours()|number|時を取得|6|
|getMinutes()|number|分を取得|35|
|getSeconds()|number|秒を取得|20|
|getMilliseconds()|number|ミリ秒を取得|333|
|getDay()|number|曜日を0〜6の値で取得（日曜日が起点）|4|

注意を要するのは、月は 0 起点で取得されるため、取得値に 1 を足す必要があります。
また、曜日は、0 〜 6 の値で取得されるため、これを 日〜土に読み替える必要があります。

#### 2-2-1. yyyy年m月d日の形式で表示する例

`2022年5月5日` のように表示するには、次のように文字列を連結させます。

```sample.ts
const date = new Date(2022, 5 - 1, 5, 6, 35, 20, 333); // 2022年5月5日6時35分20.333秒を設定

const dateText = `${date.getFullYear()}年${date.getMonth() + 1}月${date.getDate()}日`;
console.log(dateText); // 2022年5月5日
```

#### 2-2-2. yyyy年mm月dd日の形式で表示する例

`2022年05月05日` のように 0 埋めで表示するには、[padStart()](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/String/padStart) メソッドなどを使用します。
この辺りの書き方は、色々とあると思います。

```sample.ts
const date = new Date(2022, 5 - 1, 5, 6, 35, 20, 333); // 2022年5月5日6時35分20.333秒を設定

const year = date.getFullYear().toString().padStart(4, '0');
const month = (date.getMonth() + 1).toString().padStart(2, '0');
const day = date.getDate().toString().padStart(2, '0');

const dateText = year + '年' + month + '月' + day + '日';
console.log(dateText); // 2022年05月05日
```

#### 2-2-3. 曜日を表示する例

曜日は、0〜6 の値で取得（日曜日が起点）されますので、変換用のオブジェクトなどを作成して表示します。

```sample.ts
const date = new Date(2022, 5 - 1, 5, 6, 35, 20, 333); // 2022年5月5日6時35分20.333秒を設定

const weekDay: {
  [key: number]: string;
} = {
  0: '日曜日',
  1: '月曜日',
  2: '火曜日',
  3: '水曜日',
  4: '木曜日',
  5: '金曜日',
  6: '土曜日',
};

const n = date.getDay(); // 曜日を数値で取得する
console.log(weekDay[n]); // 木曜日
```

上記は、TypeScript の例です。
JavaScript の場合は `{　[key: number]: string;　}` の部分は不要です。


### 2-3. 協定世界時(UTC)で取得

使用頻度は少ないと思いますが、以下、[協定世界時 (UTC)](https://ja.wikipedia.org/wiki/%E5%8D%94%E5%AE%9A%E4%B8%96%E7%95%8C%E6%99%82)で出力するメソッドを一通り書いておきます。

#### 2-3-1. 一括で文字列に変換 （協定世界時(UTC)で取得）

```sample.ts
const date = new Date(2022, 5 - 1, 5, 6, 35, 20, 333); // 2022年5月5日6時35分20.333秒を設定

console.log(date.toUTCString()); // Wed, 04 May 2022 21:35:20 GMT
console.log(date.toISOString()); // 2022-05-04T21:35:20.333Z
console.log(date.toJSON()); // 2022-05-04T21:35:20.333Z
```

|メソッド名|戻り値の型|表示例（全て協定世界時(UTC)）|
|---|---|---|
|toUTCString()|string|Wed, 04 May 2022 21:35:20 GMT|
|toISOString()|string|2022-05-04T21:35:20.333Z|
|toJSON()|string|2022-05-04T21:35:20.333Z|

**ISO 8601 と タイムゾーン**
`toISOString()` および `toJSON()` で表示される `2022-05-04T21:35:20.333Z` のフォーマットは、[ISO 8601](https://ja.wikipedia.org/wiki/ISO_8601) という国際規格になります。
これを日本時間で表示する場合は、`2022-05-05T06:35:20.333+09:00` のように、末尾に `+09:00` というタイムゾーン（協定世界時との時間差）を記載することになります。

#### 2-3-2. 年・月・日・時・分・秒・曜日で個別に値を取得する （協定世界時(UTC)で取得）

```sample.ts
const date = new Date(2022, 5 - 1, 5, 6, 35, 20, 333); // 2022年5月5日6時35分20.333秒を設定

console.log(date.getUTCFullYear()); // 2022
console.log(date.getUTCMonth()); // 4 (注)取得値に1を足して5月となる
console.log(date.getUTCDate()); // 4
console.log(date.getUTCHours()); // 21
console.log(date.getUTCMinutes()); // 35
console.log(date.getUTCSeconds()); // 20
console.log(date.getUTCMilliseconds()); // 333
console.log(date.getUTCDay()); // 3 (注)曜日を数値で取得している（3は水曜日）
```

|メソッド名|戻り値の型|取得内容|表示例|
|---|---|---|---|
|getUTCFullYear()|number|協定世界時(UTC)で年を取得|2022|
|getUTCMonth()|number|協定世界時(UTC)で月を取得（0 起点）|4|
|getUTCDate()|number|協定世界時(UTC)で日を取得|5|
|getUTCHours()|number|協定世界時(UTC)で時を取得|6|
|getUTCMinutes()|number|協定世界時(UTC)で分を取得|35|
|getUTCSeconds()|number|協定世界時(UTC)で秒を取得|20|
|getUTCMilliseconds()|number|協定世界時(UTC)でミリ秒を取得|333|
|getUTCDay()|number|協定世界時(UTC)で曜日を0〜6の値で取得（日曜日が起点）|4|

### 2-4. 1970年1月1日からの経過ミリ秒数を取得する

Date オブジェクトは協定世界時 (UTC) の1970年1月1日からの経過ミリ秒数を表す Number の値を含んでいます（[Date - JavaScript | MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Date)）。
次のように記載することで、値を取得することができます。

```sample.ts
const date = new Date(2022, 5 - 1, 5, 6, 35, 20, 333); // 2022年5月5日6時35分20.333秒を設定

console.log(date.valueOf()); // 1651700120333
console.log(date.getTime()); // 1651700120333
```

valueOf() でも getTime() でも取得結果は同じ値となります。

|メソッド名|戻り値の型|表示例（全て協定世界時(UTC)）|
|---|---|---|
|valueOf()|number|1651700120333|
|getTime()|number|1651700120333|

### 2-5. タイムゾーンの差（協定世界時との差）を取得する

getTimezoneOffset() メソッドは、 現在のロケールから協定世界時（UTC）までのタイムゾーンの差を分単位で返します（[Date.prototype.getTimezoneOffset() - JavaScript | MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Date/getTimezoneOffset)）。

```sample.ts
console.log(new Date().getTimezoneOffset()); // -540
```

|メソッド名|戻り値の型|表示例|
|---|---|---|
|getTimezoneOffset()|number|-540|

## 3. 文字列型から日付型に変換する

### 3-1. 一般的な日付フォーマット（文字列）を日付型に変換する

Date オブジェクトに、`2022-5-5`, `2022/5/5`, `2022.5.5` などの文字列を指定すれば、簡単に日付型に変換することができます。
この場合、基本的には、日本標準時（2022年5月5日午前0時0分）として入力を受け付け、協定世界時（2022年5月４日午後15時0分）に変換されて格納されます。

ただし、<font color="red">**2022-05-05**</font> のように 0 埋めの形式（yyyy-mm-dd）で指定すると、協定世界時 (UTC) として入力を受け付けることになるため、注意を要します。

```sample.ts
let date;

// ハイフン区切り
date = new Date('2022-5-5');
console.log(date.toLocaleString()); // 2022/5/5 0:00:00 <- 日本標準時で出力
console.log(date.toISOString()); // 2022-05-04T15:00:00.000Z <- 協定世界時で出力

// ハイフン区切り（0埋め）※この場合だけ格納される時間が異なる
date = new Date('2022-05-05');
console.log(date.toLocaleString()); // 2022/5/5 9:00:00
console.log(date.toISOString()); // 2022-05-05T00:00:00.000Z

// スラッシュ区切り
date = new Date('2022/5/5');
console.log(date.toLocaleString()); // 2022/5/5 0:00:00

// スラッシュ区切り（0埋め）
date = new Date('2022/05/05');
console.log(date.toLocaleString()); // 2022/5/5 0:00:00

// ピリオド区切り
date = new Date('2022.5.5');
console.log(date.toLocaleString()); // 2022/5/5 0:00:00

// ピリオド区切り（0埋め）
date = new Date('2022.05.05');
console.log(date.toLocaleString()); // 2022/5/5 0:00:00
```

**yyyy-mm-dd 形式が協定世界時 (UTC) と認識される理由について**

なぜ、`2022-05-05` のように 0 埋めの形式（yyyy-mm-dd）の場合だけ、協定世界時として値が格納されるかですが、このフォーマットの場合は、ISO 8601 の規格として認識されてしまうためです。
具体的には、次の指定をしていることと同じことになります。

```sample.ts
// ISO 8601 フォーマット（世界協定時）
date = new Date('2022-05-05T00:00:00.000Z');
console.log(date.toLocaleString()); // 2022/5/5 9:00:00
console.log(date.toISOString()); // 2022-05-05T00:00:00.000Z
```

### 3-2. 様々な日付フォーマット（文字列）を日付型に変換する

JavaScript 上で出力される日付文字列のフォーマットであれば、正しく日付型に変換されます。
次の例のとおりです。

```sample.ts
// ISO 8601 フォーマット（世界協定時）
date = new Date('2022-05-05T06:35:20.000Z');
console.log(date.toLocaleString()); // 2022/5/5 15:35:20 <- 日本標準時で出力
console.log(date.toISOString()); // 2022-05-05T06:35:20.000Z <- 協定世界時で出力

// ISO 8601 フォーマット（日本標準時）
date = new Date('2022-05-05T06:35:20.000+09:00');
console.log(date.toLocaleString()); // 2022/5/5 6:35:20
console.log(date.toISOString()); // 2022-05-04T21:35:20.000Z

// 英語のフォーマット
date = new Date('Thu May 05 2022 06:35:20 GMT+0900 (日本標準時)');
console.log(date.toLocaleString()); // 2022/5/5 6:35:20
console.log(date.toISOString()); // 2022-05-04T21:35:20.000Z

// 英語のフォーマット（日付のみ）
date = new Date('Thu May 05 2022');
console.log(date.toLocaleString()); // 2022/5/5 0:00:00
console.log(date.toISOString()); // 2022-05-04T15:00:00.000Z

// 日本の一般的なフォーマット
date = new Date('2022/5/5 06:35:20.333');
console.log(date.toLocaleString()); // 2022/5/5 6:35:20
console.log(date.toISOString()); // 2022-05-04T21:35:20.000Z
```

### 3-3. 変換できない文字列

数字や区切り文字に**全角文字**が含まれていると、日付型への変換は失敗します。

```sample.ts

// 全角文字を入れると変換できない
console.log(new Date('2022－5－5')); // Invalid Date
console.log(new Date('2022／5／5')); // Invalid Date
console.log(new Date('2022．5．5')); // Invalid Date
```

### 3-4. 補足（文字列型以外からの日付への変換）

#### 3-4-1. 現在日時を取得する

`new Date()` のように、何も指定しないと現在日時が取得されます。

```sample.ts
// 現在日時を取得する
date = new Date(); 
console.log(date.toLocaleString()); // 2022/5/6 1:59:09
console.log(date.toISOString()); // 2022-05-05T16:59:09.098Z
```

#### 3-4-2. 年・月・日・時・分・秒・ミリ秒で指定して変換

これは、冒頭で書いているのと同じ例です。
年・月・日・時・分・秒・ミリ秒の順で、カンマ区切りで指定します。
月の指定は `0` が起点となるため0 〜 11 の数値で指定します（指定したい月から 1 引いた数値で指定）。

```sample.ts
// 2022年5月5日6時35分20.333秒を設定
const date = new Date(2022, 5 - 1, 5, 6, 35, 20, 333);
console.log(date.toLocaleString()); // 2022/5/5 6:35:20
console.log(date.toISOString()); // 2022-05-04T21:35:20.000Z
```

#### 3-4-3. 1970年1月1日からの経過ミリ秒数で指定して変換

1970年1月1日からの経過ミリ秒数を指定すれば、日付型に変換されます。

```sample.ts
// 1970年1月1日からの経過ミリ秒数で指定
const date = new Date(1651700120333); 
console.log(date.toLocaleString()); // 2022/5/5 6:35:20
console.log(date.toISOString()); // 2022-05-04T21:35:20.000Z
```

#### 3-4-4. 取得できる日付の範囲（上限・下限）

取得できる日付の範囲は、1970年1月1日から前後 100,000,000 日（1 億日）となります。
1 億日をミリ秒で表すと、前後 8640000000000000 ミリ秒となります。

次のように、格納できる上限は 275760年9月1日、下限は -271821年4月20日となっています。


```sample.ts
console.log(new Date(8639999999999999)); // +275760-09-12T23:59:59.999Z
console.log(new Date(8640000000000000)); // +275760-09-13T00:00:00.000Z
console.log(new Date(8640000000000001)); // Invalid Date
console.log(new Date(-8640000000000001)); // Invalid Date
console.log(new Date(-8640000000000000)); // -271821-04-20T00:00:00.000Z
console.log(new Date(-8639999999999999)); // -271821-04-20T00:00:00.001Z
```