JavaScript の日付を特定のタイムゾーンに初期化する方法 質問する

JavaScript の日付を特定のタイムゾーンに初期化する方法 質問する

特定のタイムゾーンの日付時刻を文字列として持っており、これをローカル時刻に変換したいと考えています。ただし、Date オブジェクトでタイムゾーンを設定する方法がわかりません。

例えば、私Feb 28 2013 7:00 PM ET,

var mydate = new Date();
mydate.setFullYear(2013);
mydate.setMonth(02);
mydate.setDate(28);
mydate.setHours(7);
mydate.setMinutes(00);  

私の知る限り、UTC 時間または現地時間を設定できます。しかし、別のタイムゾーンで時間を設定するにはどうすればよいでしょうか?

UTC からのオフセットの加算/減算を使用しようとしましたが、夏時間に対処する方法がわかりません。正しい方向に向かっているかどうかわかりません。

JavaScript で異なるタイムゾーンの時間をローカル時間に変換するにはどうすればよいでしょうか?

ベストアンサー1

背景

JavaScript のDateオブジェクトは内部的には UTC で時間を追跡しますが、通常は実行しているコンピューターのローカル時間で入力を受け入れ、出力を生成します。他のタイムゾーンの時間を操作する機能はほとんどありません。

オブジェクトの内部表現は、うるう秒に関係なく、から経過したミリ秒数を表すDate単一の数値、つまりタイムスタンプです。1970-01-01 00:00:00 UTC

Date オブジェクト自体にはタイムゾーンや文字列形式は保存されません。

オブジェクトのさまざまな関数Dateが使用される場合、コンピュータのローカル タイム ゾーンが内部表現に適用されます。関数が文字列を生成する場合、その文字列の生成方法を決定するためにコンピュータのロケール情報が考慮される場合があります。詳細は関数ごとに異なり、実装固有のものもあります。

Dateオブジェクトが非ローカル タイム ゾーンで実行できる操作は次のとおりです。

  • 任意のタイムゾーンからの数値 UTC オフセットを含む文字列を解析できます。これを使用して解析する値を調整し、UTC 相当を保存します。元のローカル時間とオフセットは結果のDateオブジェクトには保持されません。例:

      var d = new Date("2020-04-13T00:00:00.000+08:00");
      d.toISOString()  //=> "2020-04-12T16:00:00.000Z"
      d.valueOf()      //=> 1586707200000  (this is what is actually stored in the object)
    
  • を実装した環境では、ECMASCript 国際化 API(別名「Intl」) を使用すると、Dateオブジェクトは、特定のタイム ゾーン識別子に合わせて調整されたロケール固有の文字列を生成できます。これは、 のtimeZoneオプションtoLocaleStringとそのバリエーションによって実現されます。ほとんどの実装では、 などの IANA タイム ゾーン識別子がサポートされます'America/New_York'。例:

      var d = new Date("2020-04-13T00:00:00.000+08:00");
      d.toLocaleString('en-US', { timeZone: 'America/New_York' })
      //=> "4/12/2020, 12:00:00 PM"
      // (midnight in China on April 13th is noon in New York on April 12th)
    

    最近のほとんどの環境では、IANAタイムゾーン識別子の完全なセットがサポートされています(互換性表はこちらをご覧ください)。ただし、 Intl でサポートする必要がある識別子は のみであるため'UTC'、古いブラウザや非標準的な環境 (軽量の IoT デバイスなど) をサポートする必要がある場合は慎重に確認する必要があります。

図書館

タイムゾーンの操作に使用できるライブラリはいくつかあります。これらのDateライブラリは、オブジェクトの動作を変えることはできませんが、通常、標準の IANA タイムゾーン データベースを実装し、JavaScript で使用するための関数を提供します。最新のライブラリは、Intl API によって提供されるタイムゾーン データを使用しますが、古いライブラリは、特に Web ブラウザーで実行している場合、データベースが少し大きくなるため、通常オーバーヘッドが発生します。これらのライブラリの一部では、サポートされるタイムゾーンや操作できる日付の範囲によって、データセットを選択的に削減することもできます。

