JSON Stringify ändert die Datumszeit aufgrund von UTC


98

Meine Datumsobjekte in JavaScript werden immer durch UTC +2 dargestellt, da ich mich dort befinde. Daher so

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

Problem ist die JSON.stringifyKonvertierung des oben genannten Datums in

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

Was ich brauche, ist, dass Datum und Uhrzeit eingehalten werden, aber es ist nicht so, daher sollte es so sein

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

Grundsätzlich benutze ich das:

var jsonData = JSON.stringify(jsonObject);

Ich habe versucht, einen Ersetzerparameter (zweiter Parameter bei stringify) zu übergeben, aber das Problem ist, dass der Wert bereits verarbeitet wurde.

Ich habe auch versucht mit toString()und toUTCString()am Tag Objekt, aber diese geben Sie mir nicht , was ich entweder will ..

Kann mir jemand helfen?


17
2009-09-28T10:00:00Z repräsentiert nicht den gleichen Zeitpunkt wie Mon Sep 28 10:00:00 UTC+0200 2009. Das Datum Zin ISO 8601 bedeutet UTC, und 10 Uhr in UTC ist ein anderer Zeitpunkt als 10 Uhr in +0200. Es wäre eine Sache, wenn das Datum mit der richtigen Zeitzone serialisiert werden soll, aber Sie bitten uns, Ihnen bei der Serialisierung zu einer Darstellung zu helfen, die eindeutig und objektiv falsch ist .
Mark Amery

1
In den meisten Fällen empfiehlt es sich, Ihre Datenzeiten als UTC-Zeit zu speichern, damit Sie Benutzer in verschiedenen Zeitzonen unterstützen können
JoeCodeFrog

Antworten:


67

Vor kurzem bin ich auf das gleiche Problem gestoßen. Und es wurde mit dem folgenden Code gelöst:

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

Ja, aber dies ist, wenn die Website in meinem Land verwendet wird, wenn sie in einem anderen Land wie den USA verwendet wird - es wäre nicht 2 ...
Mark Smith

Offensichtlich sollte dieser Wert berechnet werden.
Anatoliy

3
danke ... Ich habe hier tatsächlich eine großartige Bibliothek gefunden, blog.stevenlevithan.com/archives/date-time-format alles , was Sie dazu brauchen (vielleicht hilft es Ihnen), Sie übergeben false und es wird nicht konvertiert. var Something = DateFormat (myStartDate, "isoDateTime", false);
Mark Smith

11
Dies ist falsch, da es Ihren Code nicht zeitzonensicher macht - Sie sollten die Zeitzone korrigieren, wenn Sie das Datum wieder
einlesen

4
Diese Antwort ist falsch. Das OP erkennt nicht, dass "2009-09-28T08: 00: 00Z" und "Mon Sep 28 10:00:00 UTC + 0200 2009" genau der gleiche Zeitpunkt sind und dass das Anpassen des Zeitzonenversatzes tatsächlich erzeugt die falsche Zeit.
RobG

41

JSON verwendet die Date.prototype.toISOStringFunktion, die keine Ortszeit darstellt - sie stellt die Zeit in unveränderter UTC dar. Wenn Sie sich Ihre Datumsausgabe ansehen, sehen Sie, dass Sie sich in UTC + 2 Stunden befinden. Aus diesem Grund ändert sich die JSON-Zeichenfolge um zwei Stunden. Wenn dies jedoch ermöglicht, dass dieselbe Zeit in mehreren Zeitzonen korrekt dargestellt wird.


2
Ich habe nie daran gedacht, aber du hast recht. Dies ist die Lösung: Ich kann mithilfe des Prototyping jedes Format angeben, das ich bevorzuge.
Rennen


9

Hier ist eine andere Antwort (und ich persönlich halte es für angemessener)

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 danke für den Hinweis, aber die Tags auf der Frage erwähnen JavaScript.
August

6

date.toJSON () druckt das UTC-Datum in einen formatierten String (fügt also den Offset hinzu, wenn es in das JSON-Format konvertiert wird).

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

6
Normalerweise ist es eine gute Idee, eine Erklärung hinzuzufügen, was Ihr Code tut. Dadurch können neuere Entwickler verstehen, wie der Code funktioniert.
Caleb Kleveter

Können Sie erklären, warum der Code in der Antwort funktionieren sollte?
Cristik

Das funktioniert auch bei mir. Aber können Sie erklären, wie Sie das gemacht haben?
Deven Patil

Ich werde versuchen, die zweite Zeile dieses Codes zu erklären. date.getTime()Gibt die Zeit in Millesekunden zurück, daher sollten wir auch den zweiten Operanden in Millisekunden konvertieren. Da die date.getTimezoneOffset()Rückgabe in Minuten versetzt ist, multiplizieren wir sie mit 60000, da 1 Minute = 60000 Millisekunden. Durch Subtrahieren des Versatzes von der aktuellen Zeit erhalten wir die Zeit in UTC.
Maksim Pavlov

4

Sie können moment.js verwenden, um mit der Ortszeit zu formatieren:

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

