Javaの現在の時間(マイクロ秒)


104

Unixシステムで、Javaでマイクロ秒レベルの精度のタイムスタンプを取得する方法はありますか?Cのgettimeofday関数のようなもの。


6
コンピュータの時計は、その精度レベルに近い場所には設定されていないことに注意してください。高精度の同期手順の設定に力を入れていない限り、通常、異なるコンピュータの2つの時計は少なくとも数ミリ秒はずれます。 (そのようなことが物理的にも可能な場合)。コンピューターのマイクロ秒までの時間を知ることにはどのような点があるのか​​想像できません。(1台のコンピューターで正確に間隔を測定しようとしている場合は、それは完全に妥当ですが、完全なタイムスタンプは必要ありません。)
David Z

2
また、Unix / Linuxの一部のバージョンは、マイクロ秒フィールドで1ミリ秒または10ミリ秒の粒度のみを返します。
スティーブンC

間接的な方法は、現在の時間をマイクロ秒でキャプチャするPostgresなどのデータベースに接続されている場合、JDBCを介する方法です。
バジルブルク

2
Java 9以降:Instant.now()
Basil Bourque 2017年

Instantを使用して、エポック以降のマイクロ秒を計算します: val instant = Instant.now(); val currentTimeMicros = instant.getEpochSecond() * 1000_000 + instant.getNano() / 1000;
Michael M.

回答:


148

いいえ、Javaにはその機能はありません。

System.nanoTime()はありますが、これは既知の時間からのオフセットを提供するだけです。したがって、これから絶対数を取得することはできませんが、それを使用してナノ秒(またはそれ以上)の精度を測定できます。

JavaDocは、これがナノ秒の精度を提供するが、それはナノ秒の精度を意味しないと言っていることに注意してください。したがって、戻り値の適切に大きい係数をいくつか取得します。


3
JavaにgetTimeInMicroseconds()がない理由には、1)多くのプラットフォームで精度が利用できない、2)マイクロ秒の呼び出しでミリ秒の精度を返すことがアプリケーションの移植性の問題につながると推測する人もいます。
スティーブンC

9
Linuxでは、System.nanoTime()がclock_gettime(CLOCK_MONOTONIC、_)を呼び出します。Brian Oxleyは、このナゲットを見つけるためにJavaのソースコードを掘り下げました。
David Weber

7
この回答は古くなっています。Java 9のOpenJDKおよびOracle実装にはClock、ミリ秒よりも細かい分解能で現在の瞬間をキャプチャするための新しい実装が付属しています。MacBook Pro Retinaでは、現在の時刻をマイクロ秒(小数の6桁)で取得しています。実際の結果と精度は、ホストコンピューターの基になるクロックハードウェアによって異なります。
バジルブルク2017年

1
@BasilBourque多くのシステムは、移行する必要がないため、Java 8またはそれ以前でも実行されています。答えは古くなっていますが、それでも役に立ちます。
Dragas

1
@Dragas実際には、そこだろう、この質問で尋ねたとして、マイクロ秒で現在の時刻を取得するために...それらを移行する必要があること。
バジルブルク

78

tl; dr

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.time

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()Clockjava.timeに新しいインターフェースがありますが、そのインターフェースの実装は同じ古いミリ秒クロックです。

したがって、結果のテキスト表現をフォーマットしZonedDateTime.now( ZoneId.of( "America/Montreal" ) )て小数秒の9桁を表示することもできますが、最初の3桁のみが次のような数値になります。

2017-12-23T12:34:56.789000000Z

Java 9の新しい時計

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は、現在の瞬間を知るために、基盤となるコンピューターハードウェアのクロックに依存しています。

  • ハードウェアクロックの分解能は大きく異なります。たとえば、特定のコンピューターのハードウェアクロックがマイクロ秒の粒度のみをサポートしている場合、生成される日付時刻値の端数秒は6桁のみで、最後の3桁はゼロになります。
  • ハードウェアクロックの精度は大きく異なります。時計が生成する値が小数点以下1秒未満の数桁であるため、これらの桁は、原子時計から読み取られるように、実際の時刻からずれているだけで、正確ではない可能性があります。言い換えると、小数点の右側に一連の数字が表示されているからといって、そのような測定値間の経過時間がその分程度に信頼できるとは限りません。

それらはナノ秒に解決される可能性がありますが、それらは依然としてSystem.currentTimeMillisに基づいているため、最後に一連の0を追加するだけです。マイクロ/ナノ秒単位で時間を取得しようとしている場合はまったく役に立ちません。ユーザーはミリ秒の時間に手動で0を追加することができます。
annedroiid 2016

@annedroiid私は私の答えでそれをカバーしました。Java 8 では、ナノ秒の解像度でモーメントを保存できますが、現在のモーメントのキャプチャはミリ秒単位でしか行えません。の新しい実装によりJava 9で改善されましたClock。それでも、Java 8では、java.timeクラスは、Postgresデータベースでマイクロ秒などの他のソースによってキャプチャされた値を保持するのに役立ちます。ただし、マイクロ秒とナノ秒の範囲の値の不正確さに注意してください。一般的なコンピューターハードウェアは、ハードウェアクロックトラッキング時間を正確に伝達しない場合があります。小数秒が6桁または9桁の値は、正しくない場合があります。
バジルブルク2016

