【问题标题】:FLEX: Handling Timezone OffsetFLEX:处理时区偏移
【发布时间】:2011-06-28 08:50:44
【问题描述】:

我开发了一个用于分布式数据管理的 FLEX 应用程序。当我们的亚洲员工指定日期时,将保存 +1 天。

如果我检查我的时区偏移量是 +60,它们的偏移量是 +520。

var dNow:Date = new Date();
    trace("Your time zone offset: " + dNow.getTimezoneOffset() + " minutes");

我认为这是问题所在?如果是这样,您是否建议我将输入的日期更正 460 分钟,然后将其发送到我们的服务器进行保存?该怎么做?

【问题讨论】:

    标签: apache-flex timezone offset


    【解决方案1】:

    当您在 ActionScript 中创建 Date 对象时,它会在内部将其值存储在一个无时区的 UTC 数值中,但是由于客户端的本地时区/夏令时偏移,该值将在应用校正后进行计算。 Flash通过底层操作系统获取当前时区,目前无法设置自定义时区。

    因此,除非您恰好处于 UTC+0 的情况,否则 Date 的实际值将包含一定数量的小时/分钟的偏移量。

    当再次显示相同的日期时,默认格式化程序和标准 Flex 控件会将日期转换回本地时区:当在同一台机器上(或在具有相同时区偏移的机器上)执行这两个操作时,那些更正会相互补偿,您根本不会注意到这种行为。

    但是,如果您不准备处理这些值,则存储该值(例如,将其发送到 BlazeDS/LCDS 以将其保存在数据库中)并从具有不同时区的客户端检索它可能会产生意想不到的效果:对于例如,如果两个客户端的时区校正之间的差异是负数(例如,-1 小时),则输入为 28/06/2011 的日期可以在 DateField 组件中显示为 27/06/2011。

    这是一个复杂的问题,没有快速简便的解决方案:这取决于您要提供的时区支持类型。

    最简单的解决方案是将所有客户端设置为使用公共时区,例如服务器的时区。不幸的是,当前版本的 Flash Player 不允许指定明确的时区,并且要实施此策略,您需要在将 Flex 组件创建的任何 Date 发送到服务器之前手动设置其内部 UTC 值,以补偿本地时区偏移。另一个常见的解决方法是避免使用 Date 对象并使用 ISO 字符串表示日期。

    您可以在 Adob​​e Bug Tracker 中找到很多信息(以及一些关于时区管理的想法),请参阅 https://bugs.adobe.com/jira/browse/FP-175 问题,标题为“在 flashplayer 上设置特定时区。这将使应用程序在所有应用程序上都保持相同的时区不同时区的客户。”

    【讨论】:

    • 很好的答案,但是您似乎听起来很难设置正确的日期。很多时候,我让服务器保存/发送一个通用日期字符串(包括日期、时间和偏移量),然后让DateFormatter.parseString 完成我的命令类的工作。
    • 是的,根据您正在构建的应用程序的类型,使用字符串而不是 Date 对象进行服务器通信可能是一个可行的解决方案(我在答案中提到了它,没有详细说明)。但是,根据我的经验,当您有自定义复杂对象(结构化 DTO/VO)并且日期字段可以嵌套在这些结构中以及涉及客户端日期计算时,事情会变得棘手。我只是想提醒一下,独立于选择的解决方案,对问题的充分理解对于避免意外情况很重要。
    【解决方案2】:

    我终于实现了这个解决方案:

    从服务器获取数据作为 ISO 字符串(冷融合到 MS SQL Server):

    SELECT CONVERT(varchar, CONTRACTED_DELIVERY, 104) AS CONTRACTED_DELIVERY
    FROM (...)
    WHERe (...)
    

    然后当我收到它时,我在 ValueObject 中转换它(遵循 Cairngorm 框架):

                if (obj.CONTRACTED_DELIVERY != null){
                this.CONTRACTED_DELIVERY = DateField.stringToDate(obj.CONTRACTED_DELIVERY,"DD.MM.YYYY");
            }else{
                this.CONTRACTED_DELIVERY = obj.CONTRACTED_DELIVERY;
            }
    

    发送日期作为 ISO 字符串到服务器:

    UPDATE (...)
    SET CONTRACTED_DELIVERY = <cfif productionDetails.CONTRACTED_DELIVERY EQ ''>null<cfelse>'#dateFormat(productionDetails.CONTRACTED_DELIVERY,"YYYY-MM-DD")#'</cfif>
    WHERE (...)
    

    请随时询问更多信息!

    【讨论】:

      【解决方案3】:

      基于https://forums.adobe.com/thread/1076594 的 Blaze DS / Adob​​e LiveCycle DS 解决方案:

      服务配置.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;
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-02-26
        • 2015-02-04
        • 2017-08-31
        • 1970-01-01
        • 2016-04-09
        • 1970-01-01
        • 2020-01-19
        • 2015-11-20
        相关资源
        最近更新 更多