如何在Java中将System.nanoTime的结果转换为日期?

12

我想将System.nanoTime()的结果转换为日期。

public void tempBan(Player p, Player banner, int timeInSeconds){
    Long timeInNano = (long) (timeInSeconds * 10^9);
    int newTime = (int) (System.nanoTime() + timeInNano);
    // here I want to convert newTime to a date 
}

我已经通过将秒乘以10^9来将其转换为纳秒。现在,我需要将当前系统时间加上我转换成纳秒的参数转换为日期。


1
通常最好在代码块之外说明您想要什么。虽然有人可以阅读它们以弄清发生了什么,但是您使其更容易,就越有可能有人会帮助您。 - Cel Skeggs
你想要如何精确地将纳秒转换为日期? - Bruno Caceiro
1
投反对票的人,请发表批评意见。对我来说,这似乎是一个合理的问题。日期时间工作是棘手的事情,这个问题可能是一个常见的困惑点。 - Basil Bourque
请参考这个类似的问题,它比较了新的java.time框架和它对纳秒分辨率的支持以及这里提到的System.nanoTime()。那里的答案提醒我们,当前的计算机时钟实际上并没有产生任何接近准确的纳秒读数。 - Basil Bourque
如果你的目标是以纳秒分辨率追踪经过的时间,可以使用 InstantDuration。请注意,普通的计算机硬件时钟无法以纳秒精度捕捉当前时刻。 - Basil Bourque
3个回答

17

很不幸,System.nanoTime() 不是您所需要的。

引用 JavaDoc 的话:

此方法只能用于测量经过的时间,与任何系统或挂钟时间概念无关。返回的值表示自某个固定但任意的原始时间以来经过的纳秒数(可能在未来,因此值可能为负)。所有在 Java 虚拟机实例中调用此方法的调用都使用相同的起源; 其他虚拟机实例可能会使用不同的起源。

您可能需要 System.currentTimeMillis(),这样您就可以使用 new Date(System.currentTimeMillis() + milliseconds) 来获取未来那段毫秒数所对应的日期。

尽管您可以减去 System.nanoTime(),缩放该值,并添加 System.currentTimeMillis() 以获得类似的结果...但由于您已经添加了 System.nanoTime(),因此已经有了原始秒数,所以您可以直接使用 System.currentTimeMillis()


3
在理论上,你不应该仅使用System.nanotime(),但你可以通过这个方法做一个简单的技巧来获取当前时间的纳秒数。
public class TimeProvider{
    private final static long  jvm_diff;
    static {
        jvm_diff = System.currentTimeMillis()*1000_000-System.nanoTime();   
    }

    public static long getAccurateNow(){
        return System.nanoTime()+jvm_diff;

    }
}

即使如此,您可以使用高级Java日期时间类创建自己的时钟实现。
public class HighLevelClock extends Clock {

    private final ZoneId zoneId;

    public HighLevelClock(ZoneId zoneId) {
        this.zoneId = zoneId;
    }
    static long nano_per_second = 1000_000_000L;

    @Override
    public ZoneId getZone() {
        return zoneId;
    }

    @Override
    public Clock withZone(ZoneId zoneId) {
        return new HighLevelClock(zoneId);
    }

    @Override
    public Instant instant() {
        long nanos = TimeProvider.getAccurateNow();
        return Instant.ofEpochSecond(nanos/nano_per_second, nanos%nano_per_second);
    }

}

现在我们可以像下面这样使用我们的时钟实现:
Clock highLevelClock = new HighLevelClock(ZoneId.systemDefault());
System.out.println(LocalDateTime.now(highLevelClock));  //2020-04-04T19:22:06.756194290
System.out.println(ZonedDateTime.now(highLevelClock));  //2020-04-04T19:22:06.756202923+04:00[Asia/Baku]
System.out.println(LocalTime.now(highLevelClock));  //19:22:06.756220764

-4

你可以使用以下代码将其转换为系统时间

public static long convertToUnixMs(final long timeMs) {
    final long refMonoMs = monoTimeMs();
    final long refUnixMx = System.currentTimeMillis();

    return refUnixMx + (timeMs - refMonoMs);
}
public static long monoTimeMs() {
        return System.nanoTime() / 1000000;
    }

解释:

System.nanoTime() 是一个单调递增的时间,它没有意识到当前时间是多少,但它只会不断增加。因此,它是测量经过时间的好方法。但是,由于它没有参考当前时间,所以无法将其转换为有意义的时间。

提供的方法是将存储的纳秒时间转换为有意义的时间的一种方法。首先,您有一个时间Ms,它是以纳秒为单位的,您想要将其转换。然后,您创建了另一个nanotime(即refMonoMs)和另一个System.currentTimeMillis()(即refUnixMx)。然后,您从timeMs中减去refMonoMs,并将参考添加回其中,以获取有意义的时间。


1
这个方法 monoTimeMs() 是从哪里来的?它与 System.nanoTime() 有什么关系? - Mark Rotteveel
道歉,添加修正 - Tom chan
是的,timeMs是通过使用另一个monoTimeMs创建的。我想发布这篇文章,因为我有一堆事件存储在monoTimeMs中,我想将它们转换为日期,而这篇文章误导了人们认为这是不可能的。 - Tom chan
1
它不可能(或不应该)这样做,你也不会这样做。你正在将System.currentTimeMillis() - some millis进行转换,而实际上这里的“some millis”并不重要。Cels的答案表明,你不能(或不应该)将单个System.nanoTime()调用的结果转换为日期,并期望其是准确的。 - Tom
下午2点 - MonoTime中的30000 --> 下午3点 - MonoTime中的400002pm = 3pm - (4000 - 3000) - Tom chan
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接