Java 根据UTC偏移量查找地区名

Java 根据UTC偏移量查找地区名,给定某个 UTC 偏移量时,用户希望查找 ISO 8601 标准定义的地区名,可以根据给定的偏移量,筛选所有可用的时区 ID。尽管“东部夏令时”(Eastern Daylight Time)和“印度标准时间”(Indian Standard Time)这样的时区名已广为人知,但它们并非 ISO 官方名称,其缩写“EDT”和“IST”在某些情况下甚至不是唯一的。

Java 根据UTC偏移量查找地区名 问题描述

给定某个 UTC 偏移量时,用户希望查找 ISO 8601 标准定义的地区名。

Java 根据UTC偏移量查找地区名 解决方案

根据给定的偏移量,筛选所有可用的时区 ID。

Java 根据UTC偏移量查找地区名 具体实例

尽管“东部夏令时”(Eastern Daylight Time)和“印度标准时间”(Indian Standard Time)这样的时区名已广为人知,但它们并非 ISO 官方名称,其缩写“EDT”和“IST”在某些情况下甚至不是唯一的。ISO 8601 标准采用以下两种方式定义时区 ID。

  • 根据地区名(region name),如“America/Chicago”。

  • 根据以小时和分为单位的 UTC 偏移量(UTC offset),如“+05:30”。

那么,如何根据给定的 UTC 偏移量获取相应的地区名呢?对于任意给定的时间,虽然许多地区的 UTC 偏移量相同,但在给定偏移量的情况下,不难计算出相应的地区名列表。
ZoneOffset 类用于获取某个时区相对于格林尼治 /UTC 时间的偏移量。如果给定偏移量,也可以使用它筛选完整的地区名列表,如例 8-35 所示。

例 8-35 根据给定的偏移量,获取相应的地区名

public static List<String> getRegionNamesForOffset(ZoneOffset offset) {
    LocalDateTime now = LocalDateTime.now();
    return ZoneId.getAvailableZoneIds().stream()
                 .map(ZoneId::of)
                 .filter(zoneId -> now.atZone(zoneId).getOffset().equals(offset))
                 .map(ZoneId::toString)
                 .sorted()
                 .collect(Collectors.toList());
}

在本例中,ZoneId.getAvailableZoneIds 方法返回一个由字符串构成的 List,每个字符串通过 ZoneId.of 方法映射到相应的 ZoneId。利用 LocalDateTime 类定义的 atZone 方法确定 ZoneId 对应的 ZonedDateTime 之后,就能得到所有 ZoneIdZoneOffset,并筛掉其中不匹配的 ZoneOffset。接下来,程序将结果映射到字符串、对字符串排序并将它们收集到 List 中。
反过来,如何获取 ZoneOffset 呢?一种方案是利用给定的 ZoneId,如例 8-36 所示。

例 8-36 根据给定的时区,获取相应的偏移量

public static List<String> getRegionNamesForZoneId(ZoneId zoneId) {
    LocalDateTime now = LocalDateTime.now();
    ZonedDateTime zdt = now.atZone(zoneId);
    ZoneOffset offset = zdt.getOffset();

    return getRegionNamesForOffset(offset);
}

上述代码适用于任何给定的 ZoneId
例 8-37 显示了如何获取与用户当前位置对应的地区名列表。

例 8-37 获取当前的地区名

@Test
public void getRegionNamesForSystemDefault() throws Exception {
    ZonedDateTime now = ZonedDateTime.now();
    ZoneId zoneId = now.getZone();
    List<String> names = getRegionNamesForZoneId(zoneId);

    assertTrue(names.contains(zoneId.getId()));
}

如果希望通过 GMT 偏移量(以小时和分为单位)获取地区名,也可以使用 ZoneOffset 类定义的 ofHoursMinutes 方法,如例 8-38 所示。

例 8-38 根据给定的偏移量(以小时和分为单位),获取地区名

public static List<String> getRegionNamesForOffset(int hours, int minutes) {
    ZoneOffset offset = ZoneOffset.ofHoursMinutes(hours, minutes);
    return getRegionNamesForOffset(offset);
}

如例 8-39 所示,我们编写几个测试,验证在给定偏移量的情况下,能否成功获取相应的地区名。

例 8-39 根据给定的偏移量,测试能否成功获取地区名

@Test
public void getRegionNamesForGMT() throws Exception {
    List<String> names = getRegionNamesForOffset(0, 0);
    assertTrue(names.contains("GMT"));
    assertTrue(names.contains("Etc/GMT"));
    assertTrue(names.contains("Etc/UTC"));
    assertTrue(names.contains("UTC"));
    assertTrue(names.contains("Etc/Zulu"));
}

@Test
public void getRegionNamesForNepal() throws Exception {
    List<String> names = getRegionNamesForOffset(5, 45);

    assertTrue(names.contains("Asia/Kathmandu"));
    assertTrue(names.contains("Asia/Katmandu"));
}

@Test
public void getRegionNamesForChicago() throws Exception {
    ZoneId chicago = ZoneId.of("America/Chicago");
    List<String> names = RegionIdsByOffset.getRegionNamesForZoneId(chicago);

    assertTrue(names.contains("America/Chicago"));
    assertTrue(names.contains("US/Central"));
    assertTrue(names.contains("Canada/Central"));
    assertTrue(names.contains("Etc/GMT+5") || names.contains("Etc/GMT+6"));
}

有关时区列表的详细信息,请参见维基百科。

赞(0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

Java 实例