【JavaScript】Date

# 概要
JavaScriptを学習、理解を深めるため「[JavaScript Primer 迷わないための入門書](https://jsprimer.net/)」を読み、
理解した内容等を記載していく。

「[【JavaScript】JavaScript入門一覧](https://qiita.com/andota05/items/22fae452225b785fd405)」に他の記事をまとめています。

# この記事で理解できること
* Dateオブジェクトとは
* Dateオブジェクトのインスタンス作成方法
* Dateオブジェクトに関連するメソッドの使用方法

# Dateオブジェクト
* ECMAScriptで定義された`ビルトインオブジェクト`
* Dateオブジェクトにおける時刻は、`UTC`の`1970年1月1日0時0分0秒`を基準とした相対的なミリ秒として保持される。

# Dateオブジェクトのインスタンス作成
* インスタンスの作成には`new演算子`を使用する。
* `現在の時刻`、もしくは`任意の時刻`をインスタンス化する方法がある。

## 現在の時刻をインスタンス化
* コンストラクタ引数に何も渡さない場合、`現在の時刻`を表すインスタンスを作成できる。
* 作成したインスタンスが持つ時刻値を取得するには`getTime`メソッドを使用する。
* インスタンスを作成せず、現在の時刻値のみ取得する場合は、`Date.now`メソッドで取得できる。

```js
// 現在の時刻を表すインスタンスを作成
const now = new Date();

// インスタンスが保持する時刻値を取得
console.log(now.getTime());        // => 1656710295341(UNIX timeと呼ばれる表現方法)
// ISO 8601形式の文字列に変換
console.log(now.toISOString());    // => 2022-07-01T21:18:15.341Z(日本時間は+9時間で計算する)

// インスタンス化せず、現在の時刻値のみ取得
console.log(Date.now());           // => 1656710295341(DateインスタンスのgetTime()メソッドと同様の動作)
```

## 任意の時刻をインスタンス化
* コンストラクタ引数を渡すことで、`任意の時刻`を表すインスタンスを作成できる。
* 引数としてサポートしている3種類
    * 時刻値
    * 時刻を示す文字列
    * 時刻の部分(年・月・日...)を示す数値

### 時刻値を渡す
```js
// 時刻値(ミリ秒)を引数として渡す
const date = new Date(1656710295341);

console.log(date.toISOString()); // => 2022-07-01T21:18:15.341Z(日本時間は+9時間で計算する)
```

### 時刻を示す文字列を渡す
* 文字列に含まれる`タイムゾーン`をもとに時刻値が計算される。
* 文字列からタイムゾーンが読み取れない場合は、`実行環境のタイムゾーン`によって時刻値を計算する。
* ISO 8601形式以外の文字列のパースは、ブラウザごとに異なる結果を返す可能性があるため注意が必要。

```js
// RFC2822形式
console.log(new Date("25 Jun 2022 14:31:00"));

// ISO 8601の形式タイムゾーン未指定(タイムゾーン:Asia/Tokyoの環境で現在時刻を引数として渡している想定)
console.log(new Date("2022-06-16T14:31:00"));
// => 2022-06-16T14:31:00.000Z
// => 2022-06-16T05:31:00.000Z(環境がタイムゾーン:UTCだとこちらになる)
```

### 時刻の部分(年・月・日...)を示す数値を渡す
* この方法はタイムゾーンを指定できず、渡した数値は常に`ローカルのタイムゾーンにおける時刻`とみなされる。
* 月を表す第二引数は`0から11`までの数値で指定する
* 結果が実行環境に依存してしまうため、基本的にこの方法は非推奨。

```js
// タイムゾーンAsia/Tokyoの現在時刻が2022年06月25日10時20分30秒40の想定
// new Date(year, month, day, hour, minutes, seconds, milliseconds);
const date = new Date(2022, 5, 25, 10, 20, 30, 40);

// UTCの環境で実行
console.log(date.toISOString()); // => 2022-06-25T01:20:30.040Z(-9時間になっている)
```

### 不正値があった場合
* どのオーバーロードにも当てはまらない引数や、時刻としてパースできない文字列を渡した場合でも、Dateのインスタンスは作成される。
* ただし、インスタンスが持つ時刻は不正であるため、getTimeメソッドは`NaN`を返し、toStringメソッドは`Invalid Date`という文字列を返す。

```js
const nanDate = new Date("");
console.log(nanDate.getTime());     // => NaN

const invaliDate = new Date("");
console.log(invaliDate.toString()); // => Invalid Date
```

# Dateのインスタンスメソッド
* [Dataオブジェクトに用意されているメソッド](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Date)は、「年のみ」「月のみ」など部分取得のメソッドが多い。
* 月を取得した場合、`0〜11`の数値が返されるため`+1`する必要がある。

```js
// 環境のタイムゾーンはAsia/Tokyoの想定
const date = new Date("2022-06-25T14:45:30");

console.log(date); // => 2022-06-25T14:45:30.000Z

// 年を取得
console.log(date.getFullYear());  // => 2022

// 月を取得
console.log(date.getMonth());     // => 5
console.log(date.getMonth() + 1); // => (+1して)6
```

# 現実のユースケースとDate
* 多くのユースケースにおいては機能が不十分であると想定される部分が多い。
* そのため、JavaScriptにおける日付・時刻の処理は、標準のDateではなくライブラリを使うことが一般的になっている。
* 代表的なライブラリとしては、`moment.js`や`js-joda`、`date-fns`などが存在する。
※現在「[moment.js](https://momentjs.com/docs/)」は新規プロジェクトへの使用を非推奨としている。