Saturday, July 4, 2015

Javascript UTC to Local Time for Display

If you are developing an application which will only be used by a people in one timezone, then DateTime.Now with the current time zone will work for you. This is a rather short sighted. As the userbase grows, users will have to translate the dates manually. Additionally, if you have migrate the application to servers in different locations which have a different time zone set or a time zone that you can't control, the date and times generated will be off. This is especially true when developing applications for the cloud (which by and large use UTC).

There are a couple options:
  1. Have a setting per users which indicates the users timezone and convert the times on every view/page render
  2. Have the user's browser handle the conversion

The former requires significantly more development, user interaction, and more processing time. The latter requires a bit of HTML5 and javascript. So let's see what it takes to do it in javascript. There are javascript libraries like Moment.js which do this with potentially more robustness, but it is more than 12KB minified and gzipped. If it can be done in 1-2KB's, why tote the rest around. When page load times are so important, every kilobyte saved is time spent loading your page. Lets say we want to render the following render the following HTML to the browser.
<time datetime="@Html.DisplayFor(modelItem => item.Created) UTC">
 @Html.DisplayFor(modelItem => item.Created) UTC
</time>
We can iterate over all of the time elements and convert the UTC times and leverage javascript to translate the times to local with the following code.
function UtcTimesToLocal() {
 $("time").each(function (index, element) {
  var el = $(element),
   time = el.attr("datetime"),
   converted = new Date(time);
  var dateString = ToDateString(converted);
  el.text(dateString);
 });
}

function ToDateString(dateObj, dateFormat) {
 var curr_year = dateObj.getFullYear(),
  curr_month = LeadingZero(dateObj.getMonth() + 1),
  curr_date = LeadingZero(dateObj.getDate()),
  curr_hour = LeadingZero(dateObj.getHours()),
  curr_min = LeadingZero(dateObj.getMinutes()),
  curr_sec = LeadingZero(dateObj.getSeconds()),
  curr_ampm = "AM";
 if (curr_hour > 11) {
  curr_ampm = "PM";
  curr_hour = (curr_hour == 12) ? 12 : curr_hour - 12;
 }
 var timestamp = curr_year + "-" + curr_month + "-" + curr_date + " " + curr_hour + ":" + curr_min + ":" + curr_sec + " " + curr_ampm + " " + LocalTimeZone();
 return timestamp;
}

function LeadingZero(val) {
 return (val < 10) ? "0" + val : val;
}

function LocalTimeZone () {
  // From http://stackoverflow.com/questions/2897478/get-client-timezone-not-gmt-offset-amount-in-js
  var now = new Date().toString(),
      timezone = now.indexOf('(') > -1 ?
        //now.match(/\([^\)]+\)/)[0] :  // Uncomment this line to return the full time zone text
        now.match(/\([^\)]+\)/)[0].match(/[A-Z]/g).join('') :  // Uncomment this line to return the full time zone abbreviation
        now.match(/[A-Z]{3,4}/)[0];
  if (timezone == "GMT" && /(GMT\W*\d{4})/.test(now))
    timezone = RegExp.$1;
  return timezone;
}
Then at the bottom of the page, run the UtcTimesToLocal function.
<script>
 $(function() { UtcTimesToLocal(); });
</script>
An example project can be found on my UTCtoLocalJS GitHub repository.

No comments: