JavaScriptでgetTimezoneOffset()を使ったタイムゾーン変換

JavaScriptでgetTimezoneOffset()を使ったタイムゾーン変換 JS
この記事は約19分で読めます。

【サイト内のコードはご自由に個人利用・商用利用いただけます】

この記事では、プログラムの基礎知識を前提に話を進めています。

説明のためのコードや、サンプルコードもありますので、もちろん初心者でも理解できるように表現してあります。

基本的な知識があればサンプルコードを活用して機能追加、目的を達成できるように作ってあります。

※この記事は、一般的にプロフェッショナルの指標とされる『実務経験10,000時間以上』を凌駕する現役のプログラマチームによって監修されています。

サイト内のコードを共有する場合は、参照元として引用して下さいますと幸いです

※Japanシーモアは、常に解説内容のわかりやすさや記事の品質に注力しております。不具合、分かりにくい説明や不適切な表現、動かないコードなど気になることがございましたら、記事の品質向上の為にお問い合わせフォームにてご共有いただけますと幸いです。
(送信された情報は、プライバシーポリシーのもと、厳正に取扱い、処分させていただきます。)

●JavaScriptでのタイムゾーン取得方法

JavaScriptを使ってWeb開発をしていると、必ずと言っていいほどタイムゾーンの扱いに頭を悩ませたことがあるのではないでしょうか。

特に、グローバルなサービスを開発する際には、タイムゾーンの違いによる時刻のずれを適切に処理することが求められます。

そこで、本記事ではJavaScriptでタイムゾーンを取得する方法について、詳しく解説していきたいと思います。

JavaScriptでタイムゾーンを扱う際に欠かせないのが、getTimezoneOffset()メソッドです。

○getTimezoneOffset()の使い方

getTimezoneOffset()は、Date オブジェクトのメソッドの一つで、現在の日付と時刻に基づいて、UTCとの時差をミリ秒単位で返します。

つまり、このメソッドを使えば、ユーザーのブラウザに設定されているタイムゾーンを取得することができるんです。

getTimezoneOffset()の使い方はとてもシンプルです。

Date オブジェクトのインスタンスに対して、getTimezoneOffset()を呼び出すだけ。

返り値は、UTCとの時差を分単位で表した数値となります。

○サンプルコード1:現在のタイムゾーンオフセットを取得する

では早速、getTimezoneOffset()を使って、現在のタイムゾーンオフセットを取得してみましょう。

const date = new Date();
const timezoneOffset = date.getTimezoneOffset();
console.log(`現在のタイムゾーンオフセットは${timezoneOffset}分です。`);

実行結果は次のようになります。

現在のタイムゾーンオフセットは-540分です。

この結果から、現在のタイムゾーンがUTCより9時間(540分)進んでいることがわかります。

日本の標準時は、UTCより9時間進んでいるため、この結果は日本のタイムゾーンを反映したものといえるでしょう。

●サマータイム期間中の注意点

JavaScriptでタイムゾーンを扱う際に、もう一つ注意しなければならないのがサマータイム期間中の挙動です。

サマータイムを採用している国や地域では、夏の間、時計を1時間進めるため、タイムゾーンオフセットが変化します。

このサマータイムによるオフセットの変化を考慮しないと、意図しない時刻になってしまうことがあるんです。

特に、サーバーサイドとクライアントサイドでタイムゾーンを混同すると、データの不整合などの深刻な問題につながりかねません。

○サマータイム期間中のずれと判定方法

それでは、サマータイム期間中のタイムゾーンオフセットのずれを確認し、サマータイム期間かどうかを判定する方法について見ていきましょう。

サマータイム期間中は、通常のオフセットから1時間分だけずれるため、その差分を利用することで、サマータイム期間かどうかを判断することができます。

具体的には、1月1日と7月1日のオフセットを比較し、その差が1時間(60分)であればサマータイム期間と判定できるわけです。

○サンプルコード2:サマータイム期間かどうかを判定する

コードで見てみましょう。

次のサンプルコードは、現在の日時がサマータイム期間かどうかを判定するものです。

