Cara mendapatkan milidetik dari LocalDateTime di Java 8

285

Saya bertanya-tanya apakah ada cara untuk mendapatkan milidetik saat ini sejak 1-1-1970 (zaman) menggunakan yang baru LocalDate, LocalTimeatau LocalDateTimekelas Java 8.

Cara yang dikenal di bawah ini:

long currentMilliseconds = new Date().getTime();

atau

long currentMilliseconds = System.currentTimeMillis();
George Siggouroglou
sumber
6
Ada apa dengan ini System.currentTimeMillis()?
Dawood ibn Kareem
16
@ Davidvidallall Dia mencoba mendapatkan waktu kencan, bukan waktu saat ini?
Anubian Noob
2
"... cara untuk mendapatkan milidetik saat ini ..."
Dawood ibn Kareem
milidetik terhitung mulai 1-1-1970. Saya berkeliaran jika ada metode untuk mendapatkan mereka menggunakan kelas baru Java 8 LocalDate, LocalTime dan LocalDateTime, karena saya tidak menemukan satu.
George Siggouroglou
1
Pemahaman saya tentang tujuan untuk kelas-kelas itu adalah bahwa itu adalah pemahaman waktu yang "berfokus pada manusia", dan currentTimeMillistidak akan relevan dalam konteks itu. Pikirkan Kalender + Jam Dinding dengan presisi yang sangat baik, dan tidak ada kekhawatiran tentang zona waktu dan lokalitas. Jadi tidak ada cara untuk kembali ke "Waktu UTC" dari LocalTime
Gus

Jawaban:

325

Saya tidak sepenuhnya yakin apa yang Anda maksud dengan "milidetik saat ini" tetapi saya akan menganggap itu adalah jumlah milidetik sejak "zaman", yaitu tengah malam, 1 Januari 1970 UTC.

Jika Anda ingin menemukan jumlah milidetik sejak zaman sekarang, maka gunakan System.currentTimeMillis()seperti yang ditunjukkan Anubian Noob . Jika demikian, tidak ada alasan untuk menggunakan API java.time baru untuk melakukan ini.

Namun, mungkin Anda sudah memiliki LocalDateTimeobjek serupa dari suatu tempat dan Anda ingin mengubahnya menjadi milidetik sejak zamannya. Tidak mungkin untuk melakukan itu secara langsung, karena LocalDateTimekeluarga objek tidak memiliki gagasan tentang zona waktu mereka. Dengan demikian, informasi zona waktu perlu diberikan untuk menemukan waktu relatif terhadap zaman, yaitu di UTC.

Misalkan Anda memiliki yang LocalDateTimeseperti ini:

LocalDateTime ldt = LocalDateTime.of(2014, 5, 29, 18, 41, 16);

Anda perlu menerapkan informasi zona waktu, memberikan a ZonedDateTime. Saya berada di zona waktu yang sama dengan Los Angeles, jadi saya akan melakukan sesuatu seperti ini:

ZonedDateTime zdt = ldt.atZone(ZoneId.of("America/Los_Angeles"));

Tentu saja, ini membuat asumsi tentang zona waktu. Dan ada kasus tepi yang dapat terjadi, misalnya, jika waktu lokal kebetulan menyebutkan waktu di dekat transisi Daylight Saving Time (Summer Time). Mari kita kesampingkan ini, tetapi Anda harus menyadari bahwa kasus ini ada.

Bagaimanapun, jika Anda bisa mendapatkan yang valid ZonedDateTime, Anda dapat mengonversinya ke jumlah milidetik sejak zaman, seperti:

