JSON StringifyはUTCのために日付時刻を変更します


98

JavaScriptの日付オブジェクトは、私がいる場所のため、常にUTC +2で表されます。したがって、このように

Mon Sep 28 10:00:00 UTC+0200 2009

問題はJSON.stringify、上記の日付をaに変換することです

2009-09-28T08:00:00Z  (notice 2 hours missing i.e. 8 instead of 10)

私が必要なのは、日時が尊重されることですが、それは守られないので、

2009-09-28T10:00:00Z  (this is how it should be)

基本的に私はこれを使用します:

var jsonData = JSON.stringify(jsonObject);

replacerパラメーター(stringifyの2番目のパラメーター)を渡してみましたが、問題は値が既に処理されていることです。

私も日付オブジェクトを使用toString()してみtoUTCString()ましたが、これらは私が望んでいるものも与えません。

誰か助けてもらえますか?


17
2009-09-28T10:00:00Z 時間内に同じ瞬間を表すものではないとしてMon Sep 28 10:00:00 UTC+0200 2009ZISO 8601の日付はUTCを意味し、UTCで10時はある時間の異なる瞬間 0200で10時まで。日付を正しいタイムゾーンでシリアル化することは1つのことですが、明確に、客観的に間違っている表現に日付をシリアル化するのを支援するように求めています。
Mark Amery 2015

1
Marksコメントに追加するには、ほとんどの場合、日時をUTC時間として保存することがベストプラクティスです。これにより、さまざまなタイムゾーンのユーザーをサポートできます
JoeCodeFrog

回答:


67

最近、同じ問題に遭遇しました。そして、それは次のコードを使用して解決されました:

x = new Date();
let hoursDiff = x.getHours() - x.getTimezoneOffset() / 60;
let minutesDiff = (x.getHours() - x.getTimezoneOffset()) % 60;
x.setHours(hoursDiff);
x.setMinutes(minutesDiff);

はい、しかしこれは私のウェブサイトが私の国内で使用されている場合、それが米国のような他の国で使用されている場合です-それは2ではありません...
mark smith

明らかに、この値は計算する必要があります。
アナトリー

3
おかげで...私は実際にここに素晴らしいライブラリを見つけました、blog.stevenlevithan.com / archives / date-time-format これを行うために必要なすべて(おそらくそれはあなたを助けるでしょう)、あなたはfalseを渡し、変換しません。var something = dateFormat(myStartDate、 "isoDateTime"、false);
マークスミス

11
あなたの日付のバックを読むときにタイムゾーンを修正しなければならない-それはあなたのコードの非タイムゾーンに安全になりますので、これは正しくありません。
olliej

4
この答えは間違っています。OPは、「2009-09-28T08:00:00Z」と「Mon Sep 28 10:00:00 UTC + 0200 2009」がまったく同じ瞬間であり、タイムゾーンオフセットの調整が実際に作成されていることを認識していません間違った時間。
RobG 2017年

41

JSONは、Date.prototype.toISOString現地時間を表さない関数を使用します-変更されていないUTCでの時間を表しています-日付出力を見ると、UTC + 2時間であることがわかります。これが、JSON文字列が2時間変化する理由です。ただし、これにより、同じ時間を複数のタイムゾーンで正しく表すことができる場合。


2
これを考えたことはありませんが、あなたは正しいです。これが解決策です。プロトタイピングを使用して、好きな形式を指定できます。
rac


9

ここに別の答えがあります(そして個人的にはそれがより適切だと思います)

var currentDate = new Date(); 
currentDate = JSON.stringify(currentDate);

// Now currentDate is in a different format... oh gosh what do we do...

currentDate = new Date(JSON.parse(currentDate));

// Now currentDate is back to its original form :)

@Rohaanは指摘してくれてありがとう。質問のタグはJavaScriptについて言及しています。
2015年

6

date.toJSON()は、UTC-Dateをフォーマットされた文字列に出力します(JSON形式に変換するときにオフセットを追加します)。

date = new Date();
new Date(date.getTime() - (date.getTimezoneOffset() * 60000)).toJSON();

6
通常、コードの動作に関する説明を追加することをお勧めします。これにより、新しい開発者はコードがどのように機能するかを理解できます。
Caleb Kleveter 2017年

