How do I format a Microsoft JSON date?

Viewed 788562

I'm taking my first crack at Ajax with jQuery. I'm getting my data onto my page, but I'm having some trouble with the JSON data that is returned for Date data types. Basically, I'm getting a string back that looks like this:

/Date(1224043200000)/

From someone totally new to JSON - How do I format this to a short date format? Should this be handled somewhere in the jQuery code? I've tried the jQuery.UI.datepicker plugin using $.datepicker.formatDate() without any success.

FYI: Here's the solution I came up with using a combination of the answers here:

function getMismatch(id) {
  $.getJSON("Main.aspx?Callback=GetMismatch",
    { MismatchId: id },

    function (result) {
      $("#AuthMerchId").text(result.AuthorizationMerchantId);
      $("#SttlMerchId").text(result.SettlementMerchantId);
      $("#CreateDate").text(formatJSONDate(Date(result.AppendDts)));
      $("#ExpireDate").text(formatJSONDate(Date(result.ExpiresDts)));
      $("#LastUpdate").text(formatJSONDate(Date(result.LastUpdateDts)));
      $("#LastUpdatedBy").text(result.LastUpdateNt);
      $("#ProcessIn").text(result.ProcessIn);
    }
  );

  return false;
}

function formatJSONDate(jsonDate) {
  var newDate = dateFormat(jsonDate, "mm/dd/yyyy");
  return newDate;
}

This solution got my object from the callback method and displayed the dates on the page properly using the date format library.

41 Answers

eval() is not necessary. This will work fine:

var date = new Date(parseInt(jsonDate.substr(6)));

The substr() function takes out the /Date( part, and the parseInt() function gets the integer and ignores the )/ at the end. The resulting number is passed into the Date constructor.


I have intentionally left out the radix (the 2nd argument to parseInt); see my comment below.

Also, I completely agree with Rory's comment: ISO-8601 dates are preferred over this old format - so this format generally shouldn't be used for new development.

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

You can use this to get a date from JSON:

var date = eval(jsonDate.replace(/\/Date\((\d+)\)\//gi, "new Date($1)"));

And then you can use a JavaScript Date Format script (1.2 KB when minified and gzipped) to display it as you want.

For those using Newtonsoft Json.NET, read up on how to do it via Native JSON in IE8, Firefox 3.5 plus Json.NET.

Also the documentation on changing the format of dates written by Json.NET is useful: Serializing Dates with Json.NET

For those that are too lazy, here are the quick steps. As JSON has a loose DateTime implementation, you need to use the IsoDateTimeConverter(). Note that since Json.NET 4.5 the default date format is ISO so the code below isn't needed.

string jsonText = JsonConvert.SerializeObject(p, new IsoDateTimeConverter());

The JSON will come through as

"fieldName": "2009-04-12T20:44:55"

Finally, some JavaScript to convert the ISO date to a JavaScript date:

function isoDateReviver(value) {
  if (typeof value === 'string') {
    var a = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)(?:([\+-])(\d{2})\:(\d{2}))?Z?$/.exec(value);
      if (a) {
        var utcMilliseconds = Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4], +a[5], +a[6]);
        return new Date(utcMilliseconds);
      }
  }
  return value;
}

I used it like this

$("<span />").text(isoDateReviver(item.fieldName).toLocaleString()).appendTo("#" + divName);

The original example:

/Date(1224043200000)/  

does not reflect the formatting used by WCF when sending dates via WCF REST using the built-in JSON serialization. (at least on .NET 3.5, SP1)

I found the answer here helpful, but a slight edit to the regex is required, as it appears that the timezone GMT offset is being appended onto the number returned (since 1970) in WCF JSON.

In a WCF service I have:

[OperationContract]
[WebInvoke(
    RequestFormat = WebMessageFormat.Json,
    ResponseFormat = WebMessageFormat.Json,
    BodyStyle = WebMessageBodyStyle.WrappedRequest
    )]
ApptVisitLinkInfo GetCurrentLinkInfo( int appointmentsId );

ApptVisitLinkInfo is defined simply:

public class ApptVisitLinkInfo {
    string Field1 { get; set; }
    DateTime Field2 { get; set; }
    ...
}

When "Field2" is returned as Json from the service the value is:

/Date(1224043200000-0600)/

Notice the timezone offset included as part of the value.

The modified regex:

/\/Date\((.*?)\)\//gi

It's slightly more eager and grabs everything between the parens, not just the first number. The resulting time sinze 1970, plus timezone offset can all be fed into the eval to get a date object.

The resulting line of JavaScript for the replace is:

