Tag Archives: different time zones

World Time Engine

In my last post I discussed about the procedure to show local date time in our application UI. Toady I am going to tell you the concept which you can think just an extension of my previous post. I told that in the case of localization we should store our date time in UTC format and at the time of showing we can convert in local time. I showed some sample code in C# and JavaScript to convert local date time to UTC and vice versa. But those code depending on the system time zone on which the code is executing. If we change our system time zone to a different time zone which is not right, then the conversion will also showing the wrong date time. For example suppose in a web application the user who is using our application from browser change her time zone to a wrong time zone then our JavaScript code will actually calculate the wrong date time. If this is not ok with our application we are currently developing then what is the solution?

The solution is we have to track the original time zone of the user who is using our application. For that we can use a third party service. There are many actually, I am using here ‘World Time Engine’ which is a paid service.

There are two procedures to access the service. One is through IP address and another is through Latitude and Longitude of the user who is using our application. When we create a membership in the service then they will generate a unique key for us and send it to our mail. We have to send this unique key along with the IP address.

http://worldtimeengine.com/api/ip/[unique key]/[IP address]

If all are going well and right then the service will send a XML as a response to us.

<?xml version="1.0" encoding="UTF-8" ?>
<timezone xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  xsi:noNamespaceSchemaLocation="http://worldtimeengine.com/timezone.xsd">
    <version>1.1</version>
    <location>
        <region>United Kingdom</region>
        <latitude>51.5</latitude>
        <longitude>-0.1167</longitude>
    </location>
    <time>
        <utc>2008-07-11 13:30:38</utc>
        <local>2008-07-11 14:30:38</local>
        <zone>
            <hasDST>true</hasDST>
            <current>
                <abbreviation>BST</abbreviation>
                <description>British Summer Time</description>
                <utcoffset>+1:00</utcoffset>
                <isdst>true</isdst>
                <effectiveUntil>2008-10-26 00:00:00</effectiveUntil>
            </current>
            <next>
                <abbreviation>GMT</abbreviation>
                <description>Greenwich Mean Time</description>
                <utcoffset>+0:00</utcoffset>
                <isdst>false</isdst>
                <effectiveUntil>2009-03-29 01:00:00</effectiveUntil>
            </next>
        </zone>
    </time>
</timezone>

In the case of any error the service will send a XML response with the error code and message.

<?xml version="1.0" encoding="UTF-8" ?>
<error xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://worldtimeengine.com/error.xsd" type="exception">
    <code>10001</code>
    <message>Invalid or Expired API Key used</message>
</error>

You can write some code to calculate the local time from UTC or vice versa. The folling sample is to convert UTC date time to local date time using the third party service.

using System;
using System.IO;
using System.Net;
using System.Xml;
using UsingWorldTimeEngine.Codes;

namespace UsingWorldTimeEngine
{
    public partial class _Default : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            // Use the 3rd party service with a demo key.
            string requestUrl = string.Format("http://worldtimeengine.com/api/ip/{0}/{1}", 
                "9d89405104e16732fa00caa1e8e6cdfd", Request.UserHostAddress);             
            
