2015-07-03 26 views
7

aşağıdaki kod parçasını bakınız davranır:SimpleDateFormat tutarsız

String timeString = "1980-01-01T14:00:00+0300"; 
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ"); 
Date date2 = sdf.parse(timeString); 

// sdf.getCalendar().get(Calendar.ZONE_OFFSET); 
System.out.println(sdf.format(date2)); 

şimdi, ofset +2h olan bir ülkede yaşıyorum +1 yaz saati (şu anda). Olduğu gibi Bu kodu çalıştırırsanız ben takvim en offset soran çizgiyi yorumsuz , bu

1980-01-01T13:00:00+0200 

yazdırır, programın çıktısı

1980-01-01T14:00:00+0300 

neden oluyor ki herhangi bir fikir olduğunu ve tutarlı bir çıktı nasıl elde edebilirim?

Daha açık olmayan şeylerden kaçınmak için: Bazı eski kodları kullandığım için, java 8 bir seçenek değil. Ve evet, burada kilit nokta NEDEN, ve ne gibi geçici çözümler var? Ve orada 2 whys:

  1. Neden ben bir 0300 TZ geçmek yapmak ve varsayılan olarak ben bir 0200 tane alıyorsunuz? (SimpleDateFormat, her zaman aksi belirtilmedikçe, TimeZone.getDefault kullanmalıdır).
  2. Neden farklı bir yanıt veriyor, çünkü onun takvim örneğinde bir alıcı buluyorum.
+3

İçinde tutarsız ne var? Ofset kullanmadığınız zaman, size olduğu gibi tarih verir ve kullandığınız zaman dilimine göre değişir. –

+1

@RamanShrivastava Bir zamanlayıcıyı çağırmak, format işlevinin çıktısını değiştirmemelidir. – wonderb0lt

cevap

2

sorun Calendar#get basit alıcı olmadığı,, bu şuna benzer:

public int get(int field) 
{ 
    complete(); 
    return internalGet(field); 
} 

nerede complete yapar bu, Javadoc göre: Herhangi unset içinde

Dolgularının Takvim alanlarındaki alanlar. İlk olarak, computeTime() yöntemi, zaman değeri (Epoch'dan milisaniye ofseti) takvim alanı değerlerinden hesaplanmamışsa çağrılır. Ardından, tüm takvim alanı değerlerini hesaplamak için computeFields() yöntemi çağrılır.

Kaynak here kaynağına baktım, ancak kod en son Java sürümü için de aynı.

+0

Evet Bunu biliyordum. Ama bu sadece bir tür "yapar çünkü yapar". Benim için kesinlikle bir böcek gibi görünüyor. –

+0

Diyelim ki bu tartışmalı bir tasarım kararıdır. Java 8'in yeni bir tarih ve zaman API'sine sahip olmasının bir nedeni vardır :) – meskobalazs

+0

Bu yanıt, küçük bir snippet ile mükemmel olacaktır çünkü OP'nin kodunu değiştirmesini engellemek için kodunu değiştirebilir (örneğin); takvim örneği, vb.) – wonderb0lt

0

sdf.parse Biçemleyicinin iç takvim bölge çıkış hatlarının sonunda farkı görebilirsiniz 0300

System.out.println(sdf.getCalendar()); 
    sdf.parse(timeString); 
    System.out.println(sdf.getCalendar()); 

ofset

... ,ZONE_OFFSET=7200000,DST_OFFSET=0] 
... ,ZONE_OFFSET=10800000,DST_OFFSET=0] 

sdf.getCalendar().get(Calendar.ZONE_OFFSET); geçerli saatle

geri ofset takvimin dilimini geri değiştirir
+1

Soru şudur: neden bunu yapıyor? Önsezim şu şekildedir: Takvim bir saat dilimi nesnesine bir referansa sahip. Tarih ayrıştırıldığında, "+0300" arasında hiçbir zaman dilimi belirlenemez. Takvimin 'ZONE_OFFSET 'alanında 3 saat süreyle ofset depolar. 'Get()' yöntemi, dahili olarak 'ZONE_OFFSET' alanı da dahil olmak üzere tüm alanlar için henüz yapılmadığında bir Takvim için tüm alanları hesaplar. Takvim, ofseti hesaplamak için bildiği zaman dilimini kullanır ve farklı bir ofset belirler. – gogognome

+0

Evet, bunun en doğru cevap olduğunu kabul ediyorum. Aslında, şu anda olduğum yerde, ilk yazımda da yazdığım gibi, +2 ofset +1 dst bölgesindeyim. Bu, herhangi bir şekilde bir SimpleDateFormat deseninde reprezentable değildir. Bu yüzden onu +3 olarak birleştiriyoruz. Ama yine de, bir yerde bir yerde tüm iç işlemenin içinde, Takvim ve SimpleDateFormat'ın yaptığı bir hata vardır, çünkü (+2 + 1) 'de (+ + +1) dönüşümün (+ + +1) davranışı ya da onu olduğu gibi bırakma tutarlı olmalı ve etkilenmemelidir. bir olsun. Sdf'yi herhangi bir şekilde post oluşturmadan değiştirmediğim için sdf.format (sdf.parse (txt)) her zaman txt olmalıdır. –

0

SimpleDateFormate, Tarihi oluşturmak için Takvim'i kullanır. Date-Object, java.util.GregorianCalendar.computeTime()'da Hesaplanan Timestamp ile oluşturulur. 2789 no'lu hatta ilk zaman dilimi kullanılır (java.text.SimpleDateFormat.initializeCalendar(Locale) olarak ayarlanmıştır). Bu yüzden yanlış Timezone'u görüyorsunuz.

get(Calendar.ZONE_OFFSET) numaralı telefonu aradığınızda, başlangıçta ayarlanmış Zaman Dilimini kullanan Yöntem java.util.GregorianCalendar.computeFields() yöntemi çağrılır.

Sanırım bu bir böcek.