【问题标题】:convert from millis since Epoch to LocalDateTime in Java 10 vs Java 8在 Java 10 与 Java 8 中从 Epoch 以来的毫秒转换为 LocalDateTime
【发布时间】:2019-02-12 08:36:57
【问题描述】:

我有一个应用程序,我使用自 Epoch 以来的毫秒数转换为 LocalDateTime 并返回,该应用程序在 Java 8 上运行良好,但我尝试更新到 Java 10 并发现以下问题

这是 Java 8 中的输出

 ✘ magg@MacBook-Pro-de-Miguel  ~/Desktop/CODE  java TimeTest
2018-09-06T20:13:30.253
1536290010253
2018-09-06T20:13:30.253
 ✘ magg@MacBook-Pro-de-Miguel  ~/Desktop/CODE  java -version
java version "1.8.0_181"
Java(TM) SE Runtime Environment (build 1.8.0_181-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.181-b13, mixed mode)

这是 Java 10 中的输出,如果您看到格式末尾是 6 位而不是 Java 8 中的 3 位,这会中断从 Epoch 到 LocalDateTime 的毫秒数的转换

✘ magg@MacBook-Pro-de-Miguel  ~/Desktop/CODE  java TimeTest
2018-09-06T20:13:18.568414
1536289998568
2018-09-06T20:13:18.568
 ✘ magg@MacBook-Pro-de-Miguel  ~/Desktop/CODE  java -version
java version "10.0.2" 2018-07-17
Java(TM) SE Runtime Environment 18.3 (build 10.0.2+13)
Java HotSpot(TM) 64-Bit Server VM 18.3 (build 10.0.2+13, mixed mode)

这里是源代码

public class TimeTest{


public static void main(String[] args)
{

TimeZone.setDefault(TimeZone.getTimeZone("America/Los_Angeles"));

LocalDateTime issueTime = LocalDateTime.now();

System.out.println(issueTime.toString());

ZonedDateTime zdt = issueTime.atZone(TimeZone.getDefault().toZoneId());
long timeInMillis = zdt.toInstant().toEpochMilli();
System.out.println(timeInMillis );

LocalDateTime date = LocalDateTime.ofInstant(Instant.ofEpochMilli(timeInMillis), TimeZone.getDefault().toZoneId());

System.out.println(date.toString());
}
}

如何在 Java 10 中解决此问题?

【问题讨论】:

  • 试试LocalDateTime.now().truncatedTo(ChronoUnit.MILLIS)
  • LocalDateTime 是在这里使用的错误类。它确实 代表一个时刻,缺乏任何时区或与UTC 偏移的概念。使用InstantOffsetDateTimeZonedDateTime 来表示时刻,时间轴上的特定点。

标签: java date java-8 java-10 localdate


【解决方案1】:

首先,LocalDateTime.toString() 的输出不是固定长度的。从它的 Javadoc(从 8 到 10 没有变化):

public String toString()
Outputs this date-time as a String, such as 2007-12-03T10:15:30.
The output will be one of the following ISO-8601 formats:

uuuu-MM-dd'T'HH:mm
uuuu-MM-dd'T'HH:mm:ss
uuuu-MM-dd'T'HH:mm:ss.SSS
uuuu-MM-dd'T'HH:mm:ss.SSSSSS
uuuu-MM-dd'T'HH:mm:ss.SSSSSSSSS
The format used will be the shortest that outputs the full value of the time where the omitted parts are implied to be zero.

您的 Java 10 运行碰巧打印了带六位小数的秒值,但它可能打印了带三个小数位或九位小数的值,具体取决于几个因素:

  • 计算机的时钟,可能具有或可能不具有纳米精度。
  • now() 返回的实际值。

在统计上不太可能,但绝对有可能只用三位小数而不是六位来表示。如果您的硬件支持,则更有可能需要九位小数而不是六位。当我在 Java 10 下运行您的代码时,通常会打印九位小数,但有时只需要六位。

其次,在 Java 9 中 “java.time.Clock 返回的系统时钟” 已更改 “以便它们提供至少与系统上可用的底层时钟相同的精度"。请参阅JDK-8068730 Increase the precision of the implementation of java.time.Clock.systemUTC(),它明确解决了您的情况:

一个应用程序假设时钟由这些返回 系统工厂方法将始终具有毫秒精度,并且 积极依赖它,因此可能需要更新以 考虑到更大分辨率的可能性...

关于您的问题“如何在 Java 10 中解决这个问题?”,我不确定您要解决什么问题,因为我不知道您的应用程序的详细信息要求。

teppic 的评论已经解释了如何使用 LocalDateTime.now().truncatedTo(ChronoUnit.MILLIS) 将精度限制在小数点后三位,但除非您有以下应用要求,否则我看不出这样做的好处小数点后三位的固定精度。另一种方法可能是使用纳米精度,必要时将零填充到九位;那么您将获得更高精度的好处,但仍然具有固定长度值。

【讨论】:

  • 感谢您的精彩解释,是的,teppic 解决方案将适用于我的代码。我想修复我的代码并让 LocalDateTime 在 Java 10 中使用 3 个小数位而不是 6 个小数位。基本上我的应用程序是一个 REST api,它将 LocalDateTime 保存到数据库中,并且它与其他值一起用作复合键。 API 返回一个具有长值的 JSON。您能否进一步扩展使用纳米精度的替代方法?我可以将 LocalDateTime 转换为考虑到最后 6 位小数并返回的长值吗? toEpochMilli 只会转换为毫秒
  • 我建议添加一个注释,说明 LocalDateTime 类是此处使用的错误类,因为它不能代表片刻。
猜你喜欢
  • 1970-01-01
  • 2021-08-19
  • 1970-01-01
  • 2014-07-19
  • 2021-08-31
  • 2016-05-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多