Java comment obtenir la liste des ID de fuseau horaire pour l'abréviation de fuseau horaire donnée


Est-il possible de trouver la liste des ID de fuseau horaire pour une abréviation de fuseau horaire donnée? Par exemple, pour l'abréviation IST, le fuseau horaire ID sont Asia/Jerusalem, Asia/Kolkata et Europe/Dublin.

Author: saikamesh, 2017-06-28

3 answers

Question intéressante. Étant donné que les abréviations ne sont pas standardisées, il ne peut y avoir de réponse faisant autorité ni de moyen à l'épreuve des balles d'obtenir une telle réponse. Du haut de ma tête, j'ai pensé à deux approches:

  1. Obtenez-les de votre JVM.
  2. Trouvez-les sur le net.

Obtenir les zones de votre JVM:

    String givenAbbr = "IST";
    LocalDateTime summerSouthernHemisphere = LocalDate.of(2018, Month.JANUARY, 31).atStartOfDay();
    LocalDateTime summerNorthernHemisphere = LocalDate.of(2018, Month.JULY, 31).atStartOfDay();
    DateTimeFormatter dtf = DateTimeFormatter.ofPattern("z");
    Set<ZoneId> zones = new HashSet<>();
    for (String id : ZoneId.getAvailableZoneIds()) {
        ZoneId zone = ZoneId.of(id);
        String abbr = summerSouthernHemisphere.atZone(zone).format(dtf);
        if (abbr.equals(givenAbbr)) {
            zones.add(zone);
        }
        abbr = summerNorthernHemisphere.atZone(zone).format(dtf);
        if (abbr.equals(givenAbbr)) {
            zones.add(zone);
        }
    }
    System.out.println(zones);

Ceci imprime:

[Asia/Calcutta, Eire, Europe/Dublin, Asia/Jerusalem, Asia/Tel_Aviv, Israel, Asia/Kolkata, Asia/Colombo]

Certains d'entre eux ne sont que des noms pour le même fuseau horaire, cependant. Par exemple, l'Eire a les mêmes règles que l'Europe/Dublin. Un filtrage supplémentaire pourrait donc être effectué si vous le souhaitez. Vous pouvez utiliser oneZoneId.getRules().equals(anotherZoneId.getRules()) pour déterminer si deux objets ZoneId ont les mêmes règles de zone.

Pour l'abréviation CST la liste est encore plus longue et a plus de synonymes:

[PRC, America/Matamoros, Asia/Taipei, America/Regina, America/El_Salvador,
        America/North_Dakota/New_Salem, Asia/Harbin, America/Costa_Rica,
        America/North_Dakota/Center, America/Guatemala, America/Winnipeg,
        Asia/Chongqing, America/Rankin_Inlet, America/Indiana/Knox,
        America/Belize, SystemV/CST6CDT, Mexico/General,
        America/North_Dakota/Beulah, CST6CDT, America/Swift_Current,
        America/Knox_IN, Asia/Chungking, Asia/Macao, Asia/Shanghai,
        America/Indiana/Tell_City, America/Menominee, America/Bahia_Banderas,
        America/Managua, Canada/East-Saskatchewan, Asia/Macau, America/Havana,
        America/Resolute, US/Central, US/Indiana-Starke, Cuba, America/Monterrey,
        America/Chicago, America/Merida, America/Mexico_City, Canada/Central,
        America/Tegucigalpa, America/Rainy_River, Canada/Saskatchewan, SystemV/CST6]

Une limitation de mon approche est que certains fuseaux horaires sont connus par plus d'un nom et donc plus d'une abréviation de trois ou quatre lettres. Mon code ci-dessus n'en attrape qu'un seul.

Une autre limitation est que choisir deux dates comme je le fais ne donnera jamais vous avez toutes les possibilités dans le passé et le futur, et peut même en manquer où je ne frappe pas la bonne date. J'ai essayé de choisir une date où c'est l'hiver sur l'hémisphère nord et de l'été sur la côte sud, et celui où il est dans l'autre sens. Cela couvrira la plupart des cas pour le moment, mais vous ne savez jamais s'il y a un fuseau horaire ou trois où la transition ne suit pas l'été et l'hiver tels que nous les connaissons. Si vous voulez une meilleure couverture, il y a quelques excellentes suggestions dans La réponse de Hugo .

