J'ai testé avec Java 1.8.0_121 et certaines zones sont vraiment manquantes. La manière la plus évidente de le réparer est de mettre à jour la version de Java - dans Java 1.8.0_131 toutes les zones ci-dessus sont disponibles - excepté les noms de 3 lettres (EST
, HST
, etc.), plus sur cela ci-dessous.
Mais je sais que les mises à jour dans les environnements de production ne sont pas aussi faciles (ni rapides) que nous le souhaiterions. Dans ce cas, vous pouvez utiliser le TZUpdater tool, qui peut mettre à jour les données de fuseau horaire de JDK sans modifier la version de Java.
Le seul détail est que ZoneId
ne fonctionne pas avec les abréviations 3 lettres (EST
, HST
et ainsi de suite). C'est parce que ces noms sont ambiguous and not standard. Cependant, si vous souhaitez les utiliser, vous pouvez utiliser une carte d'ID personnalisée. ZoneId
est livré avec une carte intégrée:
ZoneId.of("EST", ZoneId.SHORT_IDS);
Le problème est que le choices used in the SHORT_IDS
map sont - comme tout autre choix - arbitraire et même controversé.Si vous souhaitez utiliser différentes zones pour chaque abréviation, il suffit de créer votre propre carte:
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
Les seules exceptions pour les noms de 3 lettres sont, bien sûr, GMT et UTC, mais dans ce cas, il est mieux vaut simplement utiliser la constante ZoneOffset.UTC
.
Si vous ne pouvez pas mettre à jour votre version Java, ni exécuter l'outil tzupdater, il y a un autre (beaucoup plus difficile) alternative.
Vous pouvez étendre la classe java.time.zone.ZoneRulesProvider
et faire un fournisseur qui peut créer les ID manquants de. Quelque chose comme ça:
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;
}
}
Créer la ZoneRules
est la partie la plus compliquée.
Une façon est d'obtenir la dernière IANA files et les lire. Vous pouvez jeter un oeil à JDK source code pour voir comment il crée ZoneRules
de ce (même si je ne sais pas si le fichier qui est à l'intérieur est dans JDK exactement le même format que les fichiers de l'IANA).
Quoi qu'il en soit, explique comment lire les fichiers de l'IANA. Ensuite, vous pouvez jeter un oeil à ZoneRules
javadoc pour savoir comment mapper l'information de l'IANA aux classes Java. En this answer je crée un très simple ZoneRules
avec seulement 2 règles de transition, de sorte que vous pouvez avoir une idée de base de la façon de le faire.
Ensuite, vous devez enregistrer le fournisseur:
ZoneRulesProvider.registerProvider(new MissingZonesProvider());
Et maintenant les nouvelles zones seront disponibles:
ZoneId.of("America/Punta_Arenas");
ZoneId.of("Europe/Saratov");
... and any other you added in the MissingZonesProvider class
Il existe d'autres façons d'utiliser le fournisseur (au lieu de l'enregistrement), check the javadoc pour plus de détails. Dans le même javadoc il y a aussi plus de détails sur la manière d'implémenter un fournisseur de règles de zone (ma version est au-dessus très simple et probablement il manque quelques détails, comme la mise en œuvre de provideVersions
- il doit utiliser la version du fournisseur comme une clé, pas identifiant de zone comme je le fais, etc).
Bien sûr, ce fournisseur doit être supprimé dès que vous mettez à jour la version Java (car vous ne pouvez pas avoir 2 fournisseurs qui créent des zones avec le même ID: si le nouveau fournisseur crée un ID existant, il lance un exception lorsque vous essayez de l'enregistrer).
Quelle version de Java utilisez-vous exactement? la dernière mise à jour de Java 8? Les informations de fuseau horaire sont fréquemment mises à jour avec de nouvelles mises à jour Java, il est possible que vous utilisiez une version Java spécifique dans laquelle celle que vous référencez n'est pas définie. – Jesper
Je l'ai essayé avec Java 8 mise à jour 144 (actuellement la dernière version) et cela fonctionne comme prévu. – Jesper
version java "1.8.0_121" Environnement d'exécution Java (TM) SE (version 1.8.0_121-b13) Java serveur HotSpot (TM) 64 bits (version 25.121-b13, mode mixte) – dvelopp