如何在 ICU4J 中获取整个时间的 "current" IANA 时区缩写?
How can I get the "current" IANA time zone abbreviation throughout time in ICU4J?
我目前正在尝试写 suite of time zone validation programs to see whether various platforms interpret the IANA time zone data。
我的目标输出格式包括在特定时间有效的缩写 - 例如 "BST" 表示 "British Summer Time",或 "PST" 表示 "Pacific Standard Time"。
在大多数平台上,这很容易 - 但奇怪的是,ICU4J 似乎无法正常工作。根据 SimpleDateFormat
documentation 我应该能够使用 "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 数据中没有任何迹象表明此处存在差异。
它似乎也受到区域设置的影响,我认为这是合理的 - 使用美国区域设置我可以看到 EST/EDT 用于 America/New_York,但没有用于 Europe/London;在英国语言环境中,我看到 GMT/BST 代表 Europe/London,但没有看到 America/New_York :(
有没有办法说服 ICU4J 退回到 tz 缩写?在我非常具体的情况下,这就是我要找的。
更新
感谢 RealSkeptic 的评论,看起来 TimeZoneNames
是一种无需格式化即可获取此数据的更简洁的方法。这一切听起来很有希望 - 甚至还有 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).
这几乎正是我想要的 - 但在大多数情况下都不会早于 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
,这是 class return 从 TimeZoneNames.getTZDBInstance(ULocale)
编辑而来,通过调用 com.ibm.icu.impl.TimeZoneNamesImpl._getMetaZoneID(String,long)
实现 getMetaZoneID(String,Long)
,它检索映射从给定的时区名称到元区域名称,然后检查日期是否在任何这些映射中的 from
和 to
参数之间。
映射由嵌套的 class 读取,如下所示:
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)
如您所见,它具有 to
和 from
的硬编码值,它将 return (尽管它读取 to
和 from
来自资源包本身,当元区域条目有三个项目时,它们中的大多数没有 - 正如构建包的实际 meta zone file 中所见 - 那些有的,也有没有 'from' 日期早于 1970 年 1 月。)
因此,对于 1970 年 1 月之前的任何日期,元区域 ID 都将是 null
,而显示名称也是如此。
我目前正在尝试写 suite of time zone validation programs to see whether various platforms interpret the IANA time zone data。
我的目标输出格式包括在特定时间有效的缩写 - 例如 "BST" 表示 "British Summer Time",或 "PST" 表示 "Pacific Standard Time"。
在大多数平台上,这很容易 - 但奇怪的是,ICU4J 似乎无法正常工作。根据 SimpleDateFormat
documentation 我应该能够使用 "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 数据中没有任何迹象表明此处存在差异。
它似乎也受到区域设置的影响,我认为这是合理的 - 使用美国区域设置我可以看到 EST/EDT 用于 America/New_York,但没有用于 Europe/London;在英国语言环境中,我看到 GMT/BST 代表 Europe/London,但没有看到 America/New_York :(
有没有办法说服 ICU4J 退回到 tz 缩写?在我非常具体的情况下,这就是我要找的。
更新
感谢 RealSkeptic 的评论,看起来 TimeZoneNames
是一种无需格式化即可获取此数据的更简洁的方法。这一切听起来很有希望 - 甚至还有 TimeZoneNames.getTZDBInstance
:
Returns an instance of TimeZoneNames containing only short specific zone names (
TimeZoneNames.NameType.SHORT_STANDARD
andTimeZoneNames.NameType.SHORT_DAYLIGHT
), compatible with the IANA tz database's zone abbreviations (not localized).
这几乎正是我想要的 - 但在大多数情况下都不会早于 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
,这是 class return 从 TimeZoneNames.getTZDBInstance(ULocale)
编辑而来,通过调用 com.ibm.icu.impl.TimeZoneNamesImpl._getMetaZoneID(String,long)
实现 getMetaZoneID(String,Long)
,它检索映射从给定的时区名称到元区域名称,然后检查日期是否在任何这些映射中的 from
和 to
参数之间。
映射由嵌套的 class 读取,如下所示:
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)
如您所见,它具有 to
和 from
的硬编码值,它将 return (尽管它读取 to
和 from
来自资源包本身,当元区域条目有三个项目时,它们中的大多数没有 - 正如构建包的实际 meta zone file 中所见 - 那些有的,也有没有 'from' 日期早于 1970 年 1 月。)
因此,对于 1970 年 1 月之前的任何日期,元区域 ID 都将是 null
,而显示名称也是如此。