Mengonversi Long to Date di Java menghasilkan 1970

118

Saya memiliki daftar dengan nilai panjang (misalnya: 1220227200, 1220832000, 1221436800 ...) yang saya unduh dari layanan web. Saya harus mengubahnya menjadi Tanggal. Sayangnya begini, misalnya:

Date d = new Date(1220227200);

mengembalikan 1 Jan 1970. Ada yang tahu cara lain untuk mengonversinya dengan benar?

mmmiki
sumber
Bisakah Anda memberi tahu nilai apa yang Anda harapkan? Pertanyaan tentang detik / milidetik mungkin valid, tetapi 1220227200 bukan 1/1/1970. Sepertinya Anda meneruskan 0 ke konstruktor. Beberapa kode lagi mungkin membantu.
SJuan76
1
@mmmiki - Anda harus menerima jawaban
Stewart
itu mengembalikan 15 Januari 1970, di sini, bukan 1 Januari.
njzk2
FYI, kelas tanggal-waktu yang sangat cacat seperti java.util.Date, java.util.Calendar, dan java.text.SimpleDateFormatsekarang warisan , digantikan oleh java.time kelas dibangun ke Jawa 8 dan kemudian.
Basil Bourque

Jawaban:

161

The Datekonstruktor (klik link!) Menerima saat itu sebagai longdi milidetik , tidak detik. Anda perlu mengalikannya dengan 1000 dan memastikan bahwa Anda memasukkannya sebagai long.

Date d = new Date(1220227200L * 1000);

Ini terlihat di sini

Min 31 Agustus 20:00:00 GMT-04:00 2008

BalusC
sumber
22
Atau sebagai alternatif, gunakan Date d = new Date(TimeUnit.SECONDS.toMillis(1220227200L));untuk solusi yang lebih bersih dan tidak terlalu ajaib .
Priidu Neemre
56

tl; dr

java.time.Instant                    // Represent a moment as seen in UTC. Internally, a count of nanoseconds since 1970-01-01T00:00Z.
.ofEpochSecond( 1_220_227_200L )     // Pass a count of whole seconds since the same epoch reference of 1970-01-01T00:00Z.

Ketahui Data Anda

Orang menggunakan berbagai presisi dalam melacak waktu sebagai angka sejak zaman . Jadi, ketika Anda memperoleh beberapa angka untuk ditafsirkan sebagai hitungan sejak zaman, Anda harus menentukan:

  • Zaman apa?
    Banyak tanggal zaman telah digunakan dalam berbagai sistem. Yang umum digunakan adalah waktu POSIX / Unix , dimana epoch adalah momen pertama tahun 1970 di UTC. Tetapi Anda tidak harus menganggap zaman ini.
  • Presisi apa?
    Apakah kita berbicara tentang detik, milidetik , mikrodetik , atau nanodetik sejak zaman itu?
  • Zona waktu apa?
    Biasanya penghitungan karena waktu berada dalam zona waktu UTC / GMT, artinya, tidak ada pengimbangan zona waktu sama sekali. Tapi terkadang, ketika melibatkan programmer yang tidak berpengalaman atau tidak tahu waktu, mungkin ada zona waktu yang tersirat.

Dalam kasus Anda, seperti yang dicatat orang lain, Anda tampaknya telah diberikan detik sejak zaman Unix. Tetapi Anda meneruskan detik-detik itu ke konstruktor yang mengharapkan milidetik. Jadi solusinya adalah dengan mengalikan 1.000.

Pelajaran yang dipelajari:

  • Tentukan, jangan berasumsi, arti dari data yang diterima.
  • Baca dok .

Grafik yang menunjukkan berbagai perincian resolusi dalam sistem tanggal-waktu termasuk detik penuh, milidetik, mikrodetik, dan nanodetik.

Data Anda

Data Anda sepertinya dalam hitungan detik. Jika kita mengasumsikan periode awal tahun 1970, dan jika kita mengasumsikan zona waktu UTC, maka itu 1,220,227,200adalah momen pertama pada hari pertama September 2008.

Waktu Joda

Kelas java.util.Date dan .Calendar yang digabungkan dengan Java sangat merepotkan. Hindari mereka. Gunakan library Joda-Time atau paket java.time baru yang dibundel di Java 8 (dan terinspirasi oleh Joda-Time).

