Java 8 Instant.now()具有纳秒分辨率?

时间:2013-12-19 18:29:39

标签: java time nanotime

Java 8的java.time.Instant以“纳秒分辨率”存储,但使用Instant.now()只能提供毫秒分辨率......

Instant instant = Instant.now();
System.out.println(instant);
System.out.println(instant.getNano());

结果...

2013-12-19T18:22:39.639Z
639000000

我怎样才能得到一个值为'now'但具有纳秒分辨率的Instant?

5 个答案:

答案 0 :(得分:15)

虽然默认Java8时钟不提供纳秒分辨率,但您可以将其与Java能力结合使用,以纳秒分辨率测量时差,从而创建一个实际的纳秒级时钟。

public class NanoClock extends Clock
{
    private final Clock clock;

    private final long initialNanos;

    private final Instant initialInstant;

    public NanoClock()
    {
        this(Clock.systemUTC());
    }

    public NanoClock(final Clock clock)
    {
        this.clock = clock;
        initialInstant = clock.instant();
        initialNanos = getSystemNanos();
    }

    @Override
    public ZoneId getZone()
    {
        return clock.getZone();
    }

    @Override
    public Instant instant()
    {
        return initialInstant.plusNanos(getSystemNanos() - initialNanos);
    }

    @Override
    public Clock withZone(final ZoneId zone)
    {
        return new NanoClock(clock.withZone(zone));
    }

    private long getSystemNanos()
    {
        return System.nanoTime();
    }
}

使用它非常简单:只需为Instant.now()提供额外参数,或直接调用Clock.instant():

    final Clock clock = new NanoClock();   
    final Instant instant = Instant.now(clock);
    System.out.println(instant);
    System.out.println(instant.getNano());

虽然每次重新创建NanoClock实例时此解决方案都可能有效,但最好还是坚持使用代码中早期初始化的存储时钟,然后在需要的地方使用。

答案 1 :(得分:13)

如果你的分辨率达到毫秒级,你可以认为自己很幸运。

Instant可能建模达到纳秒精度的时间,但计算机上跟踪挂钟时间的真实设备通常具有大约10毫秒的分辨率,并且几乎可以肯定准确度略低于此(100毫秒将是一个乐观的假设)。

将此与System.nanoTime()进行比较,后者以微秒为单位给出分辨率,但不给出绝对的挂钟时间。显然,在工作中已经有了权衡,给你那种分辨率,仍然是三个数量级的纳秒。

答案 2 :(得分:4)

通过使用Instant-method public static Instant now(Clock clock),使用另一个更精确的java.time.Clock,你只能得到一个“纳秒”的瞬间。在你的例子中,默认时钟通常使用System.currentTimeMillis()无法显示任何纳秒。

请注意,没有时钟可用纳秒分辨率(实时)。 java.time.Instant的内部纳秒表示工具主要是由于需要映射以纳秒精度给出的数据库时间戳(但通常不准确到纳秒!)。

从2015-12-29更新: Java-9将提供更好的时钟,请参阅my newer post

答案 3 :(得分:3)

所以我花了一些时间在这里挖掘Javadoc:

http://download.java.net/jdk8/docs/api/java/time/Instant.html

您似乎应该能够执行以下操作:

Instant inst = Instant.now();
long time = inst.getEpochSecond();
time *= 1000000000l; //convert to nanoseconds
time += inst.getNano(); //the nanoseconds returned by inst.getNano() are the nanoseconds past the second so they need to be added to the epoch second

那就是说 - 其他的回答者说得很好,因为计算机通常没有足够的时间跟踪分辨率,所以很难获得准确的纳秒时间

答案 4 :(得分:0)

我需要一个对多个 JVM 实例通用的高精度计时器。

由于 System.nanoTime() 的 Javadoc 明确指出每个 JVM 可能会为此值使用不同的来源,因此我创建了以下测试类,它计算 Epoch 的纳秒偏移量,因此我可以获得带有System.nanoTime() 的精度,但有一个共同的起源。 (这与@logtwo 发布的 NanoClock 解决方案中提出的想法基本相同)

也许有助于可视化 Instant.now()System.nanoTime() 返回的值之间的分辨率差异,尽管两者名义上都具有纳秒级精度。

在我使用的硬件上,这可能会导致 JVM 之间的原点产生大约 1 毫秒的增量,但这对于我的目的来说已经足够了。

import java.time.*;
import java.util.concurrent.TimeUnit;

public class EpochNanotimeOffset {

    private static final long NANO_TIME_EPOCH_OFFSET;
    /**/    static {
        final long     systemNanoTime         = System.nanoTime();
        final Instant  now                    = Clock.systemUTC().instant();
        final long     instantNanosSinceEpoch = Duration.between(Instant.EPOCH, now).toNanos();

        NANO_TIME_EPOCH_OFFSET = systemNanoTime - instantNanosSinceEpoch;
    }

    public static void main(final String[] args) throws InterruptedException {
        for (int i=0; i < 99; i++) {

            final long    systemNanoTime          = System.nanoTime();
            final Instant instant                 = Clock.systemUTC().instant();
            final long    instantNanos            = Duration.between(Instant.EPOCH, instant).toNanos();
            final long    correctedSystemNanoTime = systemNanoTime - NANO_TIME_EPOCH_OFFSET;
            final long    deltaNanos              = instantNanos   - correctedSystemNanoTime;

            Duration.between(Instant.EPOCH, instant).toNanos();

            System.out.print  (                  "OffsetNS=" + NANO_TIME_EPOCH_OFFSET );
            System.out.print  ('\t' + "instantNSsinceEpoch=" + instantNanos );
            System.out.print  ('\t' +   "correctedSystemNS=" + correctedSystemNanoTime );
            System.out.print  ('\t' +            "systemNS=" + systemNanoTime );
            System.out.println('\t' +             "deltaNS=" + deltaNanos );

//          TimeUnit.SECONDS.sleep(3);
        }
    }
}