replace(/\/Date\((.*?)\)\//gi, "new Date($1)");

Don't repeat yourself - automate date conversion using $.parseJSON()

Answers to your post provide manual date conversion to JavaScript dates. I've extended jQuery's $.parseJSON() just a little bit, so it's able to automatically parse dates when you instruct it to. It processes ASP.NET formatted dates (/Date(12348721342)/) as well as ISO formatted dates (2010-01-01T12.34.56.789Z) that are supported by native JSON functions in browsers (and libraries like json2.js).

Anyway. If you don't want to repeat your date conversion code over and over again I suggest you read this blog post and get the code that will make your life a little easier.

If you say in JavaScript,

var thedate = new Date(1224043200000);
alert(thedate);

you will see that it's the correct date, and you can use that anywhere in JavaScript code with any framework.

Updated

We have an internal UI library that has to cope with both Microsoft's ASP.NET built-in JSON format, like /Date(msecs)/, asked about here originally, and most JSON's date format including JSON.NET's, like 2014-06-22T00:00:00.0. In addition we need to cope with oldIE's inability to cope with anything but 3 decimal places.

We first detect what kind of date we're consuming, parse it into a normal JavaScript Date object, then format that out.

1) Detect Microsoft Date format

// Handling of Microsoft AJAX Dates, formatted like '/Date(01238329348239)/'
function looksLikeMSDate(s) {
    return /^\/Date\(/.test(s);
}

2) Detect ISO date format

var isoDateRegex = /^(\d\d\d\d)-(\d\d)-(\d\d)T(\d\d):(\d\d):(\d\d)(\.\d\d?\d?)?([\+-]\d\d:\d\d|Z)?$/;

function looksLikeIsoDate(s) {
    return isoDateRegex.test(s);
}

3) Parse MS date format:

function parseMSDate(s) {
    // Jump forward past the /Date(, parseInt handles the rest
    return new Date(parseInt(s.substr(6)));
}

4) Parse ISO date format.

We do at least have a way to be sure that we're dealing with standard ISO dates or ISO dates modified to always have three millisecond places (see above), so the code is different depending on the environment.

4a) Parse standard ISO Date format, cope with oldIE's issues:

function parseIsoDate(s) {
    var m = isoDateRegex.exec(s);

    // Is this UTC, offset, or undefined? Treat undefined as UTC.
    if (m.length == 7 ||                // Just the y-m-dTh:m:s, no ms, no tz offset - assume UTC
        (m.length > 7 && (
            !m[7] ||                    // Array came back length 9 with undefined for 7 and 8
            m[7].charAt(0) != '.' ||    // ms portion, no tz offset, or no ms portion, Z
            !m[8] ||                    // ms portion, no tz offset
            m[8] == 'Z'))) {            // ms portion and Z
        // JavaScript's weirdo date handling expects just the months to be 0-based, as in 0-11, not 1-12 - the rest are as you expect in dates.
        var d = new Date(Date.UTC(m[1], m[2]-1, m[3], m[4], m[5], m[6]));
    } else {
        // local
        var d = new Date(m[1], m[2]-1, m[3], m[4], m[5], m[6]);
    }

    return d;
}

4b) Parse ISO format with a fixed three millisecond decimal places - much easier:

function parseIsoDate(s) {
    return new Date(s);
}

5) Format it:

function hasTime(d) {
    return !!(d.getUTCHours() || d.getUTCMinutes() || d.getUTCSeconds());
}

function zeroFill(n) {
    if ((n + '').length == 1)
        return '0' + n;

    return n;
}

function formatDate(d) {
    if (hasTime(d)) {
        var s = (d.getMonth() + 1) + '/' + d.getDate() + '/' + d.getFullYear();
        s += ' ' + d.getHours() + ':' + zeroFill(d.getMinutes()) + ':' + zeroFill(d.getSeconds());
    } else {
        var s = (d.getMonth() + 1) + '/' + d.getDate() + '/' + d.getFullYear();
    }

    return s;
}

6) Tie it all together:

function parseDate(s) {
    var d;
    if (looksLikeMSDate(s))
        d = parseMSDate(s);
    else if (looksLikeIsoDate(s))
        d = parseIsoDate(s);
    else
        return null;

    return formatDate(d);
}

The below old answer is useful for tying this date formatting into jQuery's own JSON parsing so you get Date objects instead of strings, or if you're still stuck in jQuery <1.5 somehow.

Old Answer

If you're using jQuery 1.4's Ajax function with ASP.NET MVC, you can turn all DateTime properties into Date objects with:

// Once
jQuery.parseJSON = function(d) {return eval('(' + d + ')');};

$.ajax({
    ...
    dataFilter: function(d) {
        return d.replace(/"\\\/(Date\(-?\d+\))\\\/"/g, 'new $1');
    },
    ...
});

