Javascript JSON 日期反序列化

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14488745/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-26 21:46:39  来源:igfitidea点击:

Javascript JSON Date Deserialization

javascriptjsonserialization

提问by mdeangelo272

I am trying to deserialize a json object that has a javascript date in it. When JSON.stringify is called on the object, dates are serialized to strings that are not properly deserialized back to dates. I have attempted to deserialize the object using both the native browser implementation with chrome, IE, and FF and using jquery. Both give the some results. Here is the snippet:

我正在尝试反序列化一个包含 javascript 日期的 json 对象。在对象上调用 JSON.stringify 时,日期将序列化为未正确反序列化为日期的字符串。我尝试使用带有 chrome、IE 和 FF 的本机浏览器实现以及使用 jquery 来反序列化对象。两者都给出了一些结果。这是片段:

var obj = {Date: new Date()};
var objSer = JSON.stringify(obj);
var objDeser = JSON.parse(objSer);
var objJqDeser = $.parseJSON(objSer);

function getYear(value){
  try{
     return value.getYear();
  }
  catch(err){
    return err;
  }
}

$("#orig").text("Orig Year: " + getYear(obj.Date));
$("#deser").text("Deser Year: " + getYear(objDeser.Date));
$("#jqDeser").text("JqDeser Year: " + getYear(objJqDeser.Date));

I want objDeser.Date to be a js date not a string. You can see this problem in action here: http://jsbin.com/unijud/24/edit. Is there any js libraries that can properly deserialize the dates when building the javascript object?

我希望 objDeser.Date 是一个 js 日期而不是一个字符串。你可以在这里看到这个问题:http: //jsbin.com/unijud/24/edit。是否有任何 js 库可以在构建 javascript 对象时正确反序列化日期?

采纳答案by mdeangelo272

I took @LastCoder advice and wrote a simple implementation. It seems to be doing what I wanted it to.

我接受了@LastCoder 的建议并编写了一个简单的实现。它似乎在做我想做的事。

var jsonDates = {
  dtrx2: /\d{4}-\d{2}-\d{2}/,
  parse: function(obj){
      var parsedObj = JSON.parse(obj);
      return this.parseDates(parsedObj);
  },
  parseDates: function(obj){
    // iterate properties
    for(pName in obj){

      // make sure the property is 'truthy'
      if (obj[pName]){
        var value = obj[pName];
        // determine if the property is an array
        if (Array.isArray(value)){
          for(var ii = 0; ii < value.length; ii++){
            this.parseDates(value[ii]);
          }
        }
        // determine if the property is an object
        else if (typeof(value) == "object"){
          this.parseDates(value);
        }
        // determine if the property is a string containing a date
        else if (typeof(value) == "string" && this.dtrx2.test(value)){
          // parse and replace
          obj[pName] = new Date(obj[pName]);
        }
      }
    }

    return obj;
  }
};

A live example is available on jsbin. A reference is available on gist.

jsbin上提供了一个实时示例。可以在gist上找到参考。

回答by XML

JSON.parsehas a little-known second parameter: the 'reviver' function. This is used for precisely this purpose: to revive a date string into a Dateobject (or, hypothetically, any other kind of object you wanted to convert from string) during the initial parse.

JSON.parse有一个鲜为人知的第二个参数:'reviver' 函数。这正是用于此目的:Date在初始解析期间将日期字符串恢复为对象(或者,假设,您想从字符串转换的任何其他类型的对象)。

There's an SO postabout this, and here's a blog postthat includes an implementation example and a function that will do property checking for a couple common date encodings (ISO & that weird .NET AJAX format), before parsing to a Date.

有一篇关于此的SO 文章,这里有一篇博客文章,其中包含一个实现示例和一个函数,该函数将在解析为Date.

Here's the key function from that blog post, fwiw:

这是该博客文章 fwiw 中的关键功能:

// JSON date deserializer
// use as the second, 'reviver' argument to JSON.parse();

if (window.JSON && !window.JSON.dateParser) {
    var reISO = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*))(?:Z|(\+|-)([\d|:]*))?$/;
    var reMsAjax = /^\/Date\((d|-|.*)\)[\/|\]$/;

    JSON.dateParser = function (key, value) {
        // first, just make sure the property is a string:
        if (typeof value === 'string') {
            // then, use regex to see if it's an ISO-formatted string
            var a = reISO.exec(value);
            if (a) {
                // if so, Date() can parse it:
                return new Date(value);
            }
            // otherwise, see if it's a wacky Microsoft-format string:
            a = reMsAjax.exec(value);
            if (a) {
                // and perform some jujitsu to make use of it:
                var b = a[1].split(/[-+,.]/);
                return new Date(b[0] ? +b[0] : 0 - +b[1]);
            }
            // here, you could insert any additional tests and parse instructions you like, for other date syntaxes...
        }
        // important: you need to return any values you're not parsing, or they die...
        return value;
    };
}

// use: JSON.parse(json,JSON.dateParser); 

