FLEX: Handling Timezone Offset
I've developed an FLEX application for distributed data admin开发者_StackOverflow社区istration. When our Asian employees specify a date, it will be saved +1 day.
If I check my timezone offset it is +60, their offset is +520.
var dNow:Date = new Date();
trace("Your time zone offset: " + dNow.getTimezoneOffset() + " minutes");
I assume this is the problem? If so, would you suggest that I correct the entered date by 460 minutes before sending it to our server for saving? How to do that?
When you create a Date object in ActionScript, it will internally store its value in a timezione-free UTC numeric value, however this value will be calculated applying a correction due to the local timezone/daylight savings offset of the client. Flash obtain the current timezone by the underlying operating system, and currently there's no way to set a custom timezone.
So, unless you are exactly in a UTC+0 situation, the actual value of the Date will contain an offset of a certain number of hours/minuts.
When displaying the same date again, the default formatters and the standard Flex controls will convert back the Date to the local timezone: when the two operations are performed on the same machine (or on machines with the same timezone offset), those corrections will compensate for each other, and you won't notice this behavior at all.
However, storing that value (for example, sending it to BlazeDS/LCDS to save it in a DB) and retrieving it from a client with a different timezone can produce unexpected effect, if you are not prepared to handle them: for example, if the difference between the timezone corrections of the two clients is negative (for example, -1 hours) a day entered as 28/06/2011 can be displayed as 27/06/2011 in a DateField component.
It is a complex problem, and there's no quick and easy solution: it dependes on the type of timezone support you want to provide.
The simplest solution would be setting all clients to work with a common timezone, for example the timezone of the server. Unfortunately, the current version of the Flash Player doesn't allow to specify an explicit timezone, and to implement this strategy you need to manually set the internal UTC values of any Date created by Flex components before sending it to the server, to compensate the local timezone offset. Another common workaround is avoiding using Date objects and using ISO string representation for dates.
You can find a lot of information (and some ideas about timezone management) in the Adobe Bug Tracker, see the https://bugs.adobe.com/jira/browse/FP-175 issue, with title "Set specific timezone on flashplayer. This would enable applications to keep same timezone on all clients in different timezones."
Finally I've implemented this solution:
get the data from the server as ISO String (with coldfusion to a MS SQL Server):
SELECT CONVERT(varchar, CONTRACTED_DELIVERY, 104) AS CONTRACTED_DELIVERY
FROM (...)
WHERe (...)
then when receiving it I convert it in the ValueObject (following the Cairngorm framework):
if (obj.CONTRACTED_DELIVERY != null){
this.CONTRACTED_DELIVERY = DateField.stringToDate(obj.CONTRACTED_DELIVERY,"DD.MM.YYYY");
}else{
this.CONTRACTED_DELIVERY = obj.CONTRACTED_DELIVERY;
}
to send the date to the server as ISO String:
UPDATE (...)
SET CONTRACTED_DELIVERY = <cfif productionDetails.CONTRACTED_DELIVERY EQ ''>null<cfelse>'#dateFormat(productionDetails.CONTRACTED_DELIVERY,"YYYY-MM-DD")#'</cfif>
WHERE (...)
Feel free to ask for additional information!
a Blaze DS / Adobe LiveCycle DS solution based on https://forums.adobe.com/thread/1076594:
services-config.xml
<service id="myProxyBootstrapService" class="org.myapp.flex.proxy.MyProxyBootstrapService"/>
MyProxyBootstrapService.java
MyProxyBootstrapService extends AbstractBootstrapService {
@Override
public void initialize(String arg0, ConfigMap arg1) {
PropertyProxyRegistry registry = PropertyProxyRegistry.getRegistry();
registry.register(Serializable.class, new DateProxy());
}
DateProxy.java
public class DateProxy extends BeanProxy {
private static final long serialVersionUID = 8097540028987261941L;
private Integer serverOffset;
public DateProxy() {
super();
}
@Override
public Object getValue(Object instance, String propertyName) {
Object result = super.getValue(instance, propertyName);
if (result instanceof Date) {
result = toDate(result, true);
}
return result;
}
@Override
public void setValue(Object object, String propertyName, Object value) {
if (value instanceof Date) {
Date date = toDate(value, false);
super.setValue(object, propertyName, date);
} else {
super.setValue(object, propertyName, value);
}
}
private Date toDate(Object value, Boolean serverToClient) {
Date date = (Date) value;
Integer clientOffset = getClientOffset();
Integer serverOffset = getServerOffset();
if (clientOffset != null && !clientOffset.equals(serverOffset)) {
Calendar cal = new GregorianCalendar(TimeZone.getDefault());
cal.setTime(date);
cal.add(Calendar.MINUTE, serverToClient ? clientOffset - serverOffset : serverOffset - clientOffset);
date.setTime(cal.getTimeInMillis());
}
return date;
}
private Integer getClientOffset() {
return (Integer) FlexContext.getFlexSession().getAttribute("TIMEZONE_FLEX_OFFSET");
}
private Integer getServerOffset() {
if (serverOffset == null) {
serverOffset = Calendar.getInstance().getTimeZone().getOffset(new Date().getTime()) / 1000 / 60 * -1;
}
return serverOffset;
}
精彩评论