2017-10-04 93 views
2

我試圖讓輸出格式的日期(String):時區的Java時間格式

20170801 123030美洲/洛杉磯

但是使用這個代碼:

SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd hhmmss Z", Locale.US); 
sdf.setTimeZone(TimeZone.getTimeZone("America/Los_Angeles")); 
System.out.println(sdf.format(new java.util.Date())); 

我得到的輸出(注意該區域的部分):

20174904 024908 -0700

不知道如何解決它?我需要打印"​America/Los_Angeles"而不是"-0700"

+0

[您必須在幾個月內使用大寫的'M'](https://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html)。小寫'm'表示_minutes_ –

+0

爲什麼不移除'Z'並手動連接名稱? – shmosel

+2

您正在使用現在遺留的麻煩的舊日期時間類,由java.time類代替。 –

回答

4

如果你可以使用Java 8,您可以使用DateTimeFormatter及其代碼V來顯示區域ID:

Instant now = Instant.now(); 
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyyMMdd hhmmss VV") 
    .withLocale(Locale.US) 
    .withZone(ZoneId.of("America/Los_Angeles")); 
System.out.println(fmt.format(now)); 

打印:

20171004 032552美洲/洛杉磯

注意,在Alexandr's answer提到SimpleDateFormat不支持此標誌。

如果java.util.Date開始,但可以使用Java 8是,你可以將其轉換爲Instant第一:

Instant now = new java.util.Date().toInstant(); 
... 
+2

我懷疑那些'hh'應該是大寫'HH'。由於沒有上午/下午指標,我認爲我們可以假設24小時制。 –

+2

確實@Patty,請注意上面提到的'hh'和'HH'問題,以及在格式化程序中設置時區與不在[@ Hugo的詳細答案]中提到的時區之間的細微差別(https:/ /stackoverflow.com/a/46585345/396255)。這些差異取決於您的要求。 –

4

看起來像SimpleDateFormat不支持你想要的。

以下是可能的格式:

z Time zone General time zone Pacific Standard Time; PST; GMT-08:00 
Z Time zone RFC 822 time zone -0800 
X Time zone ISO 8601 time zone -08; -0800; -08:00 

您可以格式化的日期後,只需加上 「美國/洛杉磯」:

TimeZone timeZone = TimeZone.getTimeZone("America/Los_Angeles"); 
DateFormat sdf = new SimpleDateFormat("yyyyMMdd hhmmss", Locale.US); 
sdf.setTimeZone(timeZone); 
System.out.println(sdf.format(new Date()) + " " + timeZone.getID()); 

DateFormat sdfWithTimeZone = new SimpleDateFormat("yyyyMMdd hhmmss zzzz", Locale.US); 
sdfWithTimeZone.setTimeZone(timeZone); 
System.out.println(sdfWithTimeZone.format(new Date())); 

輸出:

20171004 031611 America/Los_Angeles 
20171004 031611 Pacific Daylight Time 
+1

您正在使用現在已經存在的麻煩的舊日期時間類,由java.time類代替。 –

4

正如指出的@Alexandr's answer,有一個在SimpleDateFormat沒有內置模式打印時區ID。但是有一種方法可以覆蓋這個。

首先您創建一個格式化程序,其中z模式對應於時區短名稱。 我不確定這個語言環境是否重要(我知道它影響長名稱,不確定短名稱,但無論如何我保留它)。

然後我從格式化的java.text.DateFormatSymbols並覆蓋對應於短名的字符串:

// use "z" (short timezone name) 
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd hhmmss z", Locale.US); 
sdf.setTimeZone(TimeZone.getTimeZone("America/Los_Angeles")); 

// get the java.text.DateFormatSymbols 
DateFormatSymbols symbols = sdf.getDateFormatSymbols(); 
// get the zones names 
String[][] zones = symbols.getZoneStrings(); 
// overwrite zone short names 
for (int i = 0; i < zones.length; i++) { 
    String zoneId = zones[i][0]; 
    if ("America/Los_Angeles".equals(zoneId)) { 
     zones[i][2] = zoneId; // short name for standard time 
     zones[i][4] = zoneId; // short name for Daylight Saving Time 
    } 
} 
// update the symbols in the formatter 
symbols.setZoneStrings(zones); 
sdf.setDateFormatSymbols(symbols); 

System.out.println(sdf.format(new java.util.Date())); 

這將打印:

20171005 045317美洲/洛杉磯

請注意,我僅更改了America/Los_Angeles時區的區域名稱。您可以修改if以更改所需的任何區域,或者僅刪除if以更改所有區域的區域。

另一個細節是,你使用hh幾個小時。 According to javadoc,這是小時am/pm字段(值從1到12)。沒有AM/PM指示符(模式a),輸出可能不明確。如果需要,您可以將其更改爲HH小時的日期字段,值從0到23)或kk(值從1到24)。


