GWT - Date and Timestamp RPC serialization problem

Problem:

We have the client and servers in different time zones  (i.e server is in GMT and client is running in PST time zone), and we have to serialize through RPC a Date (Timestamp) object -- the Date_Serializer class does timezone conversion for Date/Time and Timestamp using long value of miliseconds, which means that the server is converting the Date  --> long using the function date.getTime(), send the long through RPC, and the client is converting the long --> Date, using the constructor Date(long), which will use the client time-zone. All is fine, that means the long value means the universal time since January 01, 1970 ... which is the same in all the time-zones, but when converted to a time-zone or another, we get different representation of that date.

Question: But, what if we want to send a Date like a constant (i.e. 2010-01-23 11:25:00) from server and to get on the client exactly the same value (i.e. 2010-01-23 11:25:00) ?

I saw lots of answers/solutions related with this issue, same of them recommended to replace the GWT serialization class for Date (com.google.gwt.user.client.rpc.core.java.util.Date_CustomFieldSerializer), which sends instead of one long value, 6 integer values (year, month, day, hour, minute and seconds) thru RPC.

Solution:

The simplest solution is to change your RPC function return parameter "Date" with something else, which isn't sensible to the time zone. So, you have to define your one "transporter" object to send the date as you want. Here is an example code:

/* define the class to extend IsSerializable marker interface */
public class MyGwtSafeDate implements IsSerializable {
    public int year, month, day;
    public int hour, minute, second;

    /* need this one for serialization constraint */
    public MyGwtSafeDate () {
    }

    /* add here the accessors and modifiers -- setters and getters */
}

and  after that change the function from your RPC service interface definition  to use the MyGwtSafeDate instead of Date.

/* this will be in your RPC service interface, Async and implemenation */
public MyGwtSafeDate getEnrollingDate (int customerId);

Having this simple change you will not have time-zone conversion problems for the Date, and you can process it on client as you want/need.

Cheers!

PS1: some problems may appear if you want to convert that MyGwtSafeDate object to Date, back and forth, on the client side, especialy for the US/Eastern time zone. It seems that there is a bug in the building the Date from the individual values like year, month, day, hour, minute and second ... but I didn't catch it yet :-(

PS2: I got the solution for PS1) and this is so simple, use constructor Date(year, month, day, hour, minute, second) instead of Date(long) and then setting individually these values (setYear, setMonths etc).

PS3: So, if you still have to compute on the client side some temporal difference, like startDate - 1hour, you have to do it like this:
- always keep your dates in another structure, i.e. MyGwtSafeDate. 
- convert MyGwtSafeDate to Date using Date (year, month, day, hour, min, sec) constructor.
- perform the difference throu "newLong = Date.getTime() - delta"
- convert the newLong throu Date (long)
- get the individual values from the Date to your MyGwtSafeDate object.

Enjoy it!

No comments:

Post a Comment