Display All Time Zones With GMT And UTC in Java – 在Java中用GMT和UTC显示所有时区

最后修改: 2017年 11月 23日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

Whenever we deal with times and dates, we need a frame of reference. The standard for that is UTC, but we also see GMT in some applications.

每当我们处理时间和日期时,我们需要一个参考框架。这方面的标准是UTC,但我们也在一些应用中看到GMT

In short, UTC is the standard, while GMT is a time zone.

简而言之,UTC是标准,而GMT是一个时区。

This is what Wikipedia tells us regarding what to use:

这是维基百科告诉我们的关于使用的内容。

For most purposes, UTC is considered interchangeable with Greenwich Mean Time (GMT), but GMT is no longer precisely defined by the scientific community.

在大多数情况下,UTC被认为可与格林威治时间(GMT)互换,但格林威治时间已不再被科学界精确定义。

In other words, once we compile a list with time zone offsets in UTC, we’ll have it for GMT as well.

换句话说,一旦我们编制了一个包含UTC时区偏移的列表,我们也会有GMT的时区偏移。

First, we’ll have a look at the Java 8 way of achieving this and then we’ll see how we can get the same result in Java 7.

首先,我们来看看Java 8的实现方式,然后再看看我们如何在Java 7中得到同样的结果。

2. Getting a List of Zones

2.获得一个区的清单

To start with, we need to retrieve a list of all defined time zones.

首先,我们需要检索一个所有定义的时区列表。

For this purpose, the ZoneId class has a handy static method:

为此,ZoneId类有一个方便的静态方法。

Set<String> availableZoneIds = ZoneId.getAvailableZoneIds();

Then, we can use the Set to generate a sorted list of time zones with their corresponding offsets:

然后,我们可以使用Set来生成一个经过排序的时区列表,其中包括其相应的偏移量。

public 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());
}

The method above uses an enum parameter which represents the offset we want to see:

上面的方法使用了一个enum参数,代表我们想看到的偏移量。

public enum OffsetBase {
    GMT, UTC
}

Now let’s go over the code in more detail.

现在让我们更详细地了解一下这段代码。

Once we’ve retrieved all available zone IDs, we need an actual time reference, represented by LocalDateTime.now().

一旦我们检索到所有可用的区域ID,我们需要一个实际的时间参考,用LocalDateTime.now()表示。

After that, we use Java’s Stream API to iterate over each entry in our set of time zone String id’s and transform it into a list of formatted time zones with the corresponding offset.

之后,我们使用Java的Stream API来迭代时区String id’s 集合中的每个条目,并将其转化为一个带有相应偏移量的格式化时区列表。

For each of these entries, we generate a ZoneId instance with map(ZoneId::of).

对于每个条目,我们用map(ZoneId::of)生成一个ZoneId实例。

3. Getting Offsets

3.获得抵偿

We also need to find actual UTC offsets. For example, in the case of Central European Time, the offset would be +01:00.

我们还需要找到实际的UTC偏移量。例如,在中欧时间的情况下,偏移量将是+01:00.

To get the UTC offset for any given zone, we can use LocalDateTime’s getOffset() method.

为了获得任何特定区域的UTC偏移量,我们可以使用LocalDateTime的getOffset()方法。

Also note that Java represents +00:00 offsets as Z.

还要注意,Java将+00:00偏移量表示为Z

So, to have a consistent looking String for time zones with the zero offset, we’ll replace Z with +00:00:

因此,为了使时区与零点偏移的String看起来一致,我们将用+00:00:取代Z

private String getOffset(LocalDateTime dateTime, ZoneId id) {
    return dateTime
      .atZone(id)
      .getOffset()
      .getId()
      .replace("Z", "+00:00");
}

4. Making Zones Comparable

4.使各区具有可比性

Optionally, we can also sort the time zones according to offset.

作为选择,我们还可以根据偏移量对时区进行排序。

For this, we’ll use a ZoneComparator class:

为此,我们将使用一个ZoneComparator类。

private 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);
    }
}

5. Displaying Time Zones

5.显示时区

All that’s left to do is putting the above pieces together by calling the getTimeZoneList() method for each OffsetBase enum value and displaying the lists:

剩下的就是通过为每个OffsetBase枚举值调用getTimeZoneList()方法,将上述部分组合起来,并显示列表。

public class TimezoneDisplayApp {

    public static void main(String... args) {
        TimezoneDisplay display = new TimezoneDisplay();

        System.out.println("Time zones in UTC:");
        List<String> utc = display.getTimeZoneList(
          TimezoneDisplay.OffsetBase.UTC);
        utc.forEach(System.out::println);

        System.out.println("Time zones in GMT:");
        List<String> gmt = display.getTimeZoneList(
          TimezoneDisplay.OffsetBase.GMT);
        gmt.forEach(System.out::println);
    }
}

When we run the above code, it’ll print the time zones for UTC and GMT.

当我们运行上述代码时,它将打印出UTC和GMT的时区。

Here’s a snippet of how the output will look like:

下面是输出结果的一个片段,看起来像。

Time zones in UTC:
(UTC+14:00) Pacific/Apia
(UTC+14:00) Pacific/Kiritimati
(UTC+14:00) Pacific/Tongatapu
(UTC+14:00) Etc/GMT-14

6. Java 7 and Before

6.Java 7及之前

Java 8 makes this task easier by using the Stream and Date and Time APIs.

Java 8通过使用StreamDate and Time API,使这项任务变得更加容易。

However, if we have a Java 7 and before a project, we can still achieve the same result by relying on the java.util.TimeZone class with its getAvailableIDs() method:

然而,如果我们有一个Java 7并在一个项目之前,我们仍然可以通过依靠java.util.TimeZone类及其getAvailableIDs()方法来实现同样的结果。

public List<String> getTimeZoneList(OffsetBase base) {
    String[] availableZoneIds = TimeZone.getAvailableIDs();
    List<String> result = new ArrayList<>(availableZoneIds.length);

    for (String zoneId : availableZoneIds) {
        TimeZone curTimeZone = TimeZone.getTimeZone(zoneId);
        String offset = calculateOffset(curTimeZone.getRawOffset());
        result.add(String.format("(%s%s) %s", base, offset, zoneId));
    }
    Collections.sort(result);
    return result;
}

The main difference with the Java 8 code is the offset calculation.

与Java 8代码的主要区别是偏移量的计算。

The rawOffset we get from TimeZone()‘s getRawOffset() method expresses the time zone’s offset in milliseconds.

我们从TimeZone()getRawOffset()方法中得到的rawOffset表示时区的偏移量,单位为毫秒

Therefore, we need to convert this to hours and minutes using the TimeUnit class:

因此,我们需要使用TimeUnit类将其转换为小时和分钟。

private String calculateOffset(int rawOffset) {
    if (rawOffset == 0) {
        return "+00:00";
    }
    long hours = TimeUnit.MILLISECONDS.toHours(rawOffset);
    long minutes = TimeUnit.MILLISECONDS.toMinutes(rawOffset);
    minutes = Math.abs(minutes - TimeUnit.HOURS.toMinutes(hours));

    return String.format("%+03d:%02d", hours, Math.abs(minutes));
}

7. Conclusion

7.结论

In this quick tutorial, we’ve seen how we can compile a list of all available time zones with their UTC and GMT offsets.

在这个快速教程中,我们已经看到了如何编制所有可用的时区及其UTC和GMT偏移量的列表。

And, as always, the full source code for the examples is available over on GitHub.

而且,像往常一样,这些例子的完整源代码可在GitHub上获得。