Java does not have information about all IANA time zones

I'm trying to map the value from the front end to the zoneid class, as follows:

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

For most time zones, it works normally, but for some values, Java throws an exception:

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

However, according to IANA, it is a valid time zone: https://www.iana.org/time-zones

I'm considering using offsets for these time zones (only hard coded values), but I think there should be a more convenient way to solve this problem Is there any way to handle Java?

Other unsupported time zones:

> America / Punta_ Arenas > Asia / Atyrau > Asia / Famagusta > Asia / Yangon > EST > Europe / Saratov > HST > MST > ROC

My java version: "1.8.0_121" Java (TM) se runtime environment (version 1.8.0_121-b13) Java hotspot (TM) 64 bit server VM (version 25.121-b13, mixed mode)

Solution

I have used java 1.8 0_ 121 was tested and some areas were indeed missing

The most obvious solution is to update the version of Java - in Java 1.8 0_ 131, all areas above are available – except for 3-letter names (EST, HST, etc.), more is as follows

But I know that updating in a production environment is not as easy (or fast) as we think In this case, you can use tzupdater tool, which can update the time zone data of JDK without changing the Java version

The only detail is that zoneid is not applicable to 3-letter abbreviations (EST, HST, etc.) That's because these names are ambiguous and not standard

However, if you want to use them, you can use the mapping of custom IDs Zoneid with built-in map:

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

The problem is that choices used in the short_ IDS map is the same as any other option – arbitrary or even controversial If you want to use different areas for each abbreviation, just create your own 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

Of course, the only exceptions to three letter names are GMT and UTC, but in this case, it is best to use only zoneoffset UTC constant

If you cannot update the Java version or run the tzupdater tool, there is another (more difficult) alternative

You can extend Java time. zone. Zonerulesprovider class and create a provider that can create missing IDs Something like this:

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

Creating zonerules is the most complex part

One way is to get the latest IANA files and read them You can check the JDK source code to see how it creates zonerules (although I'm not sure if the file format in the JDK is exactly the same as that in IANA)

Anyway, this link explains how to read IANA files Then, you can check zonerules Javadoc to see how to map IANA information to Java classes In this answer, I created a very simple zonerules with only 2 conversion rules, so you can basically understand how to perform this operation

Then you need to register the provider:

ZoneRulesProvider.registerProvider(new MissingZonesProvider());

New areas will now be available:

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

There are other ways to use the provider (instead of registering) and check the Javadoc for more details In the same Javadoc, there are more details about how to correctly implement the region rule provider (my version above is very simple, and it may lack some details, such as the implementation of providerversions - it should use the provider's version as the key, not the region ID I'm working on)

Of course, once you update the Java version, you must discard this provider (because you cannot have 2 providers create a region with the same ID: if the new provider creates an existing ID, it will throw an exception when you try to register it)

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>