FreeToGenerate.com

Lê um valor de Date, Expires, Last-Modified ou Retry-After do jeito que a RFC 9110 manda, e mostra onde o seu próprio navegador discorda. Roda no seu navegador; nada é enviado.

Experimente:

Retry-After

A regra dos cinquenta anos

O formato obsoleto escreve o ano com dois dígitos, e a RFC 9110 diz que um receptor deve ler um valor a mais de cinquenta anos no futuro como o ano passado mais recente terminado nesses dígitos. A resposta muda com o tempo: o limite avança um a cada janeiro, e um valor que hoje significa 2076 vai significar 1976 daqui a cinquenta e um anos.

Também disponível em: English · Español · Français · العربية

Analisador de datas HTTP

Os três formatos que o HTTP permite, o que cada um significa e os seis jeitos de o Date.parse errar com eles.

O que é uma data HTTP?

Todo carimbo de tempo num cabeçalho HTTP — Date, Expires, Last-Modified, If-Modified-Since e a forma com data do Retry-After — é escrito num formato que a RFC 9110 chama de HTTP-date. São três, porque antes de 1995 os servidores usavam três, e a especificação define os três por compatibilidade.

A regra que os governa é assimétrica, e é essa assimetria que vale guardar. Quem recebe um carimbo de tempo «precisa aceitar os três formatos»; quem gera «precisa gerar no formato IMF-fixdate». Ou seja: existe exatamente uma grafia que você pode produzir — Sun, 06 Nov 1994 08:49:37 GMT — e três que você precisa saber ler.

Os três representam um instante em UTC. Os dois primeiros dizem isso com as letras GMT; o terceiro, herdado da função asctime do C, não traz fuso nenhum, e a especificação apenas declara que seus valores são presumidos em UTC. É nessa frase que quase todo o problema começa.

Como usar

  1. Cole o valor do cabeçalho. Só o valor, sem o nome do campo. Os três botões de exemplo cobrem um formato cada, e o quarto escreve este momento do jeito que um remetente é obrigado a escrever.
  2. Leia a linha do formato e as notas abaixo dela. Você vê o instante em UTC e no seu fuso, qual dos três formatos é, se um remetente pode enviá-lo e todos os pontos em que ele foge da gramática.
  3. Compare a última linha com a de cima. Essa linha é o que o Date.parse do seu próprio navegador faz com a mesma string. Onde as duas divergirem, a diferença aparece em segundos.

Seis coisas que o Date.parse erra

A mais danosa é o asctime. Esse formato não tem fuso e a RFC 9110 diz que seus valores são presumidos em UTC, mas o Date.parse o lê como hora local — a resposta sai errada pelo deslocamento de quem executa e só está certa em Greenwich. É o pior tipo de bug: silencioso, plausível e diferente em cada máquina. A linha de comparação desta página roda no seu navegador justamente para você ver o que o seu faz.

Depois vêm os anos de dois dígitos. O formato obsoleto da RFC 850 escreve o ano com dois algarismos, e a regra da especificação é relativa ao presente: quem recebe um valor a mais de cinquenta anos no futuro precisa lê-lo como o ano passado mais recente terminado nesses algarismos. Os motores de JavaScript usam em vez disso um pivô fixo em 50. Hoje as duas regras discordam em 27 dos 100 anos possíveis — todos os valores de 50 a 76 — e como o limite da especificação avança todo janeiro, esse conjunto cresce em um a cada ano. Um 68 significa 2068 pela regra e 1968 pelo pivô: um século inteiro de diferença.

Com um ano de quatro algarismos menor que 100 acontece o mesmo. A gramática diz que o ano tem quatro dígitos, então 0094 é um jeito legítimo de escrever o ano 94, e o Date.parse o transforma em 1994 mesmo assim.

O nome do dia é redundante, e por isso serve duas vezes. Se ele contradiz a data, algo montou o valor errado: Mon, 06 Nov 1994 foi um domingo, e o Date.parse aceita sem dizer nada. Além disso ele desempata o século: o exemplo acima, Tuesday, 06-Nov-68, só é coerente se o ano for 2068, porque 6 de novembro de 1968 foi uma quarta-feira. O campo redundante resolve o ambíguo — um acaso feliz num formato que nunca foi projetado para isso.

A gramática permite o segundo 60 para um segundo bissexto. O Date.parse transforma 23:59:60 em 23:59:00: joga os segundos fora e perde um minuto em vez de avançar um segundo.

Por fim, as datas impossíveis. 31 de novembro não existe, e o Date.parse devolve 1º de dezembro em vez de NaN — um valor que vai parecer perfeitamente razoável num log.

Limites honestos

Esta página confere o valor, não a mensagem de onde ele veio. Se o cabeçalho Date deveria ter sido enviado, se um cache pode usá-lo e se o relógio do remetente estava certo são coisas que uma string não conta — e a RFC 9110 permite explicitamente que um receptor com relógio substitua um valor de Date inválido pelo horário em que a resposta chegou.

Ela também aplica a regra dos cinquenta anos como ela vale hoje. Isso é o comportamento correto e vale dizer em voz alta: o mesmo carimbo da RFC 850 realmente significa anos diferentes conforme a data em que é lido, então um valor guardado hoje num log e relido daqui a décadas pode mudar de sentido. Não há como consertar isso num analisador: ao formato faltam dois dígitos.

O veredicto de conformidade é sobre a gramática, não sobre se o valor vai funcionar. Um gmt minúsculo, um dia de um algarismo e um espaço a mais são coisas que a especificação proíbe produzir e que todo analisador real aceita. A página diz de que lado dessa linha você está, em vez de fingir que é aprovado ou reprovado.

A caixa do Retry-After distingue as duas formas — um número inteiro de segundos ou um carimbo de tempo — porque esse campo é o único lugar em que o HTTP aceita as duas, e é uma fonte comum de confusão. Um número negativo e um fracionário não são nenhuma delas.

Por que é grátis?

Tudo roda no seu navegador. O valor do cabeçalho não é enviado a lugar nenhum, o que importa numa página como esta: um Last-Modified ou um If-Modified-Since de um sistema real diz algo sobre esse sistema.

Não há custo de servidor a recuperar, então não há cadastro, nem limite, nem marca d’água.