【问题标题】:How to handle time zone difference between server and native android application?如何处理服务器和原生 android 应用程序之间的时区差异?
【发布时间】:2013-08-12 17:48:40
【问题描述】:

假设我的服务器位于美国,而我住在俄罗斯。我们知道他们有不同的时区。

我的应用程序从服务器获取文本(String)。并且这个文本数据在数据库中有Date 列来保存记录日期。

当我得到数据时,我也得到了date 知识。所以我可以按时间分组。第一个在顶部,最后一个在底部。随便...

我编写了一个函数来显示更易于阅读的日期值,例如“13 小时”、“9 分钟”。服务器向我发送服务器(美国)时区的日期。

当我使用俄罗斯时区计算申请时间时(因为它是申请时的当前时区),它计算错误。所以,这不是任何人想要的东西。

我应该怎么做才能实现正确的计算?

注解:这个应用程序将被不同国家的公民使用。所以我不能让计算静态化。

【问题讨论】:

    标签: android timezone android-date


    【解决方案1】:

    只要您知道服务器和客户端使用哪个时区,Calendar 类就可以在时区之间转换时间。为避免将来移动服务器时出现问题,最好定义数据库中的时间。我更喜欢使用 UTC 作为它的标准,但是你可以使用任何你想要的时区,只要它定义在你的文档中,这样你将来就会知道。

    这里有一个问题说明如何做到这一点:Date and time conversion to some other Timezone in java

    【讨论】:

    • 麻烦的Calendar 类现在是遗留的,几年前取代了 java.time 类。
    • @BasilBourque Java.time 是 android 8,大约一个月前刚刚添加到 Android,并且仅在 v26+ 上受支持。至少 3 年,甚至更可能 5 年,根据您愿意放弃对市场的支持程度,在 android 上普遍使用它是不安全的。
    • 对于早期的 Android,请参阅 ThreeTen-BackportThreeTenABP 项目。见How to use…
    • @BasilBourque 不,谢谢。当存在现有解决方案时,我不需要向我的项目添加更多随机库来获得次要功能。我没有添加安全风险。
    【解决方案2】:

    我不知道如何以编程方式实现这一点,但我知道可以做到 :) ... 也许您应该尝试一种策略,根据 GMT 时间保存所有记录,然后在客户端制作一个公式,检查客户端的时区,然后如果它是负时区,则从当前时间记录中替换该数量,并且如果它是一个正时区,则以这种方式将该数量添加到时间记录中,它将根据该时区向客户显示.....(请原谅我的语法:)希望它可以)

    【讨论】:

      【解决方案3】:

      实际上并没有诸如“俄罗斯时区”或“美国时区”之类的东西。这两个国家都有几个不同的时区。请参阅 Time in RussiaTime in the USA 上的维基百科文章。

      您应该始终编写服务器代码,使其不依赖于服务器运行所在的时区。通常这是通过将所有时间存储为UTC 来完成的。由于客户端是 Android 设备,因此只需在客户端上转换为本地时间,只需将 UTC 发送到服务器或从服务器发送。

      如果您使用 Java,您可能应该使用 Joda Time 进行转换。它比Calendar 类更干净、更易于使用。

      更新

      正如 Basil 在 cmets 中指出的那样,Joda-Time 项目现在处于维护模式。团队建议迁移到JSR 310 定义的java.time 类。对于早期的 Android,请参阅 ThreeTen-BackportThreeTenABP 项目。见How to use…

      【讨论】:

      • 此 UTC 转换是否处理夏令时?
      • @vishnu - UTC 没有任何夏令时,但是当您转换为 本地时间 时,将考虑 DST(假设您正确使用 API并且不尝试手动调整 DST)。
      • Joda-Time 主页已移动。更新了链接。
      • Joda-Time 项目处于维护模式。团队建议迁移到 JSR 310 定义的 java.time 类。对于早期的 Android,请参阅 ThreeTen-BackportThreeTenABP 项目。见How to use…
      【解决方案4】:

      如果您在 Java 8 之前使用 Java,您可能应该使用 Joda Time 进行转换。看看这个问题:Date and time conversion to some other Timezone in java

      如果您使用的是 Java 8 和更新版本(或者如果您打算在公司中开始升级过程),Java 8 包含一个适当的日期/时间库,Joda 的创建者建议切换到使用它。看看这个问题:Joda Time - Convert UTC DateTime to Date - Using a Version 1.2.1.1 of Joda

      【讨论】:

      【解决方案5】:

      tl;博士

      时区与经过的小时-分钟-秒无关。

      Duration.between(
          Instant.parse( "2017-12-14T01:34:56.123456789Z" ) ;
          Instant.now() 
      )
      

      java.time

      现代方法使用行业领先的 java.time 类。这些取代了麻烦的旧旧日期时间类,例如 DateCalendar

      服务器通常应设置为 UTC 时区。你永远不应该依赖任何这样的设置。相反,您的代码应指定所需/预期的时区。

      作为一般规则,您的业务逻辑、数据存储和数据交换都应该使用 UTC。序列化为文本时,仅使用标准 ISO 8601 格式。

      在必要时应用其他时区,如用户在用户界面中所期望的那样。因此,通常您应该将 UTC 以外的时区视为本地化问题。

      Instant

      Instant 类代表一个时刻,即 UTC 时间轴上的一个点,分辨率为纳秒。获取当前时刻不受时区设置的影响。

      Instant instant = Instant.now() ;
      

      通过调用toString序列化为标准格式的文本。

      String output = instant.toString() ;
      

      您可以将Instant 与您的数据库交换。

      myPreparedStatement.setObject( … , instant ) ;
      

      ……和……

      Instant instant = myPreparedStatement.getObject( … , Instant.class ) ;
      

      ZonedDateTime

      申请ZoneId 以获得ZonedDateTime

      ZoneId z = ZoneId.of( "America/Montreal" ) ;
      ZonedDateTime zdt = instant.atZone( z ) ;
      

      要生成非标准格式的字符串,请使用DateTimeFormatter 类。在 Stack Overflow 上搜索许多示例和讨论。

      Duration

      要获取经过的小时数、分钟数、秒数,请使用 Duration 类。请注意,您不需要时区来表示已用时间; UTC (Instant) 给出相同的结果。

      Duration d = Duration.between( then , Instant.now() ) ;
      

      对于早期的 Android,请参阅 ThreeTen-BackportThreeTenABP 项目。见How to use…


      关于java.time

      java.time 框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧 legacy 日期时间类,例如 java.util.DateCalendarSimpleDateFormat

      Joda-Time 项目现在位于maintenance mode,建议迁移到java.time 类。

      要了解更多信息,请参阅Oracle Tutorial。并在 Stack Overflow 上搜索许多示例和解释。规格为JSR 310

      从哪里获得 java.time 类?

      【讨论】:

        猜你喜欢
        • 2014-04-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-10-30
        • 2020-07-03
        • 1970-01-01
        • 2014-04-18
        • 1970-01-01
        相关资源
        最近更新 更多