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


232

文字列として特定のタイムゾーンの日付時刻があり、これを現地時間に変換したい。しかし、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
日付オブジェクトにはタイムゾーンがなく、UTCです。
RobG

回答:


352

バックグラウンド

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 Apring 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言語自体に日付と時刻を操作するための標準オブジェクトの新しいセットを提供することを目的とします。これには、タイムゾーン対応オブジェクトのサポートが含まれます。


1
以来、「出力/パース」を「表現する」に変更してください表すタイムスタンプがタイムゾーンに依存しない
Bergi

1
@Bergi-私はこれを考え直し、あなたに同意します。それに応じて私の答えを更新しました。
Matt Johnson-Pint 2013年

1
Firebugコンソールでこれを行うと var date_time = new Date()、の値date_timeは(AESTでは私にとって)Date {Sun Aug 21 2016 22:18:47 GMT+1000 (AEST)}なので、タイムゾーン格納されているようです。date_timeタイムゾーンを含めずに、純粋にUTC時間であることをどのように確認できますか?
user1063287

うーん、この回答(stackoverflow.com/a/8047885/1063287)によると、これは次のとおりです new Date().getTime();
。– user1063287

1
@ user1063287- toStringメソッドは、ホストのタイムゾーンオフセットを使用して、「ローカル」タイムゾーンの日付と時刻を生成します。日付オブジェクト自体には、1970-01-01T00:00:00Zからのオフセットである時刻値があるため、事実上UTCになります。UTCの日付と時刻を表示するには、toISOStringを使用します
RobG 2016

69

マットジョンソンが言ったように

使用を最新のWebブラウザーに制限できる場合は、特別なライブラリーなしで以下を実行できます。

new Date().toLocaleString("en-US", {timeZone: "America/New_York"})

これは包括的なソリューションではありませんが、出力変換のみが必要な多くのシナリオ(UTCまたは現地時間から特定のタイムゾーンへの変換で、他の方向への変換は必要ありません)で機能します。

そのため、ブラウザーは日付の作成時にIANAタイムゾーンを読み取ることができないか、既存のDateオブジェクトのタイムゾーンを変更するメソッドを持っていますが、ハックがあるようです:

function changeTimezone(date, ianatz) {

  // suppose the date is 12:00 UTC
  var invdate = new Date(date.toLocaleString('en-US', {
    timeZone: ianatz
  }));

  // then invdate will be 07:00 in Toronto
  // and the diff is 5 hours
  var diff = date.getTime() - invdate.getTime();

  // so 12:00 in Toronto is 17:00 UTC
  return new Date(date.getTime() + diff);

}

// E.g.
var there = new Date();
var here = changeTimezone(there, "America/Toronto");

console.log(`Here: ${here.toString()}\nToronto: ${there.toString()}`);


6
なぜこの答えがもっと愛されないのかと思っています。私の目的にとって、それは絶対に最良の解決策です。私のアプリでは、すべての日付がUTCですが、UIで明示的なIANAタイムゾーンで入力または出力する必要があります。この目的のために、私はこのソリューションを使用し、それは完全に機能します。シンプルで効果的な標準。
ロジデリック

2
@logidelicかなり新しい投稿です。正直に言うとtoLocaleString、逆効果を達成するために使用できると思ったとき、私は自分自身を驚かせました。そうです、これは一般的な知識です。それについての記事を書いて、私に言及してください:-)
commonpike

