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:
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?
Date objects are serialized to ISO-formatted date strings (see the Date. toJSON() function), but JSON. parse() leaves these in string form and does not restore the original Date object. Function, RegExp, and Error objects and the undefined value cannot be serialized or restored.
You can get the value of the date field as String by calling the getText() method of JsonParser class and then you can simply convert it into a Date object by using the parse() method of SimpleDateFormat, as you normally parse Date in Java.
JSON does not have a built-in type for date/time values. The general consensus is to store the date/time value as a string in ISO 8601 format.
JSON.parse
has a little-known second parameter: the 'reviver' function. This is used for precisely this purpose: to revive a date string into a Date
object (or, hypothetically, any other kind of object you wanted to convert from string) during the initial parse.
There's an SO post about this, and here's a blog post that 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
.
Here's the key function from that blog post, 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 opinions about 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. )
I took @LastCoder advice and wrote a simple implementation. It seems to be doing what I wanted it to.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With