Sobre ZoneOffset
e ZoneId
: o primeiro representa um offset, e o segundo, um timezone. Estes conceitos estão relacionados, mas muitas vezes são confundidos e tratados como se fossem a mesma coisa.
Um offset é a diferença em relação a UTC. É um valor fixo, por exemplo, -03:00
é 3 horas antes do UTC. Um timezone é um identificador que representa uma região geográfica, e possui o histórico de todos os offsets que esta região teve ao longo da história. Por exemplo, America/Sao_Paulo
possui a lista de offsets que uma região específica do Brasil teve ao longo do tempo (isso inclui as mudanças de horário de verão).
Vale notar que muitos timezones podem ter o mesmo offset em determinadas épocas. Por exemplo, America/Sao_Paulo
e America/Recife
estão com o offset -03:00
, mas São Paulo teve horário de verão em épocas nas quais Recife não teve (um estava em -02:00
enquanto o outro permaneceu em -03:00
). Como o histórico é diferente, eles não são o mesmo timezone (mesmo que eles coincidam na maior parte do tempo).
Enfim, ZoneOffset
representa apenas um offset específico, e ZoneId
representa um timezone, com todo o histórico de offsets.
O mesmo vale para OffsetDateTime
(data e hora com um offset fixo) e ZonedDateTime
(data e hora em um timezone, com o offset podendo variar de acordo com o histórico do timezone). No meu blog tem exemplos em Java que explicam melhor.
Quanto a "sempre usar UTC" (ou seja, sempre usar Instant
), varia muito, nem sempre será a melhor solução. Veja aqui, principalmente a seção "UTC e eventos futuros" e também aqui para ver um caso em que somente converter para UTC não é suficiente.
não há uma medida universal de datas
Em nenhum ponto do texto eu afirmo isso. Eu só disse que não há uma norma oficial sobre como a aritmética de datas deve funcionar, e que em outro comentário foi citado como "aritmética universal".