0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Linux だと、Instant.now() の分解能が Java のバージョンが上がるごとによくなっている

Posted at

Linux 上で、簡単なコードを書いて検証しました。

for(int i = 0; i < 3; i++) {
    System.out.println(Instant.now());
}

Java 8 では、分解能は1ミリ秒でした。

Java 8 での実行結果
2025-10-18T10:23:52.806Z
2025-10-18T10:23:52.836Z
2025-10-18T10:23:52.836Z

Java 9 から Java 14 までは、分解能は1マイクロ秒でした。

Java 9 での実行結果
2025-10-18T10:23:57.709235Z
2025-10-18T10:23:57.727024Z
2025-10-18T10:23:57.727058Z

Java 15 以降では、分解能は1ナノ秒になっています。

Java 15 での実行結果
2025-10-18T10:24:03.015979993Z
2025-10-18T10:24:03.023731447Z
2025-10-18T10:24:03.023783695Z

経緯

Instant.now() の実装は、Clock.systemUTC().instant() です。

public static Instant now() {
    return Clock.systemUTC().instant();
}

この instant() メソッドの内部実装が徐々に変わっていました。

Java 8

Java 8 の時点では、Instant.now()System.currentTimeMillis() を使って実装されていました。

Clock.java(Java 8)
@Override
public long millis() {
    return System.currentTimeMillis();
}

@Override
public Instant instant() {
    return Instant.ofEpochMilli(millis());
}

Java 9

Java 9 からは、jdk.internal.misc.VM クラスに getNanoTimeAdjustment(long) というメソッドを用意し、それを使うようになりました。
[JDK-8068730] Increase the precision of the implementation of java.time.Clock.systemUTC()

Clock.java
@Override
public Instant instant() {
    long localOffset = offset;
    long adjustment = jdk.internal.misc.VM.getNanoTimeAdjustment(localOffset);
    // 中略
    return Instant.ofEpochSecond(localOffset, adjustment);

この VM.getNanoTimeAdjustment(long) から、 os::javaTimeSystemUTC(jlong, jlong) を呼び出しており、最終的には gettimeofday(&time, NULL) 関数でマイクロ秒の時刻を取得していました。

os_linux.cpp
void os::javaTimeSystemUTC(jlong &seconds, jlong &nanos) {
  timeval time;
  int status = gettimeofday(&time, NULL);
  assert(status != -1, "linux error");
  seconds = jlong(time.tv_sec);
  nanos = jlong(time.tv_usec) * 1000;
}

Java 15

os::javaTimeSystemUTC(jlong, jlong) に変更が入り、clock_gettime(CLOCK_REALTIME, &ts) が使えるのであればそれを使うようになりました。
clock_gettime の分解能はナノ秒を持つので、これまでと比べてより細かい時間の変化を捉えることができるようになりました。
[JDK-8242504] Enhance the system clock to nanosecond precision - Java Bug System

os_linux.cpp
jlong os::javaTimeMillis() {
  if (os::Posix::supports_clock_gettime()) {
    struct timespec ts;
    int status = os::Posix::clock_gettime(CLOCK_REALTIME, &ts);
    assert_status(status == 0, status, "gettime error");
    return jlong(ts.tv_sec) * MILLIUNITS +
           jlong(ts.tv_nsec) / NANOUNITS_PER_MILLIUNIT;
  } else {
    timeval time;
    int status = gettimeofday(&time, NULL);
    assert(status != -1, "linux error");
    return jlong(time.tv_sec) * MILLIUNITS  +
           jlong(time.tv_usec) / (MICROUNITS / MILLIUNITS);
  }
}

Java 17

さらに変更が入り、gettimeofday(&time, NULL); を使用するコードが削除されました。
これは、すべての POSIX 環境で clock_gettime(CLOCK_REALTIME, &ts) 関数が使えることが確認できたためです。
[JDK-8246112] Remove build-time and run-time checks for clock_gettime and CLOCK_MONOTONIC - Java Bug System

:os_posix.cpp
void os::javaTimeSystemUTC(jlong &seconds, jlong &nanos) {
  struct timespec ts;
  int status = clock_gettime(CLOCK_REALTIME, &ts);
  assert(status == 0, "clock_gettime error: %s", os::strerror(errno));
  seconds = jlong(ts.tv_sec);
  nanos = jlong(ts.tv_nsec);
}

おまけ:Windows の場合

ちなみに、Windows では、Java 8 では1ミリ秒、Java 9 以降は100ナノ秒です。

Java 9 での実行結果(Windows)
2025-10-18T10:42:03.974929300Z
2025-10-18T10:42:03.999100800Z
2025-10-18T10:42:03.999100800Z

これは、GetSystemTimeAsFileTime 関数の仕様に依存しています。
さらに高い分解能を得られるAPIに置き換えることも検討されましたが、不安定ということで却下されています。
[JDK-8180466] Clock.systemUTC has low resolution on Windows - Java Bug System

過去記事

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?