function isDaylightSavingTime(date) {
  const january = new Date(date.getFullYear(), 0, 1);
  const july = new Date(date.getFullYear(), 6, 1);
  const stdTimezoneOffset = Math.max(january.getTimezoneOffset(), july.getTimezoneOffset());
  const isDST = date.getTimezoneOffset() < stdTimezoneOffset;
  return isDST;
}

const now = new Date();
console.log(isDaylightSavingTime(now) ? "現在サマータイム期間です" : "現在サマータイム期間ではありません");

実行結果(サマータイム期間の場合)

現在サマータイム期間です

実行結果(サマータイム期間でない場合)

現在サマータイム期間ではありません

このコードでは、1月1日と7月1日のオフセットを比較し、その大きい方を標準のオフセットとみなしています。

そして、現在の日時のオフセットがその標準オフセットより小さければ、サマータイム期間と判定するという仕組みです。

○サンプルコード3:サマータイム期間中のオフセット値を取得する

サマータイム期間中のオフセット値を取得するには、次のようなコードを使います。

function getDSTOffset(date) {
  const january = new Date(date.getFullYear(), 0, 1);
  const july = new Date(date.getFullYear(), 6, 1);
  const stdTimezoneOffset = Math.max(january.getTimezoneOffset(), july.getTimezoneOffset());
  const dstOffset = stdTimezoneOffset - date.getTimezoneOffset();
  return dstOffset;
}

const now = new Date();
const dstOffset = getDSTOffset(now);
console.log(`現在のサマータイムオフセットは${dstOffset}分です`);

実行結果(サマータイム期間の場合)

現在のサマータイムオフセットは60分です

実行結果(サマータイム期間でない場合)

現在のサマータイムオフセットは0分です

このように、サマータイム期間中のオフセット値は、標準のオフセットとの差分で求めることができます。

サマータイム期間は60分(1時間)ずれるため、その差分が60分になるわけですね。

●UTC時刻との変換方法

JavaScriptを使ったWeb開発では、サーバーとクライアントの間でデータをやりとりする際に、しばしばUTC時刻を使用します。

UTCはUniversal Coordinated Timeの略で、世界共通の基準時間を表しているんです。

クライアントサイドのJavaScriptで取得した日時情報は、基本的にローカルタイムゾーンに基づいているため、そのままサーバーに送信してしまうと、タイムゾーンの違いから思わぬ不具合を引き起こす可能性があります。

そこで重要になるのが、ローカル時刻とUTC時刻を相互に変換する方法です。

JavaScriptにはUTC時刻を扱うためのメソッドが用意されているので、それを利用することで、タイムゾーンの違いを吸収し、サーバーとの時刻のずれを解消することができるわけですね。

○ローカル時刻からUTC時刻への変換

まずは、ローカル時刻をUTC時刻に変換する方法から見ていきましょう。

JavaScriptのDateオブジェクトには、UTC時刻を扱うためのメソッドがいくつか用意されています。

getUTCDate()、getUTCDay()、getUTCFullYear()、getUTCHours()、getUTCMilliseconds()、getUTCMinutes()、getUTCMonth()、getUTCSeconds()など、ローカル時刻を取得するメソッドのUTC版が存在するんです。

これらのメソッドを使えば、ローカル時刻をUTC時刻に変換することができます。

たとえば、ローカル時刻の2023年4月1日12時34分56秒をUTC時刻に変換するには、次のようなコードを書きます。

○サンプルコード4:ローカル時刻をUTC時刻に変換する

const localDate = new Date(2023, 3, 1, 12, 34, 56);
const utcDate = new Date(Date.UTC(localDate.getFullYear(), localDate.getMonth(), localDate.getDate(), localDate.getHours(), localDate.getMinutes(), localDate.getSeconds()));

console.log(localDate.toString());
console.log(utcDate.toString()); 

実行結果

Sat Apr 01 2023 12:34:56 GMT+0900 (日本標準時)  
Sat Apr 01 2023 03:34:56 GMT+0000 (Coordinated Universal Time)

このコードでは、まずローカル時刻の日時情報をDateオブジェクトとして作成し、それをDate.UTC()メソッドに渡すことで、UTC時刻に変換しています。