In jQuery 1.5 you can avoid overriding the parseJSON method globally by using the converters option in the Ajax call.

http://api.jquery.com/jQuery.ajax/

Unfortunately you have to switch to the older eval route in order to get Dates to parse globally in-place - otherwise you need to convert them on a more case-by-case basis post-parse.

There is no built in date type in JSON. This looks like the number of seconds / milliseconds from some epoch. If you know the epoch you can create the date by adding on the right amount of time.

Check up the date ISO standard; kind of like this:

yyyy.MM.ddThh:mm

It becomes 2008.11.20T22:18.

TLDR: You cannot reliably convert that date-only value, send a string instead...

...or at least that is how almost all of these answers should start off.

There is a number of conversion issues that are happening here.

This Is a Date Without Time

Something everybody seems to be missing is how many trailing zeros there are in the question - it is almost certainly started out as a date without time:

/Date(1224043200000)/

When executing this from a javascript console as a new Date (the basis of many answers)

new Date(1224043200000)

You get:

enter image description here

The original asker was probably in EST and had a pure date (sql) or a DateTime (not DateTimeOffset) with midnight.

In other words, the intention here is that the time portion is meaningless. However, if the browser executes this in the same timezone as the server that generated it it doesn't matter and most of the answers work.

Bit By Timezone

But, if you execute the code above on a machine with a different timezone (PST for example):

enter image description here

You'll note that we are now a day behind in this other timezone. This will not be fixed by changing the serializer (which will still include timezone in the iso format)

The Problem

Date (sql) and DateTime (.net) do not have timezone on them, but as soon as you convert them to something that does (javascript inferred thru json in this case), the default action in .net is to assume the current timezone.

The number that the serialization is creating is milliseconds since unix epoch or:

(DateTimeOffset.Parse("10/15/2008 00:00:00Z") - DateTimeOffset.Parse("1/1/1970 00:00:00Z")).TotalMilliseconds;

Which is something that new Date() in javascript takes as a parameter. Epoch is from UTC, so now you've got timezone info in there whether you wanted it or not.

Possible solutions:

It might be safer to create a string property on your serialized object that represents the date ONLY - a string with "10/15/2008" is not likely to confuse anybody else with this mess. Though even there you have to be careful on the parsing side: https://stackoverflow.com/a/31732581

However, in the spirit of providing an answer to the question asked, as is:

function adjustToLocalMidnight(serverMidnight){ 
  var serverOffset=-240; //injected from model? <-- DateTimeOffset.Now.Offset.TotalMinutes
  var localOffset=-(new Date()).getTimezoneOffset(); 
  return new Date(date.getTime() + (serverOffset-localOffset) * 60 * 1000)
}

var localMidnightDate = adjustToLocalMidnight(new Date(parseInt(jsonDate.substr(6))));

As a side note, KendoUI supports to convert Microsoft JSON date. So, If your project has the reference to "KendoUI", you may simply use

var newDate = kendo.parseDate(jsonDate);

I use this simple function for getting date from Microsoft JSON Date

function getDateValue(dateVal) {
    return new Date(parseInt(dateVal.replace(/\D+/g, '')));
};

replace(/\D+/g, '') will remove all characters other than numbers

parseInt will convert the string to number

Usage

$scope.ReturnDate = getDateValue(result.JSONDateVariable)

Try this...

function formatJSONDate(jsonDate) {
            var date = jsonDate;
            var parsedDate = new Date(parseInt(date.toString().substring(6)));
            var newDate = new Date(parsedDate);
            var getMonth = newDate.getMonth() + 1;
            var getDay = newDate.getDay();
            var getYear = newDate.getFullYear(); 

            var standardDate = (getMonth<10 ? '0' : '') + getMonth + '/' + (getDay<10 ? '0' : '') + getDay + '/' + getYear;
            return standardDate;
        }

getYear() returns the year - 1900, This has been deprecated for a while now, it's best to use getFullYear()

If you are using Kotlin then this will solve your problem.

val dataString = "/Date(1586583441106)/"
val date = Date(Long.parseLong(dataString.substring(6, dataString.length - 2)))

Your JSON should probably be returning an object of some sort (well, a string representation thereof).

"{ myDate : Date(1224043200000) }"

Using jQuery, you can access your data object this way:

$.get(
    "myJSONFile.php",
    function (data) {
        // data.myDate will be a date object.

        // to show in a short date format (eg: dd/mm/yyyy)
        alert (
            data.myDate.getDate() + "/"
            + (data.myDate.getMonth() + 1) + "/"
            + data.myDate.getFullYear()
        ); // alerts: "15/10/2008"
    }
);
Related