我怎样才能获得"当前" ICU4J中IANA时区的缩写?

时间:2015-07-25 12:17:56

标签: java timezone icu4j

我目前正在尝试撰写suite of time zone validation programs以查看各种平台是否解释IANA time zone data

输出格式I&#m; m目标包括在特定时间内有效的缩写 - 例如" BST"为英国夏令时"或"太平洋标准时间"太平洋标准时间"。

在大多数平台上,这很容易 - 但奇怪的是,ICU4J似乎不起作用。根据{{​​3}},我应该可以使用" zzz"得到我正在寻找的东西,但这似乎又回到了" O"很多时候GMT + X的模式。对于某些时区,根本没有缩写。

使用纽约的简短例子:

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数据中没有任何建议这里有所不同。

它似乎也受到语言环境的影响,我认为这是合理的 - 使用美国语言环境我可以看到美国/纽约的EST / EDT,但欧洲/伦敦没有;在英国的地方,我看到欧洲/伦敦的GMT / BST,但美国/纽约没有:(

有没有办法说服ICU4J回退到tz缩写?在我非常具体的案例中,我正在寻找所有这些。

更新

感谢RealSkeptic的评论,看起来TimeZoneNames更简洁,无需格式化即可获取此数据。这听起来很有希望 - 甚至TimeZoneNames.getTZDBInstance

  

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

这几乎就是我想要的 - 但在大多数情况下,这并不早于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我到底想要什么 - 我怀疑这些信息是不可用的:(

1 个答案:

答案 0 :(得分:15)

通过搜索源来查看其工作原理,结果发现,要查找显示名称,它会从区域名称和日期获取元区域的名称,然后从元区域和类型中获取,显示名称。

TimeZoneNames.getTZDBInstance(ULocale),即从getMetaZoneID(String,Long)返回的类,通过调用com.ibm.icu.impl.TimeZoneNamesImpl._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

source

正如您所看到的,它具有将返回的tofrom值的硬编码值(尽管它从资源中读取nulllist = { ... }当元区域条目有三个项目时捆绑自己,其中大多数都没有 - 从构建软件包的实际meta zone file中可以看到 - 以及那些做过的,也没有&# 39;来自1970年1月之前的日期。)

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