2016-09-12 53 views
5

我對java時間的時間處理感到困惑。我這麼長時間的工作假設,如果一個時間戳被指定爲祖魯時間,java會照顧當地時間的偏移量。與Java時間解析混淆UTC

舉例說明。我目前在BST中有UTC +1的偏移量。考慮到這一點,我希望這個祖魯時間:

2016-09-12T13:15:17.309Z 

2016-09-12T14:15:17.309 

LocalDateTime解析之後。這是因爲我的默認系統時間設置爲BST,而上述時間戳(祖魯時間)指定它是UTC時間。

而是然而考慮這個示例:

 String ts = "2016-09-12T13:15:17.309Z"; 
     LocalDateTime parse = LocalDateTime.parse(ts, DateTimeFormatter.ISO_DATE_TIME); 
     System.out.println(parse); 

這將打印:

2016-09-12T13:15:17.309 

所以時間戳,解析爲一個LocalDateTime,不被識別爲UTC時間,而不是爲本地時間直接進行處理。 所以我想,也許我需要將其解析爲ZonedDateTime並專門將其轉換爲LocalDateTime以獲得正確的本地時間。有了這個測試:

 String ts = "2016-09-12T13:15:17.309Z"; 
     ZonedDateTime parse = ZonedDateTime.parse(ts, DateTimeFormatter.ISO_DATE_TIME); 
     System.out.println(parse); 
     System.out.println(parse.toLocalDateTime()); 

我得到的輸出:

2016-09-12T13:15:17.309Z 
2016-09-12T13:15:17.309 

兩個日期相同的輸出。

正確解析這是我能找到的唯一方法,就是:

String ts = "2016-09-12T13:15:17.309Z"; 
    Instant instant = Instant.parse(ts); // parses UTC 
    LocalDateTime ofInstant = LocalDateTime.ofInstant(instant, ZoneId.systemDefault()); 
    System.out.println(instant); 
    System.out.println(ofInstant); 

此打印:

2016-09-12T13:15:17.309Z 
2016-09-12T14:15:17.309 

這是正確的。

所以問題(S)是:

  • 應該不是Java的時間認識一個UTC時間戳,並將其解析到正確的系統默認?
  • 如何使用LocalDateTime#parse方法獲得正確的結果?
  • 現在我應該使用Instant來放棄所有的解析嗎?

的問題是,jersey/jackson的Java模塊時使用解析ISO格式和定期LocalDateTime#parse方法的時間戳。我意識到我的時代沒有關閉,因爲他們被視爲LocalTime,而事實上他們在祖魯時間。

回答

5

您誤解了LocalDateTime的用途。

引述類文檔:

甲日期 - 時間而不在​​ISO-8601的日曆系統,時區,例如{@code 2007-12-03T10:15:30}。

...

此課程不存儲或表示時區。相反,它是用於生日的日期的描述,結合在掛鐘上看到的當地時間。如果沒有附加信息(如偏移量或時區),它不能表示時間線上的瞬間。

所以它明確的目的只是代表日期和時間沒有時區。它的作用是而不是表示日期和時間在當地時區

因此,每次轉換隻會剝去時區。

因此,爲了您的目的,您需要一個ZonedDateTimeZoneId.systemDefault(),因爲您已經在第三個示例中使用過。

你的第二個例子,這可能是:

String ts = "2016-09-12T13:15:17.309Z"; 
ZonedDateTime parse = 
    ZonedDateTime.parse(ts, DateTimeFormatter.ISO_DATE_TIME) 
     .withZoneSameInstant(ZoneId.systemDefault()); 
System.out.println(parse); 
System.out.println(parse.toLocalDateTime()); 
+0

你的例子看起來像它會做我的例子3的即時對話。你是對的,我誤解了什麼LocalDateTime代表。呃.. timezones :)謝謝 – pandaadb

+0

啊,所以ZonedDateTime將時區識別爲「Z」,它自動解釋爲UTC(正是我想要的) - 是嗎? – pandaadb

+0

@pandaadb是的,這可能只是寫這個的另一種方式。 –

3

TL;博士

實施例:

Instant.parse("2016-09-12T13:15:17.309Z") 
     .atZone(ZoneId.of("Europe/London")) 
     .toString(); 

2016-09-12T14:15:17.309 + 01:00 [歐洲/倫敦]

Run in IdeOne.com

詳細

Answer by Krüske是正確的。你誤解了課堂上的意義。它確實是而不是代表特定地點的日期時間。恰恰相反,它不是而是代表一個實際的時刻。

我建議你想把Instant作爲你在java.time中的基本構建塊類。 Instant類表示UTC中時間軸上的一個時刻,分辨率爲nanoseconds(小數點後最多九(9)位數字)。

輸入字符串符合Instant類中默認使用的ISO 8601格式,用於解析和生成字符串表示。 Z最後是Zulu的縮寫,意思是UTC。不需要指定格式化模式。

Instant instant = Instant.parse("2016-09-12T13:15:17.309Z"); 

作爲一名程序員,您應該學會以UTC爲主要思想和工作。忘記你自己的時區。將UTC視爲一個真實的時間。將時區應用爲變體,並且只根據需要進行。

continent/region的格式指定一個proper time zone name,如America/MontrealAfrica/Casablanca,或Pacific/Auckland。切勿使用3-4字母縮寫,如BSTESTIST,因爲它們不是真正的時區,不是標準化的,甚至不是唯一的(!)。如果按BST您的意思是英國夏令時,那麼實際的時區名稱將是Europe/London。 java.time類將決定如何針對任何異常(包括夏令時(DST))進行調整。

ZoneId z = ZoneId.of("Europe/London"); 
ZonedDateTime zdt = instant.atZone(z); 

關於java.time

java.time框架是建立在Java 8和更高版本。這些類取代了日期時間類legacy,如java.util.Date,Calendar,& SimpleDateFormat

Joda-Time項目現在位於maintenance mode,建議遷移到java.time。請參閱Oracle Tutorial。並搜索堆棧溢出了很多例子和解釋。規格是JSR 310

從何處獲取java.time類?

ThreeTen-Extra項目與其他類擴展java.time。這個項目是未來可能增加java.time的一個試驗場。您可以在這裏找到一些有用的類,如Interval,YearWeek,YearQuartermore