为什么美国时区的3个字母缩写与夏令时不一致?

时间:2017-01-10 10:55:30

标签: java timezone

我发现了以下好奇心: -

这可以通过以下代码段来演示:

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说"然而,他们的使用被弃用了......"),这看起来很混乱,而且微妙的错误的良好来源,你或不期望在多个时区使用夏令时。

是否存在这种行为差异的原因?是否存在美国时区的微妙属性,这意味着会出现这种行为?

1 个答案:

答案 0 :(得分:2)

首先要说:我们必须了解时区标识符和时区名称之间的差异。通常“MST”或“PST代表(缩写)区域名称,在夏令时状态下应解释为NOT(后缀ST =标准时间)。

但是,旧的Java版本(错误地)也将这些名称用作标识符,即允许将这些字符串用作工厂方法(如TimeZone.getTimeZone(...))的参数。这引出了一个问题:什么是有效的标识符?

区域数据的基础来源(规则,而非名称)源自TZDB,现在由IANA及其实际管理员Paul Eggert维护。它包含一个名为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。所有这些奇怪之处仅仅是为了向后兼容,用户应该避免使用。