java - Android TimeZone.getAvailableIDs() 产生奇怪的字符串

标签 java android arraylist timezone baseadapter

我有一个 Android 应用程序,它使用 TimeZone.getAvailableIDs() 来提取所有可用的时区 ID 字符串。这些 ID 将保存到 ArrayList 中,如下所示:

ArrayList<String> clocks = new ArrayList<>();
String[] ids = TimeZone.getAvailableIDs();
Collections.addAll(clocks, ids);

此 ArrayList 稍后将用于使用我的自定义 BaseAdapter 填充 ListView。有一些条目信息不是特别丰富,我不希望它们出现在列表中,例如:

Etc/GMT+10
PST8PDT
NZ-CHAT

我添加了一个 for 循环来遍历所有条目并删除任何不需要的条目,目前我出于测试目的进行了以下检查:

String string = clocks.get(i);
String[] split = string.split("/");

if(string.equals("MST7MDT")) {
    clocks.remove(i);
}

if(string.contains("Etc/")) {
    clocks.remove(i);
}

if(split.length <= 1) {
    clocks.remove(i);
}

if(!string.contains("/")) {
    clocks.remove(i);
}

现在应该删除与“MST7MDT”相同的元素(事实并非如此)、任何包含“Etc/”的元素(仅删除大约一半的 Etc/example 元素)以及任何包含“Etc/”的元素(仅删除大约一半的 Etc/example 元素)不包含“/”的拆分应该执行相同的操作(并非全部都被删除)。我已经用 trim() 尝试过,但没有帮助。这似乎不是 remove(int) 的问题,我也尝试传递对象,但仍然没有任何结果。

任何帮助将不胜感激,还有其他人遇到过 TimeZone.getAvailableIDs() 结果的问题吗?我在这里错过了一些愚蠢的事情吗?

最佳答案

保留区域,而不是丢弃

正如我们在 list of time zone names on Wikipedia 中看到的那样多年来,这些区域已经发生了变化和发展。许多条目只是其他区域的别名。有些被证明是另一个区域的无意重复。而且许多都考虑不周,现在已被弃用。

我建议您不要关注要删除的区域,而是要关注要保留的区域。本答案的其余部分展示了如何操作。

TimeZone.getAvailableIDs()

TimeZone 类多年前已被 java.time.ZoneId 类取代。切勿使用糟糕的旧版日期时间类,例如 TimeZoneDateCalendar

各大洲列表

作为获取清理列表的第一步,我建议过滤那些以这些大陆之一开头的名称:

  • 欧洲
  • 非洲
  • 南极洲
  • 大西洋
  • 美国
  • 太平洋
  • 印度
  • 澳大利亚

当用户根本不需要时区时,添加 Etc/UTC 条目。

在 Java 代码中,按字母顺序排序。

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

我建议您为用户提供一个两步流程,他们首先建议一个大陆,然后建议一个区域。

区域组名称到区域名称的多重映射

构建 Map每个区域组名称到区域 ID 名称的集合。我们需要一个组名称(例如 Europe)到区域名称列表(例如 Europe/BerlinEurope/London)的映射,以及欧洲/马耳他

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

将键映射到值的集合称为“多重映射”。我们现在拥有内置的多重 map 功能以及与 Java bundle 在一起的 Map 实现。调用Map::computeIfAbsent (参见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 );

添加一个 Etc/UTC 条目。

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

呈现给用户

向用户呈现该组列表。假设用户选择项目 # 6(索引 5),当前为欧洲。

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

显示该组的区域名称列表。假设用户选择项目 # 12(索引 11),当前为 Europe/Malta

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

根据该区域名称的字符串创建一个 ZoneId 对象。

ZoneId zoneIdChosenByUser = ZoneId.of( zoneNameChosenByUser );

zoneIdChosenByUser.toString() = Europe/Malta


关于java.time

java.time框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧类 legacy日期时间类,例如 java.util.Date , Calendar , & SimpleDateFormat .

要了解更多信息,请参阅 Oracle Tutorial 。并在 Stack Overflow 上搜索许多示例和解释。规范为JSR 310 .

Joda-Time项目,现在位于 maintenance mode ,建议迁移到java.time类。

您可以直接与数据库交换java.time对象。使用JDBC driver符合JDBC 4.2或稍后。不需要字符串,不需要 java.sql.* 类。

从哪里获取java.time类?

关于java - Android TimeZone.getAvailableIDs() 产生奇怪的字符串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27949230/

相关文章:

java - 检查两个二维 boolean 数组在给定间隔内是否相等 : Java

ANDROID 导航组件 + BottomNavigationView 带backstack

android - 强制android相机分辨率

java - 将逗号分隔的字符串转换为尾随逗号分隔的数组列表

java - Java 中的锯齿状数组 : Converting char[][] and ArrayList<ArrayList<char>>

java - 迭代 fastutil 原始 ArrayList 的最佳实践,例如整数数组列表?

java - 用数字制作一个 X block

java - 使用Java方法添加用户元素多维数组

java - DoublyLinkedList 的 toString()

android - ListView 全 View