            try
            {
                string strResponse = GetResponse(requestUrl); 
                string utcOffset = GetUtcOffset(strResponse);
                DateTime utcDateTime = DateTime.UtcNow; // UTC datetime may be comming from persistent layer.
                DateTime localDate = GetLocalDateTime(utcDateTime, utcOffset); 

                lblOutput.Text = localDate.ToString();
            }
            catch (WorldTimeEngineException ex)
            {
                // Use the custom exception object.
                lblOutput.Text = string.Format("Code: {0}<br />Message: {1}", 
                    ex.Code, ex.Message);
            }
            catch (ArgumentException ex)
            {
                lblOutput.Text = ex.Message;
            }
            catch (Exception ex)
            {
                lblOutput.Text = ex.Message;
            }
        }

        private string GetResponse(string requestUrl)
        {
            WebRequest request = HttpWebRequest.Create(requestUrl);
            WebResponse response = request.GetResponse();
            StreamReader sr = new StreamReader(response.GetResponseStream());

            return sr.ReadToEnd();
        }

        private string GetUtcOffset(string strResponse)
        {
            XmlDocument xdocResponse = new XmlDocument();
            xdocResponse.LoadXml(strResponse);

            if (xdocResponse.GetElementsByTagName("timezone").Count != 0) // Success.
            {
                // Get the first 'utcoffset' element value which is inside the 'current' tag 
                // not under the 'next' tag.
                string utcOffset = xdocResponse.GetElementsByTagName("utcoffset")[0].InnerText;
                return utcOffset;
            }
            else if (xdocResponse.GetElementsByTagName("error").Count != 0) // Error.
            {
                // Throw the custom exception object.
                throw new WorldTimeEngineException(
                    int.Parse(xdocResponse.GetElementsByTagName("code")[0].InnerText), 
                    xdocResponse.GetElementsByTagName("message")[0].InnerText); 
            }
            else
            {
                throw new ArgumentException();
            }
        }

        private TimeSpan GetTimeSpan(string utcOffset)
        {
            // Calculate hour, minute from UTC offset, for example +5:30.
            string strTimeSpan = utcOffset.Substring(1);     
            string[] arrayTimeSpan = strTimeSpan.Split(':'); 
            int hour = int.Parse(arrayTimeSpan[0]);          
            int minute = int.Parse(arrayTimeSpan[1]);        

            TimeSpan ts = new TimeSpan(hour, minute, 0);

            return ts;
        }

        private DateTime GetLocalDateTime(DateTime utcDateTime, string utcOffset)
        {
            char sign = utcOffset.ToCharArray()[0];
            TimeSpan ts = GetTimeSpan(utcOffset);

            DateTime localDate;

            switch (sign)
            {
                case '+': // Before UTC time.
                    localDate = utcDateTime.Add(ts); 
                    break;

                case '-': // After UTC time.
                    localDate = utcDateTime.Add(-ts);
                    break;

                default:
                    throw new InvalidOperationException();
            }

            return localDate;
        }   
    }
}

Along with this calculation I am also doing some error handling and for that I am creating a custom exception class.

using System;

namespace UsingWorldTimeEngine.Codes
{
    public class WorldTimeEngineException : ApplicationException
    {
        public int Code { get; set; }

        public WorldTimeEngineException()
        {
            Code = 0;
        }

        public WorldTimeEngineException(int code, string message)
            : base(message)
        {
            Code = code;
        }
    }
}

You can take a different service but the basic concept will be same. Please let me know if you are using any other service to calculate date time and if you have any better approach.

Happy coding.

Advertisements

Showing date time according to time zone

We should Localize and Globalize our software applications. Our users can see their native languages on the UI and also can see the various things are proper format as their local culture. For example date time, price format etc. But what about date time value? In the world there are many countries which are belongs to different time zones. If we are showing a date time on our application UI then we must take care of the local time. If we are showing the same date time for every users who are using from different time zones, that will not be a very user friendly!

// Show all time zones.
foreach (TimeZoneInfo zone in TimeZoneInfo.GetSystemTimeZones())
{
    Console.WriteLine(zone.Id);
    Console.WriteLine(zone.DisplayName + "\n");
}

UTC date time

Now the question is if we want to show the local date time for every user of different time zones then in what format we should store the date time? One simple solution of this problem can be whenever we need to store date time in persistent layer then use Universal Time Coordinated (UTC). This is maintained as a stander date time through out the world. UTC and GMT are same. Every time zone has a offset. This offset is the time difference from UTC. This is called UTC offset. UTC offset can be positive or negative. Time zones who have positive UTC offset are actually before the UTC date time and UTC offset with negative are after the UTC offset. We need to calculate the local time of a time zone according the UTC date time and UTC offset of that particular time zone. For example ‘Indian Slandered Time’ (IST) is the time zone name of India and it has the UTC offset +5:30. When UTC date time is 01/01/2013 12:00 AM then Indian local time will be 01/01/2013 5:30 AM. So if we store our date time in UTC every time then it will be easy to convert the date time as per different time zone local time.

// Convert date time to UTC.
DateTime dtUtc = TimeZoneInfo.ConvertTimeToUtc(dtLocal, TimeZoneInfo.Local);
// Convert back to local date time at the time of retreving.
DateTime dtLocal = TimeZoneInfo.ConvertTimeFromUtc(dtUtc, TimeZoneInfo.Local);

In our web application we can also implement this functionality using JavaScript.

// Convert date time to UTC.
var dtUtc = dtLocal.toUTCString();
// Convert back to local date time at the time of retreving.
var dtLocal = new Date(dtUtc);

Happy coding…