>我需要显示一个自定义活动,其中包含一个列表视图,按照以下格式显示所有时区:
ZoneID (UTC <+/-> hh:mm)
应对这些时区进行排序(类似于 Windows 中显示的时区设置),以便:
- 首先显示所有 UTC 负时区
- 接下来显示所有 UTC+00:00 时区
- 所有大于 UTC+00:00 的时区最后显示
我遇到了很多例子,但它们都在ZoneId
类中使用JDK 1.8(Android API级别26)。 这里和这里很少解释这样的例子。
我想要一些替代这些示例的方法,我可以在Android API Level 23或JDK 1.7中使用。
预期输出:
America/Thule (UTC-03:00)
America/Argentina/La_Rioja (UTC-03:00)
America/Belem (UTC-03:00)
America/Jujuy (UTC-03:00)
America/Bahia (UTC-03:00)
America/Goose_Bay (UTC-03:00)
America/Argentina/San_Juan (UTC-03:00)
America/Argentina/ComodRivadavia (UTC-03:00)
America/Argentina/Tucuman (UTC-03:00)
America/Rosario (UTC-03:00)
SystemV/AST4ADT (UTC-03:00)
America/Argentina/Buenos_Aires (UTC-03:00)
America/St_Johns (UTC-02:30)
Canada/Newfoundland (UTC-02:30)
America/Miquelon (UTC-02:00)
Etc/GMT+2 (UTC-02:00)
America/Godthab (UTC-02:00)
America/Noronha (UTC-02:00)
Brazil/DeNoronha (UTC-02:00)
Atlantic/South_Georgia (UTC-02:00)
Etc/GMT+1 (UTC-01:00)
Atlantic/Cape_Verde (UTC-01:00)
Africa/Dakar (UTC+00:00)
Africa/Bissau (UTC+00:00)
WET (UTC+00:00)
Etc/Greenwich (UTC+00:00)
Africa/Timbuktu (UTC+00:00)
Africa/Monrovia (UTC+00:00)
Europe/Bratislava (UTC+01:00)
Arctic/Longyearbyen (UTC+01:00)
Europe/Vatican (UTC+01:00)
Europe/Monaco (UTC+01:00)
Africa/Harare (UTC+02:00)
Europe/Tallinn (UTC+02:00)
使用java.util.TimeZone
列表并按偏移量对它们进行排序:
String[] ids = TimeZone.getAvailableIDs();
List<TimeZone> zones = new ArrayList<>();
for (String id : ids) {
zones.add(TimeZone.getTimeZone(id));
}
Collections.sort(zones, new Comparator<TimeZone>() {
// compare by the offset, reverse order
@Override
public int compare(TimeZone o1, TimeZone o2) {
return o1.getRawOffset() - o2.getRawOffset();
}});
然后打印此列表,使用 ID 和帮助程序方法来设置偏移量的格式:
public String formatOffset(int rawOffset) {
StringBuilder sb = new StringBuilder("UTC").append(rawOffset < 0 ? "-" : "+");
int secs = Math.abs(rawOffset) / 1000;
int hours = secs / 3600;
secs -= hours * 3600;
int mins = secs / 60;
sb.append(hours < 10 ? "0" : "").append(hours).append(":");
sb.append(mins < 10 ? "0" : "").append(mins);
return sb.toString();
}
for (TimeZone tz : zones) {
System.out.println(tz.getID() + " (" + formatOffset(tz.getRawOffset()) + ")");
}
输出将如下所示:
Etc/GMT+12 (UTC-12:00)
Etc/GMT+11 (UTC-11:00)
Pacific/Midway (UTC-11:00)
Pacific/Niue (UTC-11:00)
... lots of timezones
请注意,我没有包含"漂亮的选项卡"格式,这取决于您。
我还使用了getRawOffset
,它返回该区域的当前偏移量 - 检查 javadoc:https://docs.oracle.com/javase/7/docs/api/java/util/TimeZone.html#getRawOffset()
此方法不考虑夏令时更改或任何其他历史数据(例如过去使用不同偏移量的国家/地区 - 相信我,大多数国家/地区(如果不是全部国家/地区)在其历史记录中至少有一个偏移量更改)。要使用这些其他偏移量,您可以使用getOffset
方法,将引用日期/时间戳作为参数传递 - 有关详细信息,请查看 javadoc。
我还使用了getAvailableIDs
,它返回所有时区,但您可以过滤此列表以仅包含所需的区域。
但老实说,这个旧的API(java.util
的Date
、Calendar
、SimpleDateFormat
、TimeZone
等)真的很糟糕,有很多缺陷和烦人的错误,没有人值得再使用它们了。特别是今天,我们有更好的API。
在没有java.time
类(例如ZoneId
)的 API 级别中,您可以使用 ThreeTen 向后移植,如另一个答案中所述。然后,您可以按照找到的示例进行操作。
一个主要区别是,此 API 始终需要Instant
作为参考来获取偏移量 - 因为它会检查所有时区的历史数据,以了解在特定时刻使用的偏移量是多少(在下面的代码中,我使用的是当前时刻):
Set<String> availableZoneIds = ZoneId.getAvailableZoneIds();
List<ZoneId> timezones = new ArrayList<>();
for (String id : availableZoneIds) {
timezones.add(ZoneId.of(id));
}
// current instant
final Instant now = Instant.now();
Collections.sort(timezones, new Comparator<ZoneId>() {
// compare by offset in reverse order, use the Instant as a reference
@Override
public int compare(ZoneId o1, ZoneId o2) {
return o2.getRules().getOffset(now).compareTo(o1.getRules().getOffset(now));
}
});
for (ZoneId zone : timezones) {
ZoneOffset offset = zone.getRules().getOffset(now);
System.out.println(zone + " (UTC" + (offset.getTotalSeconds() == 0 ? "+00:00" : offset.toString()) + ")");
}
另请注意,ZoneOffset
类有一个很好的toString()
方法,该方法已经以正确的格式打印偏移量(除非它是零,它打印为Z
,但这并不难修复)。
作为另一个答案的补充,您可以使用格式化程序打印区域和偏移量:
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("VV '(UTC'xxx')'");
for (ZoneId zone : timezones) {
System.out.println(fmt.format(now.atZone(zone)));
}
它产生相同的输出:"VV"打印区域 ID,"xxx"打印偏移量。
只需获取 ThreeTenABP 并将其添加到您的 Android 项目中,即可使用 java.time 中的ZoneId
和其他好东西,java.time 是 Java 8 中出现的现代 Java 日期和时间 API,也被向后移植到 Java 6 和 7。
链接
- Java 规范请求 (JSR) 310,其中首次描述了
java.time
。 - ThreeTen Backport项目,将
java.time
向后移植到Java 6和7(JSR-310的ThreeTen)。 - ThreeTenABP,ThreeTen Backport 的安卓版
- 问:如何在Android项目中使用ThreeTenABP,并进行了非常详尽的解释。
使用 Joda-Time 的解决方案:
首先使用 DateTimeZone 类获取所有 ID,然后使用 DateTimeZone.getOffset(Instant) 方法对它们进行排序。DateTimeZone 考虑夏令时与 java.util 提供的 TimeZone.getrawOffset() 不同。
Set<String> availableIDs = DateTimeZone.getAvailableIDs();
List<DateTimeZone> dateTimezones = new ArrayList<>();
for (String id : availableIDs) {
dateTimezones.add(DateTimeZone.forID(id));
}
final Instant now = Instant.now();
Collections.sort(dateTimezones, new Comparator<DateTimeZone>() {
@Override
public int compare(DateTimeZone o1, DateTimeZone o2) {
return o1.getOffset(now)-o2.getOffset(now);
}
});
for (DateTimeZone dateTimeZone : dateTimezones) {
int offset = dateTimeZone.getOffset(now);
String out = String.format("%35s %s%n", dateTimeZone, " (" + formatOffset(offset) + ")");
System.out.printf(out);
}
formatOffset(int) 从上面的例子中重用。
链接:
链接到下载乔达时间