编辑:OK。不幸的是,我不得不承认我对Java时间的理解存在严重缺陷,这使得这个问题变得毫无意义。我一直认为System.currentTimeMillis()返回的是本地时间。为什么?因为当您用它创建Date时,它只包含那个,而不引用时区,但是在传递给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边界处中断,并且它会使时间转换为其他时区更加复杂。
这里是我的时钟类
在我看来,Clock.millis()和Clock.instant()方法必须使用本地时间才能正常工作。
绝对不是。Instant
不与时区关联,millis
的文档为:
返回从UTC时间1970-01-01T00:00开始以毫秒为单位测量的瞬间。这相当于System.currentTimeMillis()的定义。
再次强调,这不是当地时间。它使用本地系统时钟,但这并不等于说它是正常意义上的本地时间。
很不清楚你真正想做的是什么,但我至少会尝试按照Instant
而不是ZonedDateTime
来做所有事情。Instant
的意义在于它只是时间线上的一个点;它没有时区,甚至没有日历系统。只要您使用的所有内容(跨所有系统)使用具有相同历元的相同概念时间线(例如,如果您在任何地方使用JSR-310),那么就应该没问题。Instant
使用与Java相同的历元- UTC的1970年开始。
当然,您可能仍然希望拥有自己的时间来源,但显然您需要考虑网络延迟等。考虑使用标准化的NTP或类似的东西,而不是尝试构建自己的系统。然后,您可能想要调整它来实现Clock
的子类。如果其他所有都是在Clock
方面工作,那么您的代码将是很好的和可测试的,而不涉及您的网络服务。
解决方法是:可以更改TimeZone:
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
因此,要在时钟中使用UTC,但仍然能够在本地用户时区中显示时间值,您必须首先获取并保存默认timezone,然后只将其替换为UTC。
然后,JVM将认为您的本地时区是UTC,因此,如果时钟实际上返回UTC毫秒和瞬间,一切都将一起工作。当您想要显示时间值时,您可以获取原始的默认时区,并使用该时区创建另一个时钟实例,但是millis和instant方法保持不变,因此它们仍然返回UTC时间。
主要的好处是现在不需要在任何地方进行时区转换,除非以本地时间显示给用户。
[EDIT]转念一想,这具有有限的价值,因为其他所有内容仍将使用System.currentTimeMillis()(包括间接地通过java.util.Date和Calendar)。因此,一个人可能永远无法解决所有与时间相关的问题[/p>