2015-08-18 15 views
6

JDK8 DateTime kitaplığı neden geçerli iso8601 tarih aralığı dizelerini ayrıştırmıyor gibi görünüyor? ": 00 01"java.time.ZonedDateTime.parse ve iso8601?

Bu çalışır:

java.time.ZonedDateTime.parse("2015-08-18T00:00+01") 

ISO8601 Gönderen:

java.time.ZonedDateTime.parse("2015-08-18T00:00+01:00") 

Bir çözümleme istisna atar It "01" yerine gibi ifade saat dilimi uzaklıklar bobinleri wikipedia sayfası:

UTC offset 'Z' fo yukarıda olduğunu aynı şekilde zaman eklenir rm ± [hh]: [mm], ± [hh] [mm] veya ± [hh]. Bu nedenle, tarif edildiği zaman UTC'den bir saat ileride (örneğin, kış boyunca Berlin'de ), bölge tanımlayıcısı "+01: 00", "+0100" veya "+01" olacaktır. .

DÜZENLEME: Bu JDK gerçek bir meşru hata gibi görünüyor.

https://bugs.openjdk.java.net/browse/JDK-8032051

Vay, yıllardır bu yeni tarih saat şeyler test ettikten sonra, ben bu kadar belirgin bir şey yakalamış düşündük. Ayrıca, JDK yazar türlerinin daha iyi bir otomatik test paketi kullanacak kadar titiz olduğunu düşündüm.

UPDATE: Bu, geçerli jdk-9 yapısında tamamen giderilmiştir. Sadece doğruladım. Tam olarak aynı ayrıştırma komutu geçerli jdk-8 yapısında başarısız oldu ve jdk-9'da mükemmel çalışıyor.

EK: FWIW, ISO-8601 dayalı RFC 3339, bu kısa el için izin vermez. Saat dilimi ofsetlerinde dakika belirtmelisiniz.

+0

Ve buradaki soru ...? (Olduğunu, başlık reword isteyebilirsiniz - Bilmenizi isteriz varsayalım ya neden, ya da belki bu işi yapmak için nasıl) – StaxMan

+0

Saat dilimleri sadece bir ofset çok daha fazla karmaşıktır. Bu durumda güvende olabilirsiniz, fakat genel olarak zaman dilimleri açısından ofsetler düşünülmesinden kaçınılması gereken bir uygulamadır. – Necreaux

+0

@StaxMan, tam soruyla açıklığa kavuşturuldu ... Bunun açık olduğunu düşündüm. – clay

cevap

-1

Geçerli jdk-9 yapısında tamamen giderilmiştir. Sadece doğruladım. Tam olarak aynı ayrıştırma komutu geçerli jdk-8 yapısında başarısız oldu ve jdk-9'da mükemmel çalışıyor.

yeni jdk-9 kabuk kullanma:

➜ jdk-9 bin/jshell 
| Welcome to JShell -- Version 9-ea 
| For an introduction type: /help intro 

jshell> java.time.ZonedDateTime.parse("2015-08-18T00:00+01") 
$1 ==> 2015-08-18T00:00+01:00 
+0

Bu neden kabul edilen cevap olarak işaretlendi? Soru, bunun JDK8'de neden kırıldığını sorar. "JDK9'da çalışıyor" cevabı değil. – Jamie

+0

O Onlar 8'e düzeltme backport gerektiğini ... o JDK9 kadar sabit değil, JDK8 bir hata, ama bu Q/A amaçları için, bu konuda kesin bir eyalet. – clay

0

Örneğin

olarak saat dilimi için biçimine izin vermektedir DateTimeFormatterBuilder.appendZoneId() tarafından eklenen kullanılan kod, şu ayrıştırmak olacaktır:

"Europe/London"   -- ZoneId.of("Europe/London") 
"Z"      -- ZoneOffset.UTC 
"UT"      -- ZoneId.of("UT") 
"UTC"      -- ZoneId.of("UTC") 
"GMT"      -- ZoneId.of("GMT") 
"+01:30"     -- ZoneOffset.of("+01:30") 
"UT+01:30"    -- ZoneOffset.of("+01:30") 
"UTC+01:30"    -- ZoneOffset.of("+01:30") 
"GMT+01:30"    -- ZoneOffset.of("+01:30") 

Kendi tarihini tanımlayabilirsiniz saat ofsetlerine izin vermek için zaman formatı, ancak dünyanın birçok yerinde, son zamanlarda +0: 30: 45 ve Kuzey Kore olan Nepal gibi bir saatin kesirleri +08: 30

+0

"+01", "+01: 00" için standart kısa yoldur. Anladığım kadarıyla, "+05: 45" gibi eşit olmayan ofsetler vardır, bu durumda bunu kullanabilirsiniz ve dakikaları atlayamazsınız. – clay