gemeinsame Klasse nicht überschreiben Datum. Es kann leicht Ihre Anwendung brechen, wenn Sie einige externe Module verwenden.
Viacheslav Dobromyslov

3

Ich bin etwas spät dran, aber Sie können die toJson-Funktion bei einem Date mit Prototype wie folgt jederzeit überschreiben:

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

In meinem Fall gibt Util.getDateTimeString (this) einen String wie den folgenden zurück: "2017-01-19T00: 00: 00Z"


2
Beachten Sie, dass das Überschreiben von Browser-Globals die von Ihnen eingebetteten Bibliotheken von Drittanbietern beschädigen kann und ein großes Anti-Pattern darstellt. Mach das niemals in der Produktion.
Jakub.g

2

Normalerweise möchten Sie, dass jedem Benutzer Daten in seiner eigenen Ortszeit angezeigt werden.

Deshalb verwenden wir GMT (UTC).

Verwenden Sie Date.parse (jsondatestring), um die lokale Zeitzeichenfolge abzurufen.

es sei denn, Sie möchten , dass jedem Besucher Ihre Ortszeit angezeigt wird.

Verwenden Sie in diesem Fall die Methode von Anatoly.


2

Ich habe dieses Problem mithilfe der moment.jsBibliothek (der Nicht-Zeitzonen-Version) umgangen.

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));

Ich habe die flatpickr.min.jsBibliothek benutzt. Die Uhrzeit des resultierenden erstellten JSON-Objekts entspricht der angegebenen Ortszeit, jedoch der Datumsauswahl.


2

Out-of-the-Box-Lösung zum Erzwingen des JSON.stringifyIgnorierens von Zeitzonen:

  • Reines Javascript (basierend auf der anatolischen Antwort):

// 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);

Verwenden der Bibliothek 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

Ich habe ein bisschen Probleme damit, mit Legacy-Sachen zu arbeiten, bei denen sie nur an der Ostküste der USA arbeiten und keine Daten in UTC speichern, es ist alles EST. Ich muss die Daten basierend auf Benutzereingaben im Browser filtern, um das Datum in der Ortszeit im JSON-Format zu übergeben.

Nur um auf diese bereits veröffentlichte Lösung einzugehen - das ist, was ich benutze:

// 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();

Ich verstehe also, dass dies vor sich geht und die Zeit (in Millisekunden (also 60000)) vom Startdatum basierend auf dem Zeitzonenversatz (Rückgabe von Minuten) subtrahiert - in Erwartung der Hinzufügung von Zeit zu JSON ().


1

Hier ist etwas wirklich Ordentliches und Einfaches (zumindest glaube ich das :)) und erfordert keine Manipulation des Datums, um geklont zu werden oder eine der nativen Funktionen des Browsers wie toJSON zu überladen (Referenz: Wie JSON ein Javascript-Datum stringifiziert und die Zeitzone beibehält, höflicher Shawson)

Übergeben Sie eine Ersetzungsfunktion an JSON.stringify, die Dinge nach Herzenslust anordnet !!! Auf diese Weise müssen Sie keine Stunden- und Minutenunterschiede oder andere Manipulationen vornehmen.

Ich habe in console.logs Zwischenergebnisse eingefügt, damit klar ist, was los ist und wie die Rekursion funktioniert. Das zeigt etwas Bemerkenswertes: Der Wertparameter für den Ersatz ist bereits in das ISO-Datumsformat konvertiert :). Verwenden Sie diese [Taste], um mit Originaldaten zu arbeiten.

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 konvertiert normalerweise die lokale Zeitzone in UTC.

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

0

Alles läuft darauf hinaus, ob Ihr Server-Backend zeitzonenunabhängig ist oder nicht. Ist dies nicht der Fall, müssen Sie davon ausgehen, dass die Zeitzone des Servers mit der des Clients identisch ist, oder Informationen über die Zeitzone des Clients übertragen und diese auch in die Berechnungen einbeziehen.

Ein auf PostgreSQL-Backend basierendes Beispiel:

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'

Der letzte ist wahrscheinlich das, was Sie in der Datenbank verwenden möchten, wenn Sie nicht bereit sind, die Zeitzonenlogik ordnungsgemäß zu implementieren.


0

Stattdessen toJSONkönnen Sie die Formatierungsfunktion verwenden, die immer das richtige Datum und die richtige Uhrzeit + angibtGMT

Dies ist die robusteste Anzeigeoption. Es nimmt eine Reihe von Token und ersetzt sie durch die entsprechenden Werte.


0

Ich habe das in Winkel 8 versucht:

  1. Modell erstellen:

    export class Model { YourDate: string | Date; }
  2. in Ihrer Komponente

    model : Model;
    model.YourDate = new Date();
  3. Senden Sie das Datum zum Speichern an Ihre API

  4. Wenn Sie Ihre Daten von der API laden, gehen Sie folgendermaßen vor:

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

Sie erhalten Ihr Datum korrekt mit Ihrer Zeitzone.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.