Wednesday, January 21, 2015

Using Google Time Zone API to Convert DateTime between Geographic Locations in C#

It is extremely important that any application where the users are from different geographic locations handle date and time in a meaningful way. For an example, let’s say the application has users ranging from United States to Australia and right now, a user from Sydney, Australia creates a record in the database. So through out the application if we have only considered Sydney time, the created time for that particular record will be in Sydney time. If a user from Seattle, United States sees that record created time, it definitely is confusing because that time has not yet arrived to Seattle.

So in a world wide application, it is important to consider users’ time zones when maintaining date and times. There are variety of SDK for this such as Noda Time. But in this post, let’s see how we can consider not the time zones, but the geographic locations when converting the date time. For that we can use Google Time Zone API to convert date and time between geographic locations considering locations’ geographic coordinates.

Please note that to use Google Time Zone API, you will need to have a API key which can be acquired for free. Free API will have some request limitations, but it is more than enough to evaluate the functionality. In here, I am not going to explain how you can obtain the API key, please read this post to know how you can do it.

After getting the API key, next is to use it. Google Time Zone API expects following parameters.
  • Timestamp
    • Timestamp specifies the given time as seconds since midnight, January 1, 1970 UTC. The Time Zone API uses the timestamp to determine whether or not Daylight Savings should be applied.
  • Location's geographic coordinates
  • API Key
  • Language (optional)

If the request to Google TimeZone API gets succeeded, it will return a result containing details such as the offset for daylight-savings time in seconds (dstOffset), the offset from UTC in seconds for the given location(rawOffset),  time zone name etc. The converted time of a given location is the sum of the timestamp parameter,  dstOffset and rawOffset. Since it is again a Timestamp, we need to convert it back to DateTime value.

I am creating a console application and I am creating a class named “GoogleTimeZone”. There I have couple of local variables.
public class GoogleTimeZone
{
    private string apiKey;
    private GeoLocation location;
    private string previousAddress = string.Empty;
 
    public GoogleTimeZone(string apiKey)
    {
        this.apiKey = apiKey;
    }
}
Now let's create following helper methods.

First method is a method to return the Timestamp of a given DateTime.
private long GetUnixTimeStampFromDateTime(DateTime dt)
{
    DateTime epochDate = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
    TimeSpan ts = dt - epochDate;
    return (int)ts.TotalSeconds;
}
Then the following method will do the opposite which is converting of Timestamp to DateTime.
private DateTime GetDateTimeFromUnixTimeStamp(double unixTimeStamp)
{
    DateTime dt = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
    dt = dt.AddSeconds(unixTimeStamp);
    return dt;
}
Now the following method will return the coordinates for a given location. We can get the geographic coordinates by calling the Google Geocoding API.
private GeoLocation GetCoordinatesByLocationName(string address)
{
    string requestUri = string.Format("https://maps.googleapis.com/maps/api/geocode/xml?address={0}&key={1}", Uri.EscapeDataString(address), this.apiKey); 

    XDocument xdoc = GetXmlResponse(requestUri); 

    XElement status = xdoc.Element("GeocodeResponse").Element("status");
    XElement result = xdoc.Element("GeocodeResponse").Element("result");
    XElement locationElement = result.Element("geometry").Element("location");
    XElement lat = locationElement.Element("lat");
    XElement lng = locationElement.Element("lng");
 
    return new GeoLocation()
    {
        Latitude = Convert.ToDouble(lat.Value),
        Longitude = Convert.ToDouble(lng.Value)
    };
}
I have the following helper class to hold coordinates.
class GeoLocation
{
    public double Latitude { get; set; }
    public double Longitude { get; set; }
}
We now have the location and the time stamp. Following method will call the Google Time Zone API and get the converted time zone result.
private GoogleTimeZoneResult GetConvertedDateTimeBasedOnAddress(GeoLocation location, long timestamp)
{
    string requestUri = string.Format("https://maps.googleapis.com/maps/api/timezone/xml?location={0},{1}&timestamp={2}&key={3}", location.Latitude, location.Longitude, timestamp, this.apiKey); 

    XDocument xdoc = GetXmlResponse(requestUri); 

    XElement result = xdoc.Element("TimeZoneResponse");
    XElement rawOffset = result.Element("raw_offset");
    XElement dstOfset = result.Element("dst_offset");
    XElement timeZoneId = result.Element("time_zone_id");
    XElement timeZoneName = result.Element("time_zone_name"); 

    return new GoogleTimeZoneResult()
    {
        DateTime = GetDateTimeFromUnixTimeStamp(Convert.ToDouble(timestamp) + Convert.ToDouble(rawOffset.Value) + Convert.ToDouble(dstOfset.Value)),
        TimeZoneId = timeZoneId.Value,
        TimeZoneName = timeZoneName.Value
    };
}
I am grouping up the result to a class named GoogleTimeZoneResult as follows.
public class GoogleTimeZoneResult
{
    public DateTime DateTime { get; set; }
    public string TimeZoneId { get; set; }
    public string TimeZoneName { get; set; }
}
Finally I have the following public method which will trigger all the above methods.
public GoogleTimeZoneResult GetConvertedDateTimeBasedOnAddress(string address, DateTime dateTime)
{
    long timestamp = GetUnixTimeStampFromDateTime(TimeZoneInfo.ConvertTimeToUtc(dateTime));
 
    if (previousAddress != address)
    {
        this.location = GetCoordinatesByLocationName(address);
 
        previousAddress = address;
 
        if (this.location == null)
        {
            return null;
        }
    } 

    return GetConvertedDateTimeBasedOnAddress(this.location, timestamp);
}
That’s it. now let’s test the functionality using some test DateTime and calling the above public method from the Main.
static void Main(string[] args)
{
    GoogleTimeZone googleTimeZone = new GoogleTimeZone("your api key"); 

    string timeString = "2015-01-01T08:00:00.000+05:30";
    DateTime dt = DateTime.Parse(timeString);
 
    //string location = "Colombo, Sri Lanka";
    //string location = "Sydney, Australia";
    string location = "Seattle, United States";
 
    GoogleTimeZoneResult googleTimeZoneResult = googleTimeZone.GetConvertedDateTimeBasedOnAddress(location, dt);
    Console.WriteLine("DateTime on the server : " + dt);
    Console.WriteLine("Server time in particular to : " + location);
    Console.WriteLine("TimeZone Id : " + googleTimeZoneResult.TimeZoneId);
    Console.WriteLine("TimeZone Name : " + googleTimeZoneResult.TimeZoneName);
    Console.WriteLine("Converted DateTime : " + googleTimeZoneResult.DateTime);
}

