Anında Dizeye Biçimlendirme


228

Anında yeni java 8 time-api ve bir desen kullanarak bir dize biçimlendirmek çalışıyorum:

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

Yukarıdaki kodu kullanarak, desteklenmeyen bir alan şikayet bir istisna alıyorum:

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

Yanıtlar:


311

Saat dilimi

InstantBir saat dilimini biçimlendirmek için gereklidir. Bir saat dilimi olmadan, biçimlendirici anlıkın insan tarih-saat alanlarına nasıl dönüştürüleceğini bilmez ve bu nedenle bir istisna atar.

Saat dilimi kullanılarak doğrudan biçimlendiriciye eklenebilir withZone().

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

Dize Oluşturma

Şimdi Anında Arama'nın Dize temsilini oluşturmak için bu biçimlendiriciyi kullanın.

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

Konsola dökümü.

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

Çalıştırıldığında.

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
Teşekkür ederim!! BTW, örn. Yılı işaret eden "desteklenmeyen alan" istisnası oldukça geniştir. Belki bu durum tespit edilmeli ve Anında Arama'daki eksik bölge kimliğine doğrudan işaret eden bir istisna atılmalıdır!
davidbak

1
Daha tuhaf bir şekilde, .withZone (örn., .WithZone (ZoneId.of ("Z"))) ekler ve LocalDateTime'ı biçimlendirirseniz, bölge IGNORED olur! .WithZone () dahil olduğu sürece, aynı biçimlendirici, ikincisi için gösterilen zamanı etkilemeden hem Anında hem de LocalDateTime için kullanılabilir.
Glenn

1
Anında Arama'nın GMT olan bir TimeZone'u olduğu gerçeğini kabul etmek neden bu kadar zor?
Koray Tugay

1
@KorayTugay Bilgiçlik "Anında Zaten GMT" yorumları doğru olsa da, bir zaman dilimini belirtmeden bir Anında biçimlendirme çalışmadığı için atılan bir istisna iziyle karşılaşmaktan çok uzaktırlar . Formatlayıcı varsayılan olarak GMT'ye ayarlanmış olsaydı güzel olurdu, ama iyi.
Ti Strga

Şimdi bu size yyyy-MM-dd hh:mm:ssformat verir :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
Bu kod soruyu cevaplayabilirken, sorunun nasıl ve neden çözüldüğüne dair ek bağlam sağlamak yanıtlayıcının uzun vadeli değerini artıracaktır.
Alexander

1
Bu kod snippet'i soruyu çözebilir, ancak bir açıklama dahil olmak , yayınınızın kalitesini artırmaya yardımcı olur. Gelecekte okuyucular için soruyu cevapladığınızı ve bu kişilerin kod önerinizin nedenlerini bilmeyebileceğini unutmayın.
Rosário Pereira Fernandes

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

Bu, UTC'ye dönüştürmek zorunda kalmamanızı sağlar. Ancak, başka bir dilin zaman çerçeveleri milisaniyeyi desteklemeyebilir, bu nedenle

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

"Başka bir dilin zaman çerçeveleri" ile ne demek istiyorsun? ISO_INSTANT.format () otomatik olarak saniye olarak kesilir mi?
Guangtong Shen

Bazı çerçeveler tam ISO kuralına uymadığı ve giriş dizesinin bir parçası olarak milisaniye olduğunda kırılmadığı için yalnızca saniyeler kadar sürebilir.
Archimedes Trajano

21

InstantSınıf yalnızca depolar yani 1 Ocak 1070 UTC, UNIX çağdan milisaniye cinsinden zaman damgası, Bölge bilgi içermiyor. Bu nedenle, biçimlendirici tarih her zaman somut saat dilimi için yazdırıldığından bir tarih yazdıramaz. Biçimlendiriciye saat dilimi ayarlamalısınız ve hepsi iyi olacak, şöyle:

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

Veya yine de kalıptan oluşturulan biçimlendiriciyi kullanmak istiyorsanız, Anında Arama yerine LocalDateTime'ı kullanabilirsiniz:

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

4

Örnekler zaten UTC'de ve varsayılan bir yyyy-AA-gg biçimine sahip . Bundan memnunsanız ve saat dilimleri veya biçimlendirme ile uğraşmak istemiyorsanız, şunları da yapabilirsiniz toString():

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


T ve Z'yi istemiyor musun? (Z, bu tarihin UTC olduğunu belirtir. Z, "Zulu" aka "Sıfır saat farkı", UTC anlamına gelir):

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


Nanosaniye yerine milisaniye mi istiyorsunuz? (Böylece bir sql sorgusu içine plop yapabilirsiniz):

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

vb.


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

Bunun yardımcı olabileceğine inanıyorum, anında yerine bir tür yerel veri varyasyonu kullanmanız gerekebilir

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.