Java 8 LocalDateTime.now()仅提供毫秒精度

时间:2016-09-20 05:27:59

标签: java clock

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进行日志记录,并且需要在两者之间都有一致的微秒字段。

3 个答案:

答案 0 :(得分:6)

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.

这指的是Oracle& Java 8/9的OpenJDK实现。其他可能不同。

Java 9及更高版本

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

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

Instant.now().toString()
  

2018-03-09T21:03:33.831515Z

Java 8

java.time类是Java 8中的新类。这些类被定义为携带纳秒(九位小数的数字)。但捕获当前时刻仅限于毫秒。

  

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小时之间。仅当区域/偏移未知(不是一个好的情况)时才使用LocalDateTime,或者如果这表示类似于"圣诞节从2018年12月25日的第一时间开始,圣诞节开始于世界各地不同地区的不同时刻,首先在远东(太平洋)开始,并在午夜连续午夜后向西移动。

对于日志记录,您应该使用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.DateCalendar和& SimpleDateFormat

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

要了解详情,请参阅Oracle Tutorial。并搜索Stack Overflow以获取许多示例和解释。规范是JSR 310

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

从哪里获取java.time类?

ThreeTen-Extra项目使用其他类扩展java.time。该项目是未来可能添加到java.time的试验场。您可以在此处找到一些有用的课程,例如IntervalYearWeekYearQuartermore

答案 1 :(得分:2)

LocalDate.now()依赖于使用SystemClock::instant()的{​​{1}}方法,因此您无法使用默认时钟获得更精确的分辨率。

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

Clock

对于高精度,您可以使用LocalDate hpDate = LocalDate.now(microsecondClock); 微秒刻度:

TickClock

或子类Clock microsecondClock = Clock.tick(Clock.systemUTC(), Duration.ofNanos(1000)); 并实现您自己的高精度时钟,即使用System.currentTimemillis()和System.nanoTime()。

答案 2 :(得分:1)

虽然您的计算机能够报告更精确的内容(但可能不准确,至少不是在壁挂时间内),而不是毫秒,但这并不会改变Java默认使用基于{{Clock的事实。 1}}。

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