【问题标题】:Java 8 LocalDateTime.now() only giving precision of millisecondsJava 8 LocalDateTime.now() 仅给出毫秒精度
【发布时间】:2017-01-27 22:03:14
【问题描述】:

在 Java 8 中是否有可能获得微秒? Java 8 LocalDateTime 类有一个.getNano() 方法,该方法旨在返回nanoseconds,但在Linux(Ubuntu)和OS X(10.11.5)上它只返回milliseconds(当我运行它时它返回301000000 等于 301 milliseconds),我真的需要能够得到 microseconds

我知道可以在我的计算机上获取 nanoseconds(因此从中获取 microseconds),因为 javascript 方法 process.hrtime() 返回一个精确值。

在任何人开始精确与准确的争论之前,我知道纳秒在线程之间是完全不可靠的,不应该用于比较。

编辑

需要明确的是,LocalDateTime 类是 Java 8 java.time 类集的一部分。

更新

所以我意识到 Javascript 的 process.hrtime 就像 Java 的 System.nanoTime() 并且实际上与挂钟无关,是时候因为某些任意值在两种语言之间有所不同。

新问题:有没有办法可以从这些值中解析时钟时间? IE。如果我得到System.currentTimeMillis()System.nanoTime(),并将其与另一组这些值进行比较,我可以得到第二组值的实际时间吗?

我的问题是我需要同时使用 Java 和 Javascript 进行日志记录,并且它们需要在两者之间具有一致的微秒字段。

【问题讨论】:

标签: java clock


【解决方案1】:

tl;博士

在 Java 8 中是否可以得到微秒?

没有。使用 Java 9 或更高版本。

Instant.now()  // Returns a value in microseconds in Java 9 and later, but is restricted to mere milliseconds in Java 8.

这是指 Java 8/9 的 Oracle 和 OpenJDK 实现。其他可能会有所不同。

Java 9 及更高版本

Java 9 的 fresh implementationjava.time.Clock 能够以小于毫秒的分辨率捕获当前时刻(三位小数位)。

实际分辨率取决于主机硬件时钟的限制。在带有 Oracle Java 9.0.4 的 macOS Sierra 上,我得到了微秒的当前时刻( 位小数)。

Instant.now().toString()

2018-03-09T21:03:33.831515Z

Java 8

java.time 类是 Java 8 中的新类。这些类被定义为携带纳秒( 位十进制小数)。但捕获当前时刻仅限于 Java 8 中的 milliseconds,并在 Java 9 中增强以更精细地捕获当前时刻 microseconds

2018-03-09T21:03:33.831Z

其他问题

System.currentTimeMillis()

如果我得到 System.currentTimeMillis() 和 System.nanoTime()

无需再使用System.currentTimeMillis()。而是在 UTC 中使用 java.time.Instant 片刻,分辨率可以达到纳秒级。

如果您确实需要从 1970-01-01T00:00Z 的纪元引用计算毫秒数,请询问 Instant 对象。请注意数据丢失,因为您将忽略 Instant 中存在的任何微秒或纳秒。

long millisSinceEpoch = instant.now().toEpochMilli() ;

有没有办法可以从这些值中解析时钟时间?

是的,您可以将自 1970-01-01T00:00Z 纪元以来的毫秒数转换为 Instant

Instant instant = Instant.ofEpochMilli( millisSinceEpoch ) ;

System.nanoTime()

至于System.nanoTime(),它用于跟踪经过的时间,例如对代码的性能进行基准测试。调用 System.nanoTime() 并不会告诉你有关当前日期时间的任何信息。

此值是自某个未记录的原始时间点以来的纳秒计数。在实践中,自 JVM 启动以来,我已经看到该数字似乎在跟踪时间,但这种行为没有记录在案,因此您不应依赖它。

LocalDateTime不是片刻

我的问题是我需要同时使用 Java 和 Javascript 进行日志记录,并且它们需要在两者之间具有一致的微秒字段。