Date.UTC()メソッドは、引数で指定された日時情報をUTCベースのミリ秒単位のタイムスタンプに変換するんです。

変換結果を見ると、ローカル時刻の2023年4月1日12時34分56秒が、UTC時刻の2023年4月1日03時34分56秒に変換されていることがわかりますね。

9時間の時差が反映されているわけです。

○UTC時刻からローカル時刻への変換

次に、UTC時刻からローカル時刻への変換方法について説明しましょう。

UTCベースのタイムスタンプをローカル時刻に変換するには、DateオブジェクトのコンストラクタにUTCのタイムスタンプを渡せば、自動的にローカルタイムゾーンに変換してくれます。

たとえば、UTC時刻の2023年4月1日12時34分56秒に対応するタイムスタンプをローカル時刻に変換するには、次のようなコードになります。

○サンプルコード5:UTC時刻をローカル時刻に変換する

const utcTimestamp = Date.UTC(2023, 3, 1, 12, 34, 56);
const localDate = new Date(utcTimestamp);

console.log(localDate.toString());

実行結果

Sat Apr 01 2023 21:34:56 GMT+0900 (日本標準時)

Date.UTC()メソッドで作成したUTCのタイムスタンプを、Dateオブジェクトのコンストラクタに渡すことで、自動的にローカルタイムゾーンに変換されるんです。

実行結果を見ると、UTC時刻の2023年4月1日12時34分56秒が、ローカル時刻(日本標準時)の2023年4月1日21時34分56秒に変換されていることがわかります。

9時間の時差が反映されて、自動的にローカルタイムゾーンに合わせられているわけですね。

●よくあるエラーと対処法

JavaScriptでタイムゾーンを扱っていると、思わぬエラーに遭遇することがあります。

特に、初心者の頃は原因がわからずに頭を抱えてしまったという経験がある方も多いのではないでしょうか。

ここでは、JavaScriptのタイムゾーン処理でよく遭遇するエラーとその対処法について、具体的なコード例を交えながら解説していきたいと思います。

このエラーの原因を理解し、適切に対処できるようになることが、タイムゾーンを適切に扱うための第一歩となるでしょう。

○タイムゾーンオフセット値が9時間ずれる問題

JavaScriptでgetTimezoneOffset()メソッドを使ってタイムゾーンオフセットを取得する際に、よくある問題の一つが、オフセット値が9時間ずれてしまうというものです。

たとえば、次のようなコードを実行すると、本来は-540分(-9時間)になるはずのオフセット値が、+540分(+9時間)になってしまうことがあります。

const date = new Date();
const timezoneOffset = date.getTimezoneOffset();
console.log(timezoneOffset); // 540 (期待値は-540)

この問題は、多くの場合、DateオブジェクトをUTCベースで作成してしまっていることが原因です。

たとえば、次のようなコードを実行すると、上記の問題が再現されます。

const date = new Date(Date.UTC(2023, 3, 1, 12, 34, 56));
const timezoneOffset = date.getTimezoneOffset();
console.log(timezoneOffset); // 540 (期待値は-540)

この問題を解決するには、DateオブジェクトをUTCベースではなく、ローカルタイムベースで作成する必要があります。

つまり、Date.UTC()メソッドを使わずに、Dateオブジェクトのコンストラクタに直接日時情報を渡せば良いわけです。

const date = new Date(2023, 3, 1, 12, 34, 56);
const timezoneOffset = date.getTimezoneOffset();
console.log(timezoneOffset); // -540 (期待通り)  

このように、Dateオブジェクトをローカルタイムベースで作成することで、getTimezoneOffset()メソッドが正しいオフセット値を返すようになります。

○getMonth()やgetDate()の戻り値がずれる問題

JavaScriptのDateオブジェクトのgetMonth()メソッドやgetDate()メソッドを使う際に、しばしば戻り値がずれてしまうという問題に遭遇します。

たとえば、次のようなコードを実行すると、getMonth()の戻り値が4(5月)ではなく3(4月)になってしまいます。

const date = new Date(2023, 4, 1);
console.log(date.getMonth()); // 3 (期待値は4)

同様に、getDate()メソッドも、期待した日付と1日ずれた値を返すことがあります。

