如何处理服务器和原生android应用程序之间的时区差异?

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

我的应用程序从服务器获取文本( String )。 而这个文本数据在数据库中有Date列保留loggingdate。

当我获得数据时,我也获得date知识。 所以我可以按时分组。 第一个在顶部,最后一个在底部。 随你…

我写了一个函数来显示date值,比如“13小时”,“9分钟”等。 服务器向我发送服务器(美国)时区中的date。

当我计算俄罗斯时区的应用程序时间(因为它是应用程序当前的时区),它计算错误。 所以,这不是什么人想要的东西。

我该怎么做才能达到正确的计算?

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

Solutions Collecting From Web of "如何处理服务器和原生android应用程序之间的时区差异?"

没有像“俄罗斯时区”或“美国时区”那样的东西。 这两个国家都有几个不同的时区。 请参阅维基百科有关俄罗斯 时间和美国时间的文章。

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

如果您使用的是Java,那么您应该使用Joda Time来进行转换。 它比Calendar类更清洁和更易于使用。

更新

正如Basil在评论中指出的那样,Joda-Time项目现在处于维护模式。 该团队build议迁移到由JSR 310定义的java.time类。 对于之前的Android,请参阅ThreeTen- Backport和ThreeTenABP项目。 请参阅如何使用…。

Calendar类可以在时区之间转换时间,只要您知道服务器和客户端使用什么时区即可。 为了避免在将来如果移动服务器时出现问题,最好定义数据库中的时间。 我更喜欢使用UTC作为它的标准,但是您可以使用任何您希望的时区,只要它在您的文档中定义,并且将来您将会知道。

下面是一个问题,显示如何做到这一点: date和时间转换到一些其他的时区在Java中

TL;博士

时区与经过的小时 – 分钟 – 秒不相关。

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

java.time

现代的方法使用行业领先的java.time类。 这些代替了DateCalendar等麻烦的旧式遗留date类。

服务器通常应该设置为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 ) ; 

要以非标准格式生成string,请使用DateTimeFormatter类。 search堆栈溢出了很多例子和讨论。

Duration

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

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

对于之前的Android,请参阅ThreeTen- BackportThreeTenABP项目。 请参阅如何使用…。


关于java.time

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

Joda-Time项目现在处于维护模式 ,build议迁移到java.time类。

要了解更多信息,请参阅Oracle教程 。 并search堆栈溢出了很多例子和解释。 规范是JSR 310 。

从何处获取java.time类?

  • Java SE 8Java SE 9和更高版本
    • 内置。
    • 带有捆绑实现的标准Java API的一部分。
    • Java 9增加了一些小function和修复。
  • Java SE 6Java SE 7
    • 大部分的java.timefunction都被移植到了ThreeTen-Backport中的 Java 6&7中。
  • Android的
    • ThreeTenABP项目专门针对Android,采用了ThreeTen-Backport (上文提到)。
    • 请参阅如何使用ThreeTenABP …。

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

如果您在Java 8之前使用Java,则应该使用Joda Time来进行转换。 看看这个问题: date和时间转换到一些其他的时区在Java中

如果您使用的是Java 8或更高版本(或者如果您计划在公司中开始升级过程),Java 8将包含适当的date/时间库,Joda的创build者build议切换到使用该库。 看看这个问题: 乔达时间 – 将UTCdate时间转换为date – 使用Joda的1.2.1.1版本