【Learning】TimeZone Issue Summary

来源:互联网 发布:美国矩阵风投官网 编辑:程序博客网 时间:2024/05/30 04:48
We have been confused about time zone issues in Alcazar development. Since we need to persist java bean objects into database, we use java.sql.Timestamp to represent times all over the place. A basic requirement is that we need to store GMT representation of times in database tables. The confusion points are where to do the conversion(from local to GMT)? How to do it when the client is in different time zone than the server?....

Actually after some time of studying, I find that the time zone issue is not that complicated as we thought. To understand it well, first you need to understand two concepts:
1. Java time classes(java.util.Date, java.sql.Date, Timestamp, Calendar) all use a long number to store time. This long number is called Unix Time Number, which is the number of milliseconds since the epoch, it represents an exact time/point regardless of time zones.
2. Apart from the long number, those time classes all have Representation(YEAR, MONTH, DAY, HOUR, MINUTE,...). The representation is indeed dependent on time zones. Given a certain long number, it will result in different representation in different time zones. 
3. In distributed systems, since different components may be located in different time zones. It is not good to pass the time representation across components, as the components may see different Unix Time Numbers. Instead, it is better to pass the exact Unix Time Number, so that components all see the same point of time.

In Alcazar, there are three types of object serializations that involve time information. Let us discuss them one by one:
1. GWT Client --> GWT Server
As shown in below figure, GWT RPC uses the long number to serialize and de-serialize Timestamp. Thus, though the client and the server are in different time zones, they both see the same exact point of time. However, you can see that the time representations are distinct.

2. GWT Server --> Core Server
Since CoreServer is a web service, we use jaxb to pass XML requests and responses between WebServer and CoreServer. As shown in below figure, we configure Jaxb to use time representation in String to serialize and de-serialize Timestamp. It is not good as we mentioned before. What's worse, there is a bug in our unmarshaling process, which leads to a wrong time representation in core server. 
Implementation: We achieve the centralized jaxb serialization by implementing a jaxb Timestamp adapter. This is implemented by extending class XmlAdapter. Then we use @XmlJavaTypeAdapter annotation to tell jaxb to always invoke our adapter to do marshal and unmarshal when encountering Timestamp. Going a step further, we write the annotation in package-info.java to let it apply to all classes in that package. 
Code: @XmlJavaTypeAdapter(value=TimestampAdapter.class, type=java.sql.Timestamp.class)

So to fix the bug, we would better use the long number to pass across WebServer and CoreServer, shown in below figure:

 3. Core Server --> Scheduler
Since between CoreServer and Scheduler we use database tables to pass data, it involves Hibernate serialization. Currently, every time we persist Timestamp to database, we have to first convert the time representation from local time zone EST to GMT. Every time we get Timestamp from database, we have to first convert the time representation from GMT back to local time zone. 

Learning from Jaxb Timestamp adapter mechanism, we can use a Hibernate Timestamp adapter to do the conversion for us. As shown in below figure, with the help of the Timestamp adapter, we don't need to do the conversion any more. 
Implementation: Hibernate Timestamp adapter can be implemented by implements interface UserType. Then we use @TypeDef annotation to tell Hibernate to always invoke our adapter to do marshal and unmarshal when encountering Timestamp. Going a step further, we write the annotation in package-info.java to let it apply to all classes in that package. 
Code@TypeDef ( name = "HibernateTimestampAdapter", defaultForType = java.sql.Timestamp.class,   typeClass = CustomTimestampType.class)

 
Summary
After refactoring, we now can remove a lot of conversion code. All components will always see the time Unix Time Number and their sense of time are always in sync regardless of time zones. The only situation when time zone should be take into account is representing times, such as display time on UI, in Email, etc. In these cases, we can always build the desired representation by inputting (unixTimeNumber, desiredTimeZone).

原创粉丝点击