Deserializing JSON Strings as JavaScript Date Objects

JSON is a very lightweight data-interchange format that only supports a handful of values:

  • objects
  • arrays
  • strings
  • numbers
  • true and false
  • null

Note that there's no special type for datetimes defined in the JSON grammar. Therefore, datetimes are usually represented as strings that adhere to a specific format like ISO-8601:

{
    "date": "2016-04-26T18:09:16Z"
}

Now imagine you're making an API call that returns the above JSON in the body of the HTTP response. Generally, you'd use the JSON.parse() function to deserialize the string into a JavaScript object:

const body = `{
    "date": "2016-04-26T18:09:16Z"
}`;

const obj = JSON.parse(body);

However, the obj.date property is not a Date object, but a simple string. After all, there's no magic involved that causes JSON.parse() to deserialize certain string values as dates:

const { date } = obj;
console.log(typeof date);
// "string"

It might be desirable in some cases to establish the convention that values which look like dates are automatically deserialized as such, the premise being that further processing is simpler if a datetime is represented by an actual Date instance rather than a plain string.

To establish that convention, you can pass a function as the second argument to the JSON.parse() call which allows you to transform the value originally parsed before returning it. JSON.parse() calls that function with the current key and value:

const dateFormat = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$/;

function reviver(key, value) {
    if (typeof value === "string" && dateFormat.test(value)) {
        return new Date(value);
    }
    
    return value;
}

const text = '{ "date": "2016-04-26T18:09:16Z" }';
const obj = JSON.parse(text, reviver);

console.log(typeof obj.date);
// "object"

Here, we're parsing a JSON object with a single date property that holds a date which is expressed as a string according to ISO 8601, a standard describing the representation of dates and times. Now, the obj.date property is an instance of Date, so the typeof operator returns "object".

Of course, you're free to use whatever mechanism you want to detect datetime values. The specific regular expression pattern generally depends on how the backend(s) you're talking to deserialize(s) datetime values. However, you might also decide to inspect the key parameter to decide whether or not to create a Date instance from a given value. It's totally up to you!

Finally, please be aware that this approach isn't bulletproof in all cases, especially not with freeform user input. A string value that looks like a date but doesn't actually represent one is a false positive. Therefore, be as restrictive as possible when specifying the target datetime string format.

Use the coupon code LAUNCHDAY for $10 off!

Learn ES6

2 Comments

Luiz Felipe

awesome my bro

Paul Keefe

Using JSON.stringify with a date and then parsing it back gives me milliseconds at the end. So, for that you can make the simple change to:

// example date: 2016-11-26T16:10:28.600Z const dateFormat = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z$/;

Great article!