Memformat Instan ke String


227

Saya mencoba memformat Instan ke String menggunakan java 8 time-api dan pola baru:

Instant instant = ...;
String out = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(instant);

Dengan menggunakan kode di atas, saya mendapatkan Pengecualian yang mencakup bidang yang tidak didukung:

java.time.temporal.UnsupportedTemporalTypeException: Unsupported field: YearOfEra
    at java.time.Instant.getLong(Instant.java:608)
    at java.time.format.DateTimePrintContext.getValue(DateTimePrintContext.java:298)
    ...

Jawaban:


310

Zona waktu

Untuk memformat Instantsebuah -zona waktu diperlukan. Tanpa zona waktu, pemformat tidak tahu cara mengonversi bidang waktu instan ke waktu manusia, dan karenanya mengeluarkan pengecualian.

Zona waktu dapat ditambahkan langsung ke formatter menggunakan withZone().

DateTimeFormatter formatter =
    DateTimeFormatter.ofLocalizedDateTime( FormatStyle.SHORT )
                     .withLocale( Locale.UK )
                     .withZone( ZoneId.systemDefault() );

Menghasilkan String

Sekarang gunakan formatter itu untuk menghasilkan representasi String dari Instan Anda.

Instant instant = Instant.now();
String output = formatter.format( instant );

Dump ke konsol.

System.out.println("formatter: " + formatter + " with zone: " + formatter.getZone() + " and Locale: " + formatter.getLocale() );
System.out.println("instant: " + instant );
System.out.println("output: " + output );

Saat dijalankan.

formatter: Localized(SHORT,SHORT) with zone: US/Pacific and Locale: en_GB
instant: 2015-06-02T21:34:33.616Z
output: 02/06/15 14:34

51
Terima kasih!! BTW pengecualian "bidang tidak didukung" menunjuk ke, misalnya, tahun, adalah tumpul spektakuler. Mungkin situasi ini harus dideteksi dan pengecualian yang menunjuk langsung ke id zona hilang di Sekejap harus dilempar!
davidbak

1
Lebih aneh lagi, jika Anda menyertakan .withZone (mis. ,WithZone (ZoneId.of ("Z"))) dan memformat LocalDateTime, zona ini DIABAIKAN! Jadi selama .withZone () disertakan, formatter yang sama dapat digunakan untuk Instant dan untuk LocalDateTime, tanpa mempengaruhi waktu yang ditunjukkan untuk yang terakhir.
Glenn

1
Mengapa begitu sulit untuk menerima kenyataan bahwa Instant memiliki TimeZone yang merupakan GMT?
Koray Tugay

1
@ KorayTugay Karena sementara komentar "Instan sudah GMT" yang bertele-tele mungkin benar, komentar itu jauh dari membantu ketika menghadapi jejak pengecualian yang dilemparkan karena memformat Instan tanpa menentukan zona waktu tidak berfungsi. Akan lebih baik jika formatter default ke GMT, tapi oh well.
Ti Strga

Sekarang ini memberi Anda yyyy-MM-dd hh:mm:ssformat:DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss").withZone(ZoneId.of("Europe/Paris"));
WesternGun

39
public static void main(String[] args) {

    DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
            .withZone(ZoneId.systemDefault());

    System.out.println(DATE_TIME_FORMATTER.format(new Date().toInstant()));

}

3
Meskipun kode ini dapat menjawab pertanyaan, memberikan konteks tambahan tentang bagaimana dan mengapa pemecahan masalah akan meningkatkan nilai jangka panjang jawaban.
Alexander

1
Sementara potongan kode ini dapat menyelesaikan pertanyaan, termasuk penjelasan sangat membantu untuk meningkatkan kualitas posting Anda. Ingatlah bahwa Anda menjawab pertanyaan untuk pembaca di masa depan, dan orang-orang itu mungkin tidak tahu alasan untuk saran kode Anda.
Rosário Pereira Fernandes

23
DateTimeFormatter.ISO_INSTANT.format(Instant.now())

Ini menghemat Anda dari keharusan mengonversi ke UTC. Namun, kerangka waktu beberapa bahasa lain mungkin tidak mendukung milidetik sehingga Anda harus melakukannya

DateTimeFormatter.ISO_INSTANT.format(Instant.now().truncatedTo(ChronoUnit.SECONDS))

Apa yang Anda maksud dengan "kerangka waktu bahasa lain"? Apakah ISO_INSTANT.format () secara otomatis akan terpotong menjadi detik?
Guangtong Shen

Beberapa kerangka kerja hanya berharap waktu naik ke detik karena mereka tidak mengikuti konvensi ISO penuh dan istirahat ketika ada milidetik sebagai bagian dari string input.
Archimedes Trajano

21

The Instantkelas tidak mengandung informasi Zone, hanya toko timestamp dalam milidetik dari UNIX zaman, yaitu 1 1070 Jan dari UTC. Jadi, formatter tidak dapat mencetak tanggal karena tanggal selalu dicetak untuk zona waktu konkret. Anda harus mengatur zona waktu ke formatter dan semua akan baik-baik saja, seperti ini:

Instant instant = Instant.ofEpochMilli(92554380000L);
DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT).withLocale(Locale.UK).withZone(ZoneOffset.UTC);
assert formatter.format(instant).equals("07/12/72 05:33");
assert instant.toString().equals("1972-12-07T05:33:00Z");

4

Atau jika Anda masih ingin menggunakan formatter yang dibuat dari pola, Anda bisa menggunakan LocalDateTime alih-alih Instan:

LocalDateTime datetime = LocalDateTime.now();
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(datetime)

4

Instan sudah dalam UTC dan sudah memiliki format tanggal default yyyy-MM-dd . Jika Anda senang dengan itu dan tidak ingin mengacaukan zona waktu atau pemformatan, Anda bisa juga toString()melakukannya:

Instant instant = Instant.now();
instant.toString()
output: 2020-02-06T18:01:55.648475Z


Tidak ingin T dan Z? (Z menunjukkan tanggal ini adalah UTC. Z adalah singkatan dari "Zulu" alias "Zero hour offset" alias UTC):

instant.toString().replaceAll("[TZ]", " ")
output: 2020-02-06 18:01:55.663763


Ingin milidetik, bukan nanodetik? (Jadi, Anda dapat memasukkannya ke kueri sql):

instant.truncatedTo(ChronoUnit.MILLIS).toString().replaceAll("[TZ]", " ")
output: 2020-02-06 18:01:55.664

dll.


-3
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy MM dd");
String text = date.toString(formatter);
LocalDate date = LocalDate.parse(text, formatter);

Saya percaya ini mungkin membantu, Anda mungkin perlu menggunakan semacam variasi tanggal lokal bukan instan

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.