我怎样才能得到“电流"?ICU4J 中的 IANA 时区缩写贯穿整个时间? [英] How can I get the "current" IANA time zone abbreviation throughout time in ICU4J?

查看:21
本文介绍了我怎样才能得到“电流"?ICU4J 中的 IANA 时区缩写贯穿整个时间?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

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

使用纽约的简短示例:

import java.util.Date;导入 java.util.Locale;导入 com.ibm.icu.util.TimeZone;导入 com.ibm.icu.text.SimpleDateFormat;公共类测试{公共静态无效主(字符串 [] args){TimeZone zone = TimeZone.getTimeZone("America/New_York");SimpleDateFormat format = new SimpleDateFormat("zzz", Locale.US);format.setTimeZone(zone);//unix epoch 前一个月System.out.println(format.format(new Date(-2678400000L)));//GMT-5//在unix时代System.out.println(format.format(new Date(0L)));//美东时间}}

(我使用 ICU4J 55.1 运行,包括股票下载和使用 2015e 数据发布更新后的版本.)

我不清楚 ICU4J 是从 tz 数据还是从 CLDR 获得其缩写 - 我怀疑是后者,因为 tz 数据中没有任何内容表明此处存在差异.

它似乎也受语言环境的影响,我认为这是合理的 - 使用美国语言环境我可以看到 America/New_York 的 EST/EDT,但欧洲/伦敦什么都没有;在英国地区,我看到欧洲/伦敦的格林威治标准时间/英国夏令时,但美国/纽约没有:(

有没有办法说服 ICU4J 回退到 tz 缩写?在我非常具体的情况下,这就是我要寻找的.

更新

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

<块引用>

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

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

import static com.ibm.icu.text.TimeZoneNames.NameType.SHORT_STANDARD;导入 com.ibm.icu.text.TimeZoneNames;导入 com.ibm.icu.text.TimeZoneNames.NameType;导入 com.ibm.icu.util.ULocale;公共类测试{公共静态无效主(字符串 [] args){TimeZoneNames 名称 = TimeZoneNames.getTZDBInstance(ULocale.ROOT);1969 年 12 月长 = -2678400000L;//进入 Unix 时代 24 小时...1970 年一月长 = 86400000L;//空值System.out.println(names.getDisplayName("America/New_York", SHORT_STANDARD, december1969));//美东时间System.out.println(names.getDisplayName("America/New_York", SHORT_STANDARD, january1970));//空值System.out.println(names.getDisplayName("欧洲/伦敦", SHORT_STANDARD, december1969));//空值System.out.println(names.getDisplayName("欧洲/伦敦", NameType.SHORT_STANDARD, january1970));}}

鉴于在这一点上确实很少有间接性 - 我正在告诉 ICU4J 我想要什么 - 我怀疑是信息不可用:(

解决方案

追溯源代码以了解其工作原理,结果发现要查找显示名称,它会从区域名称中获取元区域的名称,然后日期,然后是元区域和类型,显示名称.

com.ibm.icu.impl.TZDBTimeZoneNames 是从 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";如果(mz.getSize()== 3){fromStr = mz.getString(1);toStr = mz.getString(2);}长从,到;from = parseDate(fromStr);to = parseDate(toStr);mzMaps.add(new MZMapEntry(mzid, from, to));}

(来源)

如您所见,它具有将返回的 tofrom 值的硬编码值(尽管它读取 to并且 from 来自资源包本身,当元区域条目有三个项目时,大多数都没有 - 正如实际的 meta 区域文件 构建捆绑包的人 - 以及那些这样做的人也没有'from' 日期在 1970 年 1 月之前.)

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

I'm currently trying to write a suite of time zone validation programs to see whether various platforms interpret the IANA time zone data.

The output format I'm targeting includes the abbreviation in effect for a particular time - such as "BST" for "British Summer Time", or "PST" for "Pacific Standard Time".

On most platforms, this is easy - but ICU4J seems not to be working, oddly. According to the SimpleDateFormat documentation I should be able to use a pattern of "zzz" to get what I'm looking for, but this seems to fall back to the "O" pattern of GMT+X for a lot of the time. For some time zones, there are no abbreviations at all.

Short example using New York:

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
    }
}

(I'm running using ICU4J 55.1, both the stock download and after updating it with the 2015e data release.)

It's not clear to me whether ICU4J is getting its abbreviations from the tz data or from CLDR - I suspect it's the latter, given that there's nothing in the tz data to suggest a difference here.

It also seems to be affected by locale, which I suppose is reasonable - using the US locale I can see EST/EDT for America/New_York, but nothing for Europe/London; with the UK locale I see GMT/BST for Europe/London, but nothing for America/New_York :(

Is there a way to persuade ICU4J to fall back to tz abbreviations? In my very specific case, that's all I'm looking for.

Update

Thanks to RealSkeptic's comments, it looks like TimeZoneNames is a cleaner way of getting this data without formatting. It all sounds so promising - there's even TimeZoneNames.getTZDBInstance:

Returns an instance of TimeZoneNames containing only short specific zone names (TimeZoneNames.NameType.SHORT_STANDARD and TimeZoneNames.NameType.SHORT_DAYLIGHT), compatible with the IANA tz database's zone abbreviations (not localized).

That's pretty much exactly what I want - but that doesn't go earlier than 1970 either in most cases, nor does it include all the relevant data:

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));
    }
}

Given that there's really very little indirection at this point - I'm telling ICU4J exactly what I want - my suspicion is that the information just isn't available :(

解决方案

Tracing through the sources to see how this works, it turns out that to find the display name, it gets the name of the meta zone from the zone name and the date, and then, from the meta zone and the type, the display name.

com.ibm.icu.impl.TZDBTimeZoneNames, which is the class returned from TimeZoneNames.getTZDBInstance(ULocale), implements getMetaZoneID(String,Long) by calling com.ibm.icu.impl.TimeZoneNamesImpl._getMetaZoneID(String,long), which retrieves the mappings from the given time zone name to meta zone names, and then checks if the date is between the from and to parameters in any of those mappings.

The mapping is read by a nested class, like this:

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));
}

(source)

As you can see, it has hard-coded values for the to and from values it will return (although it reads the to and from from the resource bundle itself when the meta zone entry has three items, most of them don't - as can be seen in the actual meta zone file from which the bundle is built - and those who do, also do not have 'from' dates before January 1970.)

Thus, the meta zone ID will be null for any date before January 1970, and in turn, so will the display name.

这篇关于我怎样才能得到“电流"?ICU4J 中的 IANA 时区缩写贯穿整个时间?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