Colombo, Sri Lanka

image
Colombo, Sri Lanka
Sydney, Australia

image
Sydney, Australia
Seattle, United States

image
Seattle, United States
I am uploading the sample code to OneDrive.


Happy Coding.

Regards,
Jaliya

Friday, January 2, 2015

Received Microsoft MVP Award for .NET

Kick starting the year 2015, received the Microsoft Most Valuable Professional (MVP) Award for the second consecutive year. Previous time it was awarded for the technical expertise Visual C#, but this time Microsoft has merged all previous technical expertise areas for .NET managed languages (Visual Basic, Visual C# and Visual F#) into one technical expertise area which is .NET. Under .NET technical expertise area, I will be focusing on Visual C#.

Feeling so great and I definitely will be keeping my contributions towards .NET technical community in every possible way.
MVPLogo
Microsoft Most Valuable Professional (MVP)
Thank you Microsoft and Katherine Chen for your appreciation and Thank you Fiqri Ismail, Wellington PereraChaminda Chandrasekara and all the people for your support.

Happy Coding.

Regards,
Jaliya

Thursday, January 1, 2015

Using an ICommand for ListView Item Click in Windows Runtime Apps

When we are using MVVM, events triggered from the View should be bound to a ICommand in the ViewModel. In this post let’s see how we can bind an ItemClick event of a ListView to a implementation of a ICommand in the ViewModel.

For the demonstration purposes, I am going ahead with a Windows Phone App. I am creating a Blank Windows Phone App and there I am creating two folders named “Model” and “ViewModel”. I am creating the following class named “Item” inside the Model folder.
public class Item
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
    public double Price { get; set; }
 
    public static List<Item> GetItems()
    {
        return new List<Item>()
        {
            new Item() 
            { 
                Id = 1, 
                Name = "Item 1", 
                Description = "Item 1 Description", 
                Price = 120.00 
            },
            new Item() 
            { 
                Id = 2, 
                Name = "Item 2",
                Description = "Item 2 Description", 
                Price = 360.00 
            },
            new Item() 
            { 
                Id = 3, 
                Name = "Item 3", 
                Description = "Item 3 Description",
                Price = 590.00 
            }
        };
    }
}
Now I am adding the following ItemViewModel class to ViewModel folder.
public class ItemViewModel
{
   public List<Item> Items { get; set; }
 
   public ItemViewModel()
   {
       Items = Item.GetItems();
   }
}
Next, I am modifying the MainPage.xaml adding a ListView and changing it’s ItemTemplate to show only the Name of the item.
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="20*"/>
        <RowDefinition Height="105*"/>
    </Grid.RowDefinitions>
 
    <StackPanel Grid.Row="1">
        <ScrollViewer>
            <ListView ItemsSource="{Binding Items}">
                <ListView.ItemTemplate>
                    <DataTemplate>
                        <StackPanel>
                            <TextBlock Text="{Binding Name}" 
                                       Style="{StaticResource ListViewItemTextBlockStyle}" />
                        </StackPanel>
                    </DataTemplate>
                </ListView.ItemTemplate>
            </ListView>
        </ScrollViewer>
    </StackPanel>
</Grid>
Now from the code behind of the MainPage.xaml I am setting up it’s DataContext to new ItemViewModel.
public sealed partial class MainPage : Page
{
    public MainPage()
    {
        this.InitializeComponent();
        this.DataContext = new ItemViewModel();
    }
}
Once I got all these steps completed and if I run the project, I am getting the following.

