Dayjsでタイムゾーン変換

Dayjsを利用する際にタイムゾーンの変換について毎回調べている気がするので記載しておく。

前提としてDayjsのデフォルトタイムゾーンを`JST`としている。

```typescript
import dayjs, { Dayjs } from 'dayjs';
import 'dayjs/locale/ja';
import timezone from 'dayjs/plugin/timezone';
import utc from 'dayjs/plugin/utc';

// UTCプラグインを読み込み
dayjs.extend(utc);
// timezoneプラグインを読み込み
dayjs.extend(timezone);
// 日本語化
dayjs.locale('ja');
// タイムゾーンのデフォルトをJST化
dayjs.tz.setDefault('Asia/Tokyo');
```

# 現在の日時をJSTで表現する
※現在日時 `2024-05-28T22:06:53+09:00` の場合
## OK
```typescript
dayjs().tz().format();
// → 2024-05-28T22:06:53+09:00

dayjs().tz('Asia/Tokyo').format();
// → 2024-05-28T22:06:53+09:00
```
## NG
ローカルタイムゾーンに依存するため`JST`になるとは限らない
```typescript
dayjs().format();
// → ローカルタイムゾーンに依存する
```

# 現在の日時をUTCで表現する
※現在日時 `2024-05-28T22:08:35+09:00` の場合
```typescript
dayjs().tz('utc').format();
// → 2024-05-28T13:08:35Z
```

# 与えたUTCの日時をJSTで表現する
## 与えたUTC日時が `2024-01-01 09:00:00` の場合
### OK
```typescript
dayjs.tz('2024-01-01 09:00:00', 'utc').tz().format();
// → 2024-01-01T18:00:00+09:00

dayjs.tz('2024-01-01 09:00:00', 'utc').tz('Asia/Tokyo').format();
// → 2024-01-01T18:00:00+09:00
```
### NG
```typescript
dayjs('2024-01-01 09:00:00').tz().format();
// → ローカルタイムゾーンに依存する

dayjs('2024-01-01 09:00:00').tz('Asia/Tokyo').format();
// → ローカルタイムゾーンに依存する
```

## 与えたUTC日時が`ISO8601`形式の `2024-01-01T09:00:00Z`の場合
:::note warn
**(2024/05/29時点)`ISO8601` 形式の場合は注意が必要！**
`dayjs.tz(arg)` にISO8601形式の引数を渡すと、タイムゾーン情報を無視してUTC日時に変換されてしまうようです。
issueにも上がっているためバグなのではないかと思います。
https://github.com/iamkun/dayjs/issues/2626
:::


### OK
```typescript
dayjs('2024-01-01T09:00:00Z').tz().format();
// → 2024-01-01T18:00:00+09:00

dayjs('2024-01-01T09:00:00Z').tz('Asia/Tokyo').format();
// → 2024-01-01T18:00:00+09:00
```

### NG
※与えた日時がUTCなので問題が発生していないように見えますが…
```typescript
dayjs.tz('2024-01-01T09:00:00Z', 'utc').tz().format();
// → 2024-01-01T18:00:00+09:00

dayjs.tz('2024-01-01T09:00:00Z', 'utc').tz('Asia/Tokyo').format();
// → 2024-01-01T18:00:00+09:00
```

# 与えたJSTの日時をUTCで表現する
## 与えたJST日時が `2024-01-01 09:00:00` の場合
### OK
```typescript
dayjs.tz('2024-01-01 09:00:00').tz('utc').format();
// → 2024-01-01T00:00:00Z

dayjs.tz('2024-01-01 09:00:00', 'Asia/Tokyo').tz('utc').format();
// → 2024-01-01T00:00:00Z
```
### NG
```typescript
dayjs('2024-01-01 09:00:00').tz('utc');
// → ローカルタイムゾーンに依存する
```
## 与えたJST日時が`ISO8601`形式の `2024-01-01T09:00:00+09:00` の場合
:::note warn
**(2024/05/29時点)`ISO8601` 形式の場合は注意が必要！**
`dayjs.tz(arg)` にISO8601形式の引数を渡すと、タイムゾーン情報を無視してUTC日時に変換されてしまうようです。
issueにも上がっているためバグなのではないかと思います。
https://github.com/iamkun/dayjs/issues/2626
:::

### OK
```typescript
dayjs('2024-01-01T09:00:00+09:00').tz('utc').format();
// → 2024-01-01T00:00:00Z
```

### NG
`-18:00`になってしまっている
```typescript
dayjs.tz('2024-01-01T09:00:00+09:00', 'Asia/Tokyo').tz('utc').format();
// → 2023-12-31T15:00:00Z
```

# まとめ

## dayjs('2024-01-01 09:00:00')
- タイムゾーン情報なしの文字列の場合は、ローカルタイムゾーンで扱われる（動いているマシンのタイムゾーンに依存）
- 但し`ISO8601`形式の文字列を与えた場合はそのタイムゾーンとして扱われる

## dayjs.tz('2024-01-01 09:00:00')
- `tz`の第2引数がない場合は、`dayjs.tz.setDefault`で設定したデフォルトタイムゾーン扱いとなる

## dayjs.tz('2024-01-01 09:00:00', 'Asia/Tokyo')
- `tz`の第2引数で指定したタイムゾーン扱いとなる

## dayjs.tz('2024-01-01T09:00:00Z')
- 現時点(2024/05/29)では、UTC日時に強制的に変換されてしまうため、 `dayjs('2024-01-01T09:00:00Z')` を利用すると良い