デバイスの設定に依存せず、日本の日時をJavaScriptで表示させる

まず、JavaScriptで現在日時を取得する方法としてよく、以下の記述を見たことがあると思う。

```js
var date = new Date(); // 現在日時の取得
```

インスタンス化した際のコンストラクタにおいて、コンストラクタ引数に引数情報を指定しない場合、現在の(デバイス)に設定されている日時を取得している。
つまり、`new Date()` はデバイス依存だと言えることがわかる。(違かったら、教えてください🙇‍♂️)

よって、デバイスの設定をいじると、`new Date()` での現在日時の値に影響が出てしまう。

以下、Macでデバイスの日時を変更した際の `new Date()` の挙動について記載する。

① 日時設定を変更する。
<img width="375" alt="スクリーンショット 2019-04-28 21.59.44.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/341734/88dd72ba-d211-70f4-2aba-c864c0a32af8.png">

② 設定から、時間帯を選択する。
<img width="666" alt="スクリーンショット 2019-04-28 22.00.26.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/341734/110fc95a-f8f3-4b67-af29-95652201a358.png">

③ どこでもいいので時間帯を変更する。(今回はマイドゥグリ-ナイジェリアに位置を合わせる)
<img width="663" alt="スクリーンショット 2019-04-28 14.01.03.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/341734/d57187cc-326d-17bc-4ee5-c78419ce6fcf.png">

④ ブラウザ(Chrome)の開発者ツールから `new Date()` を実行してみる。
<img width="686" alt="スクリーンショット 2019-04-28 14.02.18.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/341734/637c9de1-56a5-3e72-3cbe-2d501c9eb19e.png">

① 〜 ④から `new Date()` の挙動が変わったことがわかる。

### だから、なに？
ここまで画像も使ったりして、まとめてみたが
そもそも、だからなんなの？って思われた方もいるかもしれない。

例えば、自作で作成したアプリでリアルタイムを画面に出力している、しかし、日本から離れているため、その国のリアルタイムが出力されてしまうとか、特殊なケースではありそうだが、日時に感して日本の時刻が正確に出力されないケースがあったりします。

### 結局、何が言いたかったか
言いたかったことは、タイトルに書いてある通り、デバイスに依存せずともJavaScriptで日本の日時を表示できるよってこと。
ただ、以下に記載するソースは少しパワーコードが混ざっているので、もっといい方法あるよ！って方は教えてください。。。

### まず協定世界時を取得する。
JavaScriptで[協定世界時](https://ja.wikipedia.org/wiki/%E5%8D%94%E5%AE%9A%E4%B8%96%E7%95%8C%E6%99%82)を取得する方法は、Date prototypeの `toUTCString` を用いる。

```js
const date = new Date();
console.log(date.toUTCString());
// → Sun, 28 Apr 2019 14:40:00 GMT
```

Date prototypeにはもう一つ `toGMTString` というのがあるが、[こちらのサイト](https://www.javadrive.jp/javascript/date_class/index4.html)によると

> UTCタイムゾーンではなくGMTタイムゾーンでの日付/時刻の文字列表現を返します。ただこのメソッドは現在非推奨となっているようなので、toGMTStringメソッドではなくtoUTCStringメソッドを使うようにして下さい。

だそうなので、`toUTCString` を使用するのが良さそうです。

### 取得された文字列をDateオブジェクトのコンストラクタ引数に渡してあげる

Dateオブジェクトは、結構万能で、コンストラクタ引数の形式が複数存在します。

```js
// デバイス依存での現在の日時でインスタンス化
new Date();

// 日付と時刻をミリ秒で指定してインスタンス化
new Date(ms);

// 日付など、文字列で指定してインスタンス化(☆)
new Date(str);

// 日時と日付に関する値を個々に設定してインスタンス化
new Date(year, month[, day, hour, min, sec, ms]);
```

上記の `(☆)` の箇所でも、文字列の指定が複数存在します。

```js
new Date('2019/01/01');
// → Tue Jan 01 2019 00:00:00 GMT+0900 (日本標準時)

new Date('2019-01-01');
// → Tue Jan 01 2019 00:00:00 GMT+0900 (日本標準時)

new Date('Tue Jan 01 2019 00:00:00 GMT+0900 (日本標準時)');
// → Tue Jan 01 2019 00:00:00 GMT+0900 (日本標準時)
```

この万能なコンストラクタ引数を用いて、先ほどの協定世界時の文字列をインスタンス引数として利用します。

```js
const date = new Date();

// 協定世界時の文字列を取得
const utc = date.toUTCString();

// 取得された文字列の「GMT」を除去する
const g = utc.replace('GMT', '');

// 除去された文字列を使用し、インスタンスする
const gDate = new Date(g);
// → Sun Apr 28 2019 14:40:00 GMT+0900 (日本標準時)
```

上記のソースを見ると、気になる箇所が存在すると思います。

`date.toUTCString()` で取得される文字列中の `GMT` を `''` に置換していることと、`gDate` の中身が、以下の出力結果になっていることです。

Sun Apr 28 2019 14:40:00 <font color="Red">GMT+0900 (日本標準時)</font>

`GMT` が文字列中に存在すると、うまく指定の日時でインスタンスができなかったのと、その文字列が存在しないと、デバイスの現在位置を参照してしまうみたいです。
確かに協定世界時でDateオブジェクトを生成できたのですが、ここら辺の実装はもっといい方法がありそうです。

### インスタンス化された協定世界時から日本の時刻に変換する
最後に日本の時刻に変換したいので、協定世界時に+9してあげます。

```js
const hours = gDate.getHours();
gDate.setHours(hours + 9);
console.log(gDate.toString());
// → Sun Apr 28 2019 23:40:00 GMT+0900 (日本標準時)
```

以上で、デバイス依存せずとも日本の時刻を表示する実装ができました。

## まとめ
JavaScriptは奥が深いので、他にもいい方法がありそうです。
または、国ごとの日時などを取得するようなAPIがあれば、そのAPIを叩くのもいいのかもしれません。

本記事のような、どの国の設定でも日本の時刻を取得したいといったケースでの記事があまり見当たらなかったため本記事をまとめてみました。
そして、この記事が平成最後の投稿になりそうです。（笑）

結構、ガバガバな記事かもしれませんが、何か指摘などあればコメントください🙇‍♂️

最後に、本記事を最後まで読んでくれた方、ありがとうございました！！

## 参考文献
[[JavaScript] グリニッジ標準時(GMT時刻)を取得する](https://javascript.programmer-reference.com/js-togmtstring/)
[toUTCString / toGMTStringメソッド](https://www.javadrive.jp/javascript/date_class/index4.html)
[コンストラクタ関数](https://www.javadrive.jp/javascript/date_class/index1.html)