JavaScriptのDateオブジェクトの解説と実用例

##はじめに
Dateオブジェクト。。。
使用頻度も少ないし、なんとなくは理解してるしけど応用して使いこなすまではいってないのでコピペ率高めになってた。。。
危機感を覚えて再度学び直してみたので``Dateオブジェクト``についてと提供されている``メソッドのトラップ``、``実用例``を解説していきます。

##解説しないこと
- JavaScriptオブジェクト
- new 演算子 (インスタンス化)
- 静的メソッド、 インスタンスメソッド

##Dateオブジェクトとは
Dateオブジェクトとは、呼び出された瞬間の時刻を様々な形式で返す静的メソッドとインスタンスメソッドを持つオブジェクトです。


###もう少し詳しく
Dateオブジェクトの時刻は、``世界協定時(UTC)``からの経過ミリ秒(``UNIXエポック``)をNumber型ので返されます。

提供されているメソッドにはUTC基準で**1618028348725のようなミリ秒**や**Sat, 10 Apr 2021 04:23:27 GMT**表示、自身が使用している環境に設定されているタイムゾーン（これを読んで頂いてるのはおそらく日本）を基準にした**UTC + 時差**の地方時をミリ秒やFri Dec 17 2021 00:00:00 GMT+0900 (日本標準時)のような形式で時刻を返すものが用意されています。

####世界協定時（UTC）とUNIXエポック
世界協定時とは,ものすご〜〜く簡単に言うと、賢いおじさん達が1970年1月1日午前0時0分0秒を世界の標準時刻にしよう！と決めた規定です。

UNIXエポックとは、その世界協定時を基準に１づつ足されたものを経過ミリ秒として扱ったものの名称で、UNIX時間またはUNIX時刻も同一の意味でコンピューターシステム上での時刻表現の一種です。