long millis = zdt.toInstant().toEpochMilli();
Stuart Marks
sumber
5
Perhatikan bahwa ZonedDateTime sudah memiliki satu getEpochSecondmetode (melalui ChronoZonedDateTime bawaan ). Tidak perlu untuk Instant.
mabi
13
Tentu, jika yang Anda butuhkan adalah detik, bukan milidetik.
Stuart Marks
18
Hindari matematika pada nano dengan menggunakan zdt.get (ChronoField.MILLI_OF_SECOND). Hindari semua matematika dengan menggunakan zdt.toInstant (). ToEpochMilli ()
JodaStephen
2
Catatan yang zdt.toInstant().toEpochMilli();akan memberi Anda milidetik untuk nilai UTC yang sesuai , bukan untuk waktu tanggal yang dikategorikan. Saya menemukan ini dengan cara yang sulit. toInstant()memberi Anda UTC instan. Jika Anda ingin waktu lokal dalam millis, ini tidak akan memberi Anda apa yang Anda harapkan . Jadi, jika Anda mis menggunakan waktu +02: 00 zona waktu, waktu pengembalian Anda akan 3600 * 2 * 1000 milidetik kurang dari apa yang Anda harapkan.
Per Lundberg
2
@PerLundberg saya hanya dibandingkan ZonedDateTime.now().toInstant().toEpochMilli(), LocalDateTime.now().toInstant(OffsetDateTime.now().getOffset()).toEpochMilli(), LocalDateTime.now().toInstant(ZoneOffset.UTC).toEpochMilli(), Calendar.getInstance().getTime().getTime(), new Date().getTime()dan System.currentTimeMillis(). Satu-satunya metode yang tampaknya "mati" adalah yang Anda usulkan: LocalDateTime.now().toInstant(ZoneOffset.UTC).toEpochMilli()memberi Anda mili untuk tanggal lokal Anda seolah-olah itu adalah tanggal UTC , yaitu jika tanggal lokal adalah UTC + 2 metode Anda memberikan mili selama 2 jam di masa depan .
walen
81

Apa yang saya lakukan sehingga saya tidak menentukan zona waktu adalah,