Perhatikan bahwa tidak seperti juDate, a DateTimedi Joda-Time benar-benar mengetahui zona waktu yang telah ditetapkan . Jadi dalam contoh kode Joda-Time 2.4 yang terlihat di bawah ini, perhatikan bahwa pertama-tama kita mengurai milidetik menggunakan asumsi default UTC. Kemudian, kedua, kami menetapkan zona waktu Paris untuk disesuaikan. Momen yang sama di garis waktu Semesta, tetapi waktu jam dinding yang berbeda . Untuk demonstrasi, kita sesuaikan lagi, ke UTC. Hampir selalu lebih baik untuk secara eksplisit menentukan zona waktu yang Anda inginkan / diharapkan daripada mengandalkan default implisit (sering kali menjadi penyebab masalah dalam pekerjaan tanggal-waktu).

Kita membutuhkan milidetik untuk membuat DateTime. Jadi ambillah masukan Anda dalam hitungan detik, dan kalikan dengan seribu. Perhatikan bahwa hasilnya harus 64-bit longkarena kita akan melimpah 32-bit int.

long input = 1_220_227_200L;  // Note the "L" appended to long integer literals.
long milliseconds = ( input * 1_000L ); // Use a "long", not the usual "int". Note the appended "L".

Masukkan hitungan milidetik itu ke konstruktor. Konstruktor tertentu mengasumsikan hitungannya dari zaman Unix tahun 1970. Jadi sesuaikan zona waktu yang diinginkan, setelah konstruksi.

Gunakan nama zona waktu yang tepat , kombinasi benua dan kota / kawasan. Jangan pernah menggunakan kode 3 atau 4 huruf ESTkarena keduanya tidak terstandardisasi, tidak unik.

DateTime dateTimeParis = new DateTime( milliseconds ).withZone( DateTimeZone.forID( "Europe/Paris" ) );

Untuk demonstrasi, sesuaikan kembali zona waktu.

DateTime dateTimeUtc = dateTimeParis.withZone( DateTimeZone.UTC );
DateTime dateTimeMontréal = dateTimeParis.withZone( DateTimeZone.forID( "America/Montreal" ) );

Buang ke konsol. Perhatikan bagaimana tanggal di Montréal berbeda, karena hari baru telah dimulai di Eropa tetapi belum di Amerika.

System.out.println( "dateTimeParis: " + dateTimeParis );
System.out.println( "dateTimeUTC: " + dateTimeUtc );
System.out.println( "dateTimeMontréal: " + dateTimeMontréal );

Saat dijalankan.

dateTimeParis: 2008-09-01T02:00:00.000+02:00
dateTimeUTC: 2008-09-01T00:00:00.000Z
dateTimeMontréal: 2008-08-31T20:00:00.000-04:00

java.time

Pembuat Joda-Time telah meminta kami untuk bermigrasi ke kerangka penggantinya, java.time sesegera mungkin. Sementara Joda-Time terus didukung secara aktif, semua pengembangan di masa depan akan dilakukan pada kelas java.time dan ekstensinya dalam proyek ThreeTen-Extra.

Framework java-time ditentukan oleh JSR 310 dan dibangun ke dalam Java 8 dan yang lebih baru. Kelas java.time telah di-back-port ke Java 6 & 7 pada proyek ThreeTen-Backport dan ke Android dalam proyek ThreeTenABP .

Sebuah Instantmomen di timeline dalam UTC dengan resolusi nanodetik. Zamannya adalah momen pertama tahun 1970 di UTC.

Instant instant = Instant.ofEpochSecond( 1_220_227_200L );

Terapkan offset-from-UTC ZoneOffset untuk mendapatkan file OffsetDateTime.

Lebih baik lagi, jika diketahui, terapkan zona waktu ZoneIduntuk mendapatkan a ZonedDateTime.

ZoneId zoneId = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , zoneId );

Tabel semua jenis tanggal-waktu di Jawa, baik modern maupun lawas

Basil Bourque
sumber
1
Cheers buddy. Penjelasan yang bagus. Saya mendapatkan DateTime baru (<long number>) dari tahun 1970 ketika saya menyadari bahwa saya memberikannya dalam hitungan detik dan diperlukan dalam milidetik
Suyash Dixit
40

Sepertinya lama Anda adalah detik, dan bukan milidetik. Konstruktor tanggal membutuhkan waktu sebagai milis, jadi