[UNIXエポック](https://ja.wikipedia.org/wiki/UNIX%E6%99%82%E9%96%93)

###基本的な使い方
基本的にはインスタンス化してコンストラクターの返り値を使用するか用意されているメソッドを呼び出します。

提供されているメソッドはMDNを見ればある程度正しく記載されているので各メソッドとその挙動についてはMDNで確認してください。

[MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Date)

###使用例
```date.js
//コンストラクター関数
const date = new Date()
/*地方時を返す*/
console.log(date) // Sun Apr 11 2021 00:54:42 GMT+0900 (日本標準時)

//静的メソッド
/*UTCのミリ秒がそのまま返ってきてる*/
console.log(Date.now()) //1618071154714

//メソッド
/* 呼び出された瞬間の時間だけを返す */
console.log(date.getHours()) // 1


```

##Dateオブジェクトに潜むトラップ
Dateオブジェクト、大変便利ですが、仕様に少しだけ癖のあるものもあるので注意が必要です。

- コンストラクター
- 月の取得
- 曜日の取得

###コンストラクター

ハイフン( - )区切りは+0900されている 

```date.js
// コンストラクター
const date1 = new Date('2020-07-01');

const date2 = new Date('2020/07/01');

console.log(date1) // Wed Jul 01 2020 09:00:00 GMT+0900 (日本標準時)
console.log(date2) // Wed Jul 01 2020 00:00:00 GMT+0900 (日本標準時)
console.log(date1.toGMTString()) // "Wed, 01 Jul 2020 00:00:00 GMT"
console.log(date2.toGMTString()) // "Tue, 30 Jun 2020 15:00:00 GMT"
```
###月の取得
getMonthの結果は ***0 起点***

```date.js
// 月の取得
const today1 = new Date()
console.log(today1.getMonth()+ 1) // 4

const today2 = new Date("2021-04-11 00:00:00")
// Sun Apr 11 2021 00:00:00 GMT+0900 (日本標準時)
console.log(today2.getMonth())   // 3

const today3 = new Date("2021","04", "11", "00")
// Mon Mar 11 2021 00:00:00 GMT+0900 (日本標準時)
console.log(today3.getMonth()) // 4
```
###曜日の取得
getDayのような曜日を返すメソッドも曜日自体を返すのではなく ***０ 起点*** で始まる数値が返ってくるのでそれに配列などに当ててあげるような仕様になります。

```date.js
// 曜日取得
let arrDay = ['日曜日', '月曜日', '火曜日', '水曜日', '木曜日', '金曜日', '土曜日']
const today2 = new Date("2021-04-11 00:00:00")
console.log(arrDay[today2.getDay()]) // 日曜日
console.log(today2.getDay()) 0
```

##実用例
Dateオブジェクト単体だと日時を取得するだけですが、応用していくと独自フォーマットを作成したり日時の差分を取得、より正確なタイマーを作成することができます。

- 日付フォーマット
- カウントダウン
- タイマー

####日付フォーマット
指定された日時をDateオブジェクトのフォーマットにしたり、取得した瞬間時刻を独自フォーマットに変換する

```date.js
let year = '2021'
let month = '1'
let day = '20'
let time = '00:00'

/* 変数に入った値を初期値として扱う */
const format1 = `${year} / ${month} / ${day} / ${time}`
const date1 = new Date(format)
console.log(d) // Wed Jan 20 2021 00:00:00 GMT+0900 (日本標準時)


const date2 = new Date()

year = date.getFullYear() // 2021
month = date.getMonth() + 1 // 4
day = date.getDate() // 12
time = date.getHours() // 15
/* 独自のフォーマットを作成できる (フォーマットが不恰好なのは許し欲しい... */
const format2 = `Y${year}:M${month}:D${day}:T${time}`
//  "Y2021:M4:D12:T15"
```

####カウントダウン


```date.js
function nanNichi(){

//今の日時
const d1 = new Date();
//ターゲット日時
const d2 = new Date('2019/05/01 00:00'); //令和元年
//時差（ミリ秒）
const d3 = d2 - d1;
// ミリ秒から秒に
const d3_Sec = Math.floor(d3 / 1000);

//分、時、日の秒数
const Minute_Sec = 60;
const Hour_Sec = 60 * 60;
const Day_Sec = 60 * 60 * 24;

//あと何日  
const d4_Day = Math.floor(d3_Sec / Day_Sec);

//あと何時間
const d5_Hour = Math.floor(d3_Sec / Hour_Sec  % 24);

//あと何分
const d6_Minute = Math.floor(d3_Sec / Minute_Sec % 60);

//あと何秒
const d7_Sec = Math.floor(d3_Sec % 60);
   
//カウントダウン
counter.innerHTML = d4_Day + "日" + d5_Hour + "時間" + d6_Minute + "分" + d7_Sec + "秒！！";

//1秒ごとに実行
setTimeout(nanNichi, 1000);
}

//関数実行
nanNichi();
```

####タイマー
setTimeout、setIntervalは引数に渡された遅延時間を正確には実行しません。
１秒２秒なら問題なく見えますが、１時間単位で見ると誤差が出てきます。
正確なタイマーを作成するなら開始時刻と遅延された後の時刻を取得してその差分で計算する方がより正確に計算されます。

```date.js
// タイマースタート時の時刻を取得
const startTime = new Date()

// 再帰的に呼び出すことでスタート時刻とtimer呼び出し時刻の差分を出す
function timer(start){
  const nowTime = new Date()
  
  let time = nowTime - startTime
  /* ミリ秒を秒に形成して端数を切り落とす */
  ms = Math.floor(time/1000)
  /* 割り切れないものを秒として算出することで60秒以上の結果を出力しない */
  s = ms % 60

  setTimeout(timer, 1000, startTime)
  
  console.log(s)
}

timer(startTime)
```

##まとめ
Dateオブジェクトが基本的に何を返すか？ 各メソッドはどのような形式で返すのか？ メソッドの一部の癖をちゃんと理解しているか？ を意識した上で使用しましょう。

最後まで見ていただきありがとうございました。
間違い等あればご指導、ご指摘お待ちしております。

以上、Dateオブジェクトについての解説でした。

##参考サイト

- [MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Date)
- [【JS】DateとsetTimeout()で作るカウントダウンタイマー（令和まであと何日？）](https://www.i-ryo.com/entry/2019/04/30/173620)
- [JavascriptのDate.getDate()でハマった](https://qiita.com/Naoki_kkc/items/b880659c403217895d35)
- [UNIX時間](https://ja.wikipedia.org/wiki/UNIX%E6%99%82%E9%96%93)