📆

UTC の値を任意のタイムゾーンの日時に変換したい時は dayjs.tz(date) ではなく dayjs(date).tz() を使おう

2022/11/22に公開約4,000字

Day.js の.tz.setDefault()が動かないと思ったけど使い方が間違ってただけだった | DevelopersIO をしっかり読んだ上で変なところでハマった可哀想な人の雑記です。

TL; DR

  • dayjs.tz(date) 👉 date の日時そのまま tz.setDefault() で設定したタイムゾーンの日時として返す。 ref: Parsing in Zone · Day.js
  • dayjs(date).tz() 👉 datetz.setDefault() で設定したタイムゾーンの日時に変換して返す。 ref: Converting to Zone · Day.js
  • 現在の日時のインスタンスを生成する時は dayjs.tz(undefined) でも dayjs(undefined).tz() でも同じ結果が返る。
  • 公式のドキュメントをちゃんと読もう。

dayjs.tz()dayjs().tz() の使い方を間違えていた

dayjs.tz.setDefault() でデフォルトのタイムゾーンを設定している時、現在の日時のインスタンスを生成する時は dayjs.tz() でも dayjs().tz() でも同じ結果が返る。ただし、例えば ISO8601 拡張形式の UTC の日時の文字列 date を引数に渡す時は dayjs.tz(date) だと UTC の日時そのままデフォルトのタイムゾーンが設定される。なので、UTC をデフォルトのタイムゾーンの日時に変換したい時は dayjs(date).tz() を使う。

※ OS とブラウザのタイムゾーンも "Asia/Tokyo" (JST) だと tz.setDefault() が効いているのか分かりにくいので、 "America/New_York" (EST) に変更して検証しています。

import dayjs from "dayjs";
import utc from "dayjs/plugin/utc";
import timezone from "dayjs/plugin/timezone";

dayjs.extend(utc);
dayjs.extend(timezone);
dayjs.tz.setDefault("Asia/Tokyo");

const date = "2022-11-22T00:00:00Z";
dayjs.tz(date).format(); // 2022-11-22T00:00:00+09:00 😇
dayjs(date).tz().format(); // 2022-11-22T09:00:00+09:00 👍

// Assume the current date and time is "Mon Nov 21 2022 19:00:00 GMT-0500 (Eastern Standard Time)"
dayjs.tz(undefined).format(); // 2022-11-22T09:00:00+09:00
dayjs(undefined).tz().format(); // 2022-11-22T09:00:00+09:00

それぞれの挙動の違いはちゃんと公式ドキュメントに書いてあった 🙈


ついでにハマったポイント

なんか OS のタイムゾーン変えて検証してみたら tz.setDefault() のタイムゾーンが効いてない気がしたけどそんなことはなかった

OS (とブラウザ) のタイムゾーンを EST にした状態で dayjs(date).tz() のインスタンスをそのまま console.log して確認すると、時間は JST になっているが GMT-0500 (Eastern Standard Time)と書かれているためパッと見 EST が適用されているように見えて焦る。

しかしオブジェクトを展開するとちゃんと dayjs.tz.setDefault('Asia/Tokyo') したタイムゾーンが設定されていて、なおかつ format の結果も JST になっていた。

dayjs(null) はエラー、 現在の日時を引数ありで返したい時は dayjs(undefined)dayjs(new Date())

dayjstimezone プラグインで拡張した状態でラップした関数を定義した時に、 引数が必須の dayjs.tz() に引数なしで現在の日時を返すようにするためにデフォルトの引数を null にしていたらエラーになった。

import type { ConfigType, Dayjs } from "dayjs";
import dayjs from "dayjs";
import utc from "dayjs/plugin/utc";
import timezone from "dayjs/plugin/timezone";

dayjs.extend(utc);
dayjs.extend(timezone);
dayjs.tz.setDefault("Asia/Tokyo");

// Will return the error "Invalid Date" when the argument is null 😇
export const customDayjs = (date: ConfigType = null): Dayjs => {
  return dayjs.tz(date);
};

引数が undefined だと現在の日時が返る。

...

// Will return the current date and time when the argument is undefined 👍
export const customDayjs = (date: ConfigType = undefined): Dayjs => {
  return dayjs.tz(date)
}

Day.js の公式ドキュメントにも書いてあるのでちゃんと読もう。

Day.js treats dayjs(null) as an invalid input.

参考リンク

GitHubで編集を提案

Discussion

ログインするとコメントできます