Bagaimana cara mengekstrak epoch dari LocalDate dan LocalDateTime?


102

Bagaimana cara mengekstrak nilai epoch Longdari contoh LocalDateTimeatau LocalDate? Saya sudah mencoba yang berikut ini, tetapi memberi saya hasil lain:

LocalDateTime time = LocalDateTime.parse("04.02.2014  19:51:01", DateTimeFormatter.ofPattern("dd.MM.yyyy  HH:mm:ss"));
System.out.println(time.getLong(ChronoField.SECOND_OF_DAY)); // gives 71461
System.out.println(time.getLong(ChronoField.EPOCH_DAY)); // gives 16105

Yang saya inginkan hanyalah nilai 1391539861untuk tanggal waktu lokal "04.02.2014 19:51:01". Zona waktu saya Europe/OsloUTC + 1 dengan waktu musim panas.


Tolong jelaskan nomor yang Anda harapkan 1396468261. Saya dapatkan tanpa koreksi zona waktu: 1391543461 (lihat edit di jawaban saya). Perbedaan 57 hari!
Meno Hochschild

@MenoHochschild Saya telah memperbarui pertanyaan saya dengan info zona waktu dan mengoreksi nilai aktual dari GTM ke waktu lokal. Apakah ada cara yang lebih mudah untuk mendapatkan periode waktu tertentu LocalDateTimeselain menghitungnya secara manual?

Kembali dari jeda saya, lihat pembaruan saya.
Meno Hochschild

Jawaban:


147

Kelas LocalDatedan LocalDateTimetidak berisi informasi tentang zona waktu atau perbedaan waktu , dan detik sejak zaman akan menjadi ambigu tanpa informasi ini. Namun, objek memiliki beberapa metode untuk mengubahnya menjadi objek tanggal / waktu dengan zona waktu dengan melewatkan sebuah ZoneIdinstance.

LocalDate

LocalDate date = ...;
ZoneId zoneId = ZoneId.systemDefault(); // or: ZoneId.of("Europe/Oslo");
long epoch = date.atStartOfDay(zoneId).toEpochSecond();

LocalDateTime

LocalDateTime time = ...;
ZoneId zoneId = ZoneId.systemDefault(); // or: ZoneId.of("Europe/Oslo");
long epoch = time.atZone(zoneId).toEpochSecond();

2
Apakah mungkin untuk menghindari penggunaan ZoneId, atau menggunakan dengan instance ZoneId konstan yang disesuaikan (dari +0, artinya GMT)? Saya menanyakan ini karena saya ingin semua perhitungan dinormalisasi. Juga, bagaimana cara melakukan yang sebaliknya: mengonversi dari waktu waktu ke LocalDate / LocalDateTime (juga tanpa ZoneId, atau dengan GMT)?
pengembang android

2
Lupakan. Ketemu:ZoneId.ofOffset("UTC", ZoneOffset.ofHours(0))
pengembang android

7
Pendekatan yang lebih sederhana hanya long epoch = time.toEpochSecond(ZoneOffset.UTC)untuk kasus UTC, atau di mana Anda sudah mengetahui zona waktunya, atau long epoch = time.toEpochSecond(ZoneId.systemDefault());jika Anda ingin pergi ke rute itu.
Marcus

Ini mungkin terdengar konyol tapi bagaimana kalau mengubah kembali dari zaman ke LocalDate, LocalTime & LocalDateTime
samuel owino

Tidak masalah saya pikir saya menemukannya; Instant.ofEpochMilli(responseTime).atZone(ZoneId.systemDefault()).toLocalTime()
samuel owino

27

'Milidetik sejak zaman unix' mewakili sekejap, jadi Anda harus menggunakan kelas Instan:

private long toEpochMilli(LocalDateTime localDateTime)
{
  return localDateTime.atZone(ZoneId.systemDefault())
    .toInstant().toEpochMilli();
}

itu tidak benar untuk digunakan ZoneId.systemDefault()karena unix epoch mengacu pada UTC
ACV

10

Konversi yang Anda butuhkan membutuhkan pengimbangan dari UTC / Greewich, atau zona waktu.

Jika Anda telah offset, ada metode khusus pada LocalDateTimeuntuk tugas ini:

long epochSec = localDateTime.toEpochSecond(zoneOffset);

Jika Anda hanya memiliki ZoneIdmaka Anda dapat memperolehnya ZoneOffsetdari ZoneId:

ZoneOffset zoneOffset = ZoneId.of("Europe/Oslo").getRules().getOffset(ldt);