1
Initial Result
So now my requirement is once I click on a item, an event should be triggered and there I should be able get the clicked item information. So I can do whatever I want with that item like navigating to another page. And all these should be happened using an ICommand and not with the regular ItemClick event of the ListView. Now let’s see how we can achieve that.

First let’s create an implementation of an ICommand. I am creating a folder named “Common” and adding the following class named “DelegateCommand”.
public class DelegateCommand<T> : ICommand
{
    private readonly Action<T> executeAction;
    Func<object, bool> canExecute;
 
    public event EventHandler CanExecuteChanged;
 
    public DelegateCommand(Action<T> executeAction)
        : this(executeAction, null)
    {
    }
 
    public DelegateCommand(Action<T> executeAction, Func<object, bool> canExecute)
    {
        this.executeAction = executeAction;
        this.canExecute = canExecute;
    }
 
    public bool CanExecute(object parameter)
    {
        return canExecute == null ? true : canExecute(parameter);
    } 

    public void Execute(object parameter)
    {
        executeAction((T)parameter);
    }
    public void RaiseCanExecuteChanged()
    {
        EventHandler handler = this.CanExecuteChanged;
        if (handler != null)
        {
            handler(this, new EventArgs());
        }
    }
}
Basically if you have created a Windows Runtime App other than using the blank app template, Visual Studio will create a folder named “Common” inside your project and he will be adding several boilerplated classes there. One of them is a class named “RelayCommand”. Here my DelegateCommand is a modified version of RelayCommand. I did some changes to make it generic.

Now let’s modified the ItemViewModel by adding a property of type DelegateCommand<ItemClickEventArgs>.
public class ItemViewModel
{
    public List<Item> Items { get; set; }
    public DelegateCommand<ItemClickEventArgs> ItemClickedCommand { get; set; }
 
    public ItemViewModel()
    {
        Items = Item.GetItems();
        ItemClickedCommand = new DelegateCommand<ItemClickEventArgs>(OnItemClicked);
    }
 
    private void OnItemClicked(ItemClickEventArgs args)
    {
        Item item = args.ClickedItem as Item;
        // your navigation logic
    }
}
In the constructor, I am creating a new object of ItemClickedCommand passing in the Action method as OnItemClicked. Inside my OnItemClicked I can get the item information from which it was triggered.

Now let’s see how I can bind the created ItemClickedCommand to my ListView in the MainPage.xaml. The easy way to do this by using Blend. Right click on the MainPage.xaml and click on “Open in Blend”.

2014-12-09_21-07-14
Opened in Blend
First open up the Objects and Timeline window, and drill up to ListView. Select the ListView and from the Assets window, select Behaviors and double click on EventTriggerBehavior. A new EventTriggerBehavior will be created under the ListView and now select the EventTriggerBehavior. From the Properties window, in the EventName dropdown, select the ItemClick. Now save the project and move back to Visual Studio.

Load the changes and now you will see two new xml namespaces are added (Microsoft.Xaml.Interactivity and Microsoft.Xaml.Interactions.Core) along with the EventTriggerBehavior. Modify the EventTriggerBehavior further as follows.
<Page
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:ListItemClickCommandDemo"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:Interactivity="using:Microsoft.Xaml.Interactivity" 
    xmlns:Core="using:Microsoft.Xaml.Interactions.Core"
    x:Class="ListItemClickCommandDemo.MainPage"
    mc:Ignorable="d"
    Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
 
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="20*"/>
            <RowDefinition Height="105*"/>
        </Grid.RowDefinitions>
 
        <StackPanel Grid.Row="1">
            <ScrollViewer>
                <ListView ItemsSource="{Binding Items}"
                          IsItemClickEnabled="True">
                    <Interactivity:Interaction.Behaviors>
                        <Core:EventTriggerBehavior EventName="ItemClick">
                            <Core:InvokeCommandAction Command="{Binding ItemClickedCommand}" />
                        </Core:EventTriggerBehavior>
                    </Interactivity:Interaction.Behaviors>
                    <ListView.ItemTemplate>
                        <DataTemplate>
                            <StackPanel>
                                <TextBlock Text="{Binding Name}" 
                                           Style="{StaticResource ListViewItemTextBlockStyle}" />
                            </StackPanel>
                        </DataTemplate>
                    </ListView.ItemTemplate>
                </ListView>
            </ScrollViewer>
        </StackPanel>
    </Grid>
</Page>
Now you can see that the DelegateCommand in the ViewModel is bound to InvokeCommandAction. And please note, for the ListView to be click enabled, I have set the IsItemClickEnabled to "True".

Now put a breakpoint to OnItemClicked method in the ViewModel and run the application and click on an item. Breakpoint will get hit and you can see it is successfully getting the clicked item information.

image
Clicked Item
Now you can do whatever you want to do with item (navigate to another page showing detailed information of the item etc.). I choose to show details of an item in another page, and this is how it looks like.

SNAGHTML67a54313
Detailed Page
So that’s it. I am uploading the sample to my OneDrive.


Happy Coding.

Regards,
Jaliya