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.