当前位置: 首页 > 知识库问答 >
问题:

Java 没有关于所有 IANA 时区的信息

乌杰
2023-03-14

我正在尝试将来自前端的值映射到ZoneId类,如下所示:

Optional.ofNullable(timeZone).map(ZoneId::of).orElse(null)

对于大多数时区,它工作正常,但是,对于某些值,Java 会抛出异常:

java.time.zone.ZoneRulesException: Unknown time-zone ID: America/Punta_Arenas

但是,根据https://www.iana.org/time-zones IANA,这是一个有效的时区

美洲/Punta_Arenas区 -4:43:40 - LMT 1890

我在考虑对这样的时区使用offset(只是为了硬编码值),但是我想应该有更方便的方法来解决这个问题。Java有办法解决这个问题吗?

不支持的其他时区:

  • 美洲/Punta_Arenas
  • 亚洲/阿特劳
  • 亚洲/法马古斯塔
  • 亚洲/仰光
  • 欧洲/萨拉托夫
  • 高铁
  • MST
  • 大鹏

我的Java版本:“1 . 8 . 0 _ 121”Java(TM)SE运行时环境(build 1 . 8 . 0 _ 121-B13)Java HotSpot(TM)64位服务器VM (build 25.121-b13,混合模式)

共有1个答案

甄伟兆
2023-03-14

我用Java 1.8.0_121测试过,有些区域真的不见了。

解决这个问题最明显的方法是更新Java的版本——在Java 1.8.0_131中,除了3个字母的名称(< code>EST、< code>HST,等等)之外,上面的所有区域都是可用的,下面将详细介绍。

但我知道生产环境中的更新并不像我们希望的那样容易(也不像我们想要的那么快)。在这种情况下,您可以使用 TZUpdater 工具,该工具可以在不更改 Java 版本的情况下更新 JDK 的时区数据。

唯一的细节是< code>ZoneId不支持3个字母的缩写(< code>EST、< code>HST等)。那是因为那些名字模棱两可,不规范。

但是,如果您想使用它们,您可以使用自定义ID的映射。< code>ZoneId带有内置地图:

ZoneId.of("EST", ZoneId.SHORT_IDS);

问题是,<code>SHORT_IDS</code>映射中使用的选项与任何其他选项一样,都是任意的,甚至是有争议的。如果您想为每个缩写使用不同的区域,只需创建自己的地图:

Map<String, String> map = new HashMap<>();
map.put("EST", "America/New_York");
... put how many names you want
System.out.println(ZoneId.of("EST", map)); // creates America/New_York

当然,3 个字母名称的唯一例外是 GMT 和 UTC,但在这种情况下,最好只使用 ZoneOffset.UTC 常量。

如果您既不能更新Java版本,也不能运行TZUpdater工具,还有另一种(更难的)选择。

您可以扩展<code>java.time.zone。ZoneRulesProvider类,并创建一个可以创建缺少ID的提供程序。大概是这样的:

public class MissingZonesProvider extends ZoneRulesProvider {

    private Set<String> missingIds = new HashSet<>();

    public MissingZonesProvider() {
        missingIds.add("America/Punta_Arenas");
        missingIds.add("Europe/Saratov");
        // add all others
    }

    @Override
    protected Set<String> provideZoneIds() {
        return this.missingIds;
    }

    @Override
    protected ZoneRules provideRules(String zoneId, boolean forCaching) {
        ZoneRules rules = null;
        if ("America/Punta_Arenas".equals(zoneId)) {
            rules = // create rules for America/Punta_Arenas
        }
        if ("Europe/Saratov".equals(zoneId)) {
            rules = // create rules for Europe/Saratov
        }
        // and so on

        return rules;
    }

