基于UTC而不是本地时间创建JSR 310时钟?

时间:2013-04-14 16:22:22

标签: java timezone jsr310

编辑:好的。不幸的是,我不得不承认我对Java时间的理解存在严重缺陷,使得这个问题变得毫无意义。我一直认为System.currentTimeMillis()返回了本地时间。为什么?因为当您使用它创建日期时,它只包含该日期,并且不包含对时区的引用,但在传递给System.out.println()时仍会打印出本地时间。从来没有想过, toString()将(UTC)时间转换为当地时区。 :(

我想用Java创建一个客户端 - 服务器应用程序。时间起着重要作用。所以我决定在当时标准化GMT / UTC。我也从经验中知道,很多用户的PC都有完全错误的时间和/或时区。最后,我希望有更精确的时间,然后是毫秒。

因此,我创建了一个在开始时连接到Internet的类,并计算与UTC的偏移量,与本地时间和时区无关。换句话说,我有一个静态Java方法,以纳秒为单位返回UTC时间,并且可以独立于本地时间设置在任何PC上运行。

现在,我的问题是我想使用JSR 310来操作时间(实际上是Java 7的后端),我看不出如何定义不基于本地时间的时钟

在我看来,Clock.millis()和Clock.instant()方法必须使用本地时间才能正常工作[编辑:因为这些方法盲目地返回System.currentTimeMillis(),独立于集合时区属性]。因此我基本上必须将我的UTC时间转换为本地时间,以创建一个Instant,这样我就可以创建一个UTC ZonedDateTime,它将本地时间再次转换回UTC。这真是太疯狂了。如果我在Clock.millis()和Clock.instant()中使用UTC时间,然后创建一个UTC ZonedDateTime,那么本地时间偏移(我不想做任何事情)将被应用两次

从UTC转换到本地再返回是昂贵的,所以我真的希望能够使用纯粹的UTC。我正在制作一个实时游戏,而不是一个网络应用程序,这样的小延迟将毫无意义。

我可以返回UTC时间,“假装”时区是“本地”以获得正确的数字,但事情可能会在DST边界处中断,并且会使时间转换为其他时区更加复杂

Here my Clock class

2 个答案:

答案 0 :(得分:2)

  

在我看来,Clock.millis()和Clock.instant()方法必须使用本地时间才能正常工作。

绝对不是。 Instant与时区无关,millis记录为:

  

这将返回从1970-01-01T00:00 UTC开始测量的基于毫秒的瞬间。这相当于System.currentTimeMillis()的定义。

所以,这不是当地时间。它使用本地系统时钟,但这与正常意义上的本地时间不同。

目前还不清楚你真正想要做什么,但我至少尝试Instant而不是ZonedDateTime来做所有事情。 Instant的要点是它只是时间线上的一个点;它没有时区甚至没有日历系统。只要您使用的所有内容(在所有系统中)使用相同时间段的相同名义时间线(例如,如果您在任何地方使用JSR-310)那么您应该没问题。 Instant使用与Java相同的纪元 - 1970年的UTC开始。

当然,您可能仍然希望拥有自己的时间来源,但显然您需要考虑网络延迟等。考虑使用标准化的NTP或类似的东西,而不是尝试构建自己的系统。您可能希望自己调整它以实现Clock的子类。如果只是的所有内容都在Clock方面工作,那么您的代码将很好并且可以在不涉及您的网络服务的情况下进行测试。

答案 1 :(得分:0)

解决方案是:您可以更改TimeZone:

TimeZone.setDefault(TimeZone.getTimeZone("UTC"));

因此,要在时钟中使用UTC,但仍然能够在本地用户时区显示时间值,您必须首先获取并保存默认的TimeZone,然后仅将其替换为UTC,如上所述。

然后,JVM会认为您的本地时区是UTC,因此如果Clock实际上返回UTC millis并且即时,则一切都将一起工作。当您想要显示时间值时,您将获得原始默认时区,并使用该时区创建另一个时钟实例,但毫秒和即时方法保持不变,这样它们仍然可以返回UTC时间。

主要的好处是现在除了在当地时间向用户显示外,在任何地方都不需要进行时区转换。

[编辑第二个想法,这是有限的价值,因为其他一切仍将使用System.currentTimeMillis()(包括间接,通过java.util.Date和日历)。所以人们可能无法解决所有与时间相关的问题。]