Ir para o conteúdo
AZ Tools

Inspetor de arquivos TZif (zoneinfo)

Um arquivo TZif é a forma compilada de um fuso horário: o que está em /usr/share/zoneinfo/Europe/Berlin, o que TZ= aponta, o que viaja dentro de um JDK ou é copiado para uma imagem de contêiner. Ele é opaco, não guarda nome nenhum dentro de si e as pessoas o movem de um lado para outro sem ter como conferir. Esta ferramenta abre o arquivo no navegador e mostra o que existe de fato, conforme a RFC 8536. O cabeçalho traz a versão e os seis contadores, exibidos aqui para os dois blocos lado a lado, porque um arquivo de versão 2 ou posterior contém primeiro um bloco de 32 bits completo e depois um de 64 bits. O primeiro é um resto herdado que todo leitor moderno ignora; num arquivo slim ele fica reduzido a um único tipo e nenhuma transição, enquanto os dados reais estão no segundo. A tabela de tipos de hora local traz cada deslocamento, o indicador de horário de verão, a abreviação e os indicadores padrão/parede e UT/local, que dizem como a regra que os gerou foi escrita. A tabela de transições lista cada troca com o deslocamento antes e depois, a abreviação que entra e se começa o horário de verão; os instantes são segundos com sinal de 64 bits, então é normal haver datas de 1901 e de 2037 e alguma entrada sentinela que não muda nada. O rodapé POSIX não é apenas repetido, e sim quebrado em campos: abreviações de inverno e verão, os dois deslocamentos com o sinal do POSIX já invertido para o usual, e as regras de início e fim na forma M, J ou de base zero, resolvidas em instantes concretos para o ano de referência mostrado. Esse rodapé é o que realmente importa num arquivo slim, onde nada mais descreve a próxima primavera. Os registros de segundo bissexto aparecem só quando o arquivo os carrega, o que acontece na árvore right/. O que ele não consegue dizer é de qual fuso se trata, porque nenhum arquivo TZif guarda o próprio nome e um apelido como Asia/Istanbul é uma cópia byte a byte de Europe/Istanbul, nem se o arquivo está corrompido: o formato não tem soma de verificação, e um byte trocado apenas desloca uma transição.

Como usar

  1. Solte um arquivo de zona compilado na caixa: copie de /usr/share/zoneinfo, tire de um contêiner com docker cp ou de um JDK.
  2. Leia primeiro o resumo: a versão, quantas transições o arquivo tem e se o futuro está enumerado (fat), deixado para a regra POSIX (slim) ou fixo para sempre.
  3. Compare as duas colunas do cabeçalho. Um arquivo slim mostra um bloco de 32 bits quase vazio ao lado de um de 64 bits cheio; essa diferença é o formato funcionando, não um defeito.
  4. Veja o instante de referência e a próxima transição para saber o que este arquivo faria hoje e quando muda.
  5. Abra a seção do rodapé POSIX se o arquivo for slim: as regras M, J ou de base zero ali são a única coisa que governa qualquer data depois da última transição.

Perguntas frequentes

