Bhaskar Karambelkar's Blog

Wicket's Date & Time Components and Client-Server Timezones

 

Tags: wicket java


The problem

In a typical web application, it is often necessary to work with multiple Timezones on the Client side. On the server side you may wish to store the data in one single “Timezone” preferably “GMT”, but it hardly makes sense to display and accept dates in GMT, as this places the onus on the user to translate time in his local timezone, to GMT before entering the time information, and vice-verse for interpreting any dates shown in the Web application.

What is required is for the web application to show and display date and times in the User’s timezone, and do all the necessary conversions while transmitting the date/time information between the User and the Back end. wicket framework makes this extremely simple to implement.

The Solution

Wicket provides built in support to detect the Client’s Timezone and also provides necessary IO components as well as display components that transparently convert date/time data between the Server’s Timezone and the Client’s Timezone. What’s more you can also provide the Client an option to explicitly specify a Timezone and the said wicket components will use this user supplied Timezone instead of the User’s default Timezone.

Here I briefly describe how you can achieve seamless conversion of date/time wicket components between server and client Timezones.

The Application class

We start with the Application class. In order for wicket to determine the Client’s Timezone, it needs to do a small redirect to an internal page that gathers information about the Client’s browser, that amongst other things includes the Client’s Timezone. Note For this to work , the browser must be Javascript enabled, but even if the user’s browser has disabled Javascript you can easily fallback to the Server’s Timezone in such a case. For the internal page to gather browser information, we need to add some code in the Application.init() method.

import org.apache.wicket.Application;

public class MyApplication extends Application {
   @Override
   public void init() {
        getRequestCycleSettings().setGaterExtendedBroserInfo(true);
   }
}

The highlighted code is where the magic happens. Well not exactly. All the “setGatherExtendedBrowserInfo(true)” call does, is instructs Wicket to temporarily redirect an incoming request to an internal Wicket page, that will gather the extended browser info. Of course this will not happen for any wicket Page, but has to be specifically coded in the Page class.

The Page class

Even after setting the proper setting in the Application class, our work is not done. We need to tell wicket when to collect the browser’s information.

Typically to acchive a consistent look for your application, you would use markup inheritance, by having all your wicket Pages inherit from a BasePage. So considering this, the code we need is best placed in the BasePage of your application. This way the redirect for gathering extended browser info. happens regardless of the URL used to enter the application. It can be via the Home Page or a Bookmarked page, as long as all your wicket pages extend from your “BasePage” , you can be sure that wicket will discover the client’s Timezone (provided javascript is enabled).

public class BasePage extends WebPage {

   // we will use this to show the client what timezone are we using for this session.
   private Timezone timezone ;

   public BasePage() {

       //trigger the redirect to an intermediate page which will obtain the timezone info for us.
       getSession.getClientInfo();

       add(new Label("timezone",new PropertyModel(BasePage.this,"timezone.displayName"));

       // add date/time components from wicket-datetime project.
   }

   public Timezone getTimezone() {
       if(timezone == null) {
           timezone =
               ((WebClientInfo)getSession().getClientInfo()).getProperties().getTimezone();
       }
       // fallback to server's timezone if we can't determine the client's timezone.
       if(timezone == null) {
           timezone = Timezone.getDefault();
       }
       return timezone;
   }

}

And the corresponding BasePage.html file

<!-- somewhere in a convenient location -->
<span>America/NewYork</span>

In the constructor of ‘BasePage’ class, we trigger the redirect to the intermediate page, for obtaining the client browser’s properties, using the ‘getSession().getClinetInfo()’ call. It is very important to have this call, otherwise wicket will not determine the client browser’s properties, one of which is the client m/c’s timezone. Adding the timezone information in a wicket label is not strictly necessary, but it serves a purpose, without this the user will be unsure whether the date/time shown is in his local timezone or the server timezone. Of course as an alternative you can explictly display the timezone in each date/time textfiled/label.

The Date/Time Components

Now for some wicket magic, after the client’s Timezone has been determined, we can now use any input/label components from the wicket-datetime project, and safely rely on them to do the automatic Timezone conversions between server and client. e.g.

  • org.apache.wicket.datetime.markup.html.form.DateTextField
  • org.apache.wicket.datetime.markup.html.basic.DateLabel

The DateTextField is an INPUT component which will translate the user inputted date/time values, from the client timezone to the server’s timezone. The DateLabel is a display LABEL that will display a date/time value from the server, after converting it into the client’s timezone.

Thus using wicket you can greatly simplify working with client timezones, by coding only a few lines in about 2 Java files.

Other thoughts

One thing to stress, is that wicket’s ability to correctly determine the clinet’s timezone depends on 2 things, one is the requirement that ‘javascript’ be turned on, in the client browser and secondly on the timezone offset provided by the javascript API. So it may not always work in every situation. But from my experience it works correctly most of the time.

In my next post I’ll examine how to convert the ‘timezone’ label in our example, in to a drop down select box, that will give the user an option to select the timezone he wants to see the date/time contents in.