タイムゾーンを意識した Day.js オブジェクトの生成

自分でもあまり整理できていなかった部分だったので、今後のために調査しておきました。
(もっと洗練した書き方があれば、教えて頂けると嬉しいです)

## 注意点

Day.js のオブジェクトを生成する際に、タイムゾーンに言及する時、以下の 2 つの文脈が存在します。

- 1. (特に日時文字列を元に生成する場合に) その文字列がどのタイムゾーンでの時刻を表したものか
   - e.g. `2018-01-24T18:53:00` という時刻を解釈する時、これが UTC での時刻なのか、日本での時刻なのか
- 2. 生成されたオブジェクト自身が持つタイムゾーン
   - e.g. 生成した Day.js オブジェクトの `startOf('day')` を呼ぶ時、 UTC での一日の始まりを取得するのか、日本での一日の始まりを取得するのか

前者の方は、文字列をベースにオブジェクト生成するときにだけ問題となってきます。
文字列自体にタイムゾーンを表す情報が含まれていれば、それを用い、含まれていなければ、後者のタイムゾーンと同一のものが用いられます。

現在時刻や、 Unix Timestamp をベースにオブジェクト生成するときは、後者のタイムゾーンだけを考えれば OK です。

後者のタイムゾーンとして、どんなものが用いられるかは、以下に記載する通り、 Day.js オブジェクトの作り方 (やその後の "変換") に依存します。

## ローカルタイムとして扱う場合

Day.js は、デフォルトでは、オブジェクトを生成すると、ローカルタイム扱いになります。

```javascript
// 現在時刻
dayjs()

// 日時文字列 (ISO 8601)
// 対象文字列をローカルタイムでの時刻として解釈します
// ただし、ここにタイムゾーン情報が埋め込まれている場合は、そのタイムゾーンでの時刻として解釈されます
dayjs('2018-01-24T18:53:00')

// Unix Timestamp (milliseconds)
// Unix Timestamp 自体は 1970-01-01 UTC からの経過時刻であり、タイムゾーンの概念がないことに留意
dayjs(1516787580000)

// Unix Timestamp (seconds)
// Unix Timestamp 自体は 1970-01-01 UTC からの経過時刻であり、タイムゾーンの概念がないことに留意
dayjs.unix(1516787580)
```

## UTC として扱う場合

UTC として扱う場合には `utc` プラグインを取り込みます。

```javascript
dayjs.extend(utc)
```

以下のようにオブジェクトを生成すると、 UTC 扱いになります。

```javascript
// 現在時刻
dayjs.utc()

// 日時文字列 (ISO 8601)
// 対象文字列を UTC での時刻として解釈します
// ただし、ここにタイムゾーン情報が埋め込まれている場合は、そのタイムゾーンでの時刻として解釈されます
dayjs.utc('2018-01-24T09:53:00')

// Unix Timestamp (milliseconds)
// Unix Timestamp 自体は 1970-01-01 UTC からの経過時刻であり、タイムゾーンの概念がないことに留意
dayjs.utc(1516787580000)

// Unix Timestamp (seconds)
// Unix Timestamp 自体は 1970-01-01 UTC からの経過時刻であり、タイムゾーンの概念がないことに留意
dayjs.unix(1516787580).utc()
// もしくは
dayjs.utc(1516787580 * 1000)
```

## 指定したタイムゾーンでのローカルタイムとして扱う場合

`utc` プラグインと `timezone` プラグインを取り込みます。

```javascript
dayjs.extend(utc)
dayjs.extend(timezone)
```

以下のようにオブジェクトを生成すると、該当タイムゾーンでのローカルタイム扱いになります。

```javascript
const timezone = 'Asia/Tokyo'

// 現在時刻
dayjs().tz(timezone)

// 日時文字列 (ISO 8601)
// 対象文字列を指定したタイムゾーンでのローカルタイムでの時刻として解釈します
// ※ ここにタイムゾーン情報が埋め込まれている場合の取り扱いは、 Day.js 1.11.5 時点では、
// 動作確認した限りでは、個人的には違和感のあるものだったので、あまり使わないほうがいいかもです
// (`.tz(timezone, true)` による変換をおこなっているのと同等だった)
dayjs.tz('2018-01-24T18:53:00', timezone)

// Unix Timestamp (milliseconds)
// Unix Timestamp 自体は 1970-01-01 UTC からの経過時刻であり、タイムゾーンの概念がないことに留意
dayjs.tz(1516787580000, timezone)

// Unix Timestamp (seconds)
// Unix Timestamp 自体は 1970-01-01 UTC からの経過時刻であり、タイムゾーンの概念がないことに留意
dayjs.unix(1516787580).tz(timezone)
// もしくは
dayjs.tz(1516787580 * 1000, timezone)
```

## デフォルトで指定したタイムゾーンでのローカルタイムとして扱う場合

`utc` プラグインと `timezone` プラグインを取り込みます。

```javascript
dayjs.extend(utc)
dayjs.extend(timezone)
```

デフォルトで使いたいタイムゾーンを指定します。

```javascript
dayjs.tz.setDefault('Asia/Tokyo')
```

このコンテキストの中で、以下のようにオブジェクトを生成すると、該当タイムゾーンでのローカルタイム扱いになります。

```javascript
// 現在時刻
dayjs.tz()

// 日時文字列 (ISO 8601)
// 対象文字列を指定したタイムゾーンでのローカルタイムでの時刻として解釈します
// ※ ここにタイムゾーン情報が埋め込まれている場合の取り扱いは、 Day.js 1.11.5 時点では、
// 動作確認した限りでは、個人的には違和感のあるものだったので、あまり使わないほうがいいかもです
dayjs.tz('2018-01-24T18:53:00')

// Unix Timestamp (milliseconds)
// Unix Timestamp 自体は 1970-01-01 UTC からの経過時刻であり、タイムゾーンの概念がないことに留意
dayjs.tz(1516787580000)

// Unix Timestamp (seconds)
// Unix Timestamp 自体は 1970-01-01 UTC からの経過時刻であり、タイムゾーンの概念がないことに留意
dayjs.unix(1516787580).tz()
// もしくは
dayjs.tz(1516787580 * 1000)
```

## まとめ

タイムゾーン周りはバグりやすく、実装も煩雑になりがちです。

そんな時、世界共通時で統一すれば、エンジニアは幸せになり、世界の消費電力もほんの少し削減できるのになと思うことがあります。

そうしたら、日本では、午後 8 時頃に日が昇り、夜中の 0 時の明るい時 (夜とは!?) に多くの人が出勤し、午後 0-3 時頃に多くの人が就寝します。そして、新年のカウントダウンを世界共通で迎えることができます...！

オーストラリアで夏の 12 月にクリスマスが来るように、慣れの問題だと思うんですけどね〜 少なくともそういう世界線で一度生活してみたいなと思ったりしました。 (了)

---

ウミトロンでは、私たちと一緒に「持続可能な水産養殖を地球に実装する」仲間を積極的に募集しています。
このミッションのもと、テクノロジーを用いて水産養殖の課題に挑む航海に共に出てみませんか?

https://umitron.com/ja/career.html