Unixシステムでは、Javaでマイクロ秒レベルの精度でタイムスタンプを取得する方法はありますか? Cのgettimeofday
関数のようなもの。
いいえ、Javaにはその機能がありません。
System.nanoTime()がありますが、以前の既知の時間からのオフセットを提供するだけです。したがって、これから絶対数を取得することはできませんが、それを使用してナノ秒(またはそれ以上)の精度を測定できます。
JavaDocは、これがナノ秒の精度を提供する一方で、ナノ秒の精度を意味するわけではないことに注意してください。そのため、戻り値の適切な大きなモジュラスを取ります。
Java 9以降:現在の瞬間をキャプチャする際の最大ナノ秒の解像度。これは9桁の小数です。
Instant.now()
2017-12-23T12:34:56.123456789Z
マイクロ秒 に制限するには、切り捨てます。
Instant // Represent a moment in UTC.
.now() // Capture the current moment. Returns a `Instant` object.
.truncatedTo( // Lop off the finer part of this moment.
ChronoUnit.MICROS // Granularity to which we are truncating.
) // Returns another `Instant` object rather than changing the original, per the immutable objects pattern.
2017-12-23T12:34:56.123456Z
他の回答はJava 8の時点で多少古くなっています。
Java 8以降には Java.time フレームワークが付属しています。これらの新しいクラスは、Java.util.Date/.CalendarやJava.text.SimpleDateFormatなど、Javaの初期バージョンに同梱されていた問題のある日付時刻クラスに取って代わります。このフレームワークは、ThreeTen-Extraプロジェクトによって拡張された Joda-Time に触発されたJSR 310によって定義されています。
Java.timeのクラスは nanoseconds に解決され、古いdate-timeクラスとJoda-Timeの両方で使用される milliseconds よりもはるかに細かくなります。そして、質問で尋ねられた microseconds よりも細かい。
Clock
実装Java.timeクラスは、ナノ秒単位の値を表すデータをサポートしますが、クラスは、ナノ秒単位の値をまだgenerateしません。 now()
メソッドは、古いdate-timeクラスと同じ古いクロック実装 System.currentTimeMillis()
を使用します。 Java.timeに新しいClock
インターフェイスがありますが、そのインターフェイスの実装は同じ古いミリ秒クロックです。
したがって、ZonedDateTime.now( ZoneId.of( "America/Montreal" ) )
の結果のテキスト表現をフォーマットして、小数秒の9桁を表示できますが、最初の3桁のみが次のような数字になります。
2017-12-23T12:34:56.789000000Z
Java 9のOpenJDKおよびOracle実装には、Java.timeクラスの完全なナノ秒機能まで、より詳細な粒度の新しいデフォルトClock
実装があります。
OpenJDKの問題 Java.time.Clock.systemUTC()の実装の精度を上げる を参照してください。この問題は正常に実装されました。
2017-12-23T12:34:56.123456789Z
MacOS Sierraを搭載したMacBook Pro(Retina、15-inch、Late 2013)では、現在の瞬間をマイクロ秒(最大6桁の小数部)で取得します。
2017-12-23T12:34:56.123456Z
新しいClock
実装を使用しても、結果はコンピューターによって異なる場合があることに注意してください。 Javaは、現在の瞬間を知るために、基盤となるコンピューターハードウェアのクロックに依存します。
System.nanoTime()
を使用できます。
long start = System.nanoTime();
// do stuff
long end = System.nanoTime();
long microseconds = (end - start) / 1000;
ナノ秒単位で時間を取得しますが、これは厳密に相対的な尺度です。絶対的な意味はありません。他のナノ時間と比較して、何かにかかった時間を測定する場合にのみ役立ちます。
他のポスターがすでに示したように。システムクロックは、おそらく実際の世界時間に対してマイクロ秒まで同期されていません。それにもかかわらず、マイクロ秒の精度のタイムスタンプは、現在の壁時間を示し、物事の持続時間を測定/プロファイリングするためのハイブリッドとして有用です。
「2012-10-21 19:13:45.267128」のようなタイムスタンプを使用して、ログファイルに書き込まれたすべてのイベント/メッセージにラベルを付けます。これらはwhenが発生した(「壁」時間)の両方を伝え、ログファイル内のこのイベントと次のイベントの間のdurationの測定にも使用できます(マイクロ秒)。
これを実現するには、System.currentTimeMillis()をSystem.nanoTime()にリンクし、その瞬間からSystem.nanoTime()のみを使用する必要があります。サンプルコード:
/**
* Class to generate timestamps with microsecond precision
* For example: MicroTimestamp.INSTANCE.get() = "2012-10-21 19:13:45.267128"
*/
public enum MicroTimestamp
{ INSTANCE ;
private long startDate ;
private long startNanoseconds ;
private SimpleDateFormat dateFormat ;
private MicroTimestamp()
{ this.startDate = System.currentTimeMillis() ;
this.startNanoseconds = System.nanoTime() ;
this.dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS") ;
}
public String get()
{ long microSeconds = (System.nanoTime() - this.startNanoseconds) / 1000 ;
long date = this.startDate + (microSeconds/1000) ;
return this.dateFormat.format(date) + String.format("%03d", microSeconds % 1000) ;
}
}
System.nanoTime()とSystem.currentTimeMillis()の間のオフセットを決定するコンポーネントを作成し、エポック以降のナノ秒を効果的に取得できます。
public class TimerImpl implements Timer {
private final long offset;
private static long calculateOffset() {
final long nano = System.nanoTime();
final long nanoFromMilli = System.currentTimeMillis() * 1_000_000;
return nanoFromMilli - nano;
}
public TimerImpl() {
final int count = 500;
BigDecimal offsetSum = BigDecimal.ZERO;
for (int i = 0; i < count; i++) {
offsetSum = offsetSum.add(BigDecimal.valueOf(calculateOffset()));
}
offset = (offsetSum.divide(BigDecimal.valueOf(count))).longValue();
}
public long nowNano() {
return offset + System.nanoTime();
}
public long nowMicro() {
return (offset + System.nanoTime()) / 1000;
}
public long nowMilli() {
return System.currentTimeMillis();
}
}
次のテストでは、マシン上でかなり良い結果が得られます。
final Timer timer = new TimerImpl();
while (true) {
System.out.println(timer.nowNano());
System.out.println(timer.nowMilli());
}
差は+ -3msの範囲で変動するようです。オフセットの計算をもう少し微調整できると思います。
1495065607202174413
1495065607203
1495065607202177574
1495065607203
...
1495065607372205730
1495065607370
1495065607372208890
1495065607370
...
最終的に一緒に行った「迅速で汚い」ソリューション:
TimeUnit.NANOSECONDS.toMicros(System.nanoTime());
更新:
私はもともとSystem.nanoTimeを使用していましたが、経過時間にのみ使用されるべきであることがわかりました。
TimeUnit.MILLISECONDS.toMicros(System.currentTimeMillis());
しかし、これは値の最後にゼロを追加するだけです(micros = millis * 1000)
他の誰かがnanoTimeについて考えている場合の「警告サイン」としてこの答えをここに残しました:)
Linuxに興味がある場合:ソースコードを "currentTimeMillis()"にフィッシングアウトすると、Linuxでこのメソッドを呼び出すと、マイクロ秒の時間が戻ることがわかります。ただし、Javaはマイクロ秒を切り捨て、ミリ秒を返します。これは、Javaがクロスプラットフォームでなければならないためです。そのため、Linux専用のメソッドを提供することは、当時は大したことではありませんでした(1.6からの不正なソフトリンクのサポートを覚えていますか?!)。また、Linuxではクロックを使用するとマイクロ秒を返すことができますが、必ずしも時間を確認するのに適しているわけではありません。マイクロ秒レベルでは、NTPが時間を再調整しておらず、メソッド呼び出し中にクロックが過度にドリフトしていないことを知る必要があります。
これは、理論的には、Linuxでは、Systemパッケージと同じJNIラッパーを作成できますが、マイクロ秒は切り捨てられないことを意味します。
JavaはTimeUnit
enumを介してマイクロ秒をサポートします。
Java文書は次のとおりです。 Enum TimeUnit
次の方法でJavaでマイクロ秒を取得できます。
long microsenconds = TimeUnit.MILLISECONDS.toMicros(System.currentTimeMillis());
たとえば、マイクロ秒を別の時間単位に戻すこともできます。
long seconds = TimeUnit.MICROSECONDS.toSeconds(microsenconds);
リアルタイムシステムに使用する場合は、おそらくJavaがタイムスタンプを取得するための最良の選択ではありません。しかし、一意のキーにifを使用する場合、Jason Smithの答えで十分です。ただし、念のため、2つのアイテムが同じタイムスタンプを取得することを予測するために(これら2つがほぼ同時に処理された場合に可能)、最後のタイムスタンプが現在のタイムスタンプと等しくなくなるまでループできます。
String timestamp = new String();
do {
timestamp = String.valueOf(MicroTimestamp.INSTANCE.get());
item.setTimestamp(timestamp);
} while(lasttimestamp.equals(timestamp));
lasttimestamp = item.getTimestamp();
インスタントを使用して、エポック以降のマイクロ秒を計算します。
val instant = Instant.now();
val currentTimeMicros = instant.getEpochSecond() * 1000_000 + instant.getNano() / 1000;