Bagaimana cara mendapatkan tanggal UTC + 0 di Java 8?

108

Saya punya masalah dengan kelas Tanggal di Jawa. Kelas tanggal mengembalikan tanggal mesin lokal tetapi saya membutuhkan UTC-0.

Saya telah mencari di Google dan menemukan solusi hebat untuk JavaScript tetapi untuk Java tidak ada yang berguna.

Bagaimana cara mendapatkan tanggal UTC + 0 di Java 8?

Menandai
sumber
12
java.util.Datetidak pernah merupakan tanggal mesin lokal. Itu selalu didefinisikan sebagai milidetik berlalu sejak 1970-01-01 relatif terhadap UTC + 00: 00. Mungkin perilaku metodenya toString()membingungkan Anda yang memang menggunakan representasi di zona waktu lokal.
Meno Hochschild
Satu kemungkinan jawaban dapat ditemukan dalam pertanyaan: stackoverflow.com/questions/45350095/…
Priya Jain

Jawaban:

146

Dengan Java 8 Anda dapat menulis:

OffsetDateTime utc = OffsetDateTime.now(ZoneOffset.UTC);

Untuk menjawab komentar Anda, Anda kemudian dapat mengubahnya menjadi Tanggal (kecuali jika Anda bergantung pada kode lama, saya tidak melihat alasannya) atau menjadi milidetik sejak zaman:

Date date = Date.from(utc.toInstant());
long epochMillis = utc.toEpochSecond() * 1000;
assylias
sumber
1
Terima kasih. apakah mungkin mengkonversi ZonedDateTime ke Date atau menjadi long (ms)?
Tandai
7
Meskipun kode Penjawab ini secara teknis berfungsi, bukankah ini lebih tepat untuk digunakan OffsetDateTimedaripada ZonedDateTimemengingat bahwa kami bekerja hanya dengan offset-from-UTC daripada zona waktu penuh?
Basil Bourque
179

tl; dr

Instant.now()

java.time

Kelas tanggal-waktu lama yang merepotkan yang digabungkan dengan versi Java paling awal telah digantikan oleh kelas java.time yang dibangun ke dalam Java 8 dan yang lebih baru. Lihat Tutorial Oracle . Sebagian besar fungsionalitas telah di-back-port ke Java 6 & 7 di ThreeTen-Backport dan selanjutnya diadaptasi ke Android di ThreeTenABP .

Instant

Sebuah Instantmewakili momen di garis waktu dalam UTC dengan resolusi hingga nanodetik .

Instant instant = Instant.now();

The toStringMetode menghasilkan objek String dengan teks yang mewakili nilai tanggal-waktu menggunakan salah satu standar ISO 8601 format.

String output = instant.toString();  

2016-06-27T19: 15: 25.864Z

The Instantkelas kelas bangunan-blok dasar di java.time. Ini harus menjadi kelas andalan Anda saat menangani tanggal-waktu karena umumnya praktik terbaik adalah melacak, menyimpan, dan bertukar nilai waktu-tanggal dalam UTC.

OffsetDateTime

Tetapi Instantmemiliki keterbatasan seperti tidak ada opsi pemformatan untuk menghasilkan string dalam format alternatif. Untuk fleksibilitas lebih, ubah dari Instantmenjadi OffsetDateTime. Tentukan offset-dari-UTC . Dalam java.time itu berarti sebuah ZoneOffsetobjek. Di sini kami ingin tetap menggunakan UTC (+00) sehingga kami dapat menggunakan konstanta yang sesuai ZoneOffset.UTC.

OffsetDateTime odt = instant.atOffset( ZoneOffset.UTC );

2016-06-27T19: 15: 25.864Z

Atau lewati Instantkelas.

OffsetDateTime.now( ZoneOffset.UTC )

Sekarang dengan sebuah OffsetDateTimeobjek di tangan, Anda dapat menggunakan DateTimeFormatteruntuk membuat objek String dengan teks dalam format alternatif. Cari Stack Overflow untuk banyak contoh penggunaan DateTimeFormatter.

ZonedDateTime

Jika Anda ingin menampilkan waktu jam dinding untuk beberapa zona waktu tertentu, terapkan a ZoneIduntuk mendapatkan a ZonedDateTime.

Dalam contoh ini kami menerapkan zona waktu Montréal. Di musim panas, di bawah omong kosong Daylight Saving Time (DST) , zona memiliki offset -04:00. Jadi perhatikan bagaimana waktu hari adalah empat jam lebih awal dalam output, 15bukan 19jam. Instantdan ZonedDateTimekeduanya mewakili momen serentak yang sama, hanya dilihat melalui dua lensa berbeda.

ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = instant.atZone( z );