Date d = new Date(timeInSeconds * 1000);
Codemwnci
sumber
4
@ f1sh: Saya tidak downvote, tapi jawaban aslinya berbeda. Dia mengeditnya dalam masa tenggang 5 menit.
BalusC
terimakasih atas klarifikasinya. Itulah sisi negatifnya yang dimiliki SO ...: - /
f1sh
11

Hanya mengatur waktu di pabrik pada objek Kalender

Calendar c = Calendar.getInstance();
c.setTimeInMillis(1385355600000l);
System.out.println(c.get(Calendar.YEAR));
System.out.println(c.get(Calendar.MONTH));
System.out.println(c.get(Calendar.DAY_OF_MONTH));
// get Date
System.out.println(c.getTime());
Marlon
sumber
9

Itu mungkin stempel waktu dalam hitungan detik dan bukan dalam milidetik yang diperlukan untuk konstruktor Java new Date (long). Kalikan saja dengan 1000 dan Anda akan baik-baik saja.

Magnus Winter
sumber
23
lebih tepatnya 30000 milidetik terlalu lambat
SJuan76
5

Nilai panjang, kemungkinan besar, sesuai dengan stempel waktu Epoch , dan nilainya adalah:

1220227200 = Sen, 01 Sep 2008 00:00:00 GMT

1220832000 = Sen, 08 Sep 2008 00:00:00 GMT

1221436800 = Sen, 15 Sep 2008 00:00:00 GMT

Seseorang dapat mengonversi nilai panjang ini ke java.util.Date , dengan mempertimbangkan fakta java.util.Date menggunakan milidetik - seperti yang diisyaratkan sebelumnya, tetapi dengan beberapa kekurangan - seperti ini:

// note: enforcing long literals (L), without it the values would just be wrong.
Date date = new Date(1220227200L * 1000L); 

Sekarang, untuk menampilkan tanggal dengan benar, seseorang dapat menggunakan java.text.DateFormat seperti yang diilustrasikan selanjutnya:

DateFormat df = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL);
df.setTimeZone(TimeZone.getTimeZone("UTC"));
System.out.println("Wrong date time value: " + date);
System.out.println("Correct date time value: " + df.format(date));

Berikut hasil dari tampilan nilai long yang telah dikonversi menjadi java.util.Date tanpa menggunakan dan menggunakan DateFormat:

Date wrong (off by 2 hours): Mon Sep 01 02:00:00 CEST 2008
Correct date : Monday, 1 September 2008 00:00:00 o'clock UTC
Jack G.
sumber
4

Coba ini:

Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(1220227200 * 1000);
System.out.println(cal.getTime());
Mohammad Namvar
sumber
2

1220227200 sesuai dengan 15 Jan 1980 (dan memang Tanggal baru (1220227200) .toString () mengembalikan "Kam 15 Jan 03:57:07 CET 1970"). Jika Anda meneruskan nilai panjang ke tanggal, yaitu sebelum 01/01/1970 itu sebenarnya akan mengembalikan tanggal 01/01/1970. Pastikan bahwa nilai Anda tidak dalam situasi ini (lebih rendah dari 82800000).

Shivan Dragon
sumber
2

Coba ini dengan menyesuaikan format tanggal.

long longtime = 1212580300;
SimpleDateFormat dateFormat = new SimpleDateFormat("MMddyyHHmm");
Date date = (Date) dateFormat.parseObject(longtime + "");
System.out.println(date);

Catatan: Periksa siklus 24 jam atau 12 jam.

abimanyu
sumber
0

Tanggal Baru (angka) mengembalikan tanggal yang numbermilidetik setelah 1 Jan 1970. Kemungkinan format tanggal Anda tidak menunjukkan jam, menit, dan detik bagi Anda untuk melihat bahwa itu hanya sedikit setelah 1 Jan 1970.

Anda perlu mengurai tanggal sesuai dengan perutean parsing yang benar. Saya tidak tahu apa itu 1220227200, tetapi jika itu beberapa detik setelah 1 JAN 1970, kalikan itu untuk menghasilkan milidetik. Jika tidak, maka konversikan dengan cara tertentu menjadi milidetik setelah tahun 1970 (jika Anda ingin terus menggunakan java.util.Date).

Edwin Buck
sumber
0

Bekerja untuk saya. Anda mungkin ingin mengalikannya dengan 1000, karena yang Anda dapatkan adalah detik dari tahun 1970 dan Anda harus melewati milidetik dari 1 Januari 1970

leifg
sumber