2017-01-10 71 views
2

我來到以下好奇心: -爲什麼美國時區的三字母縮寫與夏時制不一致?

這可以用下面的代碼片段來說明:

System.out.println(
    TimeZone.getTimeZone("MST").hasSameRules(TimeZone.getTimeZone("GMT-7"))); 
System.out.println(
    TimeZone.getTimeZone("PST").hasSameRules(TimeZone.getTimeZone("America/Los_Angeles"))); 

輸出:

true 
true 

Ideone demo

而且我們可以證明使用的三個字母的縮寫,所獲得的時區美國的四個主要時區在夏令時使用方面存在不一致:

for (String id : Arrays.asList("EST", "CST", "MST", "PST")) { 
    TimeZone tz = TimeZone.getTimeZone(id); 
    System.out.printf("%s is %s; observes DST: %s%n", 
     id, tz.getDisplayName(false, TimeZone.LONG), tz.useDaylightTime()); 
} 

輸出:

EST is Eastern Standard Time; observes DST: false 
CST is Central Standard Time; observes DST: true 
MST is Mountain Standard Time; observes DST: false 
PST is Pacific Standard Time; observes DST: true 

Ideone demo

除了一個事實,即三個字母的縮寫最佳反正避免(在Javadoc說: 「不過,建議使用它們......」) ,這看起來很混亂,並且是一個很好的微妙的錯誤來源,你在或不期望在多個時區使用夏令時。

是否有這種行爲差異的原因?美國時區是否有微妙的屬性,這意味着這種行爲是可以預料的?

+0

我想,[Jon Skeet]的一個問題(http://stackoverflow.com/users/22656/jon-skeet)。 – Azodious

回答

2

首先要說的是:我們必須瞭解時區標識符與時區名稱之間的區別。通常「MST」或「PST代表(縮寫)區域名稱,並且應解釋爲不在夏令時狀態(後綴ST =標準時間)

但是,舊的Java版本使用名稱也作爲標識符,即,允許使用這些字符串作爲參數傳遞給工廠方法,如TimeZone.getTimeZone(...)這就把我們帶到了一個問題:?什麼是有效的標識符

區域數據的底層源(規則,而不是名稱)來源於IANA及其實際管理員Paul Eggert所維護的TZDB,它包含一個名爲northamerica的文件,在該文件中輸入後告訴我們MST是一個標識符,但不是PST(而不是PST8PDT)。

Zone EST  -5:00 - EST 
Zone MST  -7:00 - MST 
Zone HST  -10:00 - HST 
Zone EST5EDT  -5:00 US E%sT 
Zone CST6CDT  -6:00 US C%sT 
Zone MST7MDT  -7:00 US M%sT 
Zone PST8PDT  -8:00 US P%sT 

然而,Java仍使用 「PST」 作爲標識,太 - 通過硬連線老映射:

private static String[][] oldMappings = 
    { 
     { "ACT", "Australia/Darwin" }, 
     { "AET", "Australia/Sydney" }, 
     { "AGT", "America/Argentina/Buenos_Aires" }, 
     { "ART", "Africa/Cairo" }, 
     { "AST", "America/Anchorage" }, 
     { "BET", "America/Sao_Paulo" }, 
     { "BST", "Asia/Dhaka" }, 
     { "CAT", "Africa/Harare" }, 
     { "CNT", "America/St_Johns" }, 
     { "CST", "America/Chicago" }, 
     { "CTT", "Asia/Shanghai" }, 
     { "EAT", "Africa/Addis_Ababa" }, 
     { "ECT", "Europe/Paris" }, 
     { "IET", "America/Indiana/Indianapolis" }, 
     { "IST", "Asia/Kolkata" }, 
     { "JST", "Asia/Tokyo" }, 
     { "MIT", "Pacific/Apia" }, 
     { "NET", "Asia/Yerevan" }, 
     { "NST", "Pacific/Auckland" }, 
     { "PLT", "Asia/Karachi" }, 
     { "PNT", "America/Phoenix" }, 
     { "PRT", "America/Puerto_Rico" }, 
     { "PST", "America/Los_Angeles" }, 
     { "SST", "Pacific/Guadalcanal" }, 
     { "VST", "Asia/Ho_Chi_Minh" } 
    }; 

只是檢查JDK文件sun.util.calendar.ZoneInfoFile。所以「PST」被映射到America/Los_Angeles。 「PST8PDT」從TZDB中取代並映射到固定偏移量。那麼「MST」呢?在這裏你可以設置一個屬性如何解釋它,即布爾系統屬性「sun.timezone.ids.oldmapping」。它的默認值是「false」。同上述文件ZoneInfoFile還包含以下開關根據系統屬性的值:

private static void addOldMapping() { 
     for (String[] arrayOfString1 : oldMappings) { 
     aliases.put(arrayOfString1[0], arrayOfString1[1]); 
     } 
     if (USE_OLDMAPPING) { 
     aliases.put("EST", "America/New_York"); 
     aliases.put("MST", "America/Denver"); 
     aliases.put("HST", "Pacific/Honolulu"); 
     } else { 
     zones.put("EST", new ZoneInfo("EST", -18000000)); 
     zones.put("MST", new ZoneInfo("MST", -25200000)); 
     zones.put("HST", new ZoneInfo("HST", -36000000)); 
     } 
} 

IBM還寫an article關於這個主題。所有這些古怪只是爲了向後兼容,應該由用戶避免。

+0

謝謝@Meno,這是一個非常徹底的答案。 –