有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

Java 10与Java 8中从毫秒自历元到LocalDateTime的日期转换

我有一个应用程序,我使用从Epoch开始的毫秒数转换为LocalDateTime,然后再转换回来。该应用程序在Java8上运行良好,但我尝试更新到Java10,发现了以下问题

这是Java8中的输出

 ✘ 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)

这是Java10中的输出,如果您看到格式的末尾是6位,而不是像Java8中的3位,那么这将中断从历元到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());
}
}

如何在Java10中修复此问题


共 (1) 个答案

  1. # 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()返回的实际值

    从统计学上讲,用小数点后三位而不是六位来表示是不可能的,但绝对有可能的。如果您的硬件支持,则更可能需要9位小数,而不是6位小数。当我在Java10下运行代码时,通常会打印九位小数,但偶尔只需要六位小数

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

    An application making the assumption that the clock returned by these system factory methods will always have milliseconds precision and actively depends on it, may therefore need to be updated in order to take into account the possibility of a greater resolution...

    关于您的问题“我如何在Java 10中修复此问题?”,我不确定您想要修复什么,因为我不知道您的应用程序需求的详细信息

    teppic的一条评论已经解释了如何使用LocalDateTime.now().truncatedTo(ChronoUnit.MILLIS)将精度限制在小数点后三位,但我不认为这样做有什么好处,除非应用程序要求固定精度为小数点后三位。另一种方法可能是使用纳米精度,如有必要,将零焊盘设置为九位数;这样,您将获得更高精度的好处,但仍然具有固定的长度值