首先,对于日志记录,您应该使用LocalDateTime 类。该类故意缺少任何时区或与 UTC 偏移的概念。因此,LocalDateTime 确实代表一个时刻,不是时间线上的一个点。 LocalDateTime 是关于在大约 26-27 小时范围内的潜在时刻的想法。仅当区域/偏移量未知(不是一个好情况),或者如果这表示“圣诞节从 2018 年 12 月 25 日的第一刻开始”之类的情况下使用 LocalDateTime,其中圣诞节在不同地区的不同时间开始地球,首先从远东(太平洋)开始,在连续的午夜之后向西移动。

对于日志记录,您应该使用 UTC。在 Java 中,这将是 Instant 类,根据定义始终使用 UTC。只需致电Instant.now()

当序列化为文本(例如用于日志记录)时,请始终使用标准的ISO 8601 格式。 java.time 类在解析/生成字符串时默认使用这些标准格式。您在此答案中看到了上述示例。

查看另一个问题,What's the difference between Instant and LocalDateTime?

ISO 8601

在 ISO 8601 中,秒的小数部分可以有任意位数。所以你真的不应该关心记录的事件是以毫秒、微秒还是纳秒为单位记录的。

Instant instant = Instant.parse( "2018-03-09T21:03:33.123456789Z" ) ;
Instant instant = Instant.parse( "2018-03-09T21:03:33.123456Z" ) ;
Instant instant = Instant.parse( "2018-03-09T21:03:33.123Z" ) ;

截断

如果你真的认为你需要统一的分辨率,你可以truncate a Instant

Instant instant = Instant.now().truncatedTo( ChronoUnit.MILLIS ) ; // Strip away any microseconds or nanoseconds.

不用担心分辨率

我的问题是我需要同时使用 Java 和 Javascript 进行日志记录,并且它们需要在两者之间具有一致的微秒字段。

首先,我怀疑你真的需要关心这个。如果您使用标准 ISO 8601 格式和 Java 中的 Instant 类,您可以在毫秒、微米或纳米中成功地序列化和重新水化片刻。

即使小数秒分辨率不同,ISO 8601 格式的字符串也会方便地按时间顺序排列。

其次,如果您出于某种原因尝试将实际时刻跟踪到微秒,您可能会感到失望。截至 2018 年,传统的计算机时钟在微秒范围内并不可靠。


关于java.time

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

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

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

您可以直接与您的数据库交换 java.time 对象。使用符合JDBC 4.2 或更高版本的JDBC driver。不需要字符串,不需要java.sql.* 类。 Hibernate 5 & JPA 2.2 支持 java.time

从哪里获取 java.time 类?

【讨论】:

  • 多么好的答案!
【解决方案2】:

LocalDate.now() 依赖于使用System.currentTimeMillis()SystemClock::instant() 方法,因此使用默认时钟不会获得更精确的分辨率。

但是,您可以实现自己的高精度 Clock 并将其与 LocalDate 结合使用:

LocalDate hpDate = LocalDate.now(microsecondClock);

对于高精度,您可以使用带有微秒刻度的TickClock

Clock microsecondClock = Clock.tick(Clock.systemUTC(), Duration.ofNanos(1000));

或子类Clock 并实现您自己的高精度时钟,即使用 System.currentTimemillis() 和 System.nanoTime()。

【讨论】:

  • 如何实现自己的时钟?
  • class YourClock extends Clock { .... } ... 我假设有多种方法可以做到这一点,一种可能是运行一个计时器线程,它计算 System.currentTimeMillis() 的两次时间测量之间的循环迭代,形成这个派生该间隔内的微秒或纳秒数。但请记住,您获得的越精确,它就越不准确。
  • 我需要使用微/纳秒来发送日志,这也将与从 javascript 项目发送的日志进行比较,因此我需要能够获得系统范围的微秒值。
【解决方案3】:

虽然您的计算机能够报告比毫秒更精确的内容(但可能不准确,至少不是在墙上时间),但这并不会改变 Java 默认使用基于 System.currentTimeMillis()Clock 的事实。

您必须provide a more precise Clock 才能获得比 ms 更精确的值。即until Java 9

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-25
    • 2014-08-07
    • 2015-06-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多