草庐IT

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

coder 2024-03-28 原文

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

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

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

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

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

Zone America/Punta_Arenas -4:43:40 - LMT 1890

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

不支持的其他时区:

  • 美国/蓬塔阿雷纳斯
  • 亚洲/阿特劳
  • 亚洲/法马古斯塔
  • 亚洲/仰光
  • 东部标准时间
  • 欧洲/萨拉托夫
  • 高铁
  • 山顶
  • 中华民国

我的 Java 版本:“1.8.0_121”Java(TM) SE 运行时环境(内部版本 1.8.0_121-b13)Java HotSpot(TM) 64 位服务器虚拟机(内部版本 25.121-b13,混合模式)

最佳答案

我已经用 Java 1.8.0_121 测试过,有些区域确实缺失了。

修复它的最明显方法是更新 Java 版本 - 在 Java 1.8.0_131 中,上述所有区域都可用 - 除了 3 个字母的名称(ESTHST 等),更多内容见下文。

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


唯一的细节是 ZoneId 不适用于 3 字母缩写(ESTHST 等)。那是因为这些名字是 ambiguous and not standard .

不过,如果您想使用它们,您可以使用自定义 ID 的映射。 ZoneId 带有内置 map :

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

问题是 choices used in the SHORT_IDS map就像任何其他选择一样,是武断的,甚至是有争议的。如果您想为每个缩写使用不同的区域,只需创建您自己的 map :

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 字母名称的唯一异常(exception)当然是 GMTUTC,但在这种情况下最好只使用 ZoneOffset.UTC 常量。


如果您不能更新您的 Java 版本,也不能运行 TZUpdater 工具,还有另一种(更难)的替代方法。

您可以扩展 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;
    }
}

创建 ZoneRules 是最复杂的部分。

一种方法是获取最新的 IANA files并阅读它们。你可以看看JDK source code查看它如何从中创建 ZoneRules(尽管我不确定 JDK 中的文件是否与 IANA 文件的格式完全相同)。

无论如何,this link解释了如何阅读 IANA 的文件。那你可以看看ZoneRules javadoc了解如何将 IANA 信息映射到 Java 类。在 this answer我创建了一个非常简单的 ZoneRules,只有 2 个转换规则,因此您可以基本了解如何操作。

然后你需要注册提供者:

ZoneRulesProvider.registerProvider(new MissingZonesProvider());

现在新区域将可用:

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

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

当然,一旦您更新了 Java 版本,就必须丢弃该提供者(因为您不能让 2 个提供者创建具有相同 ID 的区域:如果新提供者创建一个已经存在的 ID,它会抛出异常当您尝试注册它时)。

关于Java 没有关于所有 IANA 时区的信息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45592878/

有关Java 没有关于所有 IANA 时区的信息的更多相关文章

  1. ruby-on-rails - Rails 常用字符串(用于通知和错误信息等) - 2

    大约一年前,我决定确保每个包含非唯一文本的Flash通知都将从模块中的方法中获取文本。我这样做的最初原因是为了避免一遍又一遍地输入相同的字符串。如果我想更改措辞,我可以在一个地方轻松完成,而且一遍又一遍地重复同一件事而出现拼写错误的可能性也会降低。我最终得到的是这样的:moduleMessagesdefformat_error_messages(errors)errors.map{|attribute,message|"Error:#{attribute.to_s.titleize}#{message}."}enddeferror_message_could_not_find(obje

  2. ruby - 如何以所有可能的方式将字符串拆分为长度最多为 3 的连续子字符串? - 2

    我试图获取一个长度在1到10之间的字符串,并输出将字符串分解为大小为1、2或3的连续子字符串的所有可能方式。例如:输入:123456将整数分割成单个字符,然后继续查找组合。该代码将返回以下所有数组。[1,2,3,4,5,6][12,3,4,5,6][1,23,4,5,6][1,2,34,5,6][1,2,3,45,6][1,2,3,4,56][12,34,5,6][12,3,45,6][12,3,4,56][1,23,45,6][1,2,34,56][1,23,4,56][12,34,56][123,4,5,6][1,234,5,6][1,2,345,6][1,2,3,456][123

  3. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  4. ruby - 难道Lua没有和Ruby的method_missing相媲美的东西吗? - 2

    我好像记得Lua有类似Ruby的method_missing的东西。还是我记错了? 最佳答案 表的metatable的__index和__newindex可以用于与Ruby的method_missing相同的效果。 关于ruby-难道Lua没有和Ruby的method_missing相媲美的东西吗?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/7732154/

  5. ruby-on-rails - rails 目前在重启后没有安装 - 2

    我有一个奇怪的问题:我在rvm上安装了ruby​​onrails。一切正常,我可以创建项目。但是在我输入“railsnew”时重新启动后,我有“程序'rails'当前未安装。”。SystemUbuntu12.04ruby-v"1.9.3p194"gemlistactionmailer(3.2.5)actionpack(3.2.5)activemodel(3.2.5)activerecord(3.2.5)activeresource(3.2.5)activesupport(3.2.5)arel(3.0.2)builder(3.0.0)bundler(1.1.4)coffee-rails(

  6. ruby - 在没有 sass 引擎的情况下使用 sass 颜色函数 - 2

    我想在一个没有Sass引擎的类中使用Sass颜色函数。我已经在项目中使用了sassgem,所以我认为搭载会像以下一样简单:classRectangleincludeSass::Script::FunctionsdefcolorSass::Script::Color.new([0x82,0x39,0x06])enddefrender#hamlengineexecutedwithcontextofself#sothatwithintemlateicouldcall#%stop{offset:'0%',stop:{color:lighten(color)}}endend更新:参见上面的#re

  7. java - 等价于 Java 中的 Ruby Hash - 2

    我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/

  8. ruby-on-rails - 跳过状态机方法的所有验证 - 2

    当我的预订模型通过rake任务在状态机上转换时,我试图找出如何跳过对ActiveRecord对象的特定实例的验证。我想在reservation.close时跳过所有验证!叫做。希望调用reservation.close!(:validate=>false)之类的东西。仅供引用,我们正在使用https://github.com/pluginaweek/state_machine用于状态机。这是我的预订模型的示例。classReservation["requested","negotiating","approved"])}state_machine:initial=>'requested

  9. ruby - Nokogiri 剥离所有属性 - 2

    我有这个html标记:我想得到这个:我如何使用Nokogiri做到这一点? 最佳答案 require'nokogiri'doc=Nokogiri::HTML('')您可以通过xpath删除所有属性:doc.xpath('//@*').remove或者,如果您需要做一些更复杂的事情,有时使用以下方法遍历所有元素会更容易:doc.traversedo|node|node.keys.eachdo|attribute|node.deleteattributeendend 关于ruby-Nokog

  10. ruby - 获取模块中定义的所有常量的值 - 2

    我想获取模块中定义的所有常量的值:moduleLettersA='apple'.freezeB='boy'.freezeendconstants给了我常量的名字:Letters.constants(false)#=>[:A,:B]如何获取它们的值的数组,即["apple","boy"]? 最佳答案 为了做到这一点,请使用mapLetters.constants(false).map&Letters.method(:const_get)这将返回["a","b"]第二种方式:Letters.constants(false).map{|c

随机推荐