Unixシステムで、Javaでマイクロ秒レベルの精度のタイムスタンプを取得する方法はありますか?Cのgettimeofday
関数のようなもの。
Instant.now()
val instant = Instant.now();
val currentTimeMicros = instant.getEpochSecond() * 1000_000 + instant.getNano() / 1000;
Unixシステムで、Javaでマイクロ秒レベルの精度のタイムスタンプを取得する方法はありますか?Cのgettimeofday
関数のようなもの。
Instant.now()
val instant = Instant.now();
val currentTimeMicros = instant.getEpochSecond() * 1000_000 + instant.getNano() / 1000;
回答:
いいえ、Javaにはその機能はありません。
System.nanoTime()はありますが、これは既知の時間からのオフセットを提供するだけです。したがって、これから絶対数を取得することはできませんが、それを使用してナノ秒(またはそれ以上)の精度を測定できます。
JavaDocは、これがナノ秒の精度を提供するが、それはナノ秒の精度を意味しないと言っていることに注意してください。したがって、戻り値の適切に大きい係数をいくつか取得します。
Clock
、ミリ秒よりも細かい分解能で現在の瞬間をキャプチャするための新しい実装が付属しています。MacBook Pro Retinaでは、現在の時刻をマイクロ秒(小数の6桁)で取得しています。実際の結果と精度は、ホストコンピューターの基になるクロックハードウェアによって異なります。
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
実際には、.now
現代の従来のコンピュータハードウェアクロックはナノ秒単位では正確ではないため、でキャプチャされたマイクロ秒のみが表示されます。
その他の回答は、Java 8の時点でやや古くなっています。
Java 8以降には、java.timeフレームワークが付属しています。これらの新しいクラスは、java.util.Date / .Calendarやjava.text.SimpleDateFormatなど、Javaの最も古いバージョンに同梱されていた問題のある日付時刻クラスに取って代わります。フレームワークは、Joda- Timeに触発され、ThreeTen-Extraプロジェクトによって拡張されたJSR 310によって定義されています。
java.timeの解決のクラスナノ秒、よりもはるかに細かいミリ古い日時のクラスの両方でとジョダ-Timeで使用。質問で尋ねられたマイクロ秒よりも細かい。
Clock
実装java.timeクラスはナノ秒単位の値を表すデータをサポートしていますが、クラスはまだナノ秒単位の値を生成していません。now()
方法は、古い日付時刻クラスと同じ古い時計の実装を使用しますSystem.currentTimeMillis()
。Clock
java.timeに新しいインターフェースがありますが、そのインターフェースの実装は同じ古いミリ秒クロックです。
したがって、結果のテキスト表現をフォーマットしZonedDateTime.now( ZoneId.of( "America/Montreal" ) )
て小数秒の9桁を表示することもできますが、最初の3桁のみが次のような数値になります。
2017-12-23T12:34:56.789000000Z
Java 9のOpenJDKおよびOracle実装にClock
は、java.timeクラスの完全なナノ秒機能まで、より細かい粒度の新しいデフォルト実装があります。
OpenJDKの問題、java.time.Clock.systemUTC()の実装の精度を上げるを参照してください。この問題は正常に実装されました。
2017-12-23T12:34:56.123456789Z
macOS Sierraを搭載したMacBook Pro(Retina、15インチ、Late 2013)では、現在の瞬間をマイクロ秒(小数点以下6桁まで)で取得します。
2017-12-23T12:34:56.123456Z
新しい細かいClock
実装でも、コンピュータによって結果が異なる場合があることに注意してください。Javaは、現在の瞬間を知るために、基盤となるコンピューターハードウェアのクロックに依存しています。
Clock
。それでも、Java 8では、java.timeクラスは、Postgresデータベースでマイクロ秒などの他のソースによってキャプチャされた値を保持するのに役立ちます。ただし、マイクロ秒とナノ秒の範囲の値の不正確さに注意してください。一般的なコンピューターハードウェアは、ハードウェアクロックトラッキング時間を正確に伝達しない場合があります。小数秒が6桁または9桁の値は、正しくない場合があります。
使用できますSystem.nanoTime()
:
long start = System.nanoTime();
// do stuff
long end = System.nanoTime();
long microseconds = (end - start) / 1000;
ナノ秒単位で時間を取得しますが、これは厳密に相対的な尺度です。絶対的な意味はありません。他のナノ時間と比較して、何かが実行するのにかかった時間を測定する場合にのみ役立ちます。
他のポスターがすでに示したように; システムクロックがマイクロ秒単位で実際の世界時間と同期していない可能性があります。それでも、マイクロ秒の精度のタイムスタンプは、現在の実時間を示したり、物事の期間を測定/プロファイリングしたりするためのハイブリッドとして役立ちます。
「2012-10-21 19:13:45.267128」のようなタイムスタンプを使用して、ログファイルに書き込まれたすべてのイベント/メッセージにラベルを付けます。これらは、それが発生したとき(「ウォール」時間)の両方を伝え、継続時間を測定するためにも使用できます、ログファイル内のこのイベントと次のイベントの間(マイクロ秒相対差)のます。
これを実現するには、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) ;
}
}
MicroTimestamp.INSTANCE.get()
問題になる可能性があります。
get()
メンバー変数を更新するメソッドには何もありません。一時的なローカル変数のみを使用します。
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
...
Linuxに興味がある場合:ソースコードを "currentTimeMillis()"に書き出すと、Linuxでは、このメソッドを呼び出すと、マイクロ秒の時間が返されることがわかります。ただし、Javaはマイクロ秒を切り捨て、ミリ秒を返します。これは、Javaがクロスプラットフォームである必要があるため、特にLinux向けのメソッドを提供することは、当時としては大げさなことでした(1.6からのソフトなリンクのサポートが不安定であることを忘れないでください!)。また、Linuxではクロックでマイクロ秒を返すことができますが、必ずしも時間をチェックするのに適しているとは限りません。マイクロ秒レベルでは、NTPが時間を再調整していないこと、およびメソッド呼び出し中にクロックがあまりずれていないことを知る必要があります。
つまり、理論的には、Linuxでは、Systemパッケージと同じJNIラッパーを作成できますが、マイクロ秒は切り捨てられません。
私が最終的に行った「迅速で汚い」ソリューション:
TimeUnit.NANOSECONDS.toMicros(System.nanoTime());
更新:
私は最初にSystem.nanoTimeを使用しましたが、それが経過時間にのみ使用されるべきであることがわかり、最終的にコードを変更してミリ秒で動作するようにしたり、一部の場所で使用したりしました。
TimeUnit.MILLISECONDS.toMicros(System.currentTimeMillis());
しかし、これは値の終わりにゼロを追加するだけです(マイクロ=ミリ* 1000)
他の誰かがnanoTimeについて考えている場合に備えて、この警告をここに「警告サイン」として残しました:)
System.nanoTime
。「この方法は経過時間を測定するためにのみ使用でき、システムまたは実時間の他の概念とは関係ありません。」
Javaは、TimeUnit
列挙型を通じてマイクロ秒をサポートします。
これが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();
以下は、UnsignedLongの現在のタイムスタンプを作成する方法の例です。
UnsignedLong current = new UnsignedLong(new Timestamp(new Date().getTime()).getTime());