回答のコードが機能する理由を説明できますか?
Cristik

これは私にとっても機能しますが、それをどのように行ったかを説明できますか?
Deven Patil

このコードの2行目を説明しようと思います date.getTime()。ミリ秒単位の時間を返すので、2番目のオペランドもミリ秒に変換する必要があります。以来date.getTimezoneOffset()1分= 60000millisecondsのでリターンは、我々は乗算それ60000分のオフセット。そのため、現在の時刻からオフセットを差し引くことで、時刻をUTCで取得します。
マクシムパブロフ

4

moment.jsを使用して、現地時間でフォーマットすることができます。

Date.prototype.toISOString = function () {
    return moment(this).format("YYYY-MM-DDTHH:mm:ss");
};

一般的なクラスの日付を上書きしないでください。一部の外部モジュールを使用すると、アプリケーションが簡単に破損する可能性があります。
Viacheslav Dobromyslov

3

私は少し遅れていますが、次のようにプロトタイプを使用して日付の場合は、いつでもtoJson関数を上書きできます。

Date.prototype.toJSON = function(){
    return Util.getDateTimeString(this);
};

私の場合、Util.getDateTimeString(this)は次のような文字列を返します: "2017-01-19T00:00:00Z"


2
ブラウザグローバルを上書きすると、埋め込んだサードパーティのライブラリが壊れる可能性があり、大きなアンチパターンであることに注意してください。本番環境ではこれを行わないでください。
jakub.g

2

通常、各ユーザーに自分の現地時間で日付を表示する必要があります。

そのため、GMT(UTC)を使用しています。

Date.parse(jsondatestring)を使用して、現地時間の文字列を取得します。

各訪問者に現地時間を表示したくない場合を除きます。

その場合は、アナトリーの方法を使用してください。


2

moment.jsライブラリ(非タイムゾーンバージョン)を使用してこの問題を回避しました。

var newMinDate = moment(datePicker.selectedDates[0]);
var newMaxDate = moment(datePicker.selectedDates[1]);

// Define the data to ask the server for
var dataToGet = {"ArduinoDeviceIdentifier":"Temperatures",
                "StartDate":newMinDate.format('YYYY-MM-DD HH:mm'),
                "EndDate":newMaxDate.format('YYYY-MM-DD HH:mm')
};

alert(JSON.stringify(dataToGet));

flatpickr.min.js図書館を利用していました。作成された結果のJSONオブジェクトの時間は、提供された現地時間と一致しますが、日付ピッカーです。


2

JSON.stringifyタイムゾーンを無視するように強制するすぐに使えるソリューション:

  • 純粋なjavascript(Anatoliyの回答に基づく):

// Before: JSON.stringify apply timezone offset
const date =  new Date();
let string = JSON.stringify(date);
console.log(string);

// After: JSON.stringify keeps date as-is!
Date.prototype.toJSON = function(){
    const hoursDiff = this.getHours() - this.getTimezoneOffset() / 60;
    this.setHours(hoursDiff);
    return this.toISOString();
};
string = JSON.stringify(date);
console.log(string);

moment.jsライブラリの使用:

const date =  new Date();
let string = JSON.stringify(date);
console.log(string);

Date.prototype.toJSON = function(){
    return moment(this).format("YYYY-MM-DDTHH:mm:ss:ms");;
};
string = JSON.stringify(date);
console.log(string);
<html>
  <header>
    <script src="https://momentjs.com/downloads/moment.min.js"></script>
    <script src="https://momentjs.com/downloads/moment-timezone-with-data-10-year-range.min.js"></script>
</header>
</html>


2

私はこれがレガシーのもので少し動作することに遭遇します。それらは米国東海岸でのみ機能し、日付をUTCに保存しません。すべてESTです。ブラウザでのユーザー入力に基づいて日付でフィルタリングする必要があるため、日付をJSON形式で現地時間で渡す必要があります。

すでに投稿されたこのソリューションについて詳しく説明するために-これは私が使用するものです:

// Could be picked by user in date picker - local JS date
date = new Date();

// Create new Date from milliseconds of user input date (date.getTime() returns milliseconds)
// Subtract milliseconds that will be offset by toJSON before calling it
new Date(date.getTime() - (date.getTimezoneOffset() * 60000)).toJSON();

