Skip to content Skip to sidebar Skip to footer

Android TimeZone.getAvailableIDs() Producing Strange Strings

I have an Android application which uses TimeZone.getAvailableIDs() to pull all available timezone ID strings. These IDs are saved to an ArrayList, as per the following: ArrayList&

Solution 1:

Keep zones, rather than discard

As we can see in the list of time zone names on Wikipedia, the zones have changed and evolved over the years. Many of the entries are mere alias for other zones. And many were ill-conceived and are now deprecated.

I suggest that rather than focusing on zones to delete, you focus on zones to keep. The rest of this Answer shows how.

TimeZone.getAvailableIDs()

The TimeZone class was years ago supplanted by the java.time.ZoneId class. Never use the terrible legacy date-time zones such as TimeZone, Date, and Calendar.

List of continents

As a first step in getting a cleaned-up list, I suggest filtering for those names that begin with one of these continents:

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

And add an entry of Etc/UTC for when the user wants no time zone at all.

In Java code, sorted alphabetically.

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

I suggest you offer a two-step process for the user, where they suggest first a continent, then a zone.

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

Add that one entry for Etc/UTC.

mapGroupNameToZoneNames.computeIfAbsent( "Etc" , ( x -> new ArrayList <>() ) ).add( "UTC" );

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


About java.time

The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.

The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.

You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.

Where to obtain the java.time classes?


Post a Comment for "Android TimeZone.getAvailableIDs() Producing Strange Strings"