Obtenez-les sur Internet

L'autre réponse est, bien sûr, celle que votre recherche a sans doute déjà soulevée: de telles listes sont publiques sur Internet. Par exemple, Liste Wikipedia des abréviations de fuseau horaire et Abréviations de fuseau horaire – Liste mondiale sur timeanddate.com . Comme prévu, les deux listes mentionnées ne sont pas d'accord. Par exemple, ce dernier connaît deux interprétations de l'ADT, la première une seule. La dernière liste donne de nombreuses abréviations synonymes et illustre ainsi mon point ci-dessus selon lequel chaque zone peut avoir plus d'une abréviation.

 3
Author: Ole V.V., 2017-06-29 06:08:13

@La réponse d'Ole V. V. donne déjà de grandes informations détaillées, comme le fait que les abréviations à 3 lettres (comme IST ou PST) sont ambiguës et non standard , et vous devriez préférer les noms longs des fuseaux horaires IANA (toujours au format Continent/City, comme Asia/Kolkata ou Europe/Berlin).

Mais il y a un détail délicat dans cette réponse: il prend janvier et juillet de 2018 comme dates de base pour l'hiver et l'été (donc l'abréviation peut être vérifiée périodes standard et heure d'été). Mais il n'est pas garanti que cela prendra à la fois l'heure d'hiver et l'heure d'été pour tous les cas, parce que les règles des fuseaux horaires peuvent changer - juste parce qu'un fuseau horaire a l'heure d'été aujourd'hui, cela ne signifie pas qu'il l'aura pour toujours (le contraire est également vrai).

Donc, au lieu de choisir une date / heure et d'espérer que tous les fuseaux horaires ont un changement DST entre eux, la meilleure approche est d'obtenir toutes les modifications de l'objet ZoneRules - il contient toute la transition dates (le moment où le décalage change pour ce fuseau horaire-en raison du début/de la fin de l'heure d'été ou parce qu'un gouvernement a décidé que son pays serait désormais dans un autre fuseau horaire).

Il couvre également le cas où un fuseau horaire a utilisé une abréviation dans le passé, mais a ensuite changé en un autre, car je vérifie l'historique de tous les changements du fuseau horaire.

Le code est très similaire. La seule différence est que, au lieu d'utiliser une date fixe (Jan / Juil 2018), je regarde toutes les transitions de la zone (et si un fuseau horaire n'a pas de transitions - ce qui signifie qu'il n'a jamais eu DST ou d'autres changements - j'obtiens la date actuelle). J'ai également créé un Set de String (comme vous voulez juste les noms, mais vous pouvez stocker le ZoneId objets):

String ist = "IST";
Set<String> zones = new HashSet<>();
// formatter to get the abbreviation
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("z");
for (String id : ZoneId.getAvailableZoneIds()) {
    ZoneId zone = ZoneId.of(id);
    ZoneRules rules = zone.getRules();
    List<ZoneOffsetTransition> transitions = rules.getTransitions();
    if (transitions.isEmpty()) {
        // no transitions found, just pick any date
        String abbrev = fmt.format(ZonedDateTime.now(zone));
        if (ist.equals(abbrev)) {
            zones.add(id);
        }
    } else {
        for (ZoneOffsetTransition transition : transitions) {
            // get the instant that the transition occurred and convert to this zone
            String abbrev = fmt.format(transition.getInstant().atZone(zone));
            if (ist.equals(abbrev)) {
                zones.add(id);
            }
        }
    }
}

System.out.println(zones);

La sortie, dans ce cas, sera la même:

[Asie / Calcutta, Eire, Europe / Dublin, Asie / Jérusalem, Asie / Tel_Aviv, Israël, Asie / Calcutta, Asie / Colombo]