新的Java日期/時間API

老班(DateCalendarSimpleDateFormat)有lots of problemsdesign issues,他們正在被新的API取代。

如果您使用Java 8,請考慮使用new java.time API。這很容易,less bugged and less error-prone than the old APIs

如果您使用的是Java 6或7,則可以使用ThreeTen Backport,這是用於Java 8的新日期/時間類的一個很好的後端。而對於Android,您還需要ThreeTenABP(更多關於如何使用它here)。

下面的代碼適用於兩者。 唯一的區別是軟件包名稱(在Java 8中爲java.time,在ThreeTen Backport(或Android的ThreeTenABP)中爲org.threeten.bp),但類別和方法名稱是相同的。

實際上,這個新API非常直接,代碼與@Juan和@Jens發佈的其他答案完全相同。但是這些差異很微妙。

讓我們假設我有2個不同ZonedDateTime對象:一個代表America/Los_Angeles時區當前的日期/時間,和另一個代表相同的當前日期/時間Asia/Tokyo時區:

// current date/time 
Instant now = Instant.now(); 
// get the same instant in different timezones 
ZonedDateTime nowLA = now.atZone(ZoneId.of("America/Los_Angeles")); 
ZonedDateTime nowTokyo = now.atZone(ZoneId.of("Asia/Tokyo")); 
System.out.println(nowLA); // 2017-10-05T05:04:31.253-07:00[America/Los_Angeles] 
System.out.println(nowTokyo); // 2017-10-05T21:04:31.253+09:00[Asia/Tokyo] 

這些日期是:

2017-10-05T05:04:31.253-07:00 [America/Los_Angeles]
2017-10-05T21:04:31。253 + 09:00 [亞洲/東京]

現在讓我們來看看區別。 @Jens's answer在格式化程序中設置時區。這意味着所有的日期將在格式化時被轉換爲特定的時區(我剛剛修改了代碼一點點,直接設置的語言環境 - 而不是使用withLocale - 但由此產生的格式等效):

// set the timezone in the formatter 
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyyMMdd hhmmss VV", Locale.US) 
    // use Los Angeles timezone 
    .withZone(ZoneId.of("America/Los_Angeles")); 
// it converts all dates to Los Angeles timezone 
System.out.println(nowLA.format(fmt)); // 20171005 050431 America/Los_Angeles 
System.out.println(nowTokyo.format(fmt)); // 20171005 050431 America/Los_Angeles 

隨着時區被格式化設置,這兩個日期被轉換爲這個時區(包括日期和時間值):

20171005 050431美國/洛杉磯
20171005 050431美國/洛杉磯

雖然@Juan's answer,格式化沒有設置時區,這意味着它會保存在ZonedDateTime對象所使用的時區:

// formatter without a timezone set 
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyyMMdd hhmmss VV", Locale.US); 
// it keeps the timezone set in the date 
System.out.println(nowLA.format(fmt)); // 20171005 050431 America/Los_Angeles 
System.out.println(nowTokyo.format(fmt)); // 20171005 090431 Asia/Tokyo 

現在的時區被保留(以及日期和時間值):

20171005 050431美洲/洛杉磯
20171005 090431通社亞洲/東京

這是一個微妙的差異,你必須選擇最適合你的情況的方法。請注意,關於hhHH相同的問題在這裏也適用:變量nowTokyo的值等於21:04:31(東京時間9:04:31 PM),但它的格式爲090431 - 沒有AM/PM標識符,這個時候是不明確的,所以IMO的模式應該使用HH(所以輸出將是210431)。但是由你來決定。

In the javadoc你可以看到所有可用模式的細節。