Java how to get list of time zone ID’s for the giv

2019-02-19 20:51发布

Is it possible to find the list of time zone ID's for a given time zone abbreviation? For example, for the abbreviation IST, the time zone ID's are Asia/Jerusalem, Asia/Kolkata and Europe/Dublin.

3条回答
beautiful°
2楼-- · 2019-02-19 21:18

Refer to Java 8 docs for ZoneDateTime api on oracle docs.

Link of a sample maven project on github implementing this method.

Implementation wise you can use the code below,

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();
查看更多
Luminary・发光体
3楼-- · 2019-02-19 21:27

@Ole V.V.'s answer already gives great and detailed information, like the fact that the 3-letter abbreviations (like IST or PST) are ambiguous and not standard, and you should prefer the long IANA timezones names (always in the format Continent/City, like Asia/Kolkata or Europe/Berlin).

But there's one tricky detail in that answer: it's taking January and July of 2018 as the base dates for winter and summer (so the abbreviation can be checked against standard and Daylight Saving periods). But it's not guaranteed that it'll take both winter and summer time for all cases, because timezones rules can change - just because a timezone has DST today, it doesn't mean it'll have it forever (the opposite is also true).

So, instead of picking some date/time and hope that all timezones have a DST change between them, the best approach is to get all the changes from the ZoneRules object - it contains all the transition dates (the moment when the offset changes for that timezone - due to DST start/end or because some government decided that their country will now be in another timezone).

It also covers the case where a timezone used an abbreviation in the past, but then changed to another, as I'm checking through all the timezone's changes history.

The code is very similar. The only difference is that, instead of using a fixed date (Jan/Jul 2018), I'm looking at all the transitions of the zone (and if a timezone has no transitions - which means it never had DST or any other changes - I get the current date). I also created a Set of String (as you want just the names, but you could store the ZoneId objects as well):

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

The output, in this case, will be the same:

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

Although this code looks more redundant (as it traverses through all the dates when a DST change occurred), it's more guaranteed to get all cases. If you look for a timezone that had DST in the past but it won't have in 2018 (or in any other arbitrary date you get), using this arbitrary date won't work. Only by checking all transitions you can be sure that all cases were covered.

One example: if instead of IST, I'd like to check the abbreviation AEDT (Australian Eastern Daylight Time).

Using @Ole V.V.'s code, I'll get:

[Australia/Sydney, Australia/Melbourne, Australia/Hobart, Australia/Victoria, Australia/ACT, Australia/Canberra, Australia/NSW, Australia/Tasmania, Australia/Currie]

Using my code, I'll get:

[Australia/Sydney, Australia/Brisbane, Australia/Melbourne, Australia/Queensland, Australia/Hobart, Australia/Victoria, Australia/ACT, Australia/Canberra, Australia/NSW, Australia/Tasmania, Australia/Currie, Australia/Lindeman]

Note the differences. One example is Australia/Brisbane, which had DST until the 90's, but now it doesn't (so it won't have it in 2018 as well). So, if you try to get AEDT (summer time) in 2018, this timezone won't be picked by @Ole V.V.'s code, because it won't have DST in 2018.

But I'm checking all the changes it had during history, no matter when it happened. This guarantees that I'm covering all cases.

PS: if you want to get the abbreviations that were valid in a specific date, then you can use @Ole V.V.'s code (just change the dates accordingly).


Another way (not easier) is to download the IANA Time Zone Database file and follow this tutorial to understand how to read the files (not trivial, IMO). Take, for example, the Dublin's entry:

# 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

You can see that IST is used for Europe/Dublin. Well, this is not the most straightforward way, but every time IANA updates its database, it takes some time for changes to be included in the JDK (although you can update just the timezone data if you want).

So, if you want the most up-to-date information, you can regularly check for updates in IANA's website.

查看更多
一夜七次
4楼-- · 2019-02-19 21:35

Interesting question. Since the abbreviations aren’t standardized, there cannot be an authoritative answer nor a bulletproof way to get such an answer. Off the top of my head I thought of two approaches:

  1. Get them from your JVM.
  2. Find them on the net.

Getting the zones from your 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);

This prints:

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

Some of these are just names for the same time zone, though. For example Eire has the same rules as Europe/Dublin. So a further filtering could be made if desired. You may use oneZoneId.getRules().equals(anotherZoneId.getRules()) to determine if two ZoneId objects have the same zone rules.

For abbreviation CST the list is even longer and has more synonyms:

[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]

One limitation of my approach is that some time zones are known by more than one name and therefore more than one three or four letter abbreviation. My code above catches only one of these.

Another limitation is that picking two dates like I do will never give you all possibilites in the past and the future, and may even miss some where I just don’t hit the right date. I have tried to pick one date where it is winter on the northern hemisphere and summer on the southern, and one where it is the other way around. This will cover most cases for the present, but you never know if there is a time zone or three where the transition don’t follow summer and winter as we know it. If you want better coverage, there are a couple of excellent suggestions in Hugo’s answer.

Get them from the Internet

The other answer is, of course, the one that your search has no doubt already brought up: such lists are public on the Internet. For example Wikipedia’s List of time zone abbreviations and Time Zone Abbreviations – Worldwide List on timeanddate.com. As expected, the two lists mentioned do not agree. For example, the latter knows two interpretations of ADT, the former only one. The latter list gives many synonym abbreviations and thereby illustrates my point above that each zone can have more than one abbreviation.

查看更多
登录 后发表回答