TimeZones in Java

后端 未结 9 1321
执念已碎
执念已碎 2020-12-03 07:19

I am allowing users on my web app to schedule events based on time zones of their choice.

I want to present a good list of time zones to the end user and then conver

相关标签:
9条回答
  • 2020-12-03 07:28

    Just to complement the answer by tbruyelle I added a few more countries (e.g. Canada), removed the "/" portion of the filter and provided a means to sort the list.

    public static void main(String[] args)
    {
        List<String> simplifiedTimezoneList = getTimezoneIdList();
    
        for (String tz : simplifiedTimezoneList)
            System.out.println(tz);
    }
    
    public static List<String> getTimezoneIdList()
    {
        String[] temp = TimeZone.getAvailableIDs();
        List<String> timezoneList = new ArrayList<String>();
        List<String> simplifiedTimezoneList = new ArrayList<String>();
        for (String tz : temp)
        {
            timezoneList.add(tz);
        }
        Collections.sort(timezoneList);
        String filterList = "Canada|Mexico|Chile|Cuba|Brazil|Japan|Turkey|Mideast|Africa|America|Asia|Atlantic|Australia|Europe|Indian|Pacific";
        Pattern p = Pattern.compile("^(" + filterList + ").*");
        for (String tz : timezoneList)
        {
            Matcher m = p.matcher(tz);
            if (m.find())
            {
                simplifiedTimezoneList.add(tz);
            }
        }
        return simplifiedTimezoneList;
    }
    
    0 讨论(0)
  • 2020-12-03 07:30

    ZoneId

    The TimeZone class is now legacy, supplanted years ago by the modern java.time classes defined in JSR 310. Specifically replaced by java.time.ZoneId.

    Most of the currently used time zones are in the name format of Continent/Region. See a sortable list at Wikipedia.

    Get a list of all the time zone names.

        Set<String> zoneIds = ZoneId.getAvailableZoneIds() ;
        System.out.println( "zoneIds = " + zoneIds );
    

    See a distinct list of those prefixes.

        zoneIds.stream().map( s -> s.split( "/" )[0] ).collect( Collectors.toSet()).stream().forEach( System.out::println );
    

    As mentioned in the Answer by tbruyelle, one way to narrow the list for presentation to the user is to filter on that Continent portion. Of those, I would guess it best to focus on:

    • Europe
    • Africa
    • Antarctica
    • Atlantic
    • America
    • Pacific
    • Indian
    • Australia

    …plus add Etc/UTC.

    In Java code, sorted alphabetically.

    List < String > zoneGroupNames = List.of(
            "Africa" ,
            "Antarctica" ,
            "Atlantic" ,
            "America" ,
            "Australia" ,
            "Europe" ,
            "Indian" ,
            "Pacific" ,
            "UTC"
    );
    

    Multimap of zone group name to zone names

    Build a Map of each zone group name to collection of zone id names. We need a map of the group name such as Europe to a list of the zone names such as Europe/Berlin, Europe/London, and Europe/Malta.

    Map < String, List < String > > mapGroupNameToZoneNames = new TreeMap <>();
    

    Mapping a key to a collection of values is known as a "multimap". We now have built-in multimap functionality with the Map implementations bundled with Java. Call Map::computeIfAbsent (see this Answer).

    Set < String > zoneIdStrings = ZoneId.getAvailableZoneIds();
    for ( String zoneIdString : zoneIdStrings )
    {
        String groupName = zoneIdString.split( "/" )[ 0 ];
        if ( zoneGroupNames.contains( groupName ) )
        {
            mapGroupNameToZoneNames.computeIfAbsent( groupName , ( x -> new ArrayList <>() ) ).add( zoneIdString );
        } // Else skip it.
    }
    
    System.out.println( "mapGroupNameToZoneNames = " + mapGroupNameToZoneNames );
    

    Present to user

    Present that list of groups to the user. Say the user selects item # 6 (index 5), which is currently Europe.

    String groupNameChosenByUser = zoneGroupNames.get( 5 ); // Europe
    List < String > zoneNamesOfGroup = mapGroupNameToZoneNames.get( groupNameChosenByUser );
    

    Present that list of zone names for that one group. Say the user selects item # 12 (index 11), which is currently Europe/Malta.

    String zoneNameChosenByUser = zoneNamesOfGroup.get( 11 );  // Malta
    

    Make a ZoneId object from the string of that zone name.

    ZoneId zoneIdChosenByUser = ZoneId.of( zoneNameChosenByUser );
    

    zoneIdChosenByUser.toString() = Europe/Malta

    0 讨论(0)
  • 2020-12-03 07:35

    I've just written a small Java utility that provides a list of Windows time zones (the zones in the time zone selection dialog in Windows), and their associated Java TimeZone objects. See https://github.com/nfergu/Java-Time-Zone-List

    This is based on the CLDR mappings at http://unicode.org/repos/cldr/trunk/common/supplemental/windowsZones.xml

    0 讨论(0)
  • 2020-12-03 07:36

    I did this for a company I don't own any of anymore, so can't provide code. The JVM on Windows comes with a file called tzmappings (look in C:\Program Files\Java\jre6\lib or similar) which maps Windows timezones to Java's zoneinfo-based Continent/City form.

    Unfortunately, the textual names in tzmappings are terrible, so you need to do a few minutes of tabulation. Open regedit and navigate to HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones. Under this is a key for each timezone on the machine; Windows 7 has about 90. Each key has a value called Display which is the textual name you want; look for the key itself in tzmappings to find the Java time zone identifier for each one.

    0 讨论(0)
  • 2020-12-03 07:46

    The list of timezones is very application and locale specific. Only you know what zones are most applicable to your users. We actually have different lists for different regions.

    Here is our list for US users for your reference,

        "Pacific/Midway",
        "US/Hawaii",
        "US/Alaska",
        "US/Pacific",
        "America/Tijuana",
        "US/Arizona",
        "America/Chihuahua",
        "US/Mountain",
        "America/Guatemala",
        "US/Central",
        "America/Mexico_City",
        "Canada/Saskatchewan",
        "America/Bogota",
        "US/Eastern",
        "US/East-Indiana",
        "Canada/Eastern",
        "America/Caracas",
        "America/Manaus",
        "America/Santiago",
        "Canada/Newfoundland",
        "Brazil/East",
        "America/Buenos_Aires",
        "America/Godthab",
        "America/Montevideo",
        "Atlantic/South_Georgia",
        "Atlantic/Azores",
        "Atlantic/Cape_Verde",
        "Africa/Casablanca",
        "Europe/London",
        "Europe/Berlin",
        "Europe/Belgrade",
        "Europe/Brussels",
        "Europe/Warsaw",
        "Africa/Algiers",
        "Asia/Amman",
        "Europe/Athens",
        "Asia/Beirut",
        "Africa/Cairo",
        "Africa/Harare",
        "Europe/Helsinki",
        "Asia/Jerusalem",
        "Europe/Minsk",
        "Africa/Windhoek",
        "Asia/Baghdad",
        "Asia/Kuwait",
        "Europe/Moscow",
        "Africa/Nairobi",
        "Asia/Tbilisi",
        "Asia/Tehran",
        "Asia/Muscat",
        "Asia/Baku",
        "Asia/Yerevan",
        "Asia/Kabul",
        "Asia/Yekaterinburg",
        "Asia/Karachi",
        "Asia/Calcutta",
        "Asia/Colombo",
        "Asia/Katmandu",
        "Asia/Novosibirsk",
        "Asia/Dhaka",
        "Asia/Rangoon",
        "Asia/Bangkok",
        "Asia/Krasnoyarsk",
        "Asia/Hong_Kong",
        "Asia/Irkutsk",
        "Asia/Kuala_Lumpur",
        "Australia/Perth",
        "Asia/Taipei",
        "Asia/Tokyo",
        "Asia/Seoul",
        "Asia/Yakutsk",
        "Australia/Adelaide",
        "Australia/Darwin",
        "Australia/Brisbane",
        "Australia/Sydney",
        "Pacific/Guam",
        "Australia/Hobart",
        "Asia/Vladivostok",
        "Asia/Magadan",
        "Pacific/Auckland",
        "Pacific/Fiji",
        "Pacific/Tongatapu",
    
    0 讨论(0)
  • 2020-12-03 07:47

    Couldn't you use a list of custom time zone IDs using "GMT +/- Hours" notation (skipping minutes)?

    (EDIT: With my first suggestion, daylight saving time transition is not automatic. To address this issue, you could first ask the user to select a GMT offset and then show a (linked) list of time zone IDs for the given offset using:

    public static String[] getAvailableIDs(int rawOffset) 
    

    This way, the user would be able choose his time zone in a shorter list (better for user experience) and benefit from daylight savings behavior.)

    0 讨论(0)
提交回复
热议问题