将时区转换为 Java 11 中的 GMT 值

Converting Time Zone to GMT values in Java 11

我们在配置 table 中保留城市的时区,使用 时区 ID 值作为 Europe/LondonAsia/Tokyo 等. 但是,当从列表中选择时区时,用户需要查看这些时区的 GMT 值,我们希望将 Display Name of Time Zone Options 显示为 (UTC+00:00) Dublin, Edinburgh, Lisbon, London 而不是比 Europe/London。正如我们所知,GMT 值不是固定的,我们应该进行一些转换才能显示当前时区显示值。那么,我怎样才能在 Java 中做到这一点?

如果return您需要什么,您可以查看下面的代码:

    public class Whosebug {
    
    public static void main(String[] args) {
        List<String> gmt = getTimeZoneList(OffsetBase.GMT);
                gmt.forEach(System.out::println);
    
    }
    
    public static List<String> getTimeZoneList(OffsetBase base) {
         
        LocalDateTime now = LocalDateTime.now();
        return ZoneId.getAvailableZoneIds().stream()
          .map(ZoneId::of)
          .sorted(new ZoneComparator())
          .map(id -> String.format(
            "(%s%s) %s", 
            base, getOffset(now, id), id.getId()))
          .collect(Collectors.toList());
    }
    
    private static String getOffset(LocalDateTime dateTime, ZoneId id) {
        return dateTime
          .atZone(id)
          .getOffset()
          .getId()
          .replace("Z", "+00:00");
    }
    
    private static class ZoneComparator implements Comparator<ZoneId> {
        
        @Override
        public int compare(ZoneId zoneId1, ZoneId zoneId2) {
            LocalDateTime now = LocalDateTime.now();
            ZoneOffset offset1 = now.atZone(zoneId1).getOffset();
            ZoneOffset offset2 = now.atZone(zoneId2).getOffset();
            
            return offset1.compareTo(offset2);
        }
    }
    enum OffsetBase {
        GMT, UTC
    }
   }

结果如下:

(GMT+14:00) Pacific/Apia
(GMT+14:00) Pacific/Kiritimati
(GMT+14:00) Etc/GMT-14

这只是示例,因为列表很长


更新 基于请求者,因此要获取特定区域 ID 的 GMT。

public static List<String> getTimeZoneList(OffsetBase base, String wantedZoneId) {
     
    LocalDateTime now = LocalDateTime.now();
    return ZoneId.getAvailableZoneIds().stream()
      .map(ZoneId::of)
      .sorted(new ZoneComparator())
      .filter(zoneId -> zoneId.getId().equals(wantedZoneId))
      .map(id -> String.format(
        "(%s%s) %s", 
        base, getOffset(now, id), id.getId()))
      .collect(Collectors.toList());
}

这个功能是一样的,只是加上[过滤]功能

比方说,您的 ID 在 Set<String> 中,就像 ZoneId.getAvailableZoneIds().

您可以使用 ZoneId 来及时创建当前时刻并根据需要格式化其偏移量:

public static void main(String[] args) throws IOException {
    // provide two formatters for the desired outputs GMT... and UTC...
    DateTimeFormatter gmtFormatter = DateTimeFormatter.ofPattern("OOOO");
    DateTimeFormatter utcFormatter = DateTimeFormatter.ofPattern("'UTC'xxx");
    // stream all the IDs (sorted) and create a ZonedDateTime at each ZoneId
    ZoneId.getAvailableZoneIds().stream().sorted().forEach(zoneId -> {
        ZonedDateTime now = ZonedDateTime.now(ZoneId.of(zoneId));
        // then print the zone id and the other representations using the formatters
        System.out.println(
                String.format("%-32s %9s / %9s", 
                                zoneId.toString(), 
                                now.format(gmtFormatter),
                                now.format(utcFormatter)
                ));
    });
}

第一个格式化程序只考虑 GMT+/-HH:mm 表示中的区域,第二个只考虑文字 UTC 加上偏移量为 +/-HH:mm.

(缩短!)输出是

Africa/Abidjan                         GMT / UTC+00:00
Africa/Accra                           GMT / UTC+00:00
Africa/Addis_Ababa               GMT+03:00 / UTC+03:00
Africa/Algiers                   GMT+01:00 / UTC+01:00
Africa/Asmara                    GMT+03:00 / UTC+03:00
Africa/Asmera                    GMT+03:00 / UTC+03:00
Africa/Bamako                          GMT / UTC+00:00
...
US/Alaska                        GMT-09:00 / UTC-09:00
US/Aleutian                      GMT-10:00 / UTC-10:00
US/Arizona                       GMT-07:00 / UTC-07:00
US/Central                       GMT-06:00 / UTC-06:00
US/East-Indiana                  GMT-05:00 / UTC-05:00
US/Eastern                       GMT-05:00 / UTC-05:00
US/Hawaii                        GMT-10:00 / UTC-10:00
US/Indiana-Starke                GMT-06:00 / UTC-06:00
US/Michigan                      GMT-05:00 / UTC-05:00
US/Mountain                      GMT-07:00 / UTC-07:00
US/Pacific                       GMT-08:00 / UTC-08:00
US/Samoa                         GMT-11:00 / UTC-11:00
UTC                                    GMT / UTC+00:00
Universal                              GMT / UTC+00:00
W-SU                             GMT+03:00 / UTC+03:00
WET                                    GMT / UTC+00:00
Zulu                                   GMT / UTC+00:00

