我有一个 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
类取代。切勿使用糟糕的旧版日期时间类,例如 TimeZone
、Date
和 Calendar
。
各大洲列表
作为获取清理列表的第一步,我建议过滤那些以这些大陆之一开头的名称:
- 欧洲
- 非洲
- 南极洲
- 大西洋
- 美国
- 太平洋
- 印度
- 澳大利亚
当用户根本不需要时区时,添加 Etc/UTC
条目。
在 Java 代码中,按字母顺序排序。
List < String > zoneGroupNames = List.of(
"Africa" ,
"Antarctica" ,
"Atlantic" ,
"America" ,
"Australia" ,
"Europe" ,
"Indian" ,
"Pacific" ,
"UTC"
);
我建议您为用户提供一个两步流程,他们首先建议一个大陆,然后建议一个区域。
区域组名称到区域名称的多重映射
构建 Map
每个区域组名称到区域 ID 名称的集合。我们需要一个组名称(例如 Europe
)到区域名称列表(例如 Europe/Berlin
、Europe/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 SE 8 , Java SE 9 , Java SE 10 , Java SE 11以及更高版本 - 具有 bundle 实现的标准 Java API 的一部分。
- Java 9 添加了一些小功能和修复。
- Java SE 6和 Java SE 7
- 大多数 java.time 功能已向后移植到 ThreeTen-Backport 中的 Java 6 和 7 .
- Android
- Android 的更高版本 bundle 了 java.time 类的实现。
- 对于早期的 Android (<26),ThreeTenABP项目适应ThreeTen-Backport (上文提到的)。请参阅How to use ThreeTenABP… .
关于java - Android TimeZone.getAvailableIDs() 产生奇怪的字符串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27949230/