ユーザーのタイムゾーンを無視し、Date()に特定のタイムゾーンを使用させる方法


104

JSアプリで、1270544790922サーバー(Ajax)からタイムスタンプ(eq。)を受け取ります。

そのタイムスタンプに基づいて、以下を使用してDateオブジェクトを作成します。

var _date = new Date();
_date.setTime(1270544790922);

現在、_date現在のユーザーロケールのタイムゾーンでデコードされたタイムスタンプ。それは欲しくない。

dateこのタイムスタンプをヨーロッパのヘルシンキ市の現在の時刻に_ 変換します(ユーザーの現在のタイムゾーンは無視します)。

どうやってやるの?


ヘルシンキのタイムゾーンオフセットは冬は+2、夏時間は+3であることは知っています。しかし、DSTがいつなのか誰が知っていますか?JSで使用できない一部のロケールメカニズムのみ
warpech

これは可能ですが、JavaScriptのネイティブメソッドを使用していません。JavaScriptには、ユーザーのシステムの現在のタイムゾーン以外のタイムゾーンのタイムゾーン遷移履歴を決定する方法がないためです(少なくとも、80年代の日付に移動した場合、ブラウザーに依存します)。しかし、この方法でそれは可能です:stackoverflow.com/a/12814213/1691517そして私の答えはあなたに正しい結果を与えると思います
TimoKähkönen2012年

回答:


64

Dateオブジェクトの基になる値は、実際にはUTCです。これを証明するには、次のように入力していることに気づくnew Date(0)、あなたのようなものが表示されます:Wed Dec 31 1969 16:00:00 GMT-0800 (PST)。0はGMTでは0として扱われますが、.toString()メソッドは現地時間を示します。

特筆すべきは、UTCはUniversal Time Codeの略です。現在2つの異なる場所にある現在の時刻は同じUTCですが、出力の形式を変えることができます。

ここで必要なのは、いくつかのフォーマットです

var _date = new Date(1270544790922); 
// outputs > "Tue Apr 06 2010 02:06:30 GMT-0700 (PDT)", for me
_date.toLocaleString('fi-FI', { timeZone: 'Europe/Helsinki' });
// outputs > "6.4.2010 klo 12.06.30"
_date.toLocaleString('en-US', { timeZone: 'Europe/Helsinki' });
// outputs > "4/6/2010, 12:06:30 PM"

これは機能しますが、ユーザーのタイムゾーンを記述しているため、目的に他の日付メソッドを実際に使用することはできません。必要なのは、ヘルシンキのタイムゾーンに関連する日付オブジェクトです。この時点でのオプションは、いくつかのサードパーティライブラリを使用するか(これをお勧めします)、または日付オブジェクトをハックアップして、そのほとんどのメソッドを使用できるようにすることです。

オプション1-モーメントタイムゾーンのようなサードパーティ

moment(1270544790922).tz('Europe/Helsinki').format('YYYY-MM-DD HH:mm:ss')
// outputs > 2010-04-06 12:06:30
moment(1270544790922).tz('Europe/Helsinki').hour()
// outputs > 12

これは、これから行うことよりもはるかにエレガントに見えます。

オプション2-日付オブジェクトをハックアップする

var currentHelsinkiHoursOffset = 2; // sometimes it is 3
var date = new Date(1270544790922);
var helsenkiOffset = currentHelsinkiHoursOffset*60*60000;
var userOffset = _date.getTimezoneOffset()*60000; // [min*60000 = ms]
var helsenkiTime = new Date(date.getTime()+ helsenkiOffset + userOffset);
// Outputs > Tue Apr 06 2010 12:06:30 GMT-0700 (PDT)

それでもGMT-0700(PDT)だと思っていますが、あまり凝視しなければ、目的に役立つ日付オブジェクトと間違える可能性があります。

一部を飛ばしてみました。定義できる必要がありますcurrentHelsinkiOffsetdate.getTimezoneOffset()サーバー側で使用できる場合、またはいくつかのifステートメントを使用して、タイムゾーンの変更がいつ発生するかを説明すれば、問題が解決するはずです。

結論 -特にこの目的では、moment-timezoneなどの日付ライブラリを使用する必要があると思います。


また、1つの場所からのgmtオフセットを使用するだけで、同様のタスクを実行できます。その場合、JavaScriptはまったく必要ありません。
パリス

申し訳ありませんが、いいえ、私は正反対を意味します:)私は質問を編集しました、多分それはより明確になりました
warpech

OKソリューションを変更しました。これはあなたが探しているものだと思います。
Parris

残念ながら、それも私が思いついた唯一のことです。ブラウザが「_helsinkiOffset」を生成するのではないかと思いました。
warpech

2
私は信じている*60*60代わりにする必要があります*60000getTimeはミリ秒であるように、とと、GetTimezoneOffsetはその分で60000ミリ秒ではなく、60 * 60 == 3600ありますが、数分である
AaronLS

20

ミリ秒とユーザーのタイムゾーンを考慮するには、以下を使用します。

