Comparação entre RFC 3339 e ISO 8601
(ijmacd.github.io)- Ao tratar de notação de data e hora, o RFC 3339 é mais próximo de um subconjunto restrito e fácil de usar na web e na internet, enquanto a ISO 8601-1:2019 inclui um conjunto de formatos muito mais amplo
- O escopo da comparação é limitado à ISO 8601-1:2019, e expressões adicionais da ISO 8601-2:2019, como estações, conjuntos, qualificadores de incerteza e aritmética de datas, ainda não estão refletidas na tabela
- Os dois padrões tratam em comum dos formatos básicos de data e hora amplamente usados, como
2026-06-26,14:08:00Z,2026-06-26T14:08:00Ze offsets+00:00 - A ISO 8601 abrange século, década, dia ordinal, data por semana, hora abreviada, frações com vírgula, duração (
P1Y) e intervalo (2026-06-26/P1Y), mas o RFC 3339 exclui a maior parte disso na tabela - Na notação Date-Time, diferenças como o separador
T, maiúsculas e minúsculas e offsets como-00:00acabam definindo a compatibilidade real entre parsers
Escopo da comparação e premissas
- A tabela de formatos não é uma lista completa
- O padrão considerado é ISO 8601-1:2019
- Há diferenças importantes em relação a edições anteriores e rascunhos
- A ISO 8601-2:2019 inclui expressões adicionais, mas isso ainda não está refletido nesta página
- Grupos de subano, por exemplo estações
- Unidades de agrupamento
- Conjuntos
- Qualificadores de incerteza
- Aritmética de datas
- O RFC 3339 propõe que padrões derivados possam substituir
Tpor outro caractere, mas os exemplos fornecem apenas o caractere de espaço - Cada padrão define formatos para finalidades específicas, e formatos fora disso não são recomendados
A ISO 8601 é mais ampla na notação de datas
- Tanto o RFC 3339 quanto a ISO 8601 aceitam datas ano-mês-dia como
2026-06-26 - A ISO 8601 trata de representações de data mais variadas do que o RFC 3339
- Século:
20 - Década:
202 - Ano:
2026 - Ano-mês:
2026-06 - Dia ordinal:
2026-177 - Data por semana:
2026-W26,2026-W26-5 - Formato básico:
20260626,2026177,2026W26,2026W265
- Século:
- Na tabela, o RFC 3339 não permite esses formatos de data exclusivos da ISO
Diferenças na notação de hora
- Os dois padrões aceitam em comum horários com segundos e offset de fuso como
14:08:00Z,14:08:00+00:00e14:08:00.372+00:00 - O RFC 3339 não diferencia maiúsculas de minúsculas, então
TeZpodem ser escritos comotez- Edições anteriores da ISO 8601 também não diferenciavam maiúsculas de minúsculas
- A ISO 8601 permite adicionar uma parte fracionária ao menor valor de tempo
- A tabela mostra principalmente exemplos com uma casa decimal, mas o padrão permite precisão arbitrária
- Tanto vírgula quanto ponto são aceitos como separador decimal, e podem ser usados de forma intercambiável em todos os formatos
- A ISO 8601-1:2019 permite omitir
Tem representações de hora isoladas quando não houver ambiguidade - A ISO 8601 aceita representações de hora abreviadas, básicas e com fração por vírgula como
14,14:08,14:08:00,140800,T14:08:00e14:08:00,372 - O RFC 3339 aceita o offset
-00:00em casos como14:08:00-00:00, mas na tabela a ISO 8601 não aceita isso
T e separadores em Date-Time
- Tanto o RFC 3339 quanto a ISO 8601 aceitam Date-Time como
2026-06-26T14:08:00Ze2026-06-26T14:08:00+00:00 - Na representação Date-Time da ISO 8601,
Té sempre obrigatório- Em edições anteriores, também era permitido omitir
Tem Date-Time - Mesmo em edições anteriores, não era permitido inserir caracteres substitutos como espaço ou sublinhado
- Em edições anteriores, também era permitido omitir
- Na tabela, o RFC 3339 aceita as seguintes variações de Date-Time
tezminúsculos:2026-06-26t14:08:00z- Separador por espaço:
2026-06-26 14:08:00Z - Separador por sublinhado:
2026-06-26_14:08:00Z - Offset
-00:00:2026-06-26T14:08:00-00:00
- A ISO 8601 trata de Date-Time abreviados e Date-Time baseados em dia ordinal e data por semana, como
2026-06-26T14,2026-06-26T14:08,2026-06-26T14:08:00,2026-177T14:08e2026-W26-5T14:08
Duração e intervalo são centrados na ISO 8601
- Na tabela, formatos de duração (Periods) estão marcados apenas para a ISO 8601
- Ex.:
P1Y,P1M,P1W,P1D - Com hora incluída:
PT1H,PT1M,PT1S - Combinações:
P1Y1M1DT1H1M1S - Frações:
P1.5Y,P1,5W,PT1.5S
- Ex.:
- Formatos de intervalo (Ranges) também estão marcados apenas para a ISO 8601
- Data e duração:
2026-06-26/P1Y - Data e data:
2026-06-26/2026-06-26 - Duração e data:
P1Y/2026-06-26 - Date-Time e duração:
2026-06-26T14:08/P1DT1H - Intervalos repetidos:
R/2026-06-26/P1Y,R10/2026-06-26/P1Y
- Data e duração:
Chaves de formato e ferramenta de teste
- A tabela de formatos usa chaves de formato como
%Y,%M,%D,%h,%m,%s%Y: Year%M: Month%D: Day%V: Week Year%W: Week%w: Week Day%O: Ordinal Day%h: Hour%m: Minute%s: Second%u: Microsecond%n: Nanosecond%Z: hora do fuso com+ou-%z: minuto do fuso
- O verificador de formato apenas confirma se o formato de entrada corresponde a um formato da tabela
- Ele não verifica todos os formatos possíveis
- ISO 8601 as a Service é um serviço em beta para testes
- Atualmente suporta apenas Date, Time e DateTime
- Period e Range não são suportados
- O código-fonte está disponível no GitHub
1 comentários
Opiniões do Hacker News
Acho estranho não haver uma forma de especificar uma data/hora futura com base em um fuso horário específico. Por exemplo, eu posso querer marcar uma reunião para 1º de julho de 2030, às 18h, no horário local de Londres, e ela deve continuar sendo “18h em Londres”, independentemente de como as regras de fuso horário do Reino Unido mudem nesse meio-tempo
Atualmente, o Reino Unido usa, aproximadamente, Z+00:00 de novembro a março e horário de verão Z+01:00 de abril a outubro[0], mas antes de 2030 poderia adotar o Horário da Europa Central[1], tentar novamente o British Double Summer Time[2] ou abolir o horário de verão. Assim, a mesma “18h” pode mudar bastante em relação a um epoch específico
Quero colocar em um evento de calendário “18h no horário de Londres naquele momento”, mas não há uma forma padrão e interoperável de representar 2030-07-01 18:00:00 Europe/London
[0] https://en.wikipedia.org/wiki/British_Summer_Time
[1] https://en.wikipedia.org/wiki/Central_European_Time
[2] https://en.wikipedia.org/wiki/British_Summer_Time#Periods_of...
tzentre colchetes depois de uma string RFC 3339 e, para expressar a hora local, também é preciso escrever junto uma estimativa do offset UTCPor exemplo,
2030-07-01 18:00:00 Europe/Londonvira2030-07-01T18:00:00+01:00[Europe/London]. Se as regras do Reino Unido mudarem antes disso, o timestamp se torna “inconsistente”, e a aplicação decide como tratá-lo. Porém, se você colocar!antes do nome do fuso horário dentro dos colchetes, o problema deve ser detectado em vez de simplesmente seguir cegamente o offset UTCEsse formato estendido de timestamp também é usado na biblioteca Temporal proposta para JavaScript[1], e a função de parsing
ZonedDateTime.from()[2] permite controlar, com a opçãooffset, qual lado deve ter prioridade em um timestamp inconsistente. Também há suporte para omitir o offset UTC e escrever apenas o fuso horário, mas ela alerta que o intervalo de uma hora repetido durante a transição do horário de verão fica ambíguo[0] https://www.ietf.org/archive/id/draft-ietf-sedate-datetime-e...
[1] https://tc39.es/proposal-temporal/docs/strings.html#iana-tim...
[2] https://tc39.es/proposal-temporal/docs/ambiguity.html#ambigu...
Mas não é impossível imaginar que, nesse meio-tempo, a Escócia realize novamente um referendo de independência e passe a adotar o Horário da Europa Central, ou crie um Scottish Standard Time
2023-11-05 01:30:00 America/New_Yorkcorresponde a um de dois instantes diferentesEm calendários, “a mesma hora no relógio de parede” costuma ser o significado desejado, então isso é razoável, mas há dificuldades de UI para lidar com horários estranhos, e talvez se queira incluir na sintaxe um modo de resolver ambiguidades. Felizmente, essas transições geralmente acontecem no meio da noite, mas já vi isso ocorrer em trabalho real
Se você convidar alguém de um fuso sem horário de verão, o horário no calendário dessa pessoa vai oscilar, e às vezes colegas internacionais precisam conviver com isso
[0]: https://www.rfc-editor.org/rfc/rfc5545#section-3.3.5
Formatos comuns de data-hora foram criados para representar um instante específico, mas, neste caso, esse instante específico ainda não existe. É comum que especificações de data/hora tenham uma estrutura não trivial, como uma reunião na última sexta-feira de cada mês, uma reunião mensal que começa em 31 de janeiro ou dois dias antes do fim do trimestre
Criar um padrão que cubra todos os casos que as pessoas conseguem imaginar provavelmente ficaria complexo rapidamente. Se uma simples data, hora ou instante não bastar, parece que a única saída é criar uma estrutura separada que contenha todos os elementos necessários
Como a especificação ISO não é disponibilizada gratuitamente, em geral é melhor seguir a RFC, e muitas implementações open source também se baseiam em rascunhos, então é difícil dizer que ela seja totalmente amigável ao open source. É um grande ônus também para desenvolvedores open source
Se você estiver criando algo que lida com datas futuras, quase sempre vai querer armazenar hora de relógio de parede + localização. Infelizmente, não há um padrão para isso. Na Europa e nos EUA os fusos horários são bastante estáveis, então talvez isso não seja tão perceptível, mas em muitas regiões os fusos mudam com frequência, de modo que armazenar o offset não é estável
5 de junho de 2026, 13:30 no relógio de parede, Parisé o que a maioria das pessoas quer dizer, e pode ser UTC+2 ou UTC+1 dependendo do que a UE decidir fazer com o horário de verão. Se for uma API que lida com instantes no passado, basta usar um timestamp POSIX em segundos, milissegundos, microssegundos ou nanossegundosO iCal também não leva em conta o problema de uma localização ser reatribuída a outro fuso horário. Além disso, um arquivo iCal correto inclui todos os dados dos fusos horários referenciados, o que é trabalhoso quando você só quer emitir uma única data-hora
[1] https://icalendar.org/iCalendar-RFC-5545/3-3-5-date-time.htm...
2026-06-05T13:30+0200[Europe/Paris]https://www.ietf.org/archive/id/draft-ietf-sedate-datetime-e...
Uma parte frequentemente ignorada nos padrões é a representação de durações
Veja a seção 5.5.4.2, “Representation of time-interval by duration only”, na página 21 de http://xml.coverpages.org/ISO-FDIS-8601.pdf. Seria bom permitir que parsers JSON de linguagens estáticas definissem um campo como duração e o serializassem em um formato válido
Um exemplo de proposta para Crystal está aqui: https://github.com/crystal-lang/crystal/issues/11942
Por exemplo, 15 dias, 5 horas e 20 segundos vira
P15DT5H0M20S, e 7 semanas viraP7Wdurationno ABNF do Apêndice A da RFC 3339Por exemplo, se usar algo como
"duration": { "days": 15, "hours": 5, "seconds": 20 }, o parser JSON não precisa entender o significado dos dados; isso fica a cargo do validador de entrada. De todo modo, qualquer que seja a forma como o JSON represente esses dados, será necessária uma etapa de conversão que pode falharÉ “engraçado” que a RFC 3339 e a ISO 8601 incluam muitos formatos de data-hora redundantes com propósitos sobrepostos, mas nenhuma das duas inclua
2023-09-01 15:30:59, que é o formato mais usado em todos os sistemas e é óbvio demaisAlém disso, ambos os padrões são muito pouco claros sobre como representar datas antes da era comum e datas posteriores a
9999-12-31ou anteriores a-9999-01-01, e bibliotecas comuns em geral não lidam com isso de forma alguma. Mesmo quando lidam, o comportamento de00-01-01é praticamente indefinidoO calendário gregoriano é estranho porque o ano depois de 1 BC é 1 CE, e quase todo software, exceto software astronômico especializado, não lida corretamente com datas fora do intervalo de tempo Unix do futuro próximo. Mesmo algo que bastaria armazenar como string, como os anos de nascimento e morte do imperador Augusto, poderia ser definido claramente pelo padrão
Tpor um espaço. A RFC 3339 faz algo parecido de uma forma muito mais verbosaTambém é difícil ter certeza de que
2023-09-01 15:30:59seja o formato de data-hora mais usado. A língua mais usada é o chinês, e separadores próprios como2023年9月1日são comunsA ISO 8601 permite anos anteriores a 1582 ou posteriores a 9999 se houver acordo mútuo. Se não couberem em quatro dígitos, é preciso prefixar um único caractere de sinal. Essas datas geralmente não são suportadas porque há pouca coisa significativa que se possa fazer com elas, mas já vi bastante bibliotecas fazerem o parsing, especialmente implementações independentes de C
00-01-01é definido como 1º de janeiro do ano 1 antes da era comum. A ISO 8601 deixa claro que a numeração dos anos segue o calendário gregoriano proléptico (proleptic Gregorian calendar), portanto é extrapolada até o infinito negativoEntendo por que era necessário um caractere que não fosse espaço, mas pelo menos poderiam ter usado sublinhado ou ponto. E também não entendo por que, sendo uma string, limitaram o campo do ano a quatro dígitos, sacrificando a universalidade do formato
Anos com 6 dígitos parecem uma solução para um problema que, na prática, não vai acontecer, só para parecer voltado ao futuro. Não há como a tecnologia atual ou as normas sociais durarem 8000 anos
A explicação de que a ISO 8601 usa U+2010 HYPHEN e U+2212 MINUS, e que em conjuntos de caracteres que não têm esses caracteres deve-se usar U+2D HYPHEN-MINUS, está errada
A ISO 8601 real especifica que, se o conjunto de caracteres de destino for baseado em ISO/IEC 646, em ambos os casos deve-se usar o caractere hífen-menos. Isso certamente inclui Unicode. Há uma pequena ambiguidade, mas em Unicode a interpretação é clara, e parece ser uma forma indireta de garantir compatibilidade com outros conjuntos de caracteres baseados no 646 ao especificar o mapeamento canônico do 646
O conteúdo diz que “todos os caracteres usados em representações de data e hora pertencem ao repertório ISO/IEC 646, exceto ‘hyphen’, ‘minus’ e ‘plus-minus’. Em ambientes que usam um repertório de caracteres baseado em ISO/IEC 646, tanto ‘hyphen’ quanto ‘minus’ devem ser mapeados para ‘hyphen-minus’”
Como Unicode é baseado em ISO 8859, e ISO 8859 é baseado em ISO 646, parece correto entender que a intenção, no conjunto de caracteres Unicode, é usar U+2D hyphen-minus
No Windows, o fato de dois-pontos ser um caractere especial frequentemente incomoda, porque não há uma forma compatível com RFC 3339 de colocar data e hora em nomes de arquivo
Seria bom se fosse possível continuar em conformidade com a ISO 8601 usando hífens na data, mas omitindo os dois-pontos. Por exemplo,
20230831T1510-0500é compatível e pode ser usado em nomes de arquivo, mas2023-08-31T1510-0500e variações semelhantes não são. Além disso, a funçãoGet-Datedo PowerShell não entende o primeiro timestamp, sem hífens e sem dois-pontosÉ uma visualização muito boa deste tema
Ao separar a parte de data e a de hora, prefiro espaço ou sublinhado em vez de
T, mas, para evitar problemas com processadores que só lidam com ISO 8601 e por consistência, geralmente continuo usandoTT. Afinal, não deve haver casos em que essa string seja acidentalmente dividida com base noTTenho duas dúvidas. Primeiro, qual é a justificativa para anos de 6 dígitos? Nenhum sistema projetado hoje vai existir no ano 100.000, certo?
Segundo, a ISO 8601 é amplamente difundida, mas a RFC 3339 também é muito usada e adotada em sistemas reais?
timede Golang e oChronode Rust têm ferramentas embutidas para lidar com RFC 3339, mas não para RFC 8601Pelo que lembro, a RFC 8601 tinha problemas de ambiguidade que a RFC 3339 não tem, e sei que o Python também teve problemas com conversão de ida e volta de datas por causa disso
Não há um formato em que o fuso horário seja especificado com quatro dígitos sem dois-pontos, mas
date +%zretorna±NNNN%:z. Relacionado a isso, também dá para ensinar odatea imprimir assim por padrão: https://gist.github.com/d081dad407432d53172e30d0d35c39db$ date2023-08-31T11:15:00-07:00±NNNNé válido sem dois-pontos quando usado como parte do “formato básico”. Ou seja, o formato inteiro não deve conter hífens nem dois-pontosPortanto, os dois exemplos abaixo são equivalentes e ambos válidos:
2023-09-01T09:40:01+08:0020230901T094001+0800