Friday, April 13, 2012

How to display a datetime in the client local timezone in ASP.NET MVCviews

Friday, April 13, 2012 Posted by Andre Broers , , , ,
For my website http://www.watzdprice.com I ran into a problem where I needed to show a datetime from a ViewModel in the client local timezone. The problem is that the Razor views are rendered on the server and the server doesn't know the users timezone. So we have to create a client side solution. We have to add the server side datetime as utc to the viewmodel and we need javascript to transform this datetime to the client local time zone.

We start with creating a new MVC web project in visual studio and name it MvcDateTime.

Now we add our model in the Models folder of our project (Person.cs):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace MvcDateTime.Models
{
    public class Person
    {
        public string Name { get; set; }
        public long AppointmentDateTime { get; set; }
    }
}

As you can see the datetime is a long and represents the milliseconds from the epoch time (01-01-1970 00:00:00) in UTC timezone. We will use this function to convert our standard DateTime objects to this long value:
        private long DateTimeToJS(DateTime dt)
        {
            DateTime inutc = dt.ToUniversalTime();
            return (inutc.Ticks - 621355968000000000) / 10000;
        }

We alter our existing HomeController to display the index view with a simple list of persons:
        public ActionResult Index()
        {
            List<Person> lp = new List<Person>();
            lp.Add(new Person() { Name = "Andre", AppointmentDateTime = DateTimeToJS(DateTime.Now.AddDays(1)) });
            lp.Add(new Person() { Name = "Scott", AppointmentDateTime = DateTimeToJS(DateTime.Now.AddDays(2)) });
            lp.Add(new Person() { Name = "Tiger", AppointmentDateTime = DateTimeToJS(DateTime.Now.AddDays(3)) });

            ViewBag.Message = "Welcome to ASP.NET MVC!";

            return View(lp);
        }

Now that we have a Controller that spits up the List of persons with an appointment date we can continue with our view:
@model IEnumerable<MvcDateTime.Models.Person>

@{
    ViewBag.Title = "Home Page";
}

<script type="text/javascript">
    $(document).ready(function () {
        $(".date").each(function () {
            $(this).text((new Date(parseInt($(this).data("datetime")))).toLocaleString());
        });
    });
</script>

<table>
    <tr>
        <th>
            name
        </th>
        <th>
            appointment
        </th>
    </tr>
@foreach (var item in Model) {
    <tr>
        <td>
            @item.Name
        </td>
        <td>
            <div class="date" data-datetime="@item.AppointmentDateTime"></div>
        </td>
    </tr>
}
</table>

@{
    var grid = new WebGrid(Model);
}

@grid.GetHtml(columns: grid.Columns(
                grid.Column("name"),
                grid.Column(
                   header: "appointment",
                   style: "text-align-center",
                   format: (item) => new HtmlString("<div class='date' data-datetime='"+item.AppointmentDateTime+"'></div>")
                )
            )
)

In this view we create two grids with our list of persons. The first uses the default table to render the data and the second uses a webgrid to display the data.
We store the long datetime in a html5 data field and give all the datetime divs the class "date". In the jquery document ready function we can render this long to a datetime that is in the clients local timezone.