    // returns a map with the ZoneRules, check javadoc for more details
    @Override
    protected NavigableMap<String, ZoneRules> provideVersions(String zoneId) {
        TreeMap<String, ZoneRules> map = new TreeMap<>();
        ZoneRules rules = provideRules(zoneId, false);
        if (rules != null) {
            map.put(zoneId, rules);
        }
        return map;
    }
}

创建Zone规则是最复杂的部分。

一种方法是获取最新的IANA文件并阅读它们。您可以查看JDK源代码,了解它如何从中创建Zone规则(尽管我不确定JDK中的文件是否与IANA文件的格式完全相同)。

无论如何,这个链接解释了如何读取IANA的文件。然后,您可以查看ZoneRulesjavadoc,了解如何将IANA信息映射到Java类。在这个答案中,我创建了一个非常简单的<code>ZoneRules</code>,只有两个转换规则,这样您就可以了解如何执行它。

然后您需要注册提供商:

ZoneRulesProvider.registerProvider(new MissingZonesProvider());

现在,新区域将可用:

ZoneId.of("America/Punta_Arenas");
ZoneId.of("Europe/Saratov");
... and any other you added in the MissingZonesProvider class

还有其他方法可以使用提供者(而不是注册),请查看javadoc以了解更多详细信息。在同一个javadoc中,还有关于如何正确实现区域规则提供程序的更多细节(我上面的版本非常简单,可能缺少了一些细节,比如provideVersions的实现——它应该使用提供程序的版本作为键,而不是像我这样使用区域ID等)。

当然,一旦您更新 Java 版本,就必须立即丢弃此提供程序(因为您不能有 2 个提供程序创建具有相同 ID 的区域:如果新提供程序创建的 ID 已存在,则当您尝试注册它时会引发异常)。

 类似资料:
  • 问题内容: 众所周知,C#提供了一个AS关键字,该关键字会自动执行一次检查,检查对象是否属于某种类型,如果是,则将其强制转换为所需的类型,否则给出null。 在上面的示例中,这里的Object obj可以是User类型或其他类型。用户将获得User类型的对象或null。这是因为C#的As关键字首先执行检查,然后在可能的情况下将对象强制转换为结果类型。 那么Java中有没有与C#的AS关键字等效的关

  • 我有一行代码: 当我这次尝试输出时,它返回: 然后我尝试格式化这个日期时间: 这让我想起: 这是错误的。这就像是在我的时区中减去6个小时,而不是加上它。为什么会这样?

  • 问题内容: 如何在Oracle中获取有关表,表的列和约束等的所有信息?我在用 但这只是给我列名称,空值和类型。 问题答案: 尝试dbms_metadata软件包,您可以在此处找到更多信息

  • 我一直在玩API、XAPI和OSM的天桥。但我无法获得所需的一些信息:获取街道的所有信息节点。 这里有一个例子:http://www.openstreetmap.org/browse/way/5671291 这提供了一种称为“瓦茨街”(在纽约)的方式的信息,但它不是所有的街道,只是其中的一部分。 另一部分:http://www.openstreetmap.org/browse/way/461163

  • 我使用JaCoCo进行代码覆盖。单元测试报告是用junit创建的,它们被正确地导入,因此单元测试信息被正确地显示出来。问题是,我得到了错误消息:没有关于每个测试覆盖率的信息。代码覆盖率显示单元测试、集成测试和整体覆盖率的值为0%。我检查了sonar项目中所有需要的信息,如二进制、src、测试等属性。 我使用的是:<br>-SonarQube 4.5.1<br>-SonarRunner 2.4<br

  • 本文向大家介绍关于IDEA git 只有Commit没有Push的问题,包括了关于IDEA git 只有Commit没有Push的问题的使用技巧和注意事项,需要的朋友参考一下 最近发现一个问题,是关于IDEA的一些骚操作的事儿~ 具体怎么回事,一起来看看。 我们都知道使用git分布式版本控制工具,提、拉 代码都会有一个本地暂存区,也就是本地仓。 这也就说我们的Commit提交到的是我们的本地仓库,