1
まだGMTになっていないノード環境の場合、上記のコードをvar invdate = new Date(date.toLocaleString( 'en-US'、{timeZone:ianatz}));から変更する必要があります。into var invdate = new Date($ {date.toLocaleString( 'en-US'、{timeZone:ianatz})} GMT`);
マイクP.

5
ブラウザはtoLocaleStringの出力を解析する必要がないため、誤った前提に基づいています。
RobG

3
「...なぜこの答えが愛を集めないのか?」- Dateそれが返すオブジェクトは嘘なので。示されている例でも、文字列出力にはローカルマシンのタイムゾーンが含まれます。私のコンピューターでは、両方の結果に "GMT-0700(太平洋夏時間)"と表示されます。これは最初の1つ(トロントは実際には東部標準時です)に対してのみ正しいです。文字列出力だけでなく、Dateオブジェクト内に保持されているタイムスタンプは別の時点にシフトしました。これ便利なテクニックですが、多くの警告が伴いDateます-主にオブジェクト関数は通常の出力を持たないということです。
Matt Johnson-Pint

30

new Date()たとえば、タイムゾーンオフセットを指定できます。

new Date('Feb 28 2013 19:00:00 EST')

または

new Date('Feb 28 2013 19:00:00 GMT-0500')

以来Date店舗UTC時刻(すなわちgetTimeUTCで返します)は、Javascriptを彼らはUTCに時間を変換すると、次のようなものを呼び出したときにtoString私が使用している場合、すなわち、JavascriptをブラウザのローカルタイムゾーンにUTC時刻に変換し、ローカルタイムゾーンの文字列を返します。UTC+8

> new Date('Feb 28 2013 19:00:00 GMT-0500').toString()
< "Fri Mar 01 2013 08:00:00 GMT+0800 (CST)"

また、あなたは通常のgetHours/Minute/Second方法を使うことができます:

> new Date('Feb 28 2013 19:00:00 GMT-0500').getHours()
< 8

(これ8は、時刻が現地時間に変換された後- UTC+8時間数はであることを意味し8ます。)


16
ISO 8601拡張形式以外の形式の解析は実装に依存するため、依存しないでください。タイムゾーンの省略形には標準がありません。たとえば、「EST」は3つの異なるゾーンのいずれかを表す場合があります。
RobG 2016

1
このコメントの例は、Internet Explorerでは機能しないことがよくあります。この投稿に対する以前のコメントで述べたように、ISO 8601は重要です。ECMA-262(Javascript 5th)版の言語仕様を読んで確認しました。
Dakusan

12

これで問題が解決します。修正を提供してください。このメソッドは、指定された日付の夏時間も考慮します。

dateWithTimeZone = (timeZone, year, month, day, hour, minute, second) => {
  let date = new Date(Date.UTC(year, month, day, hour, minute, second));

  let utcDate = new Date(date.toLocaleString('en-US', { timeZone: "UTC" }));
  let tzDate = new Date(date.toLocaleString('en-US', { timeZone: timeZone }));
  let offset = utcDate.getTime() - tzDate.getTime();

  date.setTime( date.getTime() + offset );

  return date;
};

タイムゾーンと現地時間での使用方法:

dateWithTimeZone("America/Los_Angeles",2019,8,8,0,0,0)

このソリューションは私のニーズにぴったりでした。サマータイムをどの程度正確に説明できるかわかりませんでした。
Hossein Amin、

なぜtzDate直接戻るのではないのですか?
レビ

8

サードパーティのライブラリを気にせずにこれを行うための最もサポートされている方法getTimezoneOffsetは、適切なタイムスタンプを計算するか、時刻を更新してから通常のメソッドを使用して必要な日付と時刻を取得することでした。

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

// ET timezone offset in hours.
var timezone = -5;
// Timezone offset in minutes + the desired offset in minutes, converted to ms.
// This offset should be the same for ALL date calculations, so you should only need to calculate it once.
var offset = (mydate.getTimezoneOffset() + (timezone * 60)) * 60 * 1000;

// Use the timestamp and offset as necessary to calculate min/sec etc, i.e. for countdowns.
var timestamp = mydate.getTime() + offset,
    seconds = Math.floor(timestamp / 1000) % 60,
    minutes = Math.floor(timestamp / 1000 / 60) % 60,
    hours   = Math.floor(timestamp / 1000 / 60 / 60);

// Or update the timestamp to reflect the timezone offset.
mydate.setTime(mydate.getTime() + offset);
// Then Output dates and times using the normal methods.
var date = mydate.getDate(),
    hour = mydate.getHours();

編集

以前UTCは日付変換を実行するときにメソッドを使用していましたが、これは正しくありませんでした。時間にオフセットを追加して、ローカルget関数を使用すると、目的の結果が返されます。


どこで計算しましたtimezone_offsetか?
Anand Somani

1
おっと、変数の1つに誤ったラベルを付けました。timezone_offsetだったoffset、またはその逆。正しい変数名を表示するように回答を編集しました。
Shaun Cockerill

3

ユニットテストで同様の問題に遭遇しました(特に、ユニットテストがローカルで実行されてスナップショットを作成し、その後CIサーバーが(潜在的に)異なるタイムゾーンで実行されて、スナップショットの比較が失敗した場合の冗談です)。私は私たちDateとそのようないくつかのサポート方法を模倣しました:

describe('...', () => {
  let originalDate;

  beforeEach(() => {
    originalDate = Date;
    Date = jest.fn(
      (d) => {
        let newD;
        if (d) {
          newD = (new originalDate(d));
        } else {
          newD = (new originalDate('2017-05-29T10:00:00z'));
        }
        newD.toLocaleString = () => {
          return (new originalDate(newD.valueOf())).toLocaleString("en-US", {timeZone: "America/New_York"});
        };
        newD.toLocaleDateString = () => {
          return (new originalDate(newD.valueOf())).toLocaleDateString("en-US", {timeZone: "America/New_York"});
        };
        newD.toLocaleTimeString = () => {
          return (new originalDate(newD.valueOf())).toLocaleTimeString("en-US", {timeZone: "America/New_York"});
        };
        return newD;
      }
    );
    Date.now = () => { return (Date()); };
  });

  afterEach(() => {
    Date = originalDate;
  });

});


2

上記の答えに基づいて、私はこのネイティブの1ライナーを使用して、長いタイムゾーン文字列を3文字の文字列に変換しています。

var longTz = 'America/Los_Angeles';
var shortTz = new Date().
    toLocaleString("en", {timeZoneName: "short", timeZone: longTz}).
    split(' ').
    pop();

これにより、提供された日付に応じてPDTまたはPSTが提供されます。私の特定のユースケースでは、Salesforce(Aura / Lightning)での開発で、バックエンドから長い形式でユーザーのタイムゾーンを取得できます。


「America / Los_Angeles」は時々ペダントをプレイするのが好きだからといって、タイムゾーンではなく、特定のオフセットと夏時間のルール、およびそれらの変更の履歴の「代表的な場所」です(IANAタイムゾーンデータベースごと)。 。;-)
RobG

ハハ、あなたはここで複数の答えについてそのコメントを投稿する必要があります:P
シェーン

2

私はその3年は遅すぎることを知っていますが、彼がここで求めているものとは完全に異なるモーメントタイムゾーンライブラリを除いて、そのようなものが見つからなかったため、他の誰かを助けることができるでしょう。

ドイツのタイムゾーンでも同様のことを行いましたが、夏時間と366日のうるう年のため、これは少し複雑です。

「isDaylightSavingTimeInGermany」関数を使用して少し作業を行う必要がありますが、夏時間によって異なるタイムゾーンが使用されます。

とにかく、このページをチェックしてください:https//github.com/zerkotin/german-timezone-converter/wiki

主なメソッドは次のとおりです。convertLocalDateToGermanTimezoneconvertGermanDateToLocalTimezone

私はそれを文書化することに力を入れたので、それはそれほど混乱しないでしょう。


これはコメントであるべきで、答えではありません。
RobG

1

試してみてください:date-from-timezone、ネイティブで利用可能なの助けを借りて期待される日付を解決しますIntl.DateTimeFormat

私は数年前から自分のプロジェクトの1つでその方法を使用していましたが、今は小さなOSプロジェクトとして公開することにしました:)


0

Ionicユーザーの場合.toISOString()、htmlテンプレートで使用する必要があるため、私はこれで地獄に行きました。

これは現在の日付を取得しますが、もちろん、選択した日付の以前の回答に追加できます。

私はこれを使って修正しました:

date = new Date();
public currentDate: any = new Date(this.date.getTime() - this.date.getTimezoneOffset()*60000).toISOString();

* 60000は、CSTであるUTC -6を示しているため、TimeZoneが必要な場合でも、数と違いを変更できます。


これは質問者が求めている答えではありません。彼は特定のタイムゾーンの日付を取得しようとしていました。
Richard Vergis

@RichardVergis質問は、ユーザーが現地時間に変更したいことを明確に示していますが、現在のタイムゾーンは示していません。例としてタイムゾーンを示し、ユーザーは私の例に基づいて明確に読み取ることができ、入力できますタイムゾーンのオフセット。
Stephen Romero

0

多分これはあなたを助けるでしょう

/**
 * Shift any Date timezone.
 * @param {Date} date - Date to update.
 * @param {string} timezone - Timezone as `-03:00`.
 */
function timezoneShifter(date, timezone) {
  let isBehindGTM = false;
  if (timezone.startsWith("-")) {
    timezone = timezone.substr(1);
    isBehindGTM = true;
  }

  const [hDiff, mDiff] = timezone.split(":").map((t) => parseInt(t));
  const diff = hDiff * 60 + mDiff * (isBehindGTM ? 1 : -1);
  const currentDiff = new Date().getTimezoneOffset();

  return new Date(date.valueOf() + (currentDiff - diff) * 60 * 1000);
}



const _now = new Date()
console.log(
  [
    "Here: " + _now.toLocaleString(),
    "Greenwich: " + timezoneShifter(_now, "00:00").toLocaleString(),
    "New York: " + timezoneShifter(_now, "-04:00").toLocaleString(),
    "Tokyo: " + timezoneShifter(_now, "+09:00").toLocaleString(),
    "Buenos Aires: " + timezoneShifter(_now, "-03:00").toLocaleString(),
  ].join('\n')
);


-2

同じ問題に直面していましたが、これを使用しました

Console.log(Date.parse( "2018年6月13日10:50:39 GMT + 1"));

それはあなたがチェックできるミリ秒を返します+100 timzoneがイギリスの時間を初期化します


3
(この投稿は質問に対する質の高い回答を提供していないようです。回答を編集するか、質問へのコメントとして投稿してください)。
sɐunıɔןɐqɐp
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.