JavaScript の Date オブジェクトについてのメモ

# :man_tone1: 誰向けの記事か
- JavaScript 初心者
- タイムゾーンや時差の扱いに困っている方

# :triangular_flag_on_post: 結論
- Date の実態はタイムゾーンを持たない特定の瞬間
- 比較する際には `getTime()`する

# 1. Javascript の Date とは
:::note warn
注意：個人的な理解に基づいて説明しています。細部で誤りがある可能性があります。
:::

- JavaScriptのDate型の実態は、世界協定時間(UTC)の1970年1月1日0時0分0秒から経過したミリ秒数である
- タイムゾーン情報は持たない
- 特定の瞬間を表す

MDN の説明：
>JavaScript の日付は基本的に、元期として定義される UTC の 1970 年 1 月 1 日午前 0 時（UNIX 元期と同じ）から経過したミリ秒単位の時刻を指定します。このタイムスタンプはタイムゾーンに依存せず、歴史の一瞬を固有のものとして定義します。

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Date#%E5%85%83%E6%9C%9F%E3%80%81%E3%82%BF%E3%82%A4%E3%83%A0%E3%82%B9%E3%82%BF%E3%83%B3%E3%83%97%E3%80%81%E7%84%A1%E5%8A%B9%E3%81%AA%E6%97%A5%E6%99%82

# 2 時間の概念を理解する
## 2.1 UTC, GMT, ロンドン時間の違い

- UTC：協定世界時。最も正確な時間基準
    - セシウム原子時計を使用
- GMT：グリニッジ標準時。天文学的な時間
    - 平均太陽時を基準
- ロンドン時間：UTC+00:00 だが、サマータイムが存在

MDN の説明：
>メモ: UTC をグリニッジ標準時 (GMT) と混同してはいけません。両者は常に同じではありません。

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Date#%E6%97%A5%E6%99%82%E3%81%AE%E6%88%90%E5%88%86%E3%81%A8%E3%82%BF%E3%82%A4%E3%83%A0%E3%82%BE%E3%83%BC%E3%83%B3

# 3. Date 型の初期化と比較

## 3.1 初期化時の 'Z' の意味

- `Z` なし
    - 実行環境の時間として解釈される
- `Z` あり
    - UTC として解釈される

下記の例では、
- ① JST 環境で初期化
- ② サモア環境で初期化
- ③ JST 環境で Z あり（= UTC）で初期化

渡した文字列は一致（`Z`あるなしを除く）しているが `getTime()` が異なる。
つまり別の特定の瞬間を表していることが分かる。

![Screenshot 2024-09-06 at 2.57.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/488575/ac38383c-44d5-1ece-b987-921e4b2fb4f9.png)


:::note info
new Date() と空で初期化をするか、`Z` ありの `ISOString` で初期化するかのどちらかにすることで実行環境での想定しない動作を防げることが分かりました。
:::

## 3.2 Date の比較方法
`getTime()` メソッドを利用してから比較しましょう。
同じ時間であっても、別のオブジェクトは別と認識されます。

```js
const date1 = new Date('2024-09-05T05:00:00Z');
const date2 = new Date('2024-09-05T05:00:00Z');

console.log(date1 == date2); // false
console.log(date1 === date2); // false

console.log(date1.getTime() == date2.getTime()); // true
console.log(date1.getTime() === date2.getTime()); // true
```
`>` などの比較に関してはオブジェクト同士での比較も動作します。
しかし、「`===`の比較だから...」など条件分岐があると脳がパンクするので、毎回 `getTime()` してから比較するとするのがシンプルだと思いました。


# 4. タイムゾーンの扱い
## 4.1 date-fns-tz ライブラリの使用
`toZonedTime`

実行環境とタイムゾーンのオフセットを調整します。
したがって、実行環境と引数のタイムゾーンに時差がある場合は、getTime() の値は変わります。

例：
```js
import {
  formatInTimeZone,
  toZonedTime,
  format
} from "https://esm.sh/date-fns-tz";

// 実行環境は全て JST
// UTC の 10-25 10:46:20 で初期化
// → JST の 10-25 19:46:20
const date = new Date("2014-10-25T10:46:20Z");

console.log(date.toISOString());
// "2014-10-25T10:46:20.000Z"
console.log(date.toString());
// "Sat Oct 25 2014 19:46:20 GMT+0900 (Japan Standard Time)"
console.log(date.getTime());
// 1414233980000

// 実行環境JSTとTZ（Asia/Tokyo）の差は 0
// JST で 10-25 19:46 受け取って 0 加算
// * つまり変更はなし
const tokyoDate = toZonedTime(date, "Asia/Tokyo");
console.log(tokyoDate.toISOString(), "toZonedTime tokyo");
// "2014-10-25T10:46:20.000Z" "toZonedTime tokyo"
console.log(tokyoDate.toString(), "toZonedTime tokyo");
// "Sat Oct 25 2014 19:46:20 GMT+0900 (Japan Standard Time)" "toZonedTime tokyo"
console.log(tokyoDate.getTime(), "toZonedTime tokyo");
// 1414233980000 "toZonedTime tokyo"

// 実行環境JSTとTZ（Ameriga/New_York）の差は 13時間
// JST で 10-25 19:46 受け取って 13時間前
// 10-25 10:46 の 13時間 は 10-24 21:46
const nyDate = toZonedTime(date, "America/New_York");
console.log(nyDate.toISOString(), "toZonedTime NY");
// "2014-10-24T21:46:20.000Z" "toZonedTime NY"
console.log(nyDate.toString(), "toZonedTime NY");
// "Sat Oct 25 2014 06:46:20 GMT+0900 (Japan Standard Time)" "toZonedTime ny"
console.log(nyDate.getTime(), "toZonedTime NY");
// 1414187180000 "toZonedTime ny"
```


## 4.2 異なるタイムゾーンのテスト方法

Mac のシステム時間設定を変更することで、異なるタイムゾーンでのテストが可能です。

```shell
% sudo systemsetup -settimezone Asia/Tokyo
% sudo systemsetup -settimezone Pacific/Pago_Pago
```

:::note warn
注意
システム時間の変更は他のアプリケーションにも影響を与えるため、テスト後は必ず元の設定に戻してください。
MTGの時間を間違えるなど発生しえます。
:::

# 参考リンク

https://www.rasin.co.jp/blog/special/gmt-instructionmanual/?srsltid=AfmBOopA4U8uZ0xtOZkweEySRiDVm4XG75omNvmArbvKYuKuL1Jy4MNl

https://www.ryugakuatuk.com/uk-time-zone/

https://qiita.com/labocho/items/5fbaa0491b67221419b4#%E6%AF%94%E8%BC%83%E3%81%99%E3%82%8B%E3%81%A8%E3%81%8D%E3%81%AF-gettime-%E4%BD%BF%E3%81%86

https://qiita.com/suin/items/296740d22624b530f93a

https://zenn.dev/shinkano/articles/6da260427dcd77