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



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

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

当我得到数据时,我也得到了date知识。所以我可以按时间对它们进行分组。第一个在顶部,最后一个在底部。无论什么

我写了一个函数来显示日期值,比如"13小时"、"9分钟",更便于阅读。服务器将服务器(美国)时区中的日期发送给我。

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

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

注释:此应用程序将由不同国家的公民使用。所以我不能使计算成为静态的。

实际上并没有"俄罗斯时区"或"美国时区"这样的东西。这两个国家都有几个不同的时区。请参阅维基百科上关于俄罗斯时间和美国时间的文章。

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

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

更新

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

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

这里有一个问题展示了如何做到这一点:日期和时间转换到java中的其他时区

tl;dr

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

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类。搜索堆栈溢出的许多例子和讨论。

Duration

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

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

对于早期的Android,请参阅ThreeTen BackportThreeTenABP项目。请参阅如何使用…


关于java.time

java.time框架是在java 8及更高版本中构建的。这些类取代了诸如java.util.DateCalendar、&SimpleDateFormat

JodaTime项目现在处于维护模式,建议迁移到java.Time类。

要了解更多信息,请参阅Oracle教程。并在Stack Overflow中搜索许多示例和解释。规范是JSR310。

从哪里获得java.time类?

  • Java SE 8Java SE 9及更高版本
    • 内置
    • 标准Java API的一部分,带有捆绑实现
    • Java 9添加了一些小功能和修复程序
  • Java SE 6Java SE 7
    • 大部分java.time功能都是向后移植到Java6&7英寸ThreeTen背包
  • 安卓
    • ThreeTenABP项目专门为安卓系统改编了ThreeTen Backport(如上所述)
    • 请参阅如何使用ThreeTenABP…

我不知道如何通过编程的方式实现这一点,但我知道可以做到:)。。。也许你应该尝试一种策略,根据格林尼治标准时间保存所有记录,然后在你的客户端制定一个公式,检查客户的时区,如果是负时区,则从当前时区中替换该金额,如果是正时区,则将该金额添加到时间记录中,这样它将根据该时区显示给客户。。。。。(请原谅我的语法:)希望可以)

如果你在Java 8之前使用Java,你可能应该使用Joda Time进行转换。看看这个问题:在java中,日期和时间转换为其他时区

如果您使用的是Java 8及更新版本(或者您计划在公司开始升级过程),Java 8包含一个适当的日期/时间库,Joda的创建者建议您改用该库。看看这个问题:Joda Time-将UTC DateTime转换为Date-使用Joda 的1.2.1.1版本

相关内容

  • 没有找到相关文章

最新更新