Tengo un objeto de fecha creado por el usuario, con la zona horaria completada por el navegador, así:
var date = new Date(2011, 05, 07, 04, 0, 0); > Tue Jun 07 2011 04:00:00 GMT+1000 (E. Australia Standard Time)Sin embargo, cuando lo encadeno, la zona horaria se despide.
JSON.stringify(date); > "2011-06-06T18:00:00.000Z" La mejor forma en que puedo obtener una cadena ISO8601 mientras conservo la zona horaria del navegador es usando moment.js y moment.format() , pero, por supuesto, eso no funcionará si estoy serializando un comando completo a través de algo que usa JSON.stringify internamente (en este caso, AngularJS)
var command = { time: date, contents: 'foo' }; $http.post('/Notes/Add', command);Para completar, mi dominio necesita tanto la hora local como el desplazamiento.
Suponiendo que tiene algún tipo de objeto que contiene una Date :
var o = { d : new Date() }; Puede anular la función toJSON del prototipo de Date . Aquí uso moment.js para crear un objeto de moment a partir de la fecha, luego uso la función de format de momento sin parámetros, que emite el formato extendido ISO8601, incluido el desplazamiento.
Date.prototype.toJSON = function(){ return moment(this).format(); }Ahora, cuando serialice el objeto, utilizará el formato de fecha que solicitó:
var json = JSON.stringify(o); // '{"d":"2015-06-28T13:51:13-07:00"}' Por supuesto, eso afectará a todos los objetos Date . Si desea cambiar el comportamiento de solo el objeto de fecha específico, puede anular solo la función toJSON de ese objeto en particular, así:
odtoJSON = function(){ return moment(this).format(); }Siempre me inclinaría a no meterme con las funciones en el prototipo de los objetos del sistema como la fecha, nunca se sabe cuándo eso te va a afectar de alguna manera inesperada más adelante en tu código.
En su lugar, el método JSON.stringify acepta una función de "reemplazo" ( https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#The_replacer_parameter ) que puede proporcionar, lo que permite usted para anular las entrañas de cómo JSON.stringify realiza su "stringificación"; para que puedas hacer algo como esto;
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)); console.log(JSON.stringify({ myProperty: new Date(), notADate: "I'm really not", trueOrFalse: true}, replacer));Basado en la respuesta de Matt Johnsons, volví a implementar toJSON sin tener que depender del moment (que creo que es una biblioteca espléndida, pero me molesta una dependencia en un método de tan bajo nivel como toJSON ).
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'; } El método setHours ajustará otras partes del objeto de fecha cuando el valor proporcionado se "desborde". Desde MDN :
Si un parámetro que especifica está fuera del rango esperado, setHours() intenta actualizar la información de fecha en el objeto Fecha en consecuencia. Por ejemplo, si usa 100 para segundosValor, los minutos se incrementarán en 1 (minutosValor + 1), y 40 se usará para segundos.