Exibir fusos horários com GMT e UTC em Java

Exibir fusos horários com GMT e UTC em Java

1. Visão geral

Sempre que lidamos com horários e datas, precisamos de um quadro de referência. O padrão para isso éUTC, mas também vemosGMT em alguns aplicativos.

Em resumo, o UTC é o padrão, enquanto o GMT é um fuso horário.

Isto é o que a Wikipedia nos diz sobre o que usar:

Para a maioria dos propósitos, o UTC é considerado intercambiável com o Horário Médio de Greenwich (GMT), mas o GMT não é mais definido com precisão pela comunidade científica.

Em outras palavras, assim que compilarmos uma lista com deslocamentos de fuso horário em UTC, também a teremos para GMT.

Primeiro, vamos dar uma olhada na maneira do Java 8 de conseguir isso e, em seguida, ver como podemos obter o mesmo resultado no Java 7.

2. Obtendo uma lista de zonas

Para começar, precisamos recuperar uma lista de todos os fusos horários definidos.

Para este propósito, a classeZoneId tem um método estático útil:

Set availableZoneIds = ZoneId.getAvailableZoneIds();

Então, podemos usar oSet para gerar uma lista classificada de fusos horários com seus deslocamentos correspondentes:

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

O método acima usa um parâmetroenum que representa o deslocamento que queremos ver:

public enum OffsetBase {
    GMT, UTC
}

Agora vamos examinar o código com mais detalhes.

Depois de recuperar todos os IDs de zona disponíveis, precisamos de uma referência de tempo real, representada porLocalDateTime.now().

Depois disso, usamos a APIStream do Java para iterar sobre cada entrada em nosso conjunto de IDsString de fuso horário e transformá-la em uma lista de fusos horários formatados com o deslocamento correspondente.

Para cada uma dessas entradas, geramos uma instânciaZoneId commap(ZoneId::of).

3. Obtendo Compensações

Também precisamos encontrar compensações UTC reais. Por exemplo, no caso do horário da Europa Central, o deslocamento seria+01:00.

Para obter o deslocamento UTC para qualquer zona, podemos usar o métodoLocalDateTime’s getOffset().

Observe também que Java representa+00:00 offsets comoZ.

Então, para ter uma aparência consistente deString para fusos horários com o deslocamento zero, substituiremosZ por+00:00:

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

4. Fazendo ZonasComparable

Opcionalmente, também podemos classificar os fusos horários de acordo com o deslocamento.

Para isso, usaremos uma classeZoneComparator:

private class ZoneComparator implements Comparator {

    @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. Exibindo fusos horários

Tudo o que resta a fazer é juntar as peças acima chamando o métodogetTimeZoneList() para cada valorOffsetBase enum e exibindo as listas:

public class TimezoneDisplayApp {

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

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

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

Quando executamos o código acima, ele imprime os fusos horários UTC e GMT.

Aqui está um snippet de como a saída será semelhante:

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 e anterior

Java 8 torna esta tarefa mais fácil usando as APIsStreameDate and Time.

No entanto, se tivermos um Java 7 e antes de um projeto, ainda podemos obter o mesmo resultado contando com a classejava.util.TimeZone com seu métodogetAvailableIDs():

public List getTimeZoneList(OffsetBase base) {
    String[] availableZoneIds = TimeZone.getAvailableIDs();
    List 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;
}

A principal diferença com o código Java 8 é o cálculo de deslocamento.

OrawOffset que obtemos deTimeZone()‘s getRawOffset() method expresses the time zone’s offset in milliseconds.

Portanto, precisamos converter isso para horas e minutos usando a classeTimeUnit:

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. Conclusão

Neste tutorial rápido, vimos como podemos compilar uma lista de todos os fusos horários disponíveis com seus deslocamentos UTC e GMT.

E, como sempre, o código-fonte completo dos exemplos está disponívelover on GitHub.