Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does JSON.stringify screw up my datetime object?

{ id: 1533,
  story_type_id: 1,
  content_id: 470,
  created_at: Sun, 05 Feb 2012 07:02:43 GMT,
  updated_at: Sun, 05 Feb 2012 07:02:43 GMT,
  type_name: 'post' }

I have a JSON object with the "datetime" field like above. It's perfect. But when I stringify it (I want to store it in cache), I get this format:

"created_at":"2012-02-05T07:02:43.000Z"

This causes problems, because when I want to JSON.parse this, suddenly it's no longer datetime format and it's incompatible with my other format.

What can I do to solve this problem? I have 'created_at' littered everywhere throughout my application. I don't want to manually change each one.

like image 524
TIMEX Avatar asked Feb 08 '12 13:02

TIMEX


2 Answers

It is actually possible to modify how a Date object will be serialized into JSON. Combined with the reviver function, a bi-directional solution can be created which will automatically work on serialization and can easily be used on deserialization.

First modify the serialization like this:

Date.prototype.toJSON = function() { return "{timestamp}+" . this.getTime() }

This will change the representation of a Date object into a UNIX timestamp with a prefix as a marker:

> json = JSON.stringify({test:new Date()});
"{"test":"{timestamp}1380164268633"}"

Then you can create a reviver function which will automatically filter out these values:

function json_deserialize_helper(key,value) {
  if ( typeof value === 'string' ) {
    var regexp;
    regexp = /^{timestamp}(\d*)$/.exec(value);
    if ( regexp ) {
      return new Date(+regexp[1]);
    }
  }
  return value;
}

(Credit: This code was basically copied from this answer in a related question: https://stackoverflow.com/a/14509447/2572897)

Now with this setup, deserialization of our result from before will result in a Date object again:

> JSON.parse(json, json_deserialize_helper);
Object {test: Thu Sep 26 2013 04:57:48 GMT+0200 (CEST)}

Or you can choose not to modify the serialization but instead use the regexp to catch the standard serialization format:

function json_deserialize_helper(key,value) {
  if ( typeof value === 'string' ) {
    var regexp;
    regexp = /^\d\d\d\d-\d\d-\d\dT\d\d:\d\d:\d\d.\d\d\dZ$/.exec(value);
    if ( regexp ) {
      return new Date(value);
    }
  }
  return value;
}

Example:

> json = JSON.stringify({test:new Date()})
"{"test":"2013-09-26T03:05:26.563Z"}"
> JSON.parse(json, json_deserialize_helper)
Object {test: Thu Sep 26 2013 05:05:26 GMT+0200 (CEST)}
like image 70
Juliane Holzt Avatar answered Sep 28 '22 17:09

Juliane Holzt


Date.prototype.toJSON = function() { return moment(this).format('L'); }

You can read more about moment documentation and tailor type of date you want to return.

like image 41
Navid Golforoushan Avatar answered Sep 28 '22 17:09

Navid Golforoushan