System.out.println("ldt " + LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
System.out.println("ctm " + System.currentTimeMillis());

memberi

ldt 1424812121078 
ctm 1424812121281

Seperti yang Anda lihat angka-angkanya sama kecuali untuk waktu eksekusi yang kecil.

Kalau-kalau Anda tidak suka System.currentTimeMillis, gunakan Instant.now().toEpochMilli()

brian
sumber
3
Tidak, Epoch relatif terhadap UTC tetapi Anda mendapatkan waktu saat ini dari zona lokal Anda.
Rafael Membrives
2
@ ChristofferHammarström jumlah milidetik yang telah berlalu sejak zaman adalah fakta independen dari zona waktu. Jumlahnya sama dengan milidetik, tidak peduli jam berapa kamu menyebutnya. Kedua hasil berbeda karena mesin brian membutuhkan 203 milidetik untuk menjalankan perintah kedua.
Fletch
Apakah boleh menggunakan UTC ketika pengguna mungkin berada di zona waktu yang berbeda
GilbertS
2
@ GrebertS Anda mungkin tidak boleh menggunakan kode persis ini, gunakan API sebagaimana dimaksud. Tanggal-waktu harus selalu UTC ketika disimpan di komputer atau dikirim ke pengguna lain. Biasanya harus disajikan kepada pengguna sebagai waktu tanggal lokal menggunakan pengaturan zona waktu mereka sendiri.
brian
20

Untuk menghindari ZoneId yang dapat Anda lakukan:

LocalDateTime date = LocalDateTime.of(1970, 1, 1, 0, 0);

System.out.println("Initial Epoch (TimeInMillis): " + date.toInstant(ZoneOffset.ofTotalSeconds(0)).toEpochMilli());

Mendapatkan 0 sebagai nilai, itu benar!

Dani
sumber
8
ZoneOffset.ofTotalSeconds(0)itu sama denganZoneOffset.UTC
Anton Novopashin
1
Ya, itu saya komentar @ AntonNovopashin. Karena Anda membutuhkan UTC, Anda baik-baik saja (Anda mungkin ingin menyebutkannya dalam jawabannya). BTW ZoneOffsetadalah subkelas dari ZoneId, jadi saya tidak akan persis mengatakan Anda telah menghindarinya, tetapi selama Anda bahagia ...
Ole VV
Komentar pertama saya agak kasar, tetapi tidak dimaksudkan sebagai ofensif. Anda tersinggung. Saya menyesal. Saya sudah menghapusnya. Izinkan saya untuk bertanya sebaliknya: apa yang mungkin menjadi alasan kita ingin menghindari ZoneId?
Ole VV
@ OleV.V Apakah boleh menggunakan UTC. Tidak hanya untuk orang yang tinggal di zona waktu UTC.
GilbertS
1
@ GrebertS Saya tidak berpikir ada orang yang tinggal di zona waktu UTC. Menggunakan UTC untuk waktu yang digunakan melintasi zona waktu disarankan sebagai praktik yang baik. Lihat misalnya Praktik Terbaik Java untuk Manipulasi Tanggal / Penyimpanan untuk Pengguna yang Beragam Geografis . Atau mungkin saya tidak mengerti pertanyaan Anda?
Ole VV
15

Karena Java 8 Anda dapat menelepon java.time.Instant.toEpochMilli().

Misalnya panggilan

final long currentTimeJava8 = Instant.now().toEpochMilli();

memberi Anda hasil yang sama dengan

final long currentTimeJava1 = System.currentTimeMillis();
Marteng
sumber
1
"memberi Anda hasil yang sama dengan" ... tetapi membutuhkan lebih banyak daya CPU dan lebih menekankan pengumpul sampah.
VasiliNovikov
Saya ingin melihat yang dikuantifikasi di atas (terutama untuk penggunaan normal - mis. Bukan untuk beberapa aplikasi real-time kinerja kritis ...)
Brian Agnew
11

Anda dapat menggunakan java.sql.Timestampjuga untuk mendapatkan milidetik.

LocalDateTime now = LocalDateTime.now();
long milliSeconds = Timestamp.valueOf(now).getTime();
System.out.println("MilliSeconds: "+milliSeconds);
Nalam
sumber
Anda mengabaikan kebutuhan penting untuk zona waktu. Saya tidak merekomendasikan melakukannya dengan cara ini. Juga Timestampkelas sudah lama usang dan penuh dengan masalah desain, jadi saya lebih suka menghindarinya, terutama ketika kita bisa menggunakan kelas dari java.timesuka LocalDateTime.
Ole VV
@ OleV.V. Hanya ingin tahu tentang masalah desain Timestamp, Bisakah Anda berbagi beberapa artikel tentang itu? Ini membantu saya untuk menghindari menggunakan Timestampkode saya juga. Terima kasih!
Nalam
1
Singkatnya, ini diimplementasikan sebagai subkelas dari Datetetapi seringkali tidak dapat ditangani sebagai Date. Sebagian besar metode yang diwarisi dari Datedan satu konstruktor sudah usang. Its toStringmetode menggunakan zona waktu JVM, yang membingungkan banyak karena sama Timestampdicetak berbeda pada komputer yang berbeda ( misalnya ).
Ole VV
Ini sangat cocok untuk pengujian unit. Cukup ganti sekarang denganLocalDate.of(year, month, day)
G_V
Ini harus menjadi jawaban yang diterima untuk mengatasi nilai-nilai "selalu UTC".
LeYAUable
9

Untuk mendapatkan waktu saat ini dalam milidetik (sejak zamannya), gunakan System.currentTimeMillis().

Anubian Noob
sumber
3

Jika Anda memiliki Jam Java 8, maka Anda dapat menggunakan clock.millis()(meskipun itu menyarankan Anda gunakan clock.instant()untuk mendapatkan Java 8 Instan, karena lebih akurat).

Mengapa Anda menggunakan jam Java 8? Jadi dalam kerangka DI Anda, Anda dapat membuat kacang Clock:

@Bean
public Clock getClock() {
    return Clock.systemUTC();
}

dan kemudian dalam tes Anda, Anda dapat dengan mudah mengejeknya:

@MockBean private Clock clock;

atau Anda dapat memiliki kacang yang berbeda:

@Bean
public Clock getClock() {
    return Clock.fixed(instant, zone);
}

yang membantu dengan tes yang menyatakan tanggal dan waktu tak terukur.

Astaga
sumber
1
  default LocalDateTime getDateFromLong(long timestamp) {
    try {
        return LocalDateTime.ofInstant(Instant.ofEpochMilli(timestamp), ZoneOffset.UTC);
    } catch (DateTimeException tdException) {
      //  throw new 
    }
}

default Long getLongFromDateTime(LocalDateTime dateTime) {
    return dateTime.atOffset(ZoneOffset.UTC).toInstant().toEpochMilli();
}
Mohamed.Abdo
sumber
0

Mengapa tidak ada yang menyebutkan metode ini LocalDateTime.toEpochSecond():

LocalDateTime localDateTime = ... // whatever e.g. LocalDateTime.now()
long time2epoch = localDateTime.toEpochSecond(ZoneOffset.UTC);

Tampaknya ini jauh lebih pendek daripada banyak jawaban yang disarankan di atas ...

maxxyme
sumber
ini yang saya cari. Jawaban yang diterima itu membuat saya gelisah.
Brill Pappin
Terima hanya tersedia di API 26: {
Brill Pappin
1
Karena itu hanya memberikan beberapa detik. Sungguh aneh bahwa tidak ada toEpochMillimetode, memperhitungkan fakta bahwa Anda dapat menentukan bahkan nanodetik di LocalDateTime: ada metode LocalDateTime.of(int year, int month, int dayOfMonth, int hour, int minute, int second, int nanoOfSecond).
izogfif