だから私の理解は、これが先に進み、タイムゾーンのオフセットに基づいて開始日から時間をミリ秒で(したがって60000で)差し引くこと(分を返す)-時間を追加することを見込んでtoJSON()が追加する予定です。


1

これは本当にきちんとしたシンプルなもので(少なくとも私はそう信じています:))、日付を操作したり、toJSONなどのブラウザーのネイティブ関数をオーバーロードしたりする必要はありません(参照:JSONをJavaScriptで文字列化し、タイムゾーンを保持する方法、丁寧なShawson)

JSON.stringifyに置換機能を渡して、内容を文字列化します!!! このようにして、時間や分の差分やその他の操作を行う必要がありません。

中間結果を確認するためにconsole.logsを入れたので、何が行われていて、再帰がどのように機能しているかが明確です。これは、注目に値する何かを明らかにします:replacerへの値パラメーターは、ISO日付形式に既に変換されています:)。これを使用して、元のデータを操作します。

var replacer = function(key, value)
{
    var returnVal = value;
    if(this[key] instanceof Date)
    {
        console.log("replacer called with key - ", key, " value - ", value, this[key]); 

        returnVal = this[key].toString();

        /* Above line does not strictly speaking clone the date as in the cloned object 
         * it is a string in same format as the original but not a Date object. I tried 
         * multiple things but was unable to cause a Date object being created in the 
         * clone. 
         * Please Heeeeelp someone here!

        returnVal = new Date(JSON.parse(JSON.stringify(this[key])));   //OR
        returnVal = new Date(this[key]);   //OR
        returnVal = this[key];   //careful, returning original obj so may have potential side effect

*/
    }
    console.log("returning value: ", returnVal);

    /* if undefined is returned, the key is not at all added to the new object(i.e. clone), 
     * so return null. null !== undefined but both are falsy and can be used as such*/
    return this[key] === undefined ? null : returnVal;
};

ab = {prop1: "p1", prop2: [1, "str2", {p1: "p1inner", p2: undefined, p3: null, p4date: new Date()}]};
var abstr = JSON.stringify(ab, replacer);
var abcloned = JSON.parse(abstr);
console.log("ab is: ", ab);
console.log("abcloned is: ", abcloned);

/* abcloned is:
 * {
  "prop1": "p1",
  "prop2": [
    1,
    "str2",
    {
      "p1": "p1inner",
      "p2": null,
      "p3": null,
      "p4date": "Tue Jun 11 2019 18:47:50 GMT+0530 (India Standard Time)"
    }
  ]
}
Note p4date is string not Date object but format and timezone are completely preserved.
*/

1

JavaScriptは通常、ローカルタイムゾーンをUTCに変換します。

date = new Date();
date.setMinutes(date.getMinutes()-date.getTimezoneOffset())
JSON.stringify(date)

0

結局のところ、サーバーのバックエンドがタイムゾーンに依存しないかどうかです。そうでない場合は、サーバーのタイムゾーンがクライアントと同じであると想定するか、クライアントのタイムゾーンに関する情報を転送して、それを計算に含める必要があります。

PostgreSQLバックエンドベースの例:

select '2009-09-28T08:00:00Z'::timestamp -> '2009-09-28 08:00:00' (wrong for 10am)
select '2009-09-28T08:00:00Z'::timestamptz -> '2009-09-28 10:00:00+02'
select '2009-09-28T08:00:00Z'::timestamptz::timestamp -> '2009-09-28 10:00:00'

最後の1つは、タイムゾーンロジックを適切に実装しない場合は、おそらくデータベースで使用したいものです。


0

の代わりにtoJSON、常に正しい日付と時刻を与えるフォーマット関数を使用できます+GMT

これは最も堅牢な表示オプションです。トークンの文字列を取り、それらを対応する値に置き換えます。


0

私は角度8でこれを試しました:

  1. モデルを作成:

    export class Model { YourDate: string | Date; }
  2. コンポーネント内

    model : Model;
    model.YourDate = new Date();
  3. 保存のためにAPIに日付を送信します

  4. APIからデータをロードするときは、次のようにします。

    model.YourDate = new Date(model.YourDate+"Z");

あなたはあなたのタイムゾーンであなたの日付を正しく得るでしょう。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.