ChronoUnit.MICROSではありませんか?
Roland

@Rolandはい、今修正しました、ありがとう。参考までに、スタックオーバーフローでは、このようなエラーを修正するために回答を直接編集するよう招待されています。
バジルブルク

55

使用できますSystem.nanoTime()

long start = System.nanoTime();
// do stuff
long end = System.nanoTime();
long microseconds = (end - start) / 1000;

ナノ秒単位で時間を取得しますが、これは厳密に相対的な尺度です。絶対的な意味はありません。他のナノ時間と比較して、何かが実行するのにかかった時間を測定する場合にのみ役立ちます。


14

他のポスターがすでに示したように; システムクロックがマイクロ秒単位で実際の世界時間と同期していない可能性があります。それでも、マイクロ秒の精度のタイムスタンプは、現在の実時間を示したり、物事の期間を測定/プロファイリングしたりするためのハイブリッドとして役立ちます。

「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) ;
   }
}

5
アイデアは良いですが、時々再同期する必要があります。システム時刻(currentTime)とCPUクロック(nanoTime)は、異なるハードウェアクロックに基づいていることが多いため、同期していません。さらに、オペレーティングシステムのタイムサーバーは、システムクロックを外部のタイムソース(利用可能な場合)と再同期します。したがって、一見すると非常に正確なクラスでは、タイムスタンプがずれる場合があります。
h2stein 2014

3
そのコードはスレッドセーフではないようです。への2つの同時呼び出しはMicroTimestamp.INSTANCE.get()問題になる可能性があります。
アーメド

@Ahmedなぜコードはスレッドセーフではないと思いますか?get()メンバー変数を更新するメソッドには何もありません。一時的なローカル変数のみを使用します。
Jason Smith

6

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
...

2

Linuxに興味がある場合:ソースコードを "currentTimeMillis()"に書き出すと、Linuxでは、このメソッドを呼び出すと、マイクロ秒の時間が返されることがわかります。ただし、Javaはマイクロ秒を切り捨て、ミリ秒を返します。これは、Javaがクロスプラットフォームである必要があるため、特にLinux向けのメソッドを提供することは、当時としては大げさなことでした(1.6からのソフトなリンクのサポートが不安定であることを忘れないでください!)。また、Linuxではクロックでマイクロ秒を返すことができますが、必ずしも時間をチェックするのに適しているとは限りません。マイクロ秒レベルでは、NTPが時間を再調整していないこと、およびメソッド呼び出し中にクロックがあまりずれていないことを知る必要があります。

つまり、理論的には、Linuxでは、Systemパッケージと同じJNIラッパーを作成できますが、マイクロ秒は切り捨てられません。


2

私が最終的に行った「迅速で汚い」ソリューション:

TimeUnit.NANOSECONDS.toMicros(System.nanoTime());

更新:

私は最初にSystem.nanoTimeを使用しましたが、それが経過時間にのみ使用されるべきであることがわかり、最終的にコードを変更してミリ秒で動作するようにしたり、一部の場所で使用したりしました。

TimeUnit.MILLISECONDS.toMicros(System.currentTimeMillis());

しかし、これは値の終わりにゼロを追加するだけです(マイクロ=ミリ* 1000)

他の誰かがnanoTimeについて考えている場合に備えて、この警告をここに「警告サイン」として残しました:)


1
このドキュメントは、実時間に使用しないように明示的に言ってますSystem.nanoTime。「この方法は経過時間を測定するためにのみ使用でき、システムまたは実時間の他の概念とは関係ありません。」
バジルブルク2015年

1
@BasilBourqueあなたは正しいです、これを書いた後、私は最終的に私のコードを見つけて変更しましたが、コメントをありがとう、ここで更新するのを忘れました!
ケイサー2015年

2

Javaは、TimeUnit列挙型を通じてマイクロ秒をサポートします。

これがJavaドキュメントです: Enum TimeUnit

あなたはこの方法でJavaでマイクロ秒を得ることができます:

long microsenconds = TimeUnit.MILLISECONDS.toMicros(System.currentTimeMillis());

マイクロ秒を別の時間単位に変換して戻すこともできます。次に例を示します。

long seconds = TimeUnit.MICROSECONDS.toSeconds(microsenconds);

これは正しくありません。MICROの解像度/長さで時間を取得しますが、時間自体は常にMILIの精度でのみになります(つまり、最後の3桁が常に0になることを意味します)。
Michalsx

0

リアルタイムシステムで使用する場合は、タイムスタンプを取得するために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();

0

Instantを使用して、エポック以降のマイクロ秒を計算します。

val instant = Instant.now();
val currentTimeMicros = instant.getEpochSecond() * 1000_000 + instant.getNano() / 1000;


-3

以下は、UnsignedLongの現在のタイムスタンプを作成する方法の例です。

UnsignedLong current = new UnsignedLong(new Timestamp(new Date().getTime()).getTime());

2
間違った答え。java.util.Dateクラスの分解能は、質問で指定されたマイクロ秒ではなく、ミリ秒です。java.sql.Timestampを作成しても、追加のデータが送信されません。
バジルブルク2015年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.