JavaScript Dateのタイムゾーン指定できない問題とその対策
JavaScriptのDate型では、タイムゾーンを外部から指定できない
- JavaScriptのDate型は、タイムゾーンの情報を持ってはいますが、APIで外から変更することはできません。
- getTimezoneOffset() はあるけど、setTimezoneOffset(timezone) はありません。
- getTimezoneOffset() の値は実行環境のタイムゾーンになります。
- getHours()やgetMinutes()はローカルのタイムゾーンにおける時刻表現を返すので、実行環境によって結果が異なり、問題になる場合があります。
const date = new Date( '2015-05-10T12:00:00.000Z' ); expect( date.getHours() ).toEqual(21); // ローカルタイムゾーンがJSTの場合は動作するが、他の環境では違う結果になる。
対策
以下のようにしてみました。
- Dateの代わりに、 date-with-offset を使う。
- DateWithOffsetをnewするときに、static変数からタイムゾーンを読み込んで使う。
具体的にはこんなユーティリティを作成。
import DateWithOffset from "date-with-offset" const defaultTimezoneOffset = new Date().getTimezoneOffset()*-1; export default class Dates { static date(iso8601String) { return new DateWithOffset( iso8601String, this.getTimezoneOffset() ); } static getTimezoneOffset() { return this.timezoneOffset != null ? this.timezoneOffset : defaultTimezoneOffset; } static setTimezoneOffset(timezoneOffset) { this.timezoneOffset = timezoneOffset; } static resetTimezoneOffset() { this.timezoneOffset = null; } }
ローカルタイムゾーンに依存するテストが動作するところは、以下のようにすることで、どの環境でも同じ結果が返るようになります。
beforeEach( ()=> Dates.setTimezoneOffset(540) ); afterEach( ()=> Dates.resetTimezoneOffset() ); it("ローカルタイムゾーンに依存するテスト", () => { // このテスト内では、ローカルタイムゾーンがJSTになる。 expect( Dates.date("2015-05-10T12:00:00.000Z").getHours() ).toEqual(21); });