var _userOffset = _date.getTimezoneOffset()*60*1000; // user's offset time
var _centralOffset = 6*60*60*1000; // 6 for central time - use whatever you need
_date = new Date(_date.getTime() - _userOffset + _centralOffset); // redefine variable

中央の固定オフセットを使用して置き換えるには、CSTを使用して00:00の固定時間で日付を作成し、その日付のgetUTCHHoursを作成するという概念を使用しました。
grantwparks 2012

+1これでうまくいきました。ミリ秒単位で処理しなくても、「the」の答えがどのように機能するかわかりません。
Chris Wallis

2
@Ehrenは、timezoneOffsetを追加してgmtに到達し、中央のオフセットを差し引くべきではありませんか?
コーダー、

15

ちょうど別のアプローチ

function parseTimestamp(timestampStr) {
  return new Date(new Date(timestampStr).getTime() + (new Date(timestampStr).getTimezoneOffset() * 60 * 1000));
};

//Sun Jan 01 2017 12:00:00
var timestamp = 1483272000000;
date = parseTimestamp(timestamp);
document.write(date);

乾杯!


2
これは、夏時間のために意図しない結果になる可能性があります。クライアントがDSTを使用するタイムゾーンにある場合、解析の結果は1時間ずれる可能性があります(一部のゾーンは1時間の端数を使用します)。例:ユーザーはニューヨークにいて、今日は7月4日です。これは、ユーザーがGMT -0400(夏時間開始後の東部夏時間タイムゾーン)にいることを意味します。渡されるタイムスタンプは1月30日のもので、GMT-0500(東部標準タイムゾーン-その年の夏時間なし)です。getTimezoneOffset()が1月のオフセットではなく現在のオフセットを提供するため、結果は1時間ずれます。
Dimitar Darazhanski

2
この問題を解決するには、あなたがする必要があります(ない現在のタイムシフト)に渡している日付のオフセット時間がかかるnew Date().getTimezoneOffset()に変更する必要がありますnew Date(timestampStr).getTimezoneOffset()
ディミタールDarazhanski

13

答えが正しい結果を与えていないのではないかと疑っています。質問者は、ユーザーの現在のタイムゾーンを無視して、ヘルシンキでタイムスタンプをサーバーから現在の時刻に変換したいと考えています。

これは、ユーザーのタイムゾーンがこれまでにないものになる可能性があるため、信頼できないという事実です。

たとえば タイムスタンプは1270544790922で、次の関数があります。

var _date = new Date();
_date.setTime(1270544790922);
var _helsenkiOffset = 2*60*60;//maybe 3
var _userOffset = _date.getTimezoneOffset()*60*60; 
var _helsenkiTime = new Date(_date.getTime()+_helsenkiOffset+_userOffset);

ニューヨーカーがページにアクセスすると、alert(_helsenkiTi​​me)が次のように出力します。

Tue Apr 06 2010 05:21:02 GMT-0400 (EDT)

そして、フィンランド人がページにアクセスすると、alert(_helsenkiTi​​me)が次のように出力します。

Tue Apr 06 2010 11:55:50 GMT+0300 (EEST)

そのため、ページの訪問者が自分のコンピューターにターゲットのタイムゾーン(ヨーロッパ/ヘルシンキ)を持ち、世界の他のほぼすべての場所で失敗する場合にのみ、関数は正しく機能します。また、サーバーのタイムスタンプは通常UNIXタイムスタンプであり、これはUTCの定義によると、Unixエポック(1970年1月1日00:00:00 GMT)からの秒数なので、タイムスタンプからDSTまたは非DSTを特定できません。

したがって、解決策は、ユーザーの現在のタイムゾーンを無視し、日付がDSTであるかどうかにかかわらず、UTCオフセットを計算する何らかの方法を実装することです。JavaScriptには、ユーザーの現在のタイムゾーン以外のタイムゾーンのDST遷移履歴を決定するネイティブメソッドがありません。すべてのタイムゾーンの移行履歴全体でサーバーのタイムゾーンデータベースに簡単にアクセスできるため、サーバー側のスクリプトを使用してこれを最も簡単に実現できます。

ただし、サーバー(または他のサーバー)のタイムゾーンデータベースにアクセスできず、タイムスタンプがUTCである場合、DSTルールをJavaScriptでハードコーディングすることにより、同様の機能を利用できます。

ヨーロッパ/ヘルシンキの1998〜2099年の日付をカバーするには、次の関数(jsfiddled)を使用できます。

