ASP.NET MVC JsonResult Date Format

ASP.NET MVC JsonResult Date Format

I have a controller action that effectively simply returns a JsonResult of my model. So, in my method I have something like the following:
return new JsonResult(myModel);

This works well, except for one problem. There is a date property in the model and this appears to be returned in the Json result like so:
“\/Date(1239018869048)\/”

How should I be dealing with dates so they are returned in the format I require? Or how do I handle this format above in script?

Solutions/Answers:

Solution 1:

Just to expand on casperOne’s answer.

The JSON spec does not account for Date values. MS had to make a call, and the path they chose was to exploit a little trick in the javascript representation of strings: the string literal “/” is the same as “\/”, and a string literal will never get serialized to “\/” (even “\/” must be mapped to “\\/”).

See http://msdn.microsoft.com/en-us/library/bb299886.aspx#intro_to_json_topic2 for a better explanation (scroll down to “From JavaScript Literals to JSON”)

One of the sore points of JSON is the
lack of a date/time literal. Many
people are surprised and disappointed
to learn this when they first
encounter JSON. The simple explanation
(consoling or not) for the absence of
a date/time literal is that JavaScript
never had one either: The support for
date and time values in JavaScript is
entirely provided through the Date
object. Most applications using JSON
as a data format, therefore, generally
tend to use either a string or a
number to express date and time
values. If a string is used, you can
generally expect it to be in the ISO
8601 format. If a number is used,
instead, then the value is usually
taken to mean the number of
milliseconds in Universal Coordinated
Time (UTC) since epoch, where epoch is
defined as midnight January 1, 1970
(UTC). Again, this is a mere
convention and not part of the JSON
standard. If you are exchanging data
with another application, you will
need to check its documentation to see
how it encodes date and time values
within a JSON literal. For example,
Microsoft’s ASP.NET AJAX uses neither
of the described conventions. Rather,
it encodes .NET DateTime values as a
JSON string, where the content of the
string is /Date(ticks)/ and where
ticks represents milliseconds since
epoch (UTC). So November 29, 1989,
4:55:30 AM, in UTC is encoded as
“\/Date(628318530718)\/”.

A solution would be to just parse it out:

value = new Date(parseInt(value.replace("/Date(", "").replace(")/",""), 10));

However I’ve heard that there is a setting somewhere to get the serializer to output DateTime objects with the new Date(xxx) syntax. I’ll try to dig that out.

Related:  Make javascript alert Yes/No Instead of Ok/Cancel

The second parameter of JSON.parse() accepts a reviver function where prescribes how the value originally produced by, before being returned.

Here is an example for date:

var parsed = JSON.parse(data, function(key, value) {
  if (typeof value === 'string') {
    var d = /\/Date\((\d*)\)\//.exec(value);
    return (d) ? new Date(+d[1]) : value;
  }
  return value;
});

See the docs of JSON.parse()

Solution 2:

Here’s my solution in Javascript – very much like JPot’s, but shorter (and possibly a tiny bit faster):

value = new Date(parseInt(value.substr(6)));

