如何在 ICU4J 中获取"current" IANA 时区缩写?



我目前正在尝试编写一套时区验证程序,以查看各种平台是否解释 IANA 时区数据。

我的目标输出格式包括特定时间的有效缩写 - 例如"BST"表示"英国夏令时",或"PST"表示"太平洋标准时间"。

在大多数平台上,这很容易 - 但奇怪的是,ICU4J似乎不起作用。根据SimpleDateFormat文档,我应该能够使用"zzz"模式来获取我正在寻找的内容,但这似乎在很多时候都回到了 GMT+X 的"O"模式。对于某些时区,根本没有缩写。

使用纽约的简短示例:

import java.util.Date;
import java.util.Locale;
import com.ibm.icu.util.TimeZone;
import com.ibm.icu.text.SimpleDateFormat;
public class Test {
    public static void main(String[] args) {
        TimeZone zone = TimeZone.getTimeZone("America/New_York");
        SimpleDateFormat format = new SimpleDateFormat("zzz", Locale.US);
        format.setTimeZone(zone);
        // One month before the unix epoch
        System.out.println(format.format(new Date(-2678400000L))); // GMT-5
        // At the unix epoch
        System.out.println(format.format(new Date(0L))); // EST
    }
}

(我正在使用ICU4J 55.1运行,无论是库存下载还是使用2015e数据发布更新后。

我不清楚 ICU4J 是从 tz 数据还是从 CLDR 获得缩写 - 我怀疑是后者,因为 tz 数据中没有任何内容表明这里有什么不同。

它似乎也受到区域设置的影响,我认为这是合理的 - 使用美国区域设置,我可以看到美国/New_York的 EST/EDT,但欧洲/伦敦什么都看不到;对于英国区域设置,我看到欧洲/伦敦的 GMT/BST,但美国/New_York :(

有没有办法说服ICU4J回退到tz缩写?在我的非常具体的情况下,这就是我正在寻找的全部内容。

更新

多亏了RealSkeptic的评论,看起来TimeZoneNames是一种无需格式化即可获取这些数据的更简洁的方法。这一切听起来都很有希望 - 甚至还有TimeZoneNames.getTZDBInstance

返回仅包含简短的特定区域名称(TimeZoneNames.NameType.SHORT_STANDARDTimeZoneNames.NameType.SHORT_DAYLIGHT(的 TimeZoneNames 实例,与 IANA tz 数据库的区域缩写(未本地化(兼容。

这几乎正是我想要的 - 但在大多数情况下,这也不会早于1970年,也不包括所有相关数据:

import static com.ibm.icu.text.TimeZoneNames.NameType.SHORT_STANDARD;
import com.ibm.icu.text.TimeZoneNames;
import com.ibm.icu.text.TimeZoneNames.NameType;
import com.ibm.icu.util.ULocale;
public class Test {
    public static void main(String[] args) {
        TimeZoneNames names = TimeZoneNames.getTZDBInstance(ULocale.ROOT);
        long december1969 = -2678400000L;
        // 24 hours into the Unix epoch...
        long january1970 = 86400000L;
        // null
        System.out.println(
            names.getDisplayName("America/New_York",  SHORT_STANDARD, december1969));
        // EST
        System.out.println(
            names.getDisplayName("America/New_York",  SHORT_STANDARD, january1970));
        // null
        System.out.println(
            names.getDisplayName("Europe/London",  SHORT_STANDARD, december1969));
        // null
        System.out.println(
            names.getDisplayName("Europe/London",  NameType.SHORT_STANDARD, january1970));
    }
}
鉴于目前几乎没有间接性 - 我

告诉ICU4J我想要的 - 我怀疑这些信息只是不可用:(

跟踪源代码以查看其工作原理,结果发现要查找显示名称,它从区域名称和日期中获取元区域的名称,然后从元区域和类型中获取显示名称。

com.ibm.icu.impl.TZDBTimeZoneNames 是从 TimeZoneNames.getTZDBInstance(ULocale) 返回的类,通过调用 com.ibm.icu.impl.TimeZoneNamesImpl._getMetaZoneID(String,long) 来实现getMetaZoneID(String,Long),它检索从给定时区名称到元区域名称的映射,然后检查日期是否介于这些映射中的任何一个中的fromto参数之间。

映射由嵌套类读取,如下所示:

for (int idx = 0; idx < zoneBundle.getSize(); idx++) {
    UResourceBundle mz = zoneBundle.get(idx);
    String mzid = mz.getString(0);
    String fromStr = "1970-01-01 00:00";
    String toStr = "9999-12-31 23:59";
    if (mz.getSize() == 3) {
        fromStr = mz.getString(1);
        toStr = mz.getString(2);
    }
    long from, to;
    from = parseDate(fromStr);
    to = parseDate(toStr);
    mzMaps.add(new MZMapEntry(mzid, from, to));
}

(来源(

如您所见,它具有to的硬编码值和它将返回from值(尽管当元区域条目有三个项目时,它会从资源包本身读取tofrom,其中大多数没有 - 如构建捆绑包的实际元区域文件所示 - 以及那些这样做的人, 也没有 1970 年 1 月之前的"开始"日期。

因此,元区域 ID 将null 1970 年 1 月之前的任何日期,反过来,显示名称也将如此。

相关内容

  • 没有找到相关文章

最新更新