2017-04-27 52 views
3

當字符串「2017-04-21T17:46:00Z」傳入第一個方法時,生成的格式化日期字符串爲「06:46 2017年4月21日」。爲什麼十一小時的時間移動?輸入字符串由JSON中的HTTP服務器應用程序提供。我認爲Z後綴是指祖魯語,即GMT。JodaTime時區爲什麼會改變日期時間?

private static final String DATE_TIME_FORMAT = "hh:mm dd MMM yyyy"; 

public static String formatTimestamp(String dateTimestamp) { 
    DateTime dateTime = getDateTimeFromTimestamp(dateTimestamp); 
    DateTimeFormatter fmt = DateTimeFormat.forPattern(DATE_TIME_FORMAT); 
    return fmt.print(dateTime); 
} 

private static DateTime getDateTimeFromTimestamp(String dateTimestamp) { 
    return new DateTime(dateTimestamp); 
} 

我懷疑它涉及時區,但它不清楚如何或在哪裏。該代碼在GMT時區的英國Android設備上運行。

+0

不會這項工作'返回新的SimpleDateFormat(DATE_TIME_FORMAT「)格式(dateTimestamp);' –

+0

什麼的System.out.println(DateTimeZone.getDefault())的'輸出;' – 2017-04-27 12:20:40

+0

? @Hugo「Europe/London」 –

回答

3

我做了一個測試用的Java 7和喬達時間2.7(而不是Android的版本)

這就是我怎麼能重現該問題:

// changing my default timezone (because I'm not in UK) 
DateTimeZone.setDefault(DateTimeZone.forID("Europe/London")); 
// calling your method 
System.out.println(formatTimestamp("2017-04-21T17:46:00Z")); 

輸出是

06:46 21 ABR 2017年

要檢查什麼是錯的,我已經ç忌用日期格式:

DATE_TIME_FORMAT2 = "hh:mm a dd MMM yyyy Z z zzzz"; 

a表示「上午或下午」,Z是時區偏移/ ID,z是時區「短」名稱和zzzz是時區「長」的名字。使用這種格式,輸出爲:

下午6時46分21 ABR 2017年+0100 BST英國夏令時間

所以創建的日期時間是下午6時,只需一個小時提前輸入的,而不是11小時如你所想(實際上,如果將格式更改爲HH而不是hh,則時間將爲18而不是06)。

另請注意,時區字段:+0100 BST British Summer Time。第一部分(+0100)表示此DateTime比格林威治標準時間提前1小時,而BST British Summer Time表示它在British's Daylight Saving Time


因此,有你的輸出等於你的投入,你有2種選擇:

1.更改默認的時區爲UTC:

DateTimeZone.setDefault(DateTimeZone.UTC); 
System.out.println(formatTimestamp("2017-04-21T17:46:00Z")); 

輸出將是:

05:46 2017年4月21日

如果你想改變的時間是17:46,更改日期格式,取代hh通過HH

2。使用DateTime構造函數接收一個DateTimeZone

private static DateTime getDateTimeFromTimestamp(String dateTimestamp) { 
    // creates a DateTime in UTC 
    return new DateTime(dateTimestamp, DateTimeZone.UTC); 
} 

輸出將是相同的1備選方案,但在這種情況下,你不需要更改默認的時區。

對於我來說,替代2更有意義,這是因爲:

  • 你不需要更改默認的時區(這可能會導致一些混亂在應用程序的其他部分)
  • 你已經知道由此代碼來處理所有日期爲UTC時間(because of the "Z" in the end
+1

謝謝你這樣一個詳細和明確的答案。正如你所說,指定UTC並使用24小時格式可以避免這些問題。 –

1

使用java.time

Answer by Hugo似乎是正確的和信息。但僅供參考,Joda-Time項目現在在maintenance mode,團隊建議遷移到java.time班。對於Android,請參閱下面底部的最後一個項目符號。

您的輸入字符串採用標準ISO 8601格式。在分析&生成字符串時,java.time類使用標準格式。所以不需要指定格式化模式。

Instant類表示UTC中的時間軸上的一個時刻,分辨率爲nanoseconds(最多九(9)位小數)。

String input = "2017-04-21T17:46:00Z" ; 
Instant instant = Instant.parse(input) ; 

instant.toString():2017-04-21T17:46:00Z

對於更靈活的格式如你的願望,轉換爲OffsetDateTime對象中,可以指定任何offset-from-UTC在幾小時和幾分鐘內。我們希望UTC本身(偏移量爲零),所以我們可以使用常量ZoneOffset.UTC

OffsetDateTime odt = instant.atOffset(ZoneOffset.UTC) ; 

odt.toString():2017-04-21T17:46Z

定義的格式設置模式以匹配所需的格式。請注意,您必須指定Locale來確定(a)翻譯日期名稱,月份名稱等的人類語言,以及(b)確定縮寫,大寫,標點,分隔符等問題的文化規範。

DateTimeFormatter f = DateTimeFormatter.ofPattern("hh:mm dd MMM yyyy" , Locale.US) ; 
String output = odt.format(f) ; 

輸出:05:46 2017年4月21日

如果你想通過一個區域的掛鐘時間的鏡頭,看這同一時刻,如Europe/LondonPacific/Auckland,申請時間區域獲得ZonedDateTime

continent/region的格式指定一個proper time zone name,如America/MontrealAfrica/Casablanca,或Pacific/Auckland。切勿使用3-4字母縮寫,例如ESTISTBST,因爲它們是而不是真正的時區,不是標準化的,甚至不是唯一的(!)。

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

請注意,由於夏令時(DST),每天的時間爲1小時。

zdt.toString():2017-04-21T18:46 + 01:00 [歐洲/倫敦]

見本code run live at IdeOne.com

關於java.time

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

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

從何處獲取java.time類?

相關問題