Waktu saat ini dalam mikrodetik di java


104

Pada sistem Unix, adakah cara untuk mendapatkan stempel waktu dengan tingkat akurasi mikrodetik di Java? Sesuatu seperti gettimeofdayfungsi C.


6
Perlu diingat bahwa jam komputer tidak disetel mendekati tingkat akurasi itu - dua jam di komputer yang berbeda biasanya akan berbeda setidaknya beberapa milidetik, kecuali Anda telah berusaha menyiapkan prosedur sinkronisasi akurasi tinggi. (ketika hal seperti itu mungkin secara fisik). Saya tidak bisa membayangkan apa gunanya mengetahui waktu komputer ke mikrodetik. (Jika Anda mencoba mengukur interval yang tepat di satu komputer, maka tentu, itu masuk akal, tetapi Anda tidak memerlukan stempel waktu penuh.)
David Z

2
Selain itu, beberapa versi Unix / Linux hanya mengembalikan perincian 1 milidetik atau 10 milidetik dalam bidang mikrodetik.
Stephen C

Cara tidak langsung adalah melalui JDBC , jika terhubung ke database seperti Postgres yang menangkap waktu saat ini dalam mikrodetik.
Basil Bourque

2
Java 9 dan setelahnya:Instant.now()
Basil Bourque

Gunakan Sekejap untuk menghitung mikrodetik sejak Epoch: val instant = Instant.now(); val currentTimeMicros = instant.getEpochSecond() * 1000_000 + instant.getNano() / 1000;
Michael M.

Jawaban:


148

Tidak, Java tidak memiliki kemampuan itu.

Itu memang memiliki System.nanoTime (), tetapi itu hanya memberikan offset dari beberapa waktu yang diketahui sebelumnya. Jadi, meskipun Anda tidak dapat mengambil angka absolut dari ini, Anda dapat menggunakannya untuk mengukur presisi nanodetik (atau lebih tinggi).

Perhatikan bahwa JavaDoc mengatakan bahwa meskipun ini memberikan presisi nanodetik, itu tidak berarti akurasi nanodetik. Jadi ambil beberapa modulus besar yang sesuai dari nilai pengembalian.


3
Orang akan menduga bahwa alasan Java tidak memiliki getTimeInMicroseconds () termasuk 1) akurasi yang tidak tersedia di banyak platform, 2) mengembalikan akurasi milidetik dalam panggilan mikrodetik menyebabkan masalah portabilitas aplikasi.
Stephen C

9
Di Linux, System.nanoTime () memanggil clock_gettime (CLOCK_MONOTONIC, _). Brian Oxley menggali kode sumber Java untuk menemukan nugget ini.
David Weber

7
Jawaban ini sekarang sudah usang . Implementasi OpenJDK dan Oracle dari Java 9 hadir dengan implementasi baru Clockyang menyediakan untuk menangkap momen saat ini dengan resolusi yang lebih baik dari milidetik. Di MacBook Pro Retina, saya mendapatkan waktu saat ini dalam mikrodetik (enam digit pecahan desimal). Hasil dan akurasi aktual bergantung pada perangkat keras jam yang mendasari komputer host.
Basil Bourque

1
@BasilBourque banyak sistem yang masih berjalan di Java 8 atau bahkan lebih awal karena tidak perlu memigrasikannya. Meskipun jawabannya sudah usang, namun tetap berguna.
Dragas

1
@Dragas Sebenarnya, akan ada kebutuhan untuk memigrasi mereka… untuk mendapatkan waktu saat ini dalam mikrodetik seperti yang ditanyakan oleh Pertanyaan ini.
Basil Bourque

78

tl; dr

Java 9 dan lebih baru: Resolusi hingga nanodetik saat menangkap momen saat ini. Itu berarti 9 digit pecahan desimal.

Instant.now()   

2017-12-23T12: 34: 56.123456789Z

Untuk membatasi ke mikrodetik , potong .

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