const date = new Date(2023, 3, 32);
console.log(date.getDate()); // 2 (期待値は1)

これらの問題は、JavaScriptのDateオブジェクトの仕様に起因するものです。

getMonth()メソッドは0から11の範囲の値を返し、0が1月、11が12月を表します。

また、日付の指定が月の末日を超えた場合は、自動的に繰り上げられます。

したがって、上記の問題を避けるためには、月や日付の指定には注意が必要です。

月は0から11の範囲で指定し、日付は月の末日を超えないようにするのがポイントですね。

const date1 = new Date(2023, 3, 1); // 2023年4月1日
console.log(date1.getMonth()); // 3 (期待通り) 

const date2 = new Date(2023, 3, 30); // 2023年4月30日
console.log(date2.getDate()); // 30 (期待通り)

このように、JavaScriptのDateオブジェクトの仕様を理解し、適切に月や日付を指定することが、エラーを避けるための鍵となります。

○日付文字列のフォーマットが意図しない結果になる問題

JavaScriptでDateオブジェクトを文字列に変換する際に、意図しないフォーマットになってしまうという問題もよく見られます。

たとえば、次のようなコードを実行すると、日付の文字列表現が “Sat Apr 01 2023” のようなフォーマットになってしまいます。

const date = new Date(2023, 3, 1);
console.log(date.toString()); // "Sat Apr 01 2023 00:00:00 GMT+0900 (日本標準時)" 

この問題は、Dateオブジェクトのデフォルトの文字列表現が、ロケールに依存するためです。

つまり、ユーザーの環境によって、日付の文字列表現が変わってしまうわけです。

この問題を避けるためには、明示的に日付のフォーマットを指定する必要があります。

たとえば、次のようにtoISOString()メソッドを使えば、ISO 8601形式の文字列表現を得ることができます。

const date = new Date(2023, 3, 1);
console.log(date.toISOString()); // "2023-03-31T15:00:00.000Z"

また、独自のフォーマットを適用したい場合は、Dateオブジェクトのget系メソッドを使って年、月、日などの値を取得し、それらを組み合わせて文字列を構築するのが一般的です。

const date = new Date(2023, 3, 1);
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, "0");
const day = String(date.getDate()).padStart(2, "0");
console.log(`${year}-${month}-${day}`); // "2023-04-01"

このように、日付のフォーマットを明示的に指定することで、ロケールに依存しない一貫した文字列表現を得ることができるようになります。

●getTimezoneOffset()の応用的な使用例

これまで、JavaScriptのgetTimezoneOffset()メソッドの基本的な使い方や、サマータイム期間中の挙動、UTC時刻との変換方法などについて詳しく見てきました。

ここからは、getTimezoneOffset()メソッドのより実践的な使用例について紹介していきたいと思います。

実際の開発現場では、タイムゾーンを考慮したさまざまな機能を実装することが求められます。

たとえば、ユーザーの現在地に基づいて現在時刻を表示したり、異なるタイムゾーン間の時差を計算したり、特定の都市の現在時刻を取得したりといったことです。

これらの機能を実装するためには、getTimezoneOffset()メソッドを駆使し、タイムゾーンの差異を適切に処理する必要があります。

ここでは、そうした実践的なユースケースに焦点を当て、具体的なコード例を交えながら解説していきます。

○サンプルコード6:任意のタイムゾーンでの現在時刻を取得する

まずは、任意のタイムゾーンでの現在時刻を取得する方法から見ていきましょう。

たとえば、アメリカのニューヨークの現在時刻を取得したいとします。

ニューヨークのタイムゾーンはUTC-5なので、まずはUTCの現在時刻を取得し、そこから5時間分のオフセットを加算することで、ニューヨークの現在時刻を求めることができます。

function getCurrentTimeInTimezone(timezoneOffset) {
  const now = new Date();
  const utcTime = now.getTime() + (now.getTimezoneOffset() * 60000);
  const targetTime = new Date(utcTime + (3600000 * timezoneOffset));
  return targetTime.toLocaleString();
}

const newYorkTime = getCurrentTimeInTimezone(-5);
console.log(`ニューヨークの現在時刻は${newYorkTime}です`);

