Jon*_*eet 25 java timezone icu4j
我目前正在尝试编写一套时区验证程序,以查看各种平台是否解释了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
}
}
Run Code Online (Sandbox Code Playgroud)
(我正在使用ICU4J 55.1运行,包括库存下载和使用2015e数据发布更新后.)
我不清楚ICU4J是从tz数据还是从CLDR得到它的缩写 - 我怀疑它是后者,因为tz数据中没有任何东西可以暗示这里有所不同.
它似乎也受到语言环境的影响,我认为这是合理的 - 使用美国语言环境我可以看到美国/纽约的EST/EDT,但欧洲/伦敦没有; 在英国的地方,我看到欧洲/伦敦的GMT/BST,但美国/纽约没什么:(
有没有办法说服ICU4J回退到tz缩写?在我非常具体的情况下,这就是我正在寻找的.
更新
感谢RealSkeptic的评论,它看起来TimeZoneNames更简洁,无需格式化即可获取此数据.这听起来很有希望 - 甚至有TimeZoneNames.getTZDBInstance:
返回仅包含短特定区域名称(
TimeZoneNames.NameType.SHORT_STANDARD和TimeZoneNames.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));
}
}
Run Code Online (Sandbox Code Playgroud)
鉴于此时的间接真的很少 - 我正在告诉ICU4J我到底想要什么 - 我的怀疑是信息不可用:(
Rea*_*tic 15
通过源来查看它是如何工作的,结果是找到显示名称,它从区域名称和日期获得元区域的名称,然后从元区域和类型,显示名称获取.
com.ibm.icu.impl.TZDBTimeZoneNames,它是从中返回的类TimeZoneNames.getTZDBInstance(ULocale),getMetaZoneID(String,Long)通过调用实现com.ibm.icu.impl.TimeZoneNamesImpl._getMetaZoneID(String,long),它从给定的时区名称检索映射到元区域名称,然后检查日期是否在任何这些映射中的from和to参数之间.
映射由嵌套类读取,如下所示:
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));
}
Run Code Online (Sandbox Code Playgroud)
(来源)
正如您所看到的,它具有将返回的值to和from值的硬编码值(尽管当元区域条目有三个项目时,它会从资源包本身读取to和读取from,但大多数都没有 - 可以在构建捆绑包的实际元区域文件 - 以及那些在2001年1月之前也没有'from'日期的元区域文件.)
因此,元区域ID将null用于1970年1月之前的任何日期,反过来,显示名称也是如此.
| 归档时间: |
|
| 查看次数: |
1644 次 |
| 最近记录: |