2017-07-29 146 views
1

我試圖解析日期字符串使用此代碼測試時區:SimpleDateFormat.parse()忽略時區?

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mmZZZZZ", Locale.US); 
Calendar calendar = Calendar.getInstance(); 
calendar.setTime(sdf.parse("2017-07-26T06:00-06:00")); 
int offset = calendar.getTimeZone().getRawOffset(); 

我試圖改變時區從-06+09,但offset總是包含10800000

如何正確解析日期與時區(我需要時間和時區兩者)?

+0

是的,我是。我從遠程服務器獲取它,並且無法更改它。我只需要解析它。 – BArtWell

+0

爲什麼?它完全正常,只是不包含一秒鐘。 – BArtWell

+0

'-06:00' - 那不是時候。這是時區。它可以是'-09:00'或'+05:00'或類似的東西。 – BArtWell

回答

1

注意:-06:00是一個offset, not a timezone - 這兩個概念是相關的,但它們是不同的東西(更多在下面)。


SimpleDateFormatCalendar的問題是,他們使用系統的默認時區,所以即使您解析的日期用不同的偏移(如-06:00),所產生的Calendar將有默認的時區(你可以檢查什麼區域是通過調用TimeZone.getDefault())。

這只是這個舊API的許多problemsdesign issues之一。

幸運的是,如果您不介意爲項目添加依賴項(在這種情況下,我認爲它完全值得),還有更好的選擇。在Android中,您可以使用ThreeTen Backport,它是Java 8新日期/時間類的一個很好的後端。而對於Android,您還需要ThreeTenABP才能使其正常工作(更多關於如何使用它here)。

要與補償工作,你可以使用org.threeten.bp.OffsetDateTime類:

// parse the String 
OffsetDateTime odt = OffsetDateTime.parse("2017-07-26T06:00-06:00"); 

這將正確地分析所有的字段(日期/時間和偏移量)。爲了獲得偏移值,類似於calendar.getTimeZone().getRawOffset(),你可以這樣做:

// get offset in milliseconds 
int totalSeconds = odt.getOffset().getTotalSeconds() * 1000; 

我不得不由1000因爲calendar返回值以毫秒爲單位,但在幾秒鐘內ZoneOffset返回到繁殖。

將其轉換爲另一個偏移(+09:00),這是簡單的:

// convert to +09:00 offset 
OffsetDateTime other = odt.withOffsetSameInstant(ZoneOffset.ofHours(9)); 

正如我所說,時區和偏移量是不同的東西:

  • 偏移量是從UTC的區別:-06:00表示「UTC後6小時」,+09:00表示「UTC前9小時」
  • 時區是一個地區在過去(以及當這些變化發生時)具有和將會具有的所有不同的抵消的集合。最常見的情況是Daylight Saving Time班次,當時鍾在某個區域前後變化1小時時。所有這些關於何時更改(以及更改前後的偏移量)的規則都由時區概念封裝。

所以,上面的代碼工作正常,如果你正在處理偏移量並想轉換爲另一個。但是如果你想用一個時區工作,你必須轉換OffsetDateTimeZonedDateTime

// convert to a timezone 
ZonedDateTime zdt = odt.atZoneSameInstant(ZoneId.of("Asia/Tokyo")); 
// get the offset 
totalSeconds = zdt.getOffset().getTotalSeconds() * 1000; 

getOffset()上述方法將檢查指定的時區的歷史和取得的偏移量是在相應的即時激活(因此,例如,如果您在夏令時期間拍攝日期,則會相應調整偏移量(以及日期和時間)。

API使用IANA timezones names(始終格式爲Region/City,如America/Sao_PauloEurope/Berlin)。 避免使用3字母縮寫(如CST或),因爲它們是ambiguous and not standard

通過調用ZoneId.getAvailableZoneIds(),您可以獲得可用時區列表(並選擇最適合您系統的時區)。

您也可以使用系統的默認時區ZoneId.systemDefault(),但即使在運行時也可以在不通知的情況下對其進行更改,因此最好使用特定的時區。