(There are lots of opinionsabout proper regexes for ISO 8601 dates. YMMV. Also, there's no particular reason to punch the function onto the global JSON object. You could store/reference it anywhere you like. )

(对于 ISO 8601 日期的正确正则表达式有很多意见。YMMV。此外,没有特别的理由将函数打到全局 JSON 对象上。您可以在任何您喜欢的地方存储/引用它。)

回答by James Drinkard

In order to represent dates using JavaScript, I found that JSON uses ISO 8601, a specific string format to encode dates as string. When I last checked though, there is not an official standard for what the date format should look like. The major browsers use ISO 8601 as the JSON Date encoding format.

为了使用 JavaScript 表示日期,我发现 JSON 使用 ISO 8601,这是一种将日期编码为字符串的特定字符串格式。不过,当我最后一次检查时,没有关于日期格式应该是什么样子的官方标准。主要浏览器使用 ISO 8601 作为 JSON 日期编码格式。

So, dates are encoded as ISO 8601 strings and then used just like a regular strings when the JSON is serialized and deserialized.

因此,日期被编码为 ISO 8601 字符串,然后在 JSON 序列化和反序列化时像常规字符串一样使用。

That being said, ISO dates can be converted into JavaScript dates by use of the JavaScript Date constructor, which accepts a wide variety of inputs to construct a date, ISO 8601 being one of them.

也就是说,可以使用 JavaScript Date 构造函数将 ISO 日期转换为 JavaScript 日期,该构造函数接受多种输入来构造日期,ISO 8601 就是其中之一。

Get todays date:

获取今天的日期:

 var curDate = new Date();
document.write(curDate); //Mon Feb 01 2016 12:57:12 GMT-0600 (Central Standard Time)

Parse it into a string:

将其解析为字符串:

var dateStr = JSON.parse(JSON.stringify(curDate));
document.write(dateStr);//2016-02-01T18:59:35.375Z

Then convert it back to a javascript date, using the constructor:

然后使用构造函数将其转换回 javascript 日期:

var date = new Date(curDate);
document.write(date); //Mon Feb 01 2016 12:59:35 GMT-0600 (Central Standard Time)

回答by Goyuix

The JSON spec does not include special formatting for dates. As such they are often serialized as a string, sometimes with special markings to indicate it should be treated as a Date object if the language supports them. As such, most (all?) browser-native JSON parsers can not round-trip a Date object properly.

JSON 规范不包括日期的特殊格式。因此,它们通常被序列化为字符串,有时带有特殊标记以指示如果语言支持它们,则应将其视为 Date 对象。因此,大多数(全部?)浏览器原生 JSON 解析器无法正确地往返 Date 对象。

There are several good libraries that help with this - I very much like MomentJSthough I have used datejsin the past as well. You would just need to iterate over your objects and convert the proper fields to Date objects after they have been parsed.

有几个很好的库可以帮助解决这个问题——我非常喜欢MomentJS,尽管我过去也使用过datejs。您只需要遍历对象并在解析对象后将正确的字段转换为 Date 对象。

I find it helpful to remember that the JSON format is much more restrictive than JavaScript object literal notation.

我发现 JSON 格式比 JavaScript 对象文字表示法的限制要多得多,这很有帮助。

回答by Louis Ricci

You could manually add all of the Date functions you require to the String.prototype.

您可以手动将所需的所有日期函数添加到 String.prototype。

String.prototype.getYear = function() {
    return Date.parse(this).getYear();
};
var obj = {date: new Date()};
var dtObj = JSON.parse(JSON.stringify(obj));
console.log(dtObj.date.getYear());

Or you could override JSON.parse and have it loop through the result object looking for strings that match the time stamp regex and then convert them to Date objects.

或者您可以覆盖 JSON.parse 并让它循环遍历结果对象,查找与时间戳正则表达式匹配的字符串,然后将它们转换为 Date 对象。

var JSON_parse = JSON.parse;
JSON.parse = function(str) {
    var res = JSON_parse(str);
    findAndConvertStringsToDates(res);
    return res;
} 

EDITHere's what I'd throw together for an implementation

编辑这是我为实现而拼凑的内容

(function() {
    var jsonParse = JSON.parse;
    var reDate = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/i;
    function jsonDate(obj) {
        var type = typeof(obj);
        if(type == 'object') {
            for(var p in obj)
                if(obj.hasOwnProperty(p))
                    obj[p] = jsonDate(obj[p]);
            return obj;
        } else if(type == 'string' && reDate.test(obj)) {
            return new Date(obj);
        } 
        return obj;
    }
    JSON.parse = function(str) { return jsonDate(jsonParse(str)); }
})();
/*
 * Tests
 */
var dt = JSON.parse(JSON.stringify({date: new Date()}));
console.log(typeof(dt.date));
console.log(JSON.parse(JSON.stringify(null)));
console.log(JSON.parse(JSON.stringify(123)));
console.log(JSON.parse(JSON.stringify("test")));
console.log(JSON.parse(JSON.stringify(new Date())));
console.log(JSON.parse(JSON.stringify([1,new Date(),2])));
console.log(JSON.parse(JSON.stringify({d: new Date(), d2: {d3: new Date(), d4: [0,new Date(),4]}})));