Parsing C# DateTime without timezone indicator to a cross-browser valid date object

In a recent project at Tekaris we had to calculate with date objects in JavaScript. The values were stored in a SQL database and delivered as C# DateTime instances via an ASP.NET Web Api Controller. No conversion to a string with custom formatting was done. The Api Controller did all that automatically.

The client received the DateTime object from the REST interface in the format “yyyy-MM-ddTHH:mm:ss.fff“

Example: 2014-03-14T12:33:17.948

For “typesafe” processing we created Date objects by calling the constructor of JavaScript Date.

Example:

Server

    public class BookingModel
    {
        public string Name { get; set; }
        public DateTime BookingDate { get; set; }
    }

    [RoutePrefix("api")]
    public class ValueController : ApiController
    {
        [Route("booking/")]
        [HttpGet]
        public BookingModel Get()
        {
            return new BookingModel
            {
                Name = "Test", 
                BookingDate = new DateTime(2014, 3, 10, 15, 30, 22, 219)
            };
        }
    }

Client

<div>
    <script type="text/javascript">
        function onClickHandler() {
            $.ajax({
                url: 'http://localhost:28145/api/booking',
                data: '',
                success: onSuccess,
                dataType: 'json'
            });
        }

        function onSuccess(data, textStatus, jqXHR) {
            var date = new Date(data.bookingDate);
            alert('Text: ' + data.bookingDate + '\nObject:' + date);
        }
    </script>
    <button onclick="onClickHandler();">Get datetime</button>
</div>

Everything was fine with Firefox and Internet Explorer 11 but Google Chromes JS engine created a different Date object with (in our case/timezone) one hour in the future. The problem is that the datetime string has no timezone indication and in that case Chrome interprets the given time as a UTC time and Firefox interprets it as a local time.

The following example shows you how to handle that on client side if you have no influence on the way and format the data is provided to you.

function onSuccess(data, textStatus, jqXHR) {
	var date = new Date(parseDate(data.bookingDate));
	alert('Text: ' + data.bookingDate + '\nObject:' + date);
}

function parseDate(value) {
	if (/\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d(\.\d+)*/.test(value)) {

		var dateSegments = value.substring(0, value.indexOf('T')).split('-');
		var timeSegments = value.substring(value.indexOf('T') + 1).split(':');

		var seconds = timeSegments[2];

		var milliseconds = '0';
		if (seconds.indexOf('.') > 0) {
			var segments = seconds.split('.');
			seconds = segments[0];
			milliseconds = segments[1];
		}

		var result = new Date(parseInt(dateSegments[0]),
							  parseInt(dateSegments[1]) - 1,
							  parseInt(dateSegments[2]),
							  parseInt(timeSegments[0]),
							  parseInt(timeSegments[1]),
							  parseInt(seconds),
							  parseInt(milliseconds));
		return result;
	}

	return new Date(value);
}

The function parseDate takes the string and if it´s in the described format (with or without milliseconds) and splits it into the components year, month, day, hours, minutes, seconds and milliseconds. That allows you to call the Date constructor that takes these values and you will get the same date object on different browsers.

If you can change the server logic you can set the format of the JsonFormatter to add timezone information:

Example:

GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.DateFormatString = "yyyy-MM-ddTHH:mm:ss.fffZ";

You can find the custom format strings on MSDN

http://msdn.microsoft.com/en-us/library/8kb3ddd4.aspx