这是您的其他要求的想法,列出每个偏移量的城市:

public static void main(String[] args) throws IOException {
    // provide two formatters for the desired outputs GMT... and UTC...
    DateTimeFormatter gmtFormatter = DateTimeFormatter.ofPattern("OOOO");
    DateTimeFormatter utcFormatter = DateTimeFormatter.ofPattern("'UTC'xxx");
    // get a map of zones grouped by offset
    Map<ZoneId, List<ZoneId>> zonesPerOffset = 
            ZoneId.getAvailableZoneIds().stream()
                                        .map(ZoneId::of)
                                        .collect(Collectors.toList())
                                        .stream()
                                        .collect(Collectors.groupingBy(zoneId -> ZonedDateTime.now(zoneId).getOffset()));
    // print them
    zonesPerOffset.forEach((offset, zones) -> {
        String o = ZonedDateTime.now(zones.get(0)).format(utcFormatter);
        String zs = String.join(", ", zones.stream().map(zone -> {
            String[] idParts = zone.getId().split("/");
            return idParts[idParts.length - 1];
        }).collect(Collectors.toList()));
        String out = String.format("(%9s) %s", o, zs);
        System.out.println(out);
    });
}

输出(缩短):

(UTC+04:00) Yerevan, GMT-4, Dubai, Reunion, Mauritius, Saratov, Samara, Mahe, Baku, Muscat, Volgograd, Astrakhan, Tbilisi, Ulyanovsk
(UTC+00:00) London, GMT, GMT-0, Jersey, St_Helena, Guernsey, Isle_of_Man, GMT+0, Banjul, GMT, Freetown, GB-Eire, Bamako, GB, Conakry, Portugal, Universal, Sao_Tome, Nouakchott, Troll, UTC, Universal, Faeroe, Abidjan, Eire, Accra, Faroe, UCT, GMT0, Dublin, Zulu, Ouagadougou, Reykjavik, Madeira, Zulu, Iceland, Lisbon, Canary, Lome, Greenwich, Belfast, GMT0, Danmarkshavn, Dakar, Bissau, WET, Greenwich, Timbuktu, UCT, Monrovia, UTC
(UTC+08:00) Kuching, Chungking, GMT-8, Perth, Macao, Macau, Choibalsan, Shanghai, Ulan_Bator, Chongqing, Ulaanbaatar, Taipei, Manila, PRC, Ujung_Pandang, Harbin, Singapore, Brunei, West, Hong_Kong, Makassar, Hongkong, Kuala_Lumpur, Irkutsk, Singapore
(UTC+12:00) Kwajalein, Wallis, Funafuti, Nauru, Kwajalein, Wake, Norfolk, Tarawa, Kamchatka, GMT-12, Anadyr, Majuro

这样看起来不太好,但您可以根据需要应用过滤器。也许删除前导 UTC 等的元素,也许过滤掉特定的大陆,等等。


作为方法:

public static ZoneOffset getOffsetOf(ZoneId zoneId) {
    return ZonedDateTime.now(zoneId).getOffset();
}

// this one may throw an Exception if you pass an invalid zoneId as String!
public static ZoneOffset getOffsetOf(String zoneId) {
    return ZonedDateTime.now(ZoneId.of(zoneId)).getOffset();
}

public static List<ZoneId> getAllZoneIdsWith(ZoneOffset zoneOffset) {
    return ZoneId.getAvailableZoneIds()
                 .stream()
                 .filter(zoneId -> ZonedDateTime.now(ZoneId.of(zoneId))
                                                .getOffset().equals(zoneOffset))
                 .map(ZoneId::of)
                 .collect(Collectors.toList());
}

public static String getGmtFormat(ZoneId zoneId) {
    return String.format("(%s) %s",
                        ZonedDateTime.now(zoneId)
                                     .format(DateTimeFormatter.ofPattern("OOOO")),
                        zoneId.getId());
}

使用最后一种方法获取所有可用 ZoneIds 的 GMT 格式:

List<String> gmtFormats = ZoneId.getAvailableZoneIds()
                                .stream()
                                .map(zone -> getGmtFormat(ZoneId.of(zone)))
                                .collect(Collectors.toList());