正如很多人已經說過的,ET
不是一個時區。它是一個常用的縮寫,指的是both EST and EDT(東部標準時間和東部夏令時間),但有more than one timezone that uses it。
短名稱(如EST
和EDT
)也不是時區,因爲這樣的縮寫是ambiguous and not standard。有more than one timezone that can use the same abbreviations。
理想的是使用IANA timezones names(總是格式爲Region/City
,如America/Sao_Paulo
或Europe/Berlin
)。 但是使用諸如EST
和ET
之類的短名稱是普遍和常見的,所以我們必須忍受它(並且還要做一些解決方法)。
的第一件事是到定義要爲ET
使用哪個時區(這將是一個非常隨意的選擇,但也沒有別的辦法,因爲ET
是模糊的)。在下面的示例中,我選擇了America/New_York
。您可以使用java.util.TimeZone
類(稱爲TimeZone.getAvailableIDs()
)查看所有可用時區的列表(並選擇最適合您需要的時區)。
使用java.text.DateFormatSymbols
類可以覆蓋SimpleDateFormat
使用的短名稱。所以,一個解決辦法是,當前的符號和覆蓋只是我們想要的時區:
SimpleDateFormat sdf = new SimpleDateFormat("MMM dd, yyyy, h:mm a z", Locale.ENGLISH);
// get current date symbols
String[][] zoneStrings = sdf.getDateFormatSymbols().getZoneStrings();
for (int i = 0; i < zoneStrings.length; i++) {
// overwrite just America/New_York (my arbitrary choice to be "ET")
if (zoneStrings[i][0].equals("America/New_York")) {
zoneStrings[i][2] = "ET"; // short name for standard time
zoneStrings[i][4] = "ET"; // short name for daylight time
break;
}
}
// create another date symbols and set in the formatter
DateFormatSymbols symbols = new DateFormatSymbols(Locale.ENGLISH);
symbols.setZoneStrings(zoneStrings);
sdf.setDateFormatSymbols(symbols);
String dateString = "Aug 15, 2017, 4:58 PM ET";
System.out.println(sdf.parse(dateString));
這將解析ET
爲America/New_York
,和所有其他現有的內置區將不會受到影響。
Check the javadoc有關DateFormatSymbols
的更多詳細信息。
另請注意,我使用了Locale.ENGLISH
,因爲月份名稱(Aug
)是英文的。如果我沒有指定區域設置,系統的默認值將被使用,並且不能保證永遠是英文的。即使它默認是正確的,即使在運行時也可以在沒有通知的情況下進行更改,所以最好使用明確的語言環境。
新的Java日期/時間API
如果您使用的是Java 8中,可以將這段代碼與new java.time API。這很容易,less bugged and less error-prone than the old SimpleDateFormat
and Calendar
APIs。
所有相關的類都在java.time
包中。您只需要定義首選區域的java.util.Set
並將其設置爲java.time.format.DateTimeFormatter
。然後你把它解析到java.time.ZonedDateTime
- 如果你還需要有java.util.Date
工作,你可以很容易地將其轉換:
// prefered zones
Set<ZoneId> preferredZones = new HashSet<>();
preferredZones.add(ZoneId.of("America/New_York"));
DateTimeFormatter fmt = new DateTimeFormatterBuilder()
// date and time
.appendPattern("MMM dd, yyyy, h:mm a ")
// zone (use set of prefered zones)
.appendZoneText(TextStyle.SHORT, preferredZones)
// create formatter (use English locale for month name)
.toFormatter(Locale.ENGLISH);
String dateString = "Aug 15, 2017, 4:58 PM ET";
// parse string
ZonedDateTime zdt = ZonedDateTime.parse(dateString, fmt);
// convert to java.util.Date
Date date = Date.from(zdt.toInstant());
夏令時發出
有一些極端情況。 America/New_York
時區has Daylight Saving Time (DST),所以當它開始和結束時,您可能會有意想不到的結果。
如果我當DST結束日期:
String dateString = "Nov 02, 2008, 1:30 AM ET";
凌晨2時許,鍾移1小時回凌晨1點,所以存在兩次凌晨1點和凌晨1:59。之間的本地時間(DST中和非DST偏移)。 DST結束(-05:00
),這樣的日期將等同於2008-11-02T01:30-05:00
後
SimpleDateFormat
將得到補償,而ZonedDateTime
將獲得前(-04:00
)偏移和日期將相當於2008-11-02T01:30-04:00
。
幸運的是,ZonedDateTime
有withLaterOffsetAtOverlap()
方法,它在DST結束後返回偏移量處的相應日期。所以你可以效仿SimpleDateFormat
的行爲來調用這個方法。
如果我當DST開始,雖然日期:
String dateString = "Mar 09, 2008, 2:30 AM ET";
凌晨2時許,鍾移着凌晨3點,所以不存在凌晨2點和凌晨2:59之間本地時間。在這種情況下,SimpleDateFormat
和ZonedDateTime
會將時間調整爲凌晨3:30,並使用DST偏移量(-04:00
) - 日期將相當於2008-03-09T03:30-04:00
。
'ET'不是時區。 「EDT」是東部夏令時,「EST」是東部標準時間。 –
是你的策略,因爲你不知道字符串是怎麼樣的?或者因爲你試圖找到哪一個工作? –
看來你應該用'EDT'來代替'ET'。 –