Por que o cabeçalho mostra dois conjuntos de contadores?
Porque um arquivo de versão 2 ou posterior realmente contém os dados duas vezes. Ele começa com um bloco de versão 1 completo, cujos instantes de transição são de 32 bits, e só então vêm um segundo cabeçalho, um bloco de 64 bits e o rodapé POSIX. A duplicação existe para que um leitor escrito antes de 2004 encontre algo que entenda em vez de falhar, e a RFC 8536 manda os leitores modernos pularem direto para o segundo bloco. Por isso os contadores podem divergir: na saída slim do zic o primeiro bloco é reduzido a um tipo de hora local e nenhuma transição, enquanto o segundo guarda os dados de verdade. Se uma ferramenta diz que um fuso não tem histórico, quase sempre está lendo o bloco herdado por engano, coisa que algumas bibliotecas ainda fazem.
Qual é a diferença entre um arquivo fat e um slim?
Os dois descrevem o mesmo fuso; muda quanto do futuro é escrito. Um arquivo fat enumera todas as transições até 2037, então Europe/Berlin traz cerca de 140 delas e a mudança de outubro que vem se lê direto na tabela. Um slim para na última transição que não pode ser deduzida de uma regra e deixa o resto para o rodapé POSIX, o que faz ele caber em um décimo do tamanho. Desde 2020 o zic gera slim por padrão, mas as distribuições divergem: Debian e Ubuntu ainda publicam arquivos fat, e Alpine e várias imagens base de contêiner publicam slim. Um leitor que ignora o rodapé funciona bem com um arquivo fat e erra em silêncio com um slim, que é exatamente o tipo de bug que aparece em uma imagem e não em outra.
Como se lê o rodapé POSIX e o que significam M, J e o número solto?
O rodapé é a mesma string que a variável TZ pode conter: abreviação padrão, deslocamento padrão e, opcionalmente, a abreviação de verão, o deslocamento dela e as duas regras que alternam entre as duas. Os deslocamentos usam o sinal do POSIX, positivo a oeste de Greenwich, então CET-1 significa UTC+01:00 e esta ferramenta inverte o sinal de volta. Uma regra tem três formas. Mm.w.d é mês, semana (5 querendo dizer a última) e dia da semana, então M3.5.0 é o último domingo de março. Jn é o enésimo dia do ano contando de 1 e nunca contando 29 de fevereiro, então J60 é sempre 1º de março. Um número solto conta de 0 e conta sim o 29 de fevereiro, então 59 é 1º de março em ano comum e 29 de fevereiro em ano bissexto. Essa última forma é rara e melhor evitar: as implementações discordam, e o zoneinfo do Python a resolve um dia depois do glibc.
Por que Etc/GMT+5 informa um deslocamento de -05:00?
Porque os nomes Etc seguem a convenção de sinais do POSIX, que é o contrário da que todo mundo usa: numa string TZ, positivo significa a oeste de Greenwich. Então Etc/GMT+5 é o fuso cinco horas atrás do UTC, que em ISO 8601 e em qualquer interface se escreve -05:00, e Etc/GMT-5 é o que está cinco horas à frente. A base de dados tz mantém esses nomes justamente porque o POSIX exige esse comportamento, e avisa que eles são uma armadilha. Esta ferramenta mostra os deslocamentos no modo ISO, então um arquivo cujo nome diz +5 e cujo deslocamento diz -05:00 não é contradição nem defeito: é a convenção de nomes aparecendo.
O que são os registros de segundo bissexto e por que as transições parecem estranhas num arquivo right/?
A base de dados tz pode ser compilada de duas formas: a árvore posix/ comum, em que um carimbo de tempo conta segundos sem os bissextos, e a árvore right/, em que os segundos bissextos desde 1972 ficam guardados como registros e os carimbos contam segundos realmente decorridos. A maioria dos sistemas só distribui a primeira, então uma tabela de bissextos aqui significa que você tem um arquivo right/ ou um compilado com zic -L. Nesses arquivos as transições aparecem deslocadas pela correção acumulada: uma troca que deveria marcar 01:00:00 marca 01:00:27, porque 27 segundos bissextos foram inseridos desde 1972, e a coluna de correção sobe até esse mesmo 27. Misturar um arquivo right/ num sistema que espera tempos posix/ é a maneira clássica de ficar exatamente 27 segundos fora.
Dá para saber de qual fuso é este arquivo, ou se ele está corrompido?
Não para os dois, e ambos os limites são propriedades do formato. Um arquivo TZif não contém nome algum: a identidade de um fuso vem só do caminho dele na base de dados, e por isso um link como Asia/Istanbul é uma cópia byte a byte de Europe/Istanbul, ou um link simbólico para ele, e não dá para distinguir pelo conteúdo. O máximo que se pode fazer é reconhecer o fuso pela impressão digital: as abreviações, os deslocamentos e as datas das transições, que é para isso que estas tabelas servem. Também não há soma de verificação nenhuma no formato, então um byte trocado na tabela de transições não invalida o arquivo, apenas desloca em silêncio uma transição ou a aponta para outro tipo. Só é detectável um tamanho que não bate mais com os contadores, e é isso que esta ferramenta recusa como truncado.

Ferramentas relacionadas