web-dev-qa-db-fra.com

Comment JSON stringifier une date javascript et préserver le fuseau horaire

J'ai un objet de date créé par l'utilisateur, avec le fuseau horaire renseigné par le navigateur, comme suit:

var date = new Date(2011, 05, 07, 04, 0, 0);
> Tue Jun 07 2011 04:00:00 GMT+1000 (E. Australia Standard Time)

Quand je le stratifie, cependant, le fuseau horaire passe au revoir

JSON.stringify(date);
> "2011-06-06T18:00:00.000Z"

Le meilleur moyen d'obtenir une chaîne ISO8601 tout en préservant le fuseau horaire du navigateur consiste à utiliser moment.js et à l'aide de moment.format(), mais cela ne fonctionnera bien sûr pas si je sérialise une commande entière via quelque chose qui utilise JSON.stringify En interne (dans ce cas, AngularJS)

var command = { time: date, contents: 'foo' };
$http.post('/Notes/Add', command);

Pour être complet, mon domaine ne nécessite à la fois l’heure locale et le décalage.

46
XwipeoutX

En supposant que vous ayez une sorte d’objet contenant un Date:

var o = { d : new Date() };

Vous pouvez remplacer la fonction toJSON du prototype Date. Ici, j'utilise moment.js pour créer un objet moment à partir de la date, puis j'utilise la fonction format du moment sans paramètres, qui émet le format étendu ISO8601, y compris l'offset.

Date.prototype.toJSON = function(){ return moment(this).format(); }

Maintenant, lorsque vous sérialisez l'objet, il utilisera le format de date que vous avez demandé:

var json = JSON.stringify(o);  //  '{"d":"2015-06-28T13:51:13-07:00"}'

Bien entendu, cela affectera les objets tousDate. Si vous souhaitez modifier le comportement de l'objet de date spécifique uniquement, vous pouvez remplacer la fonction toJSON de cet objet en particulier, comme ceci:

o.d.toJSON = function(){ return moment(this).format(); }
64
Matt Johnson-Pint

Sur la base de answer de Matt Johnsons, j’ai ré-implémenté toJSON sans avoir à dépendre de moment (ce qui, à mon avis, est une superbe bibliothèque, mais une dépendance une méthode de bas niveau comme toJSON me gêne).

Date.prototype.toJSON = function () {
  var timezoneOffsetInHours = -(this.getTimezoneOffset() / 60); //UTC minus local time
  var sign = timezoneOffsetInHours >= 0 ? '+' : '-';
  var leadingZero = (Math.abs(timezoneOffsetInHours) < 10) ? '0' : '';

  //It's a bit unfortunate that we need to construct a new Date instance 
  //(we don't want _this_ Date instance to be modified)
  var correctedDate = new Date(this.getFullYear(), this.getMonth(), 
      this.getDate(), this.getHours(), this.getMinutes(), this.getSeconds(), 
      this.getMilliseconds());
  correctedDate.setHours(this.getHours() + timezoneOffsetInHours);
  var iso = correctedDate.toISOString().replace('Z', '');

  return iso + sign + leadingZero + Math.abs(timezoneOffsetInHours).toString() + ':00';
}

La méthode setHours ajuste les autres parties de l'objet date lorsque la valeur fournie "déborde". De MDN :

Si un paramètre que vous spécifiez est en dehors de la plage attendue, setHours () tente de mettre à jour les informations de date dans l'objet Date en conséquence. Par exemple, si vous utilisez 100 pour secondsValue, les minutes seront incrémentées de 1 (minutesValue + 1) et 40 seront utilisées pendant des secondes.

21
bvgheluwe

Quand je le stratifie, cependant, le fuseau horaire passe au revoir

C'est parce que Tue Jun 07 2011 04:00:00 GMT+1000 (E. Australia Standard Time) est en fait le résultat de la méthode toString de l'objet Date, alors que stringify semble appeler la méthode toISOString au lieu.

Donc si le format toString est ce que vous voulez, alors simplement stringify that:

JSON.stringify(date.toString());

Ou, puisque vous voulez renforcer votre "commande" plus tard, mettez ça valeur à la première place:

var command = { time: date.toString(), contents: 'foo' };
8
CBroe

Je serais toujours enclin à ne pas jouer avec les fonctions du prototype d'objets système comme la date, vous ne savez jamais quand cela va vous mordre de manière inattendue plus tard dans votre code.

Au lieu de cela, la méthode JSON.stringify accepte une fonction "replacer" ( https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#The_replacer_parameter ) que vous pouvez fournir, ce qui vous permet d’ignorer la manière dont JSON.stringify exécute sa "stringification"; afin que vous puissiez faire quelque chose comme ça;

var replacer = function(key, value) {

   if (this[key] instanceof Date) {
      return this[key].toUTCString();
   }
   
   return value;
}

console.log(JSON.stringify(new Date(), replacer));
console.log(JSON.stringify({ myProperty: new Date()}, replacer));
4
Shawson

let date = new Date (JSON.parse (JSON.stringify (nouvelle date (2011, 05, 07, 04, 0, 0)))));

0
sujithklr93