2016-06-27T15: 15: 25.864-04: 00 [Amerika / Montreal]

Mengonversi

Meskipun Anda harus menghindari kelas tanggal-waktu lama, jika harus, Anda dapat mengonversi menggunakan metode baru yang ditambahkan ke kelas lama. Di sini kami menggunakan java.util.Date.from( Instant )dan java.util.Date::toInstant.

java.util.Date utilDate = java.util.Date.from( instant );

Dan pergi ke arah lain.

Instant instant= utilDate.toInstant();

Demikian pula, cari metode baru yang ditambahkan ke GregorianCalendar(subclass dari Calendar) untuk dikonversi ke dan dari java.time.ZonedDateTime.

Tabel jenis kelas tanggal-waktu di java.time modern versus legacy.

Tentang java.time

The java.time kerangka dibangun ke Jawa 8 dan kemudian. Kelas-kelas ini menggantikan tua merepotkan warisan kelas tanggal-waktu seperti java.util.Date, Calendar, & SimpleDateFormat.

Untuk mempelajari lebih lanjut, lihat Tutorial Oracle . Dan cari Stack Overflow untuk banyak contoh dan penjelasan. Spesifikasinya adalah JSR 310 .

Proyek Joda-Time , sekarang dalam mode pemeliharaan , menyarankan migrasi ke kelas java.time .

Anda dapat bertukar objek java.time langsung dengan database Anda. Gunakan driver JDBC yang sesuai dengan JDBC 4.2 atau yang lebih baru. Tidak perlu string, tidak perlu java.sql.*kelas. Hibernate 5 & JPA 2.2 mendukung java.time .

Dimana mendapatkan kelas java.time?

Basil Bourque
sumber
3
Menghargai karena mengatakan DST tidak masuk akal :-)
prash
jadi jika DST tidak ada ZonedDateTimetidak akan diperlukan karena semua ZoneIdakan memetakan ke satu yang ZoneOffsetbisa kita gunakan OffsetDateTime?
wilmol
1
@wilmol No. Daylight Saving Time (DST) hanyalah salah satu dari banyak alasan mengapa politisi memilih untuk mendefinisikan ulang batas zona waktu dan offset dalam zona tersebut. Baru-baru ini Korea Utara mengubah jam setengah jam mereka untuk menyelaraskan dengan Korea Selatan karena alasan diplomatik. Dalam perang, penjajah / penjajah dapat mengubah offset agar sesuai dengan negara asal. Saat ini ada mode baru di mana pemerintah memilih untuk menghentikan perubahan DST tetapi tetap menggunakan DST secara permanen daripada kembali ke waktu standar sebelumnya. Selalu rencanakan penggantian kerugian setiap perubahan zona atau aplikasi Anda pada akhirnya akan rusak.
Basil Bourque
1
Jawaban yang fantastis! Saya sangat menghargai waktu yang Anda habiskan untuk ini. :)
drognisep
ZoneId.of ("Amerika / Montreal"); mengapa seseorang menemukan hal seperti itu di jdk? itu jelek, menjijikkan, tidak memberi tahu apakah ada yang salah sampai run-time, siapa yang bisa mengingat semua kode keras itu? mengapa tidak diimplikasikan di kelas ENUM?
workplaylifecycle
4

Di java8, saya akan menggunakan Instantkelas yang sudah ada di UTC dan nyaman untuk digunakan.

import java.time.Instant;

Instant ins = Instant.now();
long ts = ins.toEpochMilli();

Instant ins2 = Instant.ofEpochMilli(ts)

Atau, Anda dapat menggunakan yang berikut ini:

import java.time.*;

Instant ins = Instant.now(); 

OffsetDateTime odt = ins.atOffset(ZoneOffset.UTC);
ZonedDateTime zdt = ins.atZone(ZoneId.of("UTC"));

Kembali ke Instant

Instant ins4 = Instant.from(odt);
Abel Terefe
sumber
3
Tidak, seorang Instantyang tidak pada waktu setempat. Sebuah Instantdefinisi oleh dalam UTC. Jadi tidak perlu intrik yang terlihat dalam Answer ini mencoba masuk ke UTC; yang Instantsudah adalah di UTC. Lihat Jawaban saya untuk info lebih lanjut dan kode yang lebih sederhana.
Basil Bourque
Terima kasih atas komentarnya.
Abel Terefe
0

Solusi 1 baris di Java 8:

public Date getCurrentUtcTime() {
    return Date.from(Instant.now());
}
Abhijeet Ashok Muneshwar
sumber