Date-Time data type is a complex issue. Complex enough to make you confuse overtime you are writing code that return dates from the web server to the browser.
ASP.NET MVC 5 and Web API 2 serialize dates differently, which might create more confusion for developers who are using both serializations in one web application.
I am trying to cover everything you need to know about Date and Date serialization to JSON, in ASP.NET, and what issues are related to them.
I wanted to cover as well the issues with JavaScript date data type, but I will leave that to another post, because there are tons of issues that can be covered when it comes to JavaScript and date.

Ambiguity of Date/Time values

The main problem with date/time is its ambiguity. For example when I have a datetime as : 2016/05/05 10:00:00 AM, I have to know to which timezone this value belong in order to clear any abmiguity.
If we add to the timezone, that the value can be from a different calendar than the GregorianCalendar, then we add more complexity to that abmiguity.
In this post, I am going to avoid talking about different calendars, assuming that all dates are from the default us-en calendar (the Gregorain canlendar).
How to clear the ambiguity of date/time values?

Unambiguous representation of Date/Time

There are different formats that the industry came up with to Unamiguously represent a single point of time. The web development industry came up with different solutions to have an Unambiguous representation of time values:

UTC Time

UTC stands for Coordinated Universal Time, which is the time in Timezone zero, disregarding the daylight saving time.
UTC is an Unambiguous representation of a single point of a time values, and a UTC time is the same for someone live in California to someone live in China.
A possible solution that web developers do, is to store date/times in their UTC values, and do all the server manipulation, calculation with the UTC value, and send it to the browsers as UTC values, and the JavaScript on the browsers will converted to local time to show it on the web pages.

ISO 8601

There are plenty of date representation in the web, but the most famous and the one that was adopted by JavaScript on a large scale was the ISO-8601. This is an example of how ISO 8601 works

Date: 2016-10-12 10:18:42 Pacific time
ISO 8601: 2016-10-11T10:18:42-06:00

Date: 2016-10-12 10:18:42 UTC time
ISO 8601: 2016-10-11T10:18:42z


Date representation in .NET

.NET specially with version 4 and later has full support for dates, time zones, and converting between timezone, which help developers achieve all the date challenges they face. In .NET the following classes are involved or related to Date:

  1. System.DateTime
  2. System.DateTimeOffset
  3. System.TimeSpan
  4. System.TimeZoneInfo

DateTime structure

The DateTime class was the first introduced by .NET since version 1.0 and it doesn’t offer so much to represent timezones. The only timezone that DateTime allow is Local time zone, and UTC time zone. It provides is a property Kind of type : DateTimeKind which is an enumeration that provides three kinds of date/time:

//DateTimeKind Enumeration 
Local
Utc
Unspecified

You can specify the kind when you create the DateTime object, which is an optional parameter, like this:

// DateTime constructor: DateTime(year, month, day, hour, minute, second, kind)
var localTime = new DateTime(2016, 10, 10, 10, 10, 10, DateTimeKind.Local);
var utcTime = new DateTime(2016, 10, 10, 10, 10, 10, DateTimeKind.Utc);
var localCurrentTime = DateTime.Now; // this is local time

//when omitted then it is Unspecified:
var localTime = new DateTime(year, month, day, hour, minute, second); // this is Unspecified


When to use DateTime?
  • You deal with only local time, and you don’t have cross-timezone calculation.
  • You deal only with UTC date time.
  • You deal with abstract date/time (using Unspecified). For example to represent multi-national stores where all stores open at 8:00 AM.

DateTimeOffset TimeZoneInfo

The new structure DateTimeOffset structure was introduce to support dates with different timezones.

DateTimeOffset = DateTime + Offset from UTC

// The constructor of DateTimeOffset has both component:
// DateTimeOffset(DateTime, TimeOffset);
var pacificTime = new DateTimeOffset(new DateTime(2016, 10, 10), new TimeOffset(-7, 0, 0));

It is not a good practice to hard code the time offset (-7) above, beside we could make mistakes because of daylight saving, and this is where we use the class TimeZoneInfo.
TimeZoneInfo has all the timezones of the world, and we can search a specific time zone by its name using the method FindSystemTimeZoneById.
For example we can rewrite the above code:

var pacificTime = new DateTimeOffset(new DateTime(2016, 10, 10), 
    TimeZoneInfo.FindSystemTimeZoneById("Pacific Standard Time").BaseUtcOffset
);

To check all the time zones ID(s), you can find it here

When to use DateTimeOffset?
  • Your code deals with different time values belong to different timezones.
  • You need to convert between different timezones.
  • You need to do date time calculation for dates that don’t belong to your local server timezone or UTC timezone.


Date/Time in JSON & JavaScipt

JSON lacks the definition of date/time, and that is because JavaScipt lacks the definition of date/time literals. JavaScript support the date/time through the Date object, and its methods and constructors.
To create a Date object in JavaScript there are these options:

  1. new Date(): To create the current date.
  2. new Date(integer_value): the number of milliseconds since 1-Jan-1970 00:00:00 UTC (Unix Epoch).
  3. new Date(string_value): the ISO-8601 format of date/time or any recognizable date string.
  4. new Date(year, month, day[, hour, minute, seconds, milliseconds])

Date/time in Javascript is a huge subject, but for this post, I am going to cover only what is related to ASP.NET and how Asp.NET serialize dates to JSON.

Asp.NET Serialization of Date/Time to JSON

ASP.NET has three different JSON Serializers, each serialize datetime differently:

  1. Web API 2 serializer: (JSON.NET).
  2. ASP.NET MVC Serializer.
  3. DataContractJsonSerializer

Let us start from WEB API 2 serializer:

Web API 2 JSON Serializer

The default JSON serializer in Web API 2 is not from Microsoft, but it is a third party library (JSON.NET) from NewtonSoft.
It is available through System.Net.Http.Formatting.JsonMediaTypeFormatter. to return JSON date in Web API 2 we do the following in the APP_Start/WebApiConfig.cs:

// in the file APP_Start/WebApiConfig.cs
config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html") );

JSON.NET serializes the datetime to ISO-8601 format, and the following examples show how it serialize the date, assuming the local time is Pacific time (-7 hours):

Date value serialized value
DateTime.Now (Pacific time) 2016-10-11T19:25:34.8346658-07:00
DateTime.UtcNow 2016-10-12T01:25:34.8346658Z
New DateTime(2016, 6, 6, 4, 5,5 ) 2016-06-06T04:05:05
New DateTimeOffset(New DateTime(2016, 6, 6, 4, 5,5 ), new TimeSpan(-2, 0,0)) 2016-06-06T04:05:05-02:00


ASP.NET MVC Serializer

ASP.NET Controller (System.Web.Mvc.Controller) has a built in method Json that return JsonResult.
This method uses JavaScriptSerializer (System.Web.Script.Serialization.JavaScriptSerializer). This serializer serializes the date differently, and it return back in the format: “\/Date(ticks)\/”.
Where ticks are the number of milliseconds since 1-Jan-1970 00:00:00 UTC (Unix Epoch). An example:

"\"\/Date(1335205592410)\/\"" 

The rational behind this format you can find it here.
To consume this value in JavaScript, we have to do more tricks on the client side, by tacking away the Date() and return the number inside and create from the number the date.
The following code will do that:

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; });

Or a simpler version, but less robust:

var parsed = JSON.parse(data, function(key, value) { 
  if (typeof value === 'string') { 
    var d = /\/Date\(/.exec(value); 
    return (d) ? new Date(parseInt(value.substr(6))) : value; 
  } 
return value; });

Obviously, JavaScriptSerializer doesn’t tell the timezone of the value, and it is not a good choise if we are dealing with different time zones.

Beside the date/time problems JavaScriptSerializer has more distadvantages comparing to JSON.NET serializer, which encouraged lots of developers in the community to abandon it and use JSON.NET serializer instead.


DataContractJsonSerializer Serializer

DataContractJsonSerializer (System.Runtime.Serialization.Json.DataContractJsonSerializer) is a third serializer that comes with .NET framework. It is not the default serializer, so you need to use it explicitaley.
In case you want to spend the effort to write code to change the default serializer, then it is better to use JSON.NET serializer instead because it is better on different aspects.
Since JSON.NET serializer was introduced, not many developers used this serializer, so I am really goint to ignore it.

Conclusion

I hope that was a good coverage of all the issues related to date/time in ASP.NET, and that you now understand why JSON.NET serializer was officially adopted by Web API team over JavaScriptSerializer.