Day.jsの.tz.setDefault()が動かないと思ったけど使い方が間違ってただけだった

2021.08.07

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

吉川@広島です。

dayjsのtimezoneプラグインに関するTips(?)です。

環境

  • node 15.11.0
  • dayjs 1.10.6

Timezoneプラグイン

Timezoneプラグインを使うことで、端末環境のタイムゾーンに左右されず時間を扱うことができます。

Time Zone · Day.js

よくあるユースケースとして、「サーバのタイムゾーンはUTCだけどJSTで時間を扱いたい」といった場合が挙げられます。

Timezoneプラグインを使わない場合

まずはTimezoneプラグインを使わない例です。

// index.js
const dayjs = require('dayjs')

console.log(dayjs().format())

こちらのコードを次のコマンドで実行します。

TZ=utc node index.js

あえて TZ=utc で環境変数TZにutcを指定しています。すると出力は次のようになります。

2021-08-06T14:59:15+00:00

今この記事を書いている時間がJSTの2021/8/6 23:59なので、ちょうど9時間前の時間が出ています。UTC時間ということですね。

Timezoneプラグインを使って.tz('Asia/Tokyo')を指定

TZ=utc でもJSTで時間を出力したいニーズに応えるのが次の例です。

const dayjs = require('dayjs')
const utc = require('dayjs/plugin/utc')
const timezone = require('dayjs/plugin/timezone')

dayjs.extend(utc)
dayjs.extend(timezone)

console.log(dayjs().tz('Asia/Tokyo').format())

Timezoneプラグインを読み込み、 .tz('Asia/Tokyo') で日本のタイムゾーンを指定しています。 こちらのコードを先程と同じコマンドで実行します。

TZ=utc node index.js

出力は以下でした。

2021-08-07T00:04:50+09:00

今、2021/8/7 00:04なので、意図通りの値ですね(日が変わってしまった)。+09:00もUTCを基準として9時間プラス(=日本時間)ということで適切です。

Timezoneプラグインを使って.tz.setDefault('Asia/Tokyo')を指定

ただ、常に日本時間で扱いたいという場合に、dayjsのメソッドを使うたびに毎回 .tz('Asia/Tokyo') を書くのは大変です。そこで、デフォルトのタイムゾーンを設定できるsetDefault()があります。

Set Default Timezone · Day.js

動かない?

では、こちらを使ったコードを書いてみます。

const dayjs = require('dayjs')
const utc = require('dayjs/plugin/utc')
const timezone = require('dayjs/plugin/timezone')

dayjs.extend(utc)
dayjs.extend(timezone)

dayjs.tz.setDefault("Asia/Tokyo")

console.log(dayjs().format())

また同じコマンドで実行します。

TZ=utc node index.js

出力は以下でした。

2021-08-06T15:08:50+00:00

今、00:08なので、12時間前のUTC時間となってしまっていますね。 .setDefault('Asia/Tokyo') が効いていない・・・?

正しい使い方

ということで「dayjs setDefault not working」みたいなキーワードで検索したところ次のissueを発見しました。

dayjs.tz.setDefault doesn't work as expected. · Issue #1195 · iamkun/dayjs

こちらから、「setDefaultを使った場合、.tz()を呼んだ際の挙動に影響を与える」という点を理解しました。

つまり、下記が正です。

const dayjs = require('dayjs')
const utc = require('dayjs/plugin/utc')
const timezone = require('dayjs/plugin/timezone')

dayjs.extend(utc)
dayjs.extend(timezone)

dayjs.tz.setDefault("Asia/Tokyo")

-console.log(dayjs().format())
+console.log(dayjs().tz().format())

このように変更して実行すると出力は以下でした。

2021-08-07T00:13:32+09:00

ちゃんと日本時間を出力してくれました。

つまり、自分は最初 setDefault を .tz() の呼び出し自体を省略できる宣言と勘違いしていたのですが、そうではなく.tz() の引数(= 'Asia/Tokyo' )を省略できるものであり、 .tz() 自体は都度呼んであげる必要があるということでした。

説明がわかりにくかったかもしれませんが、伝わったでしょうか?

同じハマり方をする人がいるかもしれないと思い共有でした。参考になれば幸いです。