+0

İkinci olarak, özel uzantıları yazmak veya kendi "tarih saat formatını" tanımlamak istemiyorum. Datetime kütüphanesinin harici kaynaklardan aldığım standart iso8601 dizelerini ayrıştırmasını istiyorum. JDK8 bunu yapamaz gibi görünüyor. – clay

+1

@clay "JDK8 bunu yapamıyor gibi görünüyor." JDK8 tam olarak istediğimiz şeyi yapmadığı zaman, geliştiriciler olarak, bu yüzden kod yazıyoruz. –

3

Bu varsayılan biçimlendirici: ISO_OFFSET_DATE_TIME (çünkü parse 2015-08-18T00:00+01:00). belgelerinde

:

Bu biçimlendirme yeteneğine değişmez bir biçimlendirici döndürür ve ISO-8601 tarih-saat biçimi genişletilmiş ofseti ayrıştırma. [...]

Ofset kimliği. Ofsetin saniyeler varsa, bu, ISO-8601 standardının bir parçası olmamasına rağmen ele alınacaktır. Ayrıştırma büyük/küçük harfe duyarsız.

It's (bu varsayılan biçimlendiricisine için yalnızca bu kullanın):

kimliği ofset için standart ISO-8601 biçimlendirilmiş dize ufak çaplı çeşididir. Üç biçimi vardır:

  • Z - UTC için (ISO-8601)
  • + ss: dd veya -hh: dd - saniyeler sıfır (ISO-8601)
  • + hh ise: dd : ss veya -hh: mm: ss - saniyeler sıfır değilse (ISO-8601 değil) (ISO-8601 gibi +hh yapmayın).

Bu java.time gibi görünüyor (JDK 8) hepsinde değil tam uygulayan ISO-8601 do.


Bu

:

java.time.ZonedDateTime.parse("2015-08-18T00:00+01:00"); // works 

(kabaca kaynağından JDK) karşılık gelir: Sen DateTimeFormatterBuilder ile kendi DataTimeFormatter oluşturabilir

DateTimeFormatterBuilder builder = new DateTimeFormatterBuilder(); 
DateTimeFormatter formatter = builder 
     .parseCaseInsensitive() 
     .append(DateTimeFormatter.ISO_LOCAL_DATE_TIME) 
     .appendOffsetId() 
     .toFormatter(); 

java.time.ZonedDateTime.parse("2015-08-18T00:00+01:00", formatter); // it's same 

. Bunun yerine appendOffsetId() arasında

DateTimeFormatterBuilder builder2 = new DateTimeFormatterBuilder(); 
DateTimeFormatter formatter2 = builder2.parseCaseInsensitive() 
     .append(DateTimeFormatter.ISO_LOCAL_DATE_TIME) 
     .appendPattern("X") // eg.: 
     .toFormatter(); 

java.time.ZonedDateTime.parse("2015-08-18T00:00+01", formatter2); // here you set +01 

appendPattern(String pattern) ve 'X' veya 'x' set kullanımı.

Şimdi, 2015-08-18T00:00+01 veri tabanınızı kullanabilirsiniz.


Ya da ... Varsayılan ISO_OFFSET_DATE_TIME ve postfix'i :00 ekleyin.

java.time.ZonedDateTime.parse("2015-08-18T00:00+01" + ":00"); 

Ama bu son kötü bir çözümdür.

0

Thx @mkczyk bu iş için kendi biçimlendirici yaptığını söyledi.

  • "2016-02-14T21: 32: 04.150 + 04" Ben
    1. ": 32 04.150Z 2016-02-14T18"

      gibi tarih en bir ayrıştırıcı gerekli
    2. "2016-02- 14T21: 32: 04.150 + 04: 00"

    private static final DateTimeFormatter DATE_TIME_NANOSECONDS_OFFSET_FORMATTER = new DateTimeFormatterBuilder().parseCaseInsensitive().append(ISO_LOCAL_DATE_TIME) .appendFraction(ChronoField.NANO_OF_SECOND, 0, 3, true) .appendOffset("+HH:mm", "Z") .toFormatter();

  • appendfraction (.., .., .., true) saniye ondalık olarak nanosaniye gördüğü ile biraz mücadele etti.

    ZonedDateTime zdt = ZonedDateTime.parse(textToParse, DATE_TIME_NANOSECONDS_OFFSET_FORMATTER);

    Ve ondan UTC saati almak için kullanılan bundan sonra

    .

    zdt = ZonedDateTime.ofInstant(zdt.toInstant(), ZoneId.of("UTC")); 
    
    İlgili konular