検討すべきライブラリは次のとおりです。

国際ベースのライブラリ

新しい開発では、タイムゾーン データに Intl API を使用する次の実装のいずれかを選択する必要があります。

非国際図書館

これらのライブラリはメンテナンスされていますが、独自のタイムゾーン データをパッケージ化するという負担があり、そのサイズはかなり大きくなる可能性があります。

* 以前は Moment と Moment-Timezone が推奨されていましたが、Moment チームは現在、新規開発にはユーザーが Luxon を選択することを推奨しています。

廃止されたライブラリ

これらのライブラリは正式に廃止されており、今後は使用しないでください。

今後の提案

TC39 暫定提案JavaScript 言語自体で日付と時刻を操作するための新しい標準オブジェクトのセットを提供することを目的としています。これには、タイムゾーン対応オブジェクトのサポートが含まれます。

よくあるエラー

よく試みられるアプローチがいくつかありますが、それらは誤りであり、通常は避けるべきです。

再解析

new Date(new Date().toLocaleString('en', {timeZone: 'America/New_York'}))

上記のアプローチでは、Intl API を正しく使用して特定のタイム ゾーンで文字列を作成していますが、その文字列を誤ってコンストラクターに渡しています。この場合、解析は実装固有になり、完全に失敗する可能性があります。成功した場合、解析中にコンピューターのローカル タイム ゾーンが適用されるため、結果のオブジェクトが間違った時点を表すDate可能性があります。Date

時代の変化

var d = new Date();
d.setTime(d.getTime() + someOffset * 60000);

Date上記のアプローチは、Unix タイムスタンプを他のタイムゾーン オフセットでシフトすることで、オブジェクトのタイムゾーンを操作しようとします。ただし、オブジェクトは UTC でのみ時間を追跡するため、実際にはオブジェクトが異なる時点を表すDateことになります。Date

同じアプローチがコンストラクターで直接使用される場合もありますが、これも無効です。

エポック シフトは、カレンダー演算の記述を避けるためのショートカットとして、日付ライブラリの内部で使用されることがあります。これを行うときは、UTC 以外のプロパティへのアクセスは避ける必要があります。たとえば、シフトすると、 の呼び出しはgetUTCHours許容されますが、 の呼び出しはgetHoursローカル タイム ゾーンを使用するため無効になります。

これは「エポックシフト」と呼ばれます。正しく使用すると、Unix エポック ( 1970-01-01T00:00:00.000Z) は のタイムスタンプに関連付けられなくなり0、オフセットの量だけ別のタイムスタンプにシフトされるからです。

日付ライブラリを作成していない場合は、エポックシフトを行うべきではありません。

エポックシフトの詳細については、このビデオクリップCppCon 2015 の Greg Miller によるビデオです。このビデオはtime_tC++ に関するものですが、説明と問題は同じです。(JavaScript ユーザーの方は、Greg が について言及するたびにtime_t、「オブジェクト」について考えてくださいDate。)

「UTC日付」を作成しようとしています

var d = new Date();
var utcDate = new Date(Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()));

この例では、 と は両方ともd同一utcDateです。 はすでに UTC に基づいているため、 を構築する作業はutcDate冗長でした。 、、または関数dの出力を調べると、両方の変数に同一の値が示されます。toISOStringgetTimevalueOf

同様のアプローチとしては、次のようなものがあります。

var d = new Date();
var utcDate = new Date(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds());

このアプローチでは、Dateローカル時間値が期待されるコンストラクタに UTC 値が渡されます。結果のDateオブジェクトは、完全に異なる時点を表します。これは、前述のエポックシフトと本質的に同じ結果であるため、避ける必要があります。

UTC ベースのDateオブジェクトを取得する正しい方法は、単に ですnew Date()。UTC での文字列表現が必要な場合は を使用しますnew Date().toISOString()

おすすめ記事