Handling dates in JSON responses is something many web developers struggle with. The JSON Specification doesn't specify how dates should be represented in a JSON string, so every implementation invented its own way of representing dates.
These are some of the formats in use today:
- {"date": new Date(ms_since_epoch) }
- {"date": Date(ms_since_epoch) }
- {"date": "Date(ms_since_epoch) }
- {"date": "/Date(ms_since_epoch)" }
- {"date": "\/Date(ms_since_epoch)\/" }
- {"date": "yyyy-MM-ddTHH:mm:ssZ" }
- {"date": "yyyy-MM-ddTHH:mm:ss" }
Formats 1 and 2 are actually invalid JSON. However, they're the only formats that were handled correctly by jQuery 1.3.2 and earlier. eval() also handles these. But again, it's not valid JSON.
That leaves the other 5 formats, which are valid according to the JSON specs.
Starting with version 1.4, jQuery's built-in JSON evaluator will check if there is a function
JSON.parse() available. If it is there, it will use that function to evaluate JSON objects. If not, jQuery will use the "unsafe"
eval() way of parsing JSON.
JSON.parse() is a function from the
json2.js file, which can be downloaded from the
JSON websiteThe problem
JSON.parse() doesn't handle dates.
At all. But it does have a way to handle non-standard values by specifying an extra parameter "reviver", which is a function that takes a value and returns the value converted to the data type of your choice.
For example: if you want to handle the ISO date format correctly, you can do this:
var parsedObject = JSON.parse(jsonData, function (key, value) {
var a;
if (typeof value === 'string') {
a =
/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
if (a) {
return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
+a[5], +a[6]));
}
}
return value;
});
(this example is taken from the json2.js source code)
This function will check if a string value parsed from the JSON string is in a specific date format, and return a Javascript date object.
You could expand this function to handle every other possible date format, which shouldn't be too hard to do, but how do you tell jQuery to use this "reviver" function?
Well, you can't.
The solution
There's an easy solution: after including
json2.js, redefine the
JSON.parse() function so it passes your conversion (
reviver) function to the original
JSON.parse() function:
<script type="text/javascript" src="json2.js"></script>
<script>
(function() {
var _origParse = JSON.parse;
JSON.parse = function(text) {
return _origParse(text, function(key, value) {
var a;
if (typeof value === 'string') {
a = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
if (a) {
return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4], +a[5], +a[6]));
}
if (value.slice(0, 5) === 'Date(' && value.slice(-1) === ')') {
var d = new Date(value.slice(5, -1));
if (d) {
return d;
}
}
}
return value;
});
}
})();
</script>
Now when you return some JSON object to your jQuery script, dates will be parsed correctly, without having to change your code. The code snippet above handles cases 3 to 6 correctly. I'll leave it up to you to add case 7...

•