如何JSON字符串化javascript日期并保留时区

时间:2015-06-28 04:23:13

标签: javascript json date datetime momentjs

我有一个由用户创建的日期对象,浏览器填写时区,如下所示:

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

但是,当我对它进行字符串化时,时区会再见

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

在保留浏览器时区的同时,我可以获得ISO8601字符串的最佳方式是使用moment.js并使用moment.format(),但当然,如果我不能使用{&#39},那么这将无法正常工作。通过内部使用JSON.stringify的东西序列化整个命令(在本例中为AngularJS)

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

为了完整性,我的域 需要本地时间和偏移量。

6 个答案:

答案 0 :(得分:62)

假设您有某种包含Date的对象:

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

您可以覆盖toJSON原型的Date功能。在这里,我使用moment.js从日期创建一个moment对象,然后使用不带参数的时刻format函数,它发出包括偏移量的ISO8601扩展格式。

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

现在,当您序列化对象时,它将使用您要求的日期格式:

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

当然,这会影响所有 Date个对象。如果要仅更改特定日期对象的行为,则可以仅覆盖该特定对象的toJSON函数,如下所示:

o.d.toJSON = function(){ return moment(this).format(); }

答案 1 :(得分:19)

基于Matt Johnsons的answer,我重新实现toJSON而不必依赖moment(我认为这是一个出色的库,但依赖于如此低的像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';
}

当提供的值“溢出”时,setHours方法将调整日期对象的其他部分。来自MDN

  

如果您指定的参数超出预期范围,则setHours()会尝试相应地更新Date对象中的日期信息。例如,如果您使用100作为secondsValue,则分钟将增加1(minutesValue + 1),并且40将用于秒。

答案 2 :(得分:8)

  

但是,当我对它进行字符串化时,时区会再见

这是因为Tue Jun 07 2011 04:00:00 GMT+1000 (E. Australia Standard Time)实际上是toString对象的Date方法的结果,而stringify似乎改为调用toISOString方法。< / p>

因此,如果toString格式符合您的要求,那么只需将字符串化

JSON.stringify(date.toString());

或者,既然你想稍后将你的“命令”字符串化,那么首先将那个值放在那里:

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

答案 3 :(得分:4)

我总是倾向于不弄乱日期之类的系统对象原型中的函数,您永远不知道什么时候以后在您的代码中以某种意外的方式咬住您。

相反,JSON.stringify方法接受您可以提供的“替换”功能(https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#The_replacer_parameter),允许您覆盖JSON.stringify如何执行其“字符串化”的内在条件;所以你可以做这样的事情;

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 :(得分:0)

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

答案 5 :(得分:0)

我创建了一个小型库,该库在JSON.stringify之后保留带有ISO8601字符串的时区。该库使您可以轻松更改本机Date.prototype.toJSON方法的行为。

npm:https://www.npmjs.com/package/lbdate

示例:

lbDate().init();

const myObj = {
  date: new Date(),
};

const myStringObj = JSON.stringify(myObj);

console.log(myStringObj);

// {"date":"2020-04-01T03:00:00.000+03:00"}

该库还为您提供了必要的选项,以自定义序列化结果。