“value.substr(6)” takes out the “/Date(” part, and the parseInt function ignores the non-number characters that occur at the end.

EDIT: I have intentionally left out the radix (the 2nd argument to parseInt); see my comment below. Also, please note that ISO-8601 dates are preferred over this old format — so this format generally shouldn’t be used for new development. See the excellent Json.NET library for a great alternative that serializes dates using the ISO-8601 format.

For ISO-8601 formatted JSON dates, just pass the string into the Date constructor:

var date = new Date(jsonDate); //no ugly parsing needed; full timezone support

Solution 3:

There are quite a bit of answers to handle it client side, but you can change the output server side if you desired.

Related:  Does Javascript pass by reference?

There are a few ways to approach this, I’ll start with the basics. You’ll have to subclass the JsonResult class and override the ExecuteResult method. From there you can take a few different approaches to change the serialization.

Approach 1:
The default implementation uses the JsonScriptSerializer. If you take a look at the documentation, you can use the RegisterConverters method to add custom JavaScriptConverters. There are a few problems with this though: The JavaScriptConverter serializes to a dictionary, that is it takes an object and serializes to a Json dictionary. In order to make the object serialize to a string it requires a bit of hackery, see post. This particular hack will also escape the string.

public class CustomJsonResult : JsonResult
{
    private const string _dateFormat = "yyyy-MM-dd HH:mm:ss";

    public override void ExecuteResult(ControllerContext context)
    {
        if (context == null)
        {
            throw new ArgumentNullException("context");
        }

        HttpResponseBase response = context.HttpContext.Response;

        if (!String.IsNullOrEmpty(ContentType))
        {
            response.ContentType = ContentType;
        }
        else
        {
            response.ContentType = "application/json";
        }
        if (ContentEncoding != null)
        {
            response.ContentEncoding = ContentEncoding;
        }
        if (Data != null)
        {
            JavaScriptSerializer serializer = new JavaScriptSerializer();

            // Use your custom JavaScriptConverter subclass here.
            serializer.RegisterConverters(new JavascriptConverter[] { new CustomConverter });

            response.Write(serializer.Serialize(Data));
        }
    }
}

Approach 2 (recommended):
The second approach is to start with the overridden JsonResult and go with another Json serializer, in my case the Json.NET serializer. This doesn’t require the hackery of approach 1. Here is my implementation of the JsonResult subclass:

public class CustomJsonResult : JsonResult
{
    private const string _dateFormat = "yyyy-MM-dd HH:mm:ss";

    public override void ExecuteResult(ControllerContext context)
    {
        if (context == null)
        {
            throw new ArgumentNullException("context");
        }

        HttpResponseBase response = context.HttpContext.Response;

        if (!String.IsNullOrEmpty(ContentType))
        {
            response.ContentType = ContentType;
        }
        else
        {
            response.ContentType = "application/json";
        }
        if (ContentEncoding != null)
        {
            response.ContentEncoding = ContentEncoding;
        }
        if (Data != null)
        {
            // Using Json.NET serializer
            var isoConvert = new IsoDateTimeConverter();
            isoConvert.DateTimeFormat = _dateFormat;
            response.Write(JsonConvert.SerializeObject(Data, isoConvert));
        }
    }
}

Usage Example:

[HttpGet]
public ActionResult Index() {
    return new CustomJsonResult { Data = new { users=db.Users.ToList(); } };
}

Additional credits:
James Newton-King

Related:  Reading environment variables with Javascript

Solution 4:

Moment.js is an extensive datetime library that also supports this. http://momentjs.com/docs/#/parsing/asp-net-json-dates/

ex: moment(“/Date(1198908717056-0700)/”)

It might help. plunker output

Solution 5:

Using jQuery to auto-convert dates with $.parseJSON

Note: this answer provides a jQuery extension that adds automatic ISO and .net date format support.

Solution 6:

I found that creating a new JsonResult and returning that is unsatisfactory – having to replace all calls to return Json(obj) with return new MyJsonResult { Data = obj } is a pain.


So I figured, why not just hijack the JsonResult using an ActionFilter:

public class JsonNetFilterAttribute : ActionFilterAttribute
{
    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        if (filterContext.Result is JsonResult == false)
        {
            return;
        }

        filterContext.Result = new JsonNetResult(
            (JsonResult)filterContext.Result);
    }

    private class JsonNetResult : JsonResult
    {
        public JsonNetResult(JsonResult jsonResult)
        {
            this.ContentEncoding = jsonResult.ContentEncoding;
            this.ContentType = jsonResult.ContentType;
            this.Data = jsonResult.Data;
            this.JsonRequestBehavior = jsonResult.JsonRequestBehavior;
            this.MaxJsonLength = jsonResult.MaxJsonLength;
            this.RecursionLimit = jsonResult.RecursionLimit;
        }

        public override void ExecuteResult(ControllerContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }

            var isMethodGet = string.Equals(
                context.HttpContext.Request.HttpMethod, 
                "GET", 
                StringComparison.OrdinalIgnoreCase);

            if (this.JsonRequestBehavior == JsonRequestBehavior.DenyGet
                && isMethodGet)
            {
                throw new InvalidOperationException(
                    "GET not allowed! Change JsonRequestBehavior to AllowGet.");
            }

            var response = context.HttpContext.Response;

            response.ContentType = string.IsNullOrEmpty(this.ContentType) 
                ? "application/json" 
                : this.ContentType;

            if (this.ContentEncoding != null)
            {
                response.ContentEncoding = this.ContentEncoding;
            }

            if (this.Data != null)
            {
                response.Write(JsonConvert.SerializeObject(this.Data));
            }
        }
    }
}

This can be applied to any method returning a JsonResult to use JSON.Net instead:

[JsonNetFilter]
public ActionResult GetJson()
{
    return Json(new { hello = new Date(2015, 03, 09) }, JsonRequestBehavior.AllowGet)
}

which will respond with

{"hello":"2015-03-09T00:00:00+00:00"}

as desired!


You can, if you don’t mind calling the is comparison at every request, add this to your FilterConfig:

// ...
filters.Add(new JsonNetFilterAttribute());

and all of your JSON will now be serialized with JSON.Net instead of the built-in JavaScriptSerializer.