2013-01-23 28 views
9

Tôi đang cố gắng deserialize một đối tượng json có một ngày javascript trong đó. Khi JSON.stringify được gọi trên đối tượng, các ngày được tuần tự hóa thành các chuỗi không được deserialized đúng vào ngày tháng. Tôi đã cố gắng deserialize đối tượng bằng cách sử dụng cả việc thực hiện trình duyệt gốc với chrome, IE và FF và sử dụng jquery. Cả hai đều đưa ra một số kết quả. Đây là đoạn mã:Javascript JSON Ngày Deserialization

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

Tôi muốn objDeser.Date là ngày js không phải là chuỗi. Bạn có thể thấy vấn đề này đang hoạt động ở đây: http://jsbin.com/unijud/24/edit. Có bất kỳ thư viện js có thể deserialize đúng ngày khi xây dựng các đối tượng javascript?

Trả lời

5

tôi đã tư vấn @LastCoder và đã viết một thực hiện đơn giản. Có vẻ như tôi đang làm điều tôi muốn.

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

Ví dụ trực tiếp có sẵn trên jsbin. Tài liệu tham khảo có sẵn trên gist.

3

Thông số JSON không bao gồm định dạng đặc biệt cho các ngày. Vì vậy chúng thường được xê-ri hóa dưới dạng một chuỗi, đôi khi có các dấu hiệu đặc biệt để cho biết nó sẽ được coi là đối tượng Ngày nếu ngôn ngữ hỗ trợ chúng. Như vậy, hầu hết (tất cả?) Trình phân tích cú pháp JSON trình duyệt nguyên gốc không thể làm tròn một đối tượng Date đúng cách.

Có một số thư viện tốt trợ giúp việc này - tôi rất thích MomentJS mặc dù tôi đã sử dụng datejs trong quá khứ. Bạn chỉ cần lặp lại các đối tượng của mình và chuyển đổi các trường thích hợp thành Date objects sau khi chúng đã được phân tích cú pháp.

Tôi thấy hữu ích khi nhớ rằng định dạng JSON là hạn chế hơn nhiều so với ký hiệu chữ của đối tượng JavaScript.

+0

Cảm ơn bạn. Các thư viện này dường như thêm chức năng cho các ngày nhưng dường như không tăng cường/triển khai thực hiện một trình phân tích cú pháp json. – mdeangelo272

0

Bạn có thể thêm thủ công tất cả các hàm Ngày bạn yêu cầu vào 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()); 

Hoặc bạn có thể ghi đè JSON.parse và lặp qua đối tượng tìm kiếm chuỗi phù hợp với dấu thời gian và sau đó chuyển đổi chúng thành Đối tượng ngày.

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

EDIT Đây là những gì tôi muốn ném lại với nhau cho một thực hiện

(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]}}))); 
+0

Tùy chọn 2 về cơ bản là những gì tôi theo sau. Tôi đã hy vọng tìm thấy một thư viện đã triển khai chức năng findAndConvertStringsToDates. Tôi không phải là một guru guru và đã hy vọng tránh phải thực hiện điều này bản thân mình. – mdeangelo272

+0

@ mdeangelo272 - Tôi đã chỉnh sửa bằng giải pháp khả thi, có thể có vấn đề với trình duyệt rất cũ, nhưng ít hơn 20 dòng mã không phải là quá nhiều để làm việc thông qua. –

+1

Đối với bất kỳ ai tìm thấy câu trả lời này trong tương lai, đây là một ý tưởng rất tồi. Điều này sửa đổi toàn bộ 'JSON', vì vậy bất kỳ thư viện nào trên trang sử dụng JSON toàn cầu sẽ nhận được phiên bản vá lỗi khỉ này hoạt động theo cách không chuẩn. Nếu bạn muốn hành vi này, đừng thêm nó vào đối tượng JSON toàn cục, nhưng sử dụng một hàm riêng biệt cho nó. – bcherny

7

JSON.parse có thông số thứ hai ít được biết đến: chức năng 'hồi sinh'. Điều này được sử dụng cho mục đích chính xác này: để hồi sinh chuỗi ngày thành đối tượng Date (hoặc, giả sử, bất kỳ loại đối tượng nào khác mà bạn muốn chuyển đổi từ chuỗi) trong phân tích cú pháp ban đầu.

Có một SO post về điều này, và đây là một blog post trong đó bao gồm một ví dụ thực hiện và một chức năng mà sẽ làm tài sản kiểm tra cho một mã hóa vài ngày chung (ISO & mà lạ dạng AJAX NET), trước khi phân tích cú pháp để một Date.

Đây là chức năng quan trọng từ đó bài đăng blog, 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); 

(Có lots of opinions về regexes thích hợp cho tiêu chuẩn ISO 8601 ngày YMMV..Ngoài ra, không có lý do cụ thể nào để nhấn hàm vào đối tượng JSON chung. Bạn có thể lưu trữ/tham khảo nó bất cứ nơi nào bạn muốn.)

+0

Regexp ngày ISO tốt hơn: '/^\ d {4} - (0 [1-9] | 1 [0-2]) - ([12] \ d | 0 [1-9] | 3 [01]) ([T \ s] (([01] \ d | 2 [0-3]) \: [0-5] \ d | 24 \: 00) (\: [0-5] \ d ([\. ,] \ d +)?)? ([zZ] | ([\ + -]) ([01] \ d | 2 [0-3]) \ :? ([0-5] \ d)?)?)?) ? $/' – asdfasdfads

0

Để đại diện cho các ngày sử dụng JavaScript, tôi thấy rằng JSON sử dụng ISO 8601, một định dạng chuỗi cụ thể để mã hóa ngày dưới dạng chuỗi. Tuy nhiên, khi tôi kiểm tra lần cuối, không có tiêu chuẩn chính thức cho định dạng ngày như thế nào. Các trình duyệt chính sử dụng ISO 8601 làm định dạng mã hóa ngày JSON.

Vì vậy, ngày được mã hóa dưới dạng chuỗi ISO 8601 và sau đó được sử dụng giống như một chuỗi thông thường khi JSON được tuần tự hóa và deserialized.

Điều đó đang được nói, ngày ISO có thể được chuyển đổi thành ngày JavaScript bằng cách sử dụng hàm tạo ngày JavaScript, chấp nhận nhiều đầu vào để tạo ngày, ISO 8601 là một trong số đó.

Nhận ngày todays:

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

phân tích nó thành một chuỗi:

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

Sau đó chuyển đổi nó trở lại một ngày javascript, sử dụng các nhà xây dựng:

var date = new Date(curDate); 
document.write(date); //Mon Feb 01 2016 12:59:35 GMT-0600 (Central Standard Time) 
Các vấn đề liên quan