Dalam praktiknya, Anda hanya akan melihat mikrodetik yang ditangkap .nowkarena jam perangkat keras komputer konvensional kontemporer tidak akurat dalam nanodetik .

Detail

Jawaban lainnya agak ketinggalan jaman pada Java 8.

java.time

Java 8 dan yang lebih baru hadir dengan framework java.time . Class baru ini menggantikan class date-time bermasalah yang dikirimkan dengan versi Java paling awal seperti java.util.Date/.Calendar dan java.text.SimpleDateFormat. Kerangka kerja ditentukan oleh JSR 310, terinspirasi oleh Joda-Time , diperpanjang oleh proyek ThreeTen-Extra.

Kelas-kelas di java.time menyelesaikan nanodetik , jauh lebih halus daripada milidetik yang digunakan oleh kelas tanggal-waktu lama dan oleh Joda-Time. Dan lebih baik dari mikrodetik yang ditanyakan dalam Pertanyaan.

masukkan deskripsi gambar di sini

Clock Penerapan

Sementara kelas java.time mendukung data yang merepresentasikan nilai dalam nanodetik, kelas tersebut belum menghasilkan nilai dalam nanodetik. The now()metode menggunakan implementasi clock yang sama tuanya dengan kelas tanggal-waktu lama, System.currentTimeMillis(). Kami memiliki Clockantarmuka baru di java.time tetapi implementasi untuk antarmuka itu adalah jam milidetik lama yang sama.

Jadi Anda dapat memformat representasi tekstual dari hasil ZonedDateTime.now( ZoneId.of( "America/Montreal" ) )untuk melihat sembilan digit pecahan detik tetapi hanya tiga digit pertama yang memiliki angka seperti ini:

2017-12-23T12:34:56.789000000Z

Jam Baru Di Jawa 9

Implementasi OpenJDK dan Oracle dari Java 9 memiliki Clockimplementasi default baru dengan perincian yang lebih baik, hingga kemampuan nanodetik penuh dari kelas java.time.

Lihat masalah OpenJDK, Meningkatkan presisi implementasi java.time.Clock.systemUTC () . Masalah itu telah berhasil diterapkan.

2017-12-23T12:34:56.123456789Z

Di MacBook Pro (Retina, 15 inci, Akhir 2013) dengan macOS Sierra, saya mendapatkan momen saat ini dalam mikrodetik (hingga enam digit pecahan desimal).

2017-12-23T12:34:56.123456Z

Jam Perangkat Keras

Ingatlah bahwa meskipun dengan Clockpenerapan baru yang lebih baik , hasil Anda mungkin berbeda menurut komputer. Java bergantung pada jam perangkat keras komputer yang mendasari untuk mengetahui momen saat ini.

  • The resolusi dari jam hardware bervariasi. Misalnya, jika jam perangkat keras komputer tertentu hanya mendukung perincian mikrodetik , nilai tanggal-waktu yang dihasilkan hanya akan memiliki enam digit pecahan detik dengan tiga digit terakhir adalah nol.
  • The akurasi dari jam hardware bervariasi. Hanya karena sebuah jam menghasilkan nilai dengan beberapa digit pecahan desimal dalam satu detik, angka tersebut mungkin tidak akurat, hanya perkiraan, terpaut dari waktu aktual seperti yang mungkin dibaca dari jam atom . Dengan kata lain, hanya karena Anda melihat sekelompok angka di sebelah kanan tanda desimal tidak berarti Anda dapat mempercayai waktu yang berlalu antara pembacaan tersebut dengan benar hingga derajat menit tersebut.

Mereka mungkin menyelesaikan hingga nanodetik tetapi mereka masih didasarkan pada System.currentTimeMillis, jadi mereka hanya menambahkan sekelompok 0 di akhir. Tidak membantu sama sekali jika Anda mencoba mendapatkan waktu dalam mikro / nano detik, pengguna cukup menambahkan 0 ke waktu milidetik secara manual.
annedroiid