function timestampToHellsinki(server_timestamp) {
    function pad(num) {
        num = num.toString();
        if (num.length == 1) return "0" + num;
        return num;
    }

    var _date = new Date();
    _date.setTime(server_timestamp);

    var _year = _date.getUTCFullYear();

    // Return false, if DST rules have been different than nowadays:
    if (_year<=1998 && _year>2099) return false;

    // Calculate DST start day, it is the last sunday of March
    var start_day = (31 - ((((5 * _year) / 4) + 4) % 7));
    var SUMMER_start = new Date(Date.UTC(_year, 2, start_day, 1, 0, 0));

    // Calculate DST end day, it is the last sunday of October
    var end_day = (31 - ((((5 * _year) / 4) + 1) % 7))
    var SUMMER_end = new Date(Date.UTC(_year, 9, end_day, 1, 0, 0));

    // Check if the time is between SUMMER_start and SUMMER_end
    // If the time is in summer, the offset is 2 hours
    // else offset is 3 hours
    var hellsinkiOffset = 2 * 60 * 60 * 1000;
    if (_date > SUMMER_start && _date < SUMMER_end) hellsinkiOffset = 
    3 * 60 * 60 * 1000;

    // Add server timestamp to midnight January 1, 1970
    // Add Hellsinki offset to that
    _date.setTime(server_timestamp + hellsinkiOffset);
    var hellsinkiTime = pad(_date.getUTCDate()) + "." + 
    pad(_date.getUTCMonth()) + "." + _date.getUTCFullYear() + 
    " " + pad(_date.getUTCHours()) + ":" +
    pad(_date.getUTCMinutes()) + ":" + pad(_date.getUTCSeconds());

    return hellsinkiTime;
}

使用例:

var server_timestamp = 1270544790922;
document.getElementById("time").innerHTML = "The timestamp " + 
server_timestamp + " is in Hellsinki " + 
timestampToHellsinki(server_timestamp);

server_timestamp = 1349841923 * 1000;
document.getElementById("time").innerHTML += "<br><br>The timestamp " + 
server_timestamp + " is in Hellsinki " + timestampToHellsinki(server_timestamp);

var now = new Date();
server_timestamp = now.getTime();
document.getElementById("time").innerHTML += "<br><br>The timestamp is now " +
server_timestamp + " and the current local time in Hellsinki is " +
timestampToHellsinki(server_timestamp);​

そして、これはユーザーのタイムゾーンに関係なく以下を出力します:

The timestamp 1270544790922 is in Hellsinki 06.03.2010 12:06:30

The timestamp 1349841923000 is in Hellsinki 10.09.2012 07:05:23

The timestamp is now 1349853751034 and the current local time in Hellsinki is 10.09.2012 10:22:31

もちろん、オフセット(DSTまたはDST以外)がサーバーのタイムスタンプに既に追加されている形式でタイムスタンプを返すことができる場合、クライアント側でタイムスタンプを計算する必要はなく、機能を大幅に簡略化できます。ただし、timezoneOffset()は使用しないでください。ユーザーのタイムゾーンを処理する必要があるため、これは望ましい動作ではありません。


2
nb。ヘルシンキには「l」が1つしかありません。この間違いは本当にこの答えを損なう。
ベンマッキンタイア

@BenMcIntyreちょっと冗談です。またはそのようなものになるはずです。:)
TimoKähkönen2017年

ああ、自分の時間/タイムゾーン実装をコード化しないでください...しかし、私は-1をするのが
面倒

3

ヘルシンキ時間でタイムスタンプを取得すると仮定して、1970年1月1日午前0時(ブラウザのローカルタイムゾーン設定を無視するため)に設定された日付オブジェクトを作成します。次に、必要なミリ秒数を追加します。

var _date	= new Date( Date.UTC(1970, 0, 1, 0, 0, 0, 0) );
_date.setUTCMilliseconds(1270544790922);

alert(_date); //date shown shifted corresponding to local time settings
alert(_date.getUTCFullYear());    //the UTC year value
alert(_date.getUTCMonth());       //the UTC month value
alert(_date.getUTCDate());        //the UTC day of month value
alert(_date.getUTCHours());       //the UTC hour value
alert(_date.getUTCMinutes());     //the UTC minutes value

後で注意して、常に日付オブジェクトからUTC値を確認してください。これにより、ローカル設定に関係なく、ユーザーは同じ日付の値を見ることができます。そうでない場合、日付値は現地時間設定に対応してシフトされます。


0

あなたは使うことができます setUTCMilliseconds()

var _date = new Date();
_date.setUTCMilliseconds(1270544790922);

この答えは間違っています。setUTCMillisecondsは、指定されたミリ秒数を日付に追加します。
ティボー

@Tibor:MozDevから:このsetUTCMilliseconds()メソッドは、世界時に従って、指定された日付のミリ秒を設定します。[...]指定したパラメーターが予期される範囲外の場合は、setUTCMilliseconds()それに応じてDateオブジェクトの日付情報を更新しようとします。つまり、DateUTCで、指定されたUnixタイムスタンプを持つオブジェクトを作成します。
jimasun 2017年

w3schoolsから:setUTCMilliseconds()メソッドは、世界時に従ってミリ秒(0〜999)を設定します。上記の答えを試して、自分の目で確かめてください。
Tibor

MDNから:パラメータmillisecondsValue:ミリ秒を表す0〜999の数値...
Tibor

new Date()は現在のローカル日付で日付オブジェクトを作成するため、この例は期待どおりに機能しません。その後、指定されたミリ秒数が追加されます。現在のローカルの日付が2017年5月4日であれば、あなたの例では、結果の日付は年4027の後にどこか...となります
ティボー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.