[JavaScript]Date.parseの挙動の違いをブラウザ毎に調べてみた



## 概要
JavaScriptで開発をしている時に、2023年2月31日など暦上存在しない日付に対して`Date.parse`を実行する機会がありました。そうしたら、MDNの説明と異なる動きが起きたため、`Date.parse`の挙動はブラウザによって異なることを知りました。そこで今回はブラウザ毎の`Date.parse`の挙動の違いを調査しました。


## 結論
- ブラウザのJSエンジン毎に`Date.parse`の挙動が一部異なります。
- 異なる点として、Chromeは2023年2月31日を2023年3月3日と繰り上げた日付を返却するのに対し、SafariとFirefoxは`NaN`を返却します。



## 動作が異なる原因
ブラウザ上でのJavaScriptの挙動は[JSエンジン](https://developer.mozilla.org/en-US/docs/Web/JavaScript/JavaScript_technologies_overview)によって決定されます。
ChromeやSafariではそれぞれ違うJSエンジンが使われています。JSエンジンが違えば挙動も違うため、`Date.parse`の挙動に差異が生じていると考えられます。


## 調査方法
MDN曰く、[`Date.parse`](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Date/parse)は日時を表す文字列を解釈します。対応するよう明示的に指定されているのは[ISO8601形式](https://tc39.es/ecma262/#sec-date-time-string-format)`YYYY-MM-DDTHH:mm:ss.sssZ`です。今回はこの形式の文字列で`Date.parse`の挙動の違いを調査します。
例：`2023-02-09T14:30:30.111+0900`は2023年2月9日14時30分30秒111ミリ秒(日本時間)を指します。
| 型 | 意味 |例|
|:-----------|:------------|:------------|
| YYYY       | 年        |2023|
| MM     | 月      |02|
| DD       | 日付        |09|
| T         |     日付と時刻の区切り      |T|
| HH       | 時間       |14|
| mm    | 分     |30|
| ss    | 秒     |30|
| sss    | ミリ秒     |111|
| Z    |   タイムゾーン   |+0900|

下記の調査対象の日付を確認し、返り値が`NaN`ではない場合、返り値をもとに日付を作成して`Date.parse`の引数とどのような違いがあるか確認します。


調査対象の日付
- 存在する日付(2023年2月10日)
- 存在しない日付(2023年2月99日)
- 特定の月には存在しない日付(2023年2月31日)
- 閏日(2024年2月29日)

調査対象のブラウザはそれぞれ使われているJSエンジンが異なる、Chrome、Safari、Firefoxを対象とします。

-------------------

### 存在する日付の場合(2023年2月9日)
```js
// Chromeの場合
console.log(Date.parse('2023-02-09T00:00:00.000+0900'))
// 1675868400000
console.log(new Date(1675868400000))
//  Thu Feb 09 2023 00:00:00 GMT+0900 (日本標準時)


// Safariの場合
console.log(Date.parse('2023-02-09T00:00:00.000+0900'))
// 1675868400000
console.log(new Date(1675868400000))
// Thu Feb 09 2023 00:00:00 GMT+0900 (日本標準時)


// Firefoxの場合
console.log(Date.parse('2023-02-09T00:00:00.000+0900'))
// 1675868400000
console.log(new Date(1675868400000))
// Thu Feb 09 2023 00:00:00 GMT+0900 (日本標準時)
```
### 存在しない日付(2023年2月99日)
```js
// Chromeの場合
console.log(Date.parse('2023-02-99T00:00:00.000+0900'))
> NaN


// Safariの場合
console.log(Date.parse('2023-02-99T00:00:00.000+0900'))
> NaN


// Firefoxの場合
console.log(Date.parse('2023-02-99T00:00:00.000+0900'))
> NaN

```
### 他の月には存在するが、特定の月には存在しない日付(2023年2月31日)
``` js
// Chromeの場合
console.log(Date.parse('2023-02-31T00:00:00.000+0900'))
> 1677769200000
console.log(new Date(1677769200000))
> Fri Mar 03 2023 00:00:00 GMT+0900 (日本標準時)


// Safariの場合
// 他の月には存在するが、特定の月には存在しない日付(2023年2月31日)
console.log(Date.parse('2023-02-31T00:00:00.000+0900'))
> NaN


// Firefoxの場合
console.log(Date.parse('2023-02-31T00:00:00.000+0900'))
> NaN
```

### 閏年など、場合によっては存在する日付(2024年2月29日)
``` js
// Chromeの場合
console.log(Date.parse('2024-02-29T00:00:00.000+0900'))
> 1709132400000
console.log(new Date(1709132400000))
> Thu Feb 29 2024 00:00:00 GMT+0900 (日本標準時)


// Safariの場合
console.log(Date.parse('2024-02-29T00:00:00.000+0900'))
> 1709132400000
console.log(new Date(1709132400000))
> Thu Feb 29 2024 00:00:00 GMT+0900 (日本標準時)


// Firefoxの場合
console.log(Date.parse('2024-02-29T00:00:00.000+0900'))
> 1709132400000
console.log(new Date(1709132400000))
> Thu Feb 29 2024 00:00:00 GMT+0900 (日本標準時)
```

## まとめ
| 条件| Chrome | Safari |Firefox|
|:-----------|:------------|:------------|:------------|
|存在する日付(2023年2月10日)|Thu Feb 09 2023 00:00:00 GMT+0900 (日本標準時)|Thu Feb 09 2023 00:00:00 GMT+0900 (日本標準時)|Thu Feb 09 2023 00:00:00 GMT+0900 (日本標準時)|
|存在しない日付(2023年2月99日)|NaN|NaN|NaN|
|特定の月には存在しない日付(2023年2月31日)|Fri Mar 03 2023 00:00:00 GMT+0900 (日本標準時)|NaN|NaN|
|閏日(2024年2月29日)|Thu Feb 29 2024 00:00:00 GMT+0900 (日本標準時)|Thu Feb 29 2024 00:00:00 GMT+0900 (日本標準時)|Thu Feb 29 2024 00:00:00 GMT+0900 (日本標準時)|

`Date.parse`の挙動はブラウザ(JSエンジン)毎によって一部異なることがわかりました。
Chromeで2023年2月31日を入力すると、2023年3月3日を返却しました。一方で、SafariとFirefoxで2023年2月31日を入力した場合、`NaN`を返すという挙動の違いを確認することができました。
## 参考記事
[JavaScript technologies overview](https://developer.mozilla.org/en-US/docs/Web/JavaScript/JavaScript_technologies_overview)
[MDN-Date.parse](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Date/parse)