@annedroiid Saya membahasnya di Jawaban saya. Di Java 8 Anda dapat menyimpan momen dengan resolusi nanodetik, tetapi menangkap momen saat ini hanya dalam milidetik. Diperbaiki di Java 9 dengan implementasi baru Clock. Meski begitu, di Java 8 kelas java.time sangat membantu untuk menyimpan nilai yang ditangkap oleh sumber lain seperti mikrodetik pada database Postgres. Namun berhati-hatilah terhadap ketidakakuratan nilai dalam kisaran mikrodetik dan nanodetik; perangkat keras komputer umum mungkin tidak membawa waktu pelacakan jam perangkat keras yang akurat. Nilai dengan enam atau sembilan digit pecahan detik mungkin tidak benar.
Basil Bourque

Bukankah itu ChronoUnit.MICROS ?
Roland

@Roland Ya, sekarang sudah diperbaiki, terima kasih. FYI, di Stack Overflow Anda diundang untuk langsung mengedit Answer untuk memperbaiki kesalahan tersebut.
Basil Bourque

55

Anda dapat menggunakan System.nanoTime():

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

untuk mendapatkan waktu dalam nanodetik tetapi itu adalah ukuran yang relatif ketat. Itu tidak memiliki arti mutlak. Ini hanya berguna untuk membandingkan dengan waktu nano lainnya untuk mengukur berapa lama waktu yang diperlukan untuk melakukan sesuatu.


14

Seperti yang telah ditunjukkan oleh poster lain; jam sistem Anda mungkin tidak disinkronkan hingga mikrodetik dengan waktu dunia sebenarnya. Meskipun demikian, stempel waktu presisi mikrodetik berguna sebagai gabungan untuk menunjukkan waktu dinding saat ini, dan mengukur / membuat profil durasi barang.

Saya memberi label semua acara / pesan yang ditulis ke file log menggunakan stempel waktu seperti "2012-10-21 19: 13: 45.267128". Ini menyampaikan baik ketika itu terjadi (waktu "dinding"), dan juga dapat digunakan untuk mengukur durasi antara ini dan peristiwa berikutnya dalam file log (perbedaan relatif dalam mikrodetik).

Untuk mencapai ini, Anda perlu menautkan System.currentTimeMillis () dengan System.nanoTime () dan bekerja secara eksklusif dengan System.nanoTime () sejak saat itu. Kode contoh:

/**
 * 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
Idenya bagus, tetapi Anda harus melakukan sinkronisasi ulang sesekali. Waktu sistem (currentTime) dan jam CPU (nanoTime) TIDAK sinkron, karena sering kali didasarkan pada jam hardware yang berbeda. Selain itu, server waktu sistem operasi Anda menyinkronkan ulang jam sistem dengan sumber waktu eksternal, jika tersedia. Oleh karena itu, kelas Anda yang tampaknya sangat tepat akan menghasilkan stempel waktu yang mungkin akan menyimpang!
h2stein

3
Kode itu tampaknya tidak aman untuk utas. Dua panggilan sekaligus ke MicroTimestamp.INSTANCE.get()bisa jadi bermasalah.
Ahmed

@Ahmed Menurut Anda, mengapa kode tersebut tidak aman untuk thread? Tidak ada dalam get()metode yang memperbarui variabel anggota; itu hanya menggunakan variabel lokal sementara.
Jason Smith

6

Anda mungkin bisa membuat komponen yang menentukan offset antara System.nanoTime () dan System.currentTimeMillis () dan secara efektif mendapatkan nanodetik sejak epoch.

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

Tes berikut menghasilkan hasil yang cukup baik di mesin saya.

    final Timer timer = new TimerImpl();
    while (true) {
        System.out.println(timer.nowNano());
        System.out.println(timer.nowMilli());
    }

Perbedaannya tampaknya berosilasi dalam kisaran + -3ms. Saya kira seseorang dapat mengubah perhitungan offset sedikit lebih banyak.

1495065607202174413
1495065607203
1495065607202177574
1495065607203
...
1495065607372205730
1495065607370
1495065607372208890
1495065607370
...

2

Jika Anda tertarik dengan Linux: Jika Anda mengeluarkan kode sumber ke "currentTimeMillis ()", Anda akan melihat bahwa, di Linux, jika Anda memanggil metode ini, waktu mikrodetik kembali. Namun Java kemudian memotong mikrodetik dan mengembalikan Anda milidetik. Ini sebagian karena Java harus lintas platform sehingga menyediakan metode khusus untuk Linux adalah hal yang tidak boleh dilakukan di masa lalu (ingat bahwa dukungan tautan lunak yang kasar dari 1,6 mundur ?!). Itu juga karena, sementara jam Anda dapat memberi Anda kembali mikrodetik di Linux, itu tidak berarti itu akan bagus untuk memeriksa waktu. Pada tingkat mikrodetik, Anda perlu tahu bahwa NTP tidak menyetel ulang waktu Anda dan bahwa jam Anda tidak terlalu banyak bergerak selama panggilan metode.

Ini berarti, secara teori, di Linux, Anda dapat menulis pembungkus JNI yang sama dengan yang ada di paket Sistem, tetapi tidak memotong mikrodetiknya.


2

solusi "cepat dan kotor" yang akhirnya saya gunakan:

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

MEMPERBARUI:

Saya awalnya menggunakan System.nanoTime tetapi kemudian saya menemukan itu hanya boleh digunakan untuk waktu yang telah berlalu, saya akhirnya mengubah kode saya untuk bekerja dengan milidetik atau di beberapa tempat menggunakan:

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

tetapi ini hanya akan menambahkan nol di akhir nilai (micros = millis * 1000)

Meninggalkan jawaban ini di sini sebagai "tanda peringatan" jika orang lain memikirkan nanoTime :)


1
The doc secara eksplisit mengatakan untuk tidak menggunakan System.nanoTimewaktu jam dinding: “Metode ini hanya dapat digunakan untuk mengukur waktu berlalu dan tidak berhubungan dengan setiap gagasan lain dari sistem atau waktu jam dinding.”
Basil Bourque

1
@BasilBourque Anda benar, setelah menulis ini saya akhirnya menemukan dan mengubah kode saya tetapi lupa memperbarui di sini, terima kasih atas komentarnya!
keisar

2

Mikrodetik dukungan Java melalui TimeUnitenum.

Ini adalah dokumen java: Enum TimeUnit

Anda bisa mendapatkan mikrodetik di java dengan cara ini:

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

Anda juga dapat mengubah mikrodetik kembali ke satuan waktu lain, misalnya:

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

Ini tidak benar, Anda akan mendapatkan waktu dalam resolusi / panjang MIKRO, tetapi waktu itu sendiri akan selalu hanya dengan akurasi MILI (artinya 3 digit terakhir akan selalu 0).
Michalsx

0

Jika Anda berniat menggunakannya untuk sistem realtime, mungkin java bukanlah pilihan terbaik untuk mendapatkan stempel waktu. Tetapi jika Anda akan menggunakan if untuk kunci unik, maka jawaban Jason Smith sudah cukup. Namun untuk berjaga-jaga, untuk mengantisipasi 2 item akhirnya mendapatkan stempel waktu yang sama (mungkin saja jika 2 item tersebut diproses hampir bersamaan), Anda dapat mengulang hingga stempel waktu terakhir tidak sama dengan stempel waktu saat ini.

String timestamp = new String();
do {
    timestamp = String.valueOf(MicroTimestamp.INSTANCE.get());
    item.setTimestamp(timestamp);
} while(lasttimestamp.equals(timestamp));
lasttimestamp = item.getTimestamp();

0

Gunakan Sekejap untuk menghitung mikrodetik sejak Epoch:

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


-3

Berikut adalah contoh cara membuat Stempel Waktu UnsignedLong saat ini:

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

2
Jawaban yang salah. Kelas java.util.Date memiliki resolusi milidetik, bukan mikrodetik yang ditentukan dalam Pertanyaan. Membuat java.sql.Timestamp tidak menarik data tambahan dari udara.
Basil Bourque
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.