実行結果(実行時の日時によって異なります)

ニューヨークの現在時刻は4/1/2023, 10:30:45 AMです

このコードでは、まず現在のUTCのタイムスタンプを取得し、そこにタイムゾーンのオフセット分だけ加算することで、目的のタイムゾーンでのタイムスタンプを求めています。

そのタイムスタンプをDateオブジェクトに変換し、toLocaleString()メソッドで文字列化することで、指定したタイムゾーンでの現在時刻を取得しているわけです。

○サンプルコード7:2つの時刻の時差を計算する

次に、2つの時刻の時差を計算する方法を見ていきましょう。異なるタイムゾーンの時刻を比較するためには、それぞれの時刻をUTCに揃える必要があります。

次のコードは、ニューヨークとロンドンの現在時刻の時差を計算するサンプルです。

function getTimeDifference(timezone1, timezone2) {
  const now = new Date();
  const utcTime = now.getTime() + (now.getTimezoneOffset() * 60000);
  const time1 = new Date(utcTime + (3600000 * timezone1)).getTime();
  const time2 = new Date(utcTime + (3600000 * timezone2)).getTime();
  const diffInHours = Math.abs(time1 - time2) / 3600000;
  return diffInHours;
}

const newYorkTimezone = -5;
const londonTimezone = 0;
const timeDifference = getTimeDifference(newYorkTimezone, londonTimezone);
console.log(`ニューヨークとロンドンの時差は${timeDifference}時間です`);

実行結果

ニューヨークとロンドンの時差は5時間です

このコードでは、ニューヨークとロンドンのタイムゾーンオフセットをそれぞれ-5と0として指定し、それぞれのタイムゾーンでの現在時刻のタイムスタンプを取得しています。

そして、その差分をミリ秒単位で求め、3600000(1時間のミリ秒数)で割ることで、時差を時間単位で算出しているわけです。

○サンプルコード8:指定した都市の現在時刻を取得する

最後に、指定した都市の現在時刻を取得する方法を紹介します。

これは、サンプルコード6の応用編とも言えるでしょう。

次のコードは、指定した都市名に対応するタイムゾーンを定義したオブジェクトを用意し、そのタイムゾーンでの現在時刻を取得するサンプルです。

const timezones = {
  "ニューヨーク": -5,
  "ロンドン": 0,
  "東京": 9,
  "シドニー": 10
};

function getCurrentTimeInCity(city) {
  const now = new Date();
  const utcTime = now.getTime() + (now.getTimezoneOffset() * 60000);
  const timezoneOffset = timezones[city];
  const targetTime = new Date(utcTime + (3600000 * timezoneOffset));
  return targetTime.toLocaleString();
}

const cities = ["ニューヨーク", "ロンドン", "東京", "シドニー"];
cities.forEach(city => {
  const currentTime = getCurrentTimeInCity(city);
  console.log(`${city}の現在時刻は${currentTime}です`);
});

実行結果(実行時の日時によって異なります)

ニューヨークの現在時刻は4/1/2023, 10:35:20 AMです
ロンドンの現在時刻は4/1/2023, 3:35:20 PMです  
東京の現在時刻は4/2/2023, 12:35:20 AMです
シドニーの現在時刻は4/2/2023, 1:35:20 AMです

このコードでは、都市名とタイムゾーンのオフセットを対応付けたtimezonesオブジェクトを定義し、指定された都市名に対応するタイムゾーンでの現在時刻を取得しています。

こうすることで、世界各地の現在時刻を簡単に取得することができるわけです。

まとめ

本記事では、JavaScriptでタイムゾーンを適切に扱うための基本的な知識と実践的なテクニックについて詳しく解説してきました。

JavaScriptでタイムゾーンを扱うことは、一見すると複雑で難しく感じるかもしれません。

しかし、本記事で紹介した基本的な知識と実践的なテクニックを身につけることで、タイムゾーンに関する問題を適切に解決し、より堅牢で使いやすいWebアプリケーションを開発することができるでしょう。

本記事がJavaScriptでタイムゾーンを扱うすべてのエンジニアにとって、実践的な指針となることを願っています。