Javascript JSON Date Deserialization
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.