For

2022.12.19

JavaScript(TypeScript)でUTCの日付データをJST(日本標準時間)で表示する方法とタイムゾーンとの関係

タイムゾーン

JavaScriptで日付を扱う場合、Dateオブジェクトで初期化して扱うことがそれなりにあるかと思いますが、扱う日付データ自体のタイムゾーンとJavaScriptが実行される環境のタイムゾーンを意識する必要があります。

この記事では、NestJS(TypeScript)で構築したバックエンドでJSTに変換した値をフロントエンドにレスポンスとして返すという状況を例に考えます。

環境

扱う日付データのタイムゾーン:UTC
バックエンド(NestJS)のコンテナのタイムゾーン:UTC
※AWSなどでバックエンドのコンテナが東京リージョンに配置されていてもコンテナのタイムゾーンがUTCの場合はUTCとして考えることに注意

JSTにする方法

バックエンドで扱う日付データをDateオブジェクトで初期化したいですが、このDateオブジェクトについて補足です。
Dateオブジェクトには toLocaleString() メソッドにtimeZoneオプションが存在しますが、Dateオブジェクト自体の設定にtimeZoneオプションは存在しないため、文字列として出力するときにタイムゾーンを設定することになります。

JavaScript_____sample_____// 日付の初期化
const date = new Date('12/8/2022, 5:00:00 AM')

// 出力
console.log(date.toLocaleString('ja-JP', {
  timeZone: 'Asia/Tokyo',
}))

// 結果
// 2022/12/8 14:00:00

// ZeroPaddingしたい場合の出力
console.log(date.toLocaleString('ja-JP', {
  timeZone: 'Asia/Tokyo',
  year: 'numeric',
  month: '2-digit',
  day: '2-digit',
  hour: '2-digit',
  minute: '2-digit',
  second: '2-digit'
}))

// 結果
// 2022/12/08 14:00:00


やっていることはとてもシンプルですが、ここで意識するのがJavaScriptの実行環境であるNestJSコンテナのタイムゾーンです。
上記のコードで期待したJSTでの出力できているのは、実行環境のタイムゾーンがUTCで toLocaleString() に適用されるデフォルトのタイムゾーンがUTCとなるためであり、UTCをJSTとして出力するため+9時間された時間が出力されています。
たとえばブラウザ上で実行されるフロントエンドで上記の処理を実行すると、実行環境がJSTとなるため、期待した結果が得られません。

フロントエンドで変換する場合

上記の例のほか、よくあるのはフロントエンドで表示するときにJSTに変換することが考えられます。
この場合は実行環境はユーザーのブラウザとなるため、日本国内で実行されたらJavaScriptの実行環境はJSTということになり、上記と同じコードを実行すると以下のようになります。

JavaScript_____sample_____// 日付の初期化
const date = new Date('12/8/2022, 5:00:00 AM')

// 出力
console.log(date.toLocaleString('ja-JP', {
  timeZone: 'Asia/Tokyo',
}))

// 結果
// 2022/12/8 5:00:00


これは実行環境がJSTで toLocaleString() のオプションで timeZone: 'Asia/Tokyo' を指定しており、 toLocaleString() からの視点ではデフォルトで timeZone: 'Asia/Tokyo' のものを timeZone: 'Asia/Tokyo' として出力しようとしたため、なにも変換されていないという状況です。

そのため、JST環境でUTCの日付データをJSTに変換するには、下記のように実行環境とUTCとの差分をもとに実行環境に適切な値を出力するという処理が必要になります。

JavaScript_____sample_____// 日付の初期化
const utcDate = new Date('12/8/2022, 5:00:00 AM')
// 実行環境とUTCとの差分(単位:時間)を取得
const timezoneOffset = new Date().getTimezoneOffset() + (9 * 60) * 60 * 1000
// 実行環境とUTCとの差分をUTC時間に足して日付を初期化
const date = new Date(utcDate.getTime() + timezoneOffset)

// 出力
console.log(date.toLocaleString('ja-JP'))

// 結果
// 2022/12/8 14:00:00