web-dev-qa-db-fra.com

JSON Stringify modifie l'heure de la date en raison de l'UTC

Mes objets de date en JavaScript sont toujours représentés par UTC +2 en raison de l'endroit où je me trouve. Donc comme ça

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

Problème fait un JSON.stringify Convertit la date ci-dessus en

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

Ce dont j'ai besoin, c'est que la date et l'heure soient respectées, mais ce n'est pas le cas.

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

Fondamentalement, j'utilise ceci:

var jsonData = JSON.stringify(jsonObject);

J'ai essayé de passer un paramètre de remplacement (second paramètre sur stringify), mais le problème est que la valeur a déjà été traitée.

J'ai aussi essayé d'utiliser toString() et toUTCString() sur l'objet date, mais ceux-ci ne me donnent pas ce que je veux non plus.

Quelqu'un peut-il m'aider?

87
mark smith

Récemment, j'ai rencontré le même problème. Et cela a été résolu en utilisant le code suivant:

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

JSON utilise le Date.prototype.toISOString fonction qui ne représente pas l'heure locale - elle représente l'heure en UTC non modifié - si vous regardez votre sortie de date, vous pouvez voir que vous êtes à UTC + 2 heures. C'est pourquoi la chaîne JSON change de deux heures, mais si cela permet à la même heure d’être correctement représentée sur plusieurs fuseaux horaires.

37
olliej

Pour mémoire, rappelez-vous que le dernier "Z" de "2009-09-28T08: 00: 00Z" signifie que l'heure est bien en UTC.

Voir http://en.wikipedia.org/wiki/ISO_8601 pour plus de détails.

15
Locoluis

Voici une autre réponse (et personnellement, je pense que c'est plus approprié)

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 :)
7
aug

Je suis un peu en retard mais vous pouvez toujours écraser la fonction toJson dans le cas d’une Date utilisant Prototype comme ceci:

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

Dans mon cas, Util.getDateTimeString (this) renvoie une chaîne comme celle-ci: "2017-01-19T00: 00: 00Z"

date.toJSON () imprime la date UTC dans une chaîne formatée (le décalage est donc ajouté lors de la conversion au format JSON).

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

J'ai contourné ce problème en utilisant le moment.js bibliothèque (version non-fuseau horaire).

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

J'utilisais le flatpickr.min.js bibliothèque. L'heure de la création de l'objet JSON résultant correspond à l'heure locale fournie mais au sélecteur de date.

2
Paul

vous pouvez utiliser moment.js pour formater avec l'heure locale:

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

Habituellement, vous souhaitez que les dates soient présentées à chaque utilisateur dans son heure locale.

c'est pourquoi nous utilisons GMT (UTC).

Utilisez Date.parse (jsondatestring) pour obtenir la chaîne d’heure locale.

sauf si vous voulez indiquer votre heure locale à chaque visiteur.

Dans ce cas, utilisez la méthode d'Anatoly.

2
kennebec

Je rencontre un peu ce problème avec les produits traditionnels, où ils ne travaillent que sur la côte est des États-Unis et ne stockent pas les dates au format UTC, il s’agit uniquement de données EST. Je dois filtrer les dates en fonction de la saisie de l'utilisateur dans le navigateur, il faut donc que la date soit passée en heure locale au format JSON.

Juste pour élaborer sur cette solution déjà affichée - voici ce que j’utilise:

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

Donc, si j'ai bien compris, cela va aller de l'avant et soustraire le temps (en millisecondes (donc 60000)) à partir de la date de début en fonction du décalage du fuseau horaire (renvoyé minutes) - en prévision de l'ajout du temps que toJSON () va ajouter.

1
MrRobboto

Solution prête à l'emploi pour forcer JSON.stringify ignorer les fuseaux horaires:

  • JavaScript pur (basé sur la réponse d'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);

Utilisation de la bibliothèque 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>
1
Benjamin Caure

Voici quelque chose de vraiment soigné et simple (au moins, je crois bien :)) et ne nécessite aucune manipulation de la date à cloner ni surcharger aucune des fonctions natives du navigateur comme toJSON (référence: Comment JSON codifier une date javascript et préserver le fuseau horaire) , courtie Shawson)

Transmettez une fonction de remplacement à JSON.stringify qui renforce le contenu à votre convenance !!! De cette façon, vous n'avez pas à faire de diffs heure et minute ou d'autres manipulations.

J'ai mis dans console.logs pour voir les résultats intermédiaires, ainsi il est clair ce qui se passe et comment fonctionne la récursivité. Cela révèle quelque chose qui mérite d'être signalé: la valeur param à remplacer est déjà convertie au format de date ISO :). Utilisez cette [touche] pour travailler avec les données d'origine.

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
Atul Lohiya

Tout se résume à savoir si le serveur de votre serveur est indépendant du fuseau horaire ou non. Si ce n'est pas le cas, vous devez supposer que le fuseau horaire du serveur est identique à celui du client, ou transférer des informations sur le fuseau horaire du client et les inclure également dans les calculs.

un exemple basé sur le backend de 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'

Le dernier est probablement ce que vous voulez utiliser dans la base de données, si vous ne souhaitez pas implémenter correctement la logique de fuseau horaire.

0
korc

Au lieu de toJSON, vous pouvez utiliser la fonction format qui donne toujours la date et l'heure correctes + GMT

C'est l'option d'affichage la plus robuste. Il prend une chaîne de jetons et les remplace par les valeurs correspondantes.

0
Asqan