Cloudflare WorkersでDayJSのタイムゾーンを制御する
Cloudflare Workersでは、DayJSのタイムゾーン設定が意図通りに機能しないことがあります。この記事では、その原因と、明示的なタイムゾーン指定による実用的な解決策を紹介します。
目次
Cloudflare Workers でアプリケーションを実装する中で、DayJSのタイムゾーンが意図しない設定になる場面がありました。問題と対策について簡単にまとめましたので紹介します。
タイムゾーンの設定をまとめて実行すると、うまく動かない
DayJSでタイムゾーンを設定する際、dayjs.tz.setDefault('Asia/Tokyo')
のようにアプリケーション全体で設定できるような実装を行うことが多いです。しかしWorkersでは期待通りに機能しないことがありました。検索してみると、GitHub Issueやコミュニティフォーラムのディスカッションなどもある様子でした。
いくつかの要因
そもそもの問題として、Cloudflare Workers は通常の Node.js環境とは少し異なる実行環境で、V8エンジンのサンドボックス内で動作します。Cloudflare Workersの公式ドキュメントによると、「ローカルテスト環境では日付関連APIはマシンのローカルタイムゾーンを使用しますが、本番環境では常にUTCが使用される」という特性があることがわかりました。また、「Date.now()は最後のI/O時の時間を返し、コード実行中には進みません」という特性もあるらしく、このあたりも影響しているように感じます。
DayJSの公式ドキュメントなどを確認すると「dayjs.tz.setDefaultは既存のdayjsオブジェクトには影響しません」という記載や、GitHub Issue #1276での「tz.setDefault()がボットの起動時にタイムゾーンを設定せず、使用時に誤った時間を表示する」という報告なども、Workersの実行環境に関連して問題につながっている可能性はありそうです。
明示的なタイムゾーン指定で回避
根本的な原因や解決策を調べきることはできませんでしたが、ひとまず都度タイムゾーンを設定すれば動作することは確認できました。そこで以下のようなヘルパー関数を実装して対応しています。
import dayjs from 'dayjs';
import timezone from 'dayjs/plugin/timezone';
import utc from 'dayjs/plugin/utc';
// プラグインを設定
dayjs.extend(utc);
dayjs.extend(timezone);
dayjs.tz.setDefault('Asia/Tokyo');
// 日本時間変換ヘルパー関数
const toJST = (date: string | Date | undefined): dayjs.Dayjs => {
if (!date) {
return dayjs().tz('Asia/Tokyo');
}
return dayjs(date).tz('Asia/Tokyo');
};
綺麗な実装というわけではありませんが、次のように差し替え可能な形で使えます。根本的な解決策が見つかるまでは、とりあえずこの実装で進めようかと考えてます。
// 変更前 - 環境によって動作不安定
const formattedDate = dayjs(someDate).format('YYYYMMDD');
// 変更後 - あらゆる環境で安定
const formattedDate = toJST(someDate).format('YYYYMMDD');
まとめ
Cloudflare Workers は非常に便利かつ低コストで使えるので、個人開発などで非常に重宝しています。が、時々このような環境の違いにハマることがありますので、ランタイム・実行環境に依存すると思われる機能を組み込むときは慎重になる必要がありそうです。
参考資料
- Cloudflare Workers公式ドキュメント – JavaScript and web standards
- Cloudflare Workers日付処理の問題 – GitHub Issue
- DayJS公式ドキュメント – Timezone
- DayJS公式ドキュメント – Set Default Timezone
- DayJSタイムゾーン問題 – GitHub Issue #1276
- Cloudflare Workersで現在の日付を取得する方法 – Stack Overflow
- DayJSでローカルタイムゾーンへの変換を防ぐ方法 – Stack Overflow
- DayJSのタイムゾーン問題 – Stack Overflow
- Cloudflare Workers Cron Triggers公式ドキュメント