Bien que ce code semble plus redondant (car il traverse toutes les dates où un changement d'heure d'été s'est produit), il est plus garanti d'obtenir tous les cas. Si vous recherchez un fuseau horaire qui avait l'heure d'été dans le passé mais qu'il ne l'aura pas en 2018 (ou dans toute autre date arbitraire que vous obtenez), l'utilisation de cette date arbitraire ne fonctionnera pas. Ce n'est qu'en vérifiant toutes les transitions que vous pouvez être sûr que tous les cas ont été couverts.

Un exemple: si au lieu de IST, je voudrais vérifier l'abréviation AEDT (Australian Eastern Daylight Time).

En utilisant le code de @Ole V. V., Je vais obtenir:

Il s'agit de l'un des plus grands noms de l'Australie-Occidentale et de l'Australie-Occidentale.]}

En utilisant mon code, je vais obtenir:

[Australie/Sydney, Australie/Brisbane, Australie/Melbourne, Australie/Queensland, Australie/Hobart, Australie/Victoria, Australie/ACT, Australie/Canberra, en Australie/nouvelle-galles du sud, l'Australie et la Tasmanie, Australie/Currie, Australie / Lindeman]

Notez les différences. Un exemple est Australia/Brisbane, qui avait DST jusqu'aux années 90, mais maintenant ce n'est pas le cas (donc il ne l'aura pas en 2018 aussi). Donc, si vous essayez d'obtenir AEDT (heure d'été) en 2018, ce fuseau horaire ne sera pas choisi par le code de @Ole V. V., car il n'aura pas d'heure d'été en 2018.

Mais je vérifie tous les changements qu'il a eu au cours de l'histoire, peu importe quand c'est arrivé. Cela garantit que je couvre tous les cas.

PS: si vous vous voulez obtenir les abréviations valides à une date spécifique, vous pouvez utiliser le code de @Ole V. V. (modifiez simplement les dates en conséquence).


Une autre façon (pas plus facile) est de télécharger le Fichier de base de données de fuseaux horaires IANAet de suivre ce tutoriel pour comprendre comment lire les fichiers (pas trivial, IMO). Prenez, par exemple, l'entrée de Dublin:

# Zone  NAME        GMTOFF  RULES   FORMAT  [UNTIL]
Zone    Europe/Dublin   -0:25:00 -  LMT 1880 Aug  2
            -0:25:21 -  DMT 1916 May 21  2:00 # Dublin MT
            -0:25:21 1:00   IST 1916 Oct  1  2:00s
             0:00   GB-Eire %s  1921 Dec  6 # independence
             0:00   GB-Eire GMT/IST 1940 Feb 25  2:00
             0:00   1:00    IST 1946 Oct  6  2:00
... etc

, Vous pouvez voir que IST est utilisé pour Europe/Dublin. Eh bien, ce n'est pas le moyen le plus simple, mais chaque le temps que l'IANA mette à jour sa base de données, il faut un certain temps pour que les modifications soient incluses dans le JDK (bien que vous puissiez mettre à jour uniquement les données du fuseau horaire si vous le souhaitez).

Donc, si vous voulez les informations les plus récentes, vous pouvez vérifier régulièrement les mises à jour sur le site Web de l'IANA.

 1
Author: , 2017-06-29 10:14:08

Référez-vous aux documents Java 8 pour Api ZoneDateTime sur oracle docs.

Lien d'un exemple de projet maven sur github implémentant cette méthode.

Mise en œuvre sage, vous pouvez utiliser le code ci-dessous,

ZoneId losAngeles = ZoneId.of("America/Los_Angeles");
ZoneId berlin = ZoneId.of("Europe/Berlin");

// 2014-02-20 12:00
LocalDateTime dateTime = LocalDateTime.of(2014, 02, 20, 12, 0);

// 2014-02-20 12:00, Europe/Berlin (+01:00)
ZonedDateTime berlinDateTime = ZonedDateTime.of(dateTime, berlin);

// 2014-02-20 03:00, America/Los_Angeles (-08:00)
ZonedDateTime losAngelesDateTime = berlinDateTime.withZoneSameInstant(losAngeles);

int offsetInSeconds = losAngelesDateTime.getOffset().getTotalSeconds(); // -28800

// a collection of all available zones
Set<String> allZoneIds = ZoneId.getAvailableZoneIds();
 -1
Author: Govind J, 2017-06-28 21:32:14