正如指出的@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
老班(Date
,Calendar
和SimpleDateFormat
)有lots of problems和design 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通社亞洲/東京
這是一個微妙的差異,你必須選擇最適合你的情況的方法。請注意,關於hh
與HH
相同的問題在這裏也適用:變量nowTokyo
的值等於21:04:31(東京時間9:04:31 PM),但它的格式爲090431
- 沒有AM/PM標識符,這個時候是不明確的,所以IMO的模式應該使用HH
(所以輸出將是210431
)。但是由你來決定。
In the javadoc你可以看到所有可用模式的細節。
[您必須在幾個月內使用大寫的'M'](https://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html)。小寫'm'表示_minutes_ –
爲什麼不移除'Z'並手動連接名稱? – shmosel
您正在使用現在遺留的麻煩的舊日期時間類,由java.time類代替。 –