Tetapi Anda mungkin menemukan konversi melalui yang ZonedDateTimelebih sederhana:

long epochSec = ldt.atZone(zoneId).toEpochSecond();

4
Jika Anda hanya peduli tentang UTC, adalong epochSec = localDateTime.toEpochSecond(ZoneOffset.UTC);
ruhong

2

Lihat metode ini untuk melihat bidang mana yang didukung. Anda akan menemukan untuk LocalDateTime:

NANO_OF_SECOND 
NANO_OF_DAY 
MICRO_OF_SECOND 
MICRO_OF_DAY 
MILLI_OF_SECOND 
MILLI_OF_DAY 
SECOND_OF_MINUTE 
SECOND_OF_DAY 
MINUTE_OF_HOUR 
MINUTE_OF_DAY 
HOUR_OF_AMPM 
CLOCK_HOUR_OF_AMPM 
HOUR_OF_DAY 
CLOCK_HOUR_OF_DAY 
AMPM_OF_DAY 
DAY_OF_WEEK 
ALIGNED_DAY_OF_WEEK_IN_MONTH 
ALIGNED_DAY_OF_WEEK_IN_YEAR 
DAY_OF_MONTH 
DAY_OF_YEAR 
EPOCH_DAY 
ALIGNED_WEEK_OF_MONTH 
ALIGNED_WEEK_OF_YEAR 
MONTH_OF_YEAR 
PROLEPTIC_MONTH 
YEAR_OF_ERA 
YEAR 
ERA 

Bidang INSTANT_SECONDS - tentu saja - tidak didukung karena LocalDateTimetidak dapat merujuk ke stempel waktu absolut (global). Tetapi yang membantu adalah bidang EPOCH_DAY yang menghitung hari yang telah berlalu sejak 1970-01-01. Pemikiran serupa berlaku untuk jenisnya LocalDate(bahkan dengan bidang yang kurang didukung).

Jika Anda bermaksud untuk mendapatkan bidang milis-sejak-unix-epoch yang tidak ada, Anda juga memerlukan zona waktu untuk mengonversi dari tipe lokal ke global. Konversi ini dapat dilakukan dengan lebih sederhana, lihat posting SO lainnya .

Kembali ke pertanyaan Anda dan nomor dalam kode Anda:

The result 1605 is correct
  => (2014 - 1970) * 365 + 11 (leap days) + 31 (in january 2014) + 3 (in february 2014)
The result 71461 is also correct => 19 * 3600 + 51 * 60 + 1

16105L * 86400 + 71461 = 1391543461 detik sejak 1970-01-01T00: 00: 00 (perhatian, tidak ada zona waktu) Kemudian Anda dapat mengurangi offset zona waktu (hati-hati terhadap kemungkinan perkalian 1000 jika dalam milidetik).

UPDATE setelah info zona waktu diberikan:

local time = 1391543461 secs
offset = 3600 secs (Europe/Oslo, winter time in february)
utc = 1391543461 - 3600 = 1391539861

Sebagai kode JSR-310 dengan dua pendekatan yang setara:

long secondsSinceUnixEpoch1 =
  LocalDateTime.of(2014, 2, 4, 19, 51, 1).atZone(ZoneId.of("Europe/Oslo")).toEpochSecond();

long secondsSinceUnixEpoch2 =
  LocalDate
    .of(2014, 2, 4)
    .atTime(19, 51, 1)
    .atZone(ZoneId.of("Europe/Oslo"))
    .toEpochSecond();

1
Terima kasih untuk penjelasannya. Dapatkan hasil yang benar dengan menggunakan LocalDateTime time = LocalDateTime.parse("04.02.2014 19:51:01", DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm:ss"));lalu Long epoch = time.atZone(ZoneId.of("Europe/Oslo")).toEpochSecond();.

1

Konversi dari tanggal yang dapat dibaca manusia ke zaman :

long epoch = new java.text.SimpleDateFormat("MM/dd/yyyyHH:mm:ss").parse("01/01/1970 01:00:00").getTime() / 1000;

Ubah dari epoch ke tanggal yang dapat dibaca manusia :

String date = new java.text.SimpleDateFormat("MM/dd/yyyyHH:mm:ss").format(new java.util.Date (epoch*1000));

Untuk pengubah bahasa lainnya: https://www.epochconverter.com


0

Ini adalah satu cara tanpa menggunakan zona waktu:

LocalDateTime now = LocalDateTime.now();
long epoch = (now.getLong(ChronoField.EPOCH_DAY) * 86400000) + now.getLong(ChronoField.MILLI_OF_DAY);
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.