1. Обзор
Всякий раз, когда мы имеем дело со временем и датами, нам нужна система отсчета. Стандартом для этого является UTC , но мы также видим GMT в некоторых приложениях.
Короче говоря, UTC — это стандарт, а GMT — это часовой пояс.
Вот что Википедия говорит нам о том, что использовать:
В большинстве случаев UTC считается взаимозаменяемым со средним временем по Гринвичу (GMT), но научное сообщество больше не дает точного определения GMT.
Другими словами, как только мы составим список со смещением часовых поясов в UTC, у нас будет он и для GMT.
Сначала мы рассмотрим способ достижения этого в Java 8, а затем посмотрим, как можно получить тот же результат в Java 7.
2. Получение списка зон
Для начала нам нужно получить список всех определенных часовых поясов.
Для этого в классе ZoneId
есть удобный статический метод:
Set<String> availableZoneIds = ZoneId.getAvailableZoneIds();
Затем мы можем использовать 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());
}
В приведенном выше методе используется параметр перечисления
, который представляет смещение, которое мы хотим увидеть:
public enum OffsetBase {
GMT, UTC
}
Теперь давайте рассмотрим код более подробно.
После того, как мы получили все доступные идентификаторы зон, нам нужна фактическая ссылка на время, представленная LocalDateTime.now().
После этого мы используем Java Stream
API для перебора каждой записи в нашем наборе идентификаторов строк
часового пояса и преобразования его в список отформатированных часовых поясов с соответствующим смещением.
Для каждой из этих записей мы генерируем экземпляр ZoneId
с помощью map(ZoneId::of).
3. Получение компенсаций
Нам также нужно найти фактические смещения UTC. Например, в случае центральноевропейского времени смещение будет +01:00.
Чтобы получить смещение UTC для любой заданной зоны, мы можем использовать метод getOffset() класса LocalDateTime
.
Также обратите внимание, что Java представляет смещения +00:00 как
Z
.
Итак, чтобы иметь последовательно выглядящую строку
для часовых поясов с нулевым смещением, мы заменим Z
на +00:00:
private String getOffset(LocalDateTime dateTime, ZoneId id) {
return dateTime
.atZone(id)
.getOffset()
.getId()
.replace("Z", "+00:00");
}
4. Делаем зоны сопоставимыми
При желании мы также можем отсортировать часовые пояса по смещению.
Для этого мы будем использовать класс 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. Отображение часовых поясов
Все, что осталось сделать, это соединить вышеуказанные части вместе, вызвав метод getTimeZoneList()
для каждого значения перечисления OffsetBase
и отобразив списки:
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);
}
}
Когда мы запустим приведенный выше код, он напечатает часовые пояса для UTC и GMT.
Вот фрагмент того, как будет выглядеть вывод:
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 и ранее
Java 8 упрощает эту задачу, используя API Stream
и Date and Time .
Однако, если у нас есть 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;
}
Основное отличие от кода Java 8 заключается в вычислении смещения.
Значение rawOffset
, которое мы получаем из метода getRawOffset () класса
TimeZone
() , выражает смещение часового пояса в миллисекундах `` .
Поэтому нам нужно преобразовать это в часы и минуты, используя класс 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. Заключение
В этом кратком руководстве мы увидели, как мы можем составить список всех доступных часовых поясов с их смещениями UTC и GMT.
И, как всегда, полный исходный код примеров доступен на GitHub .