Linux 上で、簡単なコードを書いて検証しました。
for(int i = 0; i < 3; i++) {
System.out.println(Instant.now());
}
Java 8 では、分解能は1ミリ秒でした。
2025-10-18T10:23:52.806Z
2025-10-18T10:23:52.836Z
2025-10-18T10:23:52.836Z
Java 9 から Java 14 までは、分解能は1マイクロ秒でした。
2025-10-18T10:23:57.709235Z
2025-10-18T10:23:57.727024Z
2025-10-18T10:23:57.727058Z
Java 15 以降では、分解能は1ナノ秒になっています。
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() を使って実装されていました。
@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()
@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) 関数でマイクロ秒の時刻を取得していました。
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
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
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ナノ秒です。
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