【问题标题】:How to get ZoneId values from given ZoneOffset in Java? [duplicate]如何从 Java 中的给定 ZoneOffset 获取 ZoneId 值? [复制]
【发布时间】:2021-10-25 12:13:17
【问题描述】:

我正在尝试通过提供区域偏移来获取所有 zoneId,例如“GMT+2”作为字符串。但是,我不确定是否可以使用任何 Java 8+ 库。是否可以获得具有给定区域偏移量的所有区域 id 值?

java.time中有一个叫getAvailableZoneIds()的方法,但它不带offset参数。

【问题讨论】:

  • zoneIds 和 offsets 之间的关系并不是那么简单,因为 DST 和类似的转换。您想要所有曾有/有“GMT+2”偏移量的 zoneId,还是现在?
  • 链接问题演示了如何在给定时刻获取 zoneId 的偏移量
  • @Hulk 你是什么意思?
  • 好吧,accepted one 表明 zoneID.getRules().getOffset(instant); 在给定时刻产生偏移量(就像 deHaar 的 answer 在这里)。其他人添加了更多上下文和替代方式。请注意,结果将取决于给定的 Instant - 除了每年的 DST 转换之外,还会偶尔(每隔几年)创建新区域。
  • 如果我查询当前时间,我认为没有问题。有什么想法吗?

标签: java datetime timezone java-time timezone-offset


【解决方案1】:

如果您想要当前具有偏移量的区域,例如从 UTC +02:00 开始,您可以尝试通过 getAvailableZoneIds()getRules()getOffset(Instant instant) 过滤来收集区域名称(不是直接 ZoneId 对象)。后者需要一个参数来定义此方法所基于的时间点。
在这个例子中是 nowInstant.now():

public static void main(String[] args) throws Exception {
    // define the desired offset
    ZoneOffset plusTwo = ZoneOffset.ofHours(2);
    // collect all the zones that have this offset at the moment
    List<String> zonesWithPlusTwo = 
            ZoneId.getAvailableZoneIds()
                  .stream()
                  // filter by those that currently have the given offset
                  .filter(zoneId -> ZoneId.of(zoneId)
                                          .getRules()
                                          .getOffset(Instant.now())
                                          .equals(plusTwo))
                  .sorted()
                  .collect(Collectors.toList());
    // print the collected zones
    zonesWithPlusTwo.forEach(System.out::println);
}

今天,2021 年 8 月 25 日,输出为

Africa/Blantyre
Africa/Bujumbura
Africa/Cairo
Africa/Ceuta
Africa/Gaborone
Africa/Harare
Africa/Johannesburg
Africa/Khartoum
Africa/Kigali
Africa/Lubumbashi
Africa/Lusaka
Africa/Maputo
Africa/Maseru
Africa/Mbabane
Africa/Tripoli
Africa/Windhoek
Antarctica/Troll
Arctic/Longyearbyen
Atlantic/Jan_Mayen
CET
Egypt
Etc/GMT-2
Europe/Amsterdam
Europe/Andorra
Europe/Belgrade
Europe/Berlin
Europe/Bratislava
Europe/Brussels
Europe/Budapest
Europe/Busingen
Europe/Copenhagen
Europe/Gibraltar
Europe/Kaliningrad
Europe/Ljubljana
Europe/Luxembourg
Europe/Madrid
Europe/Malta
Europe/Monaco
Europe/Oslo
Europe/Paris
Europe/Podgorica
Europe/Prague
Europe/Rome
Europe/San_Marino
Europe/Sarajevo
Europe/Skopje
Europe/Stockholm
Europe/Tirane
Europe/Vaduz
Europe/Vatican
Europe/Vienna
Europe/Warsaw
Europe/Zagreb
Europe/Zurich
Libya
MET
Poland

编辑: 考虑到@BasilBorque 的评论,这里有一个示例方法,它采用两个参数,一个偏移量值和一个Instant 来计算:

public static List<String> getZones(int offsetHours, Instant base) {
    // create the offset
    ZoneOffset offset = ZoneOffset.ofHours(offsetHours);
    // collect all the zones that have this offset at the moment 
    return ZoneId.getAvailableZoneIds()
                 .stream()
                 // filter by those that currently have the given offset
                 .filter(zoneId -> ZoneId.of(zoneId)
                                         .getRules()
                                         .getOffset(base)
                                         .equals(offset))
                 .sorted()
                 .collect(Collectors.toList());
}

您可以创建一个局部变量(可能是类成员),以便将其传递给方法。这将减少对Instant.now() 的调用量,并使您能够使用与调用方法不同的Instants。

【讨论】:

  • GMT-1 怎么样?它似乎不适用于负时区。有什么想法吗?
  • @Henry 我刚试了一下,它实际上只返回了 2 个区域:Atlantic/Cape_VerdeEtc/GMT+1,现在我们需要确定这是错误的(似乎是)还是正确的......
  • @Henry 您期望结果中有哪些区域?大西洋中的区域并不多......例如巴西的 FNT 区域目前为 GMT-2。
  • @Henry Greenland 分为 WGST (GMT-2) 和 EGST (GMT+0),冰岛位于 GMT+0
  • 一个小问题:为避免在运行该代码时覆盖时区更改,应将 Instant.now()) 移动到局部变量,以便仅调用一次。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-12-14
  • 2017-11-07
  • 1970-01-01
  • 1970-01-01
  • 2019-12-07
  • 2017-01-03
  • 1970-01-01
相关资源
最近更新 更多