---
fonte: 01-canonicos/seed-componentes.md
versao_da_fonte: v1.43
secao: 61
titulo: "Data, intervalo e hora — **`estável`** (F7.5 · promovida em 2026-08-17 por gate **declarado**, verbatim *'aprovo. siga'* · **RE-GATE OBSERVADO em 2026-08-17: a BT-P1 e a DH-P6 FECHAM — insumo nomeado, ver §64.10.1**) · DH1–DH18 · fecha C1 e C2 · bancada `banco-data.html` **v0.4** *(errata corrigida: este cabeçalho declarava v0.5, versão que nem o artefato, nem o gerador, nem o MANIFESTO, nem o mapa de cobertura têm — §64.10.3)* · `suite-data.mjs` **31 · 0 · 1 [n/a]** · **BT7 consertado em 2026-08-17** (178px de excesso a 390px: o calendário empilha os atalhos abaixo de 470px, com exceção declarada ao piso de 44px na célula do dia)"
sequencia: 67 de 98
bytes_do_corpo: 18720
md5_do_corpo: f5784b5580e2eef1d0078376e4e6a991
gerado_por: 06-validacao/geradores/gen-camada-ia.py
nota: fatia GERADA — o corpo abaixo é byte a byte o trecho do canônico; edite o canônico, nunca esta fatia. Canônico inteiro em https://ds.seed.eng.br/01-canonicos/seed-componentes.md
---
## 61. Data, intervalo e hora — **`estável`** (F7.5 · promovida em 2026-08-17 por gate **declarado**, verbatim *"aprovo. siga"* · **RE-GATE OBSERVADO em 2026-08-17: a BT-P1 e a DH-P6 FECHAM — insumo nomeado, ver §64.10.1**) · DH1–DH18 · fecha C1 e C2 · bancada `banco-data.html` **v0.4** *(errata corrigida: este cabeçalho declarava v0.5, versão que nem o artefato, nem o gerador, nem o MANIFESTO, nem o mapa de cobertura têm — §64.10.3)* · `suite-data.mjs` **31 · 0 · 1 [n/a]** · **BT7 consertado em 2026-08-17** (178px de excesso a 390px: o calendário empilha os atalhos abaixo de 470px, com exceção declarada ao piso de 44px na célula do dia)

> **Rodada zero: NÃO VISITADO — e a visita mudou a seção.** O dispositivo **existe** no produto de
> referência (o §13 já tinha lido a data *renderizada* — C80, cor por estado), mas o **seletor**
> nunca tinha sido aberto. Navegação autorizada, modo somente leitura: o seletor foi aberto, lido e
> fechado; **nenhuma data foi escolhida, alterada ou limpa**. Oito dispositivos observados,
> **C117–C124**, no §15 do `estudo-clickup-completo.md`.
>
> **E a volta estreou um método que rendeu na primeira tentativa.** Além da captura de tela, foi
> lida a **árvore de acessibilidade** da mesma região. As duas **não coincidem** — e o achado é o
> **C122**, negativo: cada dia é um `button` cujo nome acessível é **só o número** (`button "2"`),
> sem `role="grid"`, sem `gridcell`, sem `columnheader`, e **sem `aria-selected` no dia escolhido**.
> Na tela o dia 31 tem fundo sólido; na árvore ele não carrega estado nenhum.
>
> *Copiar a forma teria copiado o defeito, porque o defeito não aparece na captura.*
>
> **Base (3 rodadas, 2026-08-16), e o canon diverge em TRÊS.**
> **(a) ARIA APG** — calendário é `role="grid"` sobre `<table>` (`row`/`columnheader`/`gridcell` vêm
> implícitos de `tr`/`th`/`td`); cabeçalho de coluna com `abbr` trazendo o dia por extenso;
> `aria-selected="true"` **só** na célula escolhida; com campo vazio, o foco entra no dia de hoje;
> teclado ←/→ dia, ↑/↓ semana, Home/End na semana, PageUp/PageDown mês, Shift+PageUp/Down ano; e o
> campo de texto recebe `aria-describedby` apontando para a descrição do formato.
> **(b) GOV.UK / NHS** — **não** use calendário quando o usuário **já sabe** a data: use campos de
> texto, com `inputmode="numeric"` e `autocomplete` (`bday-day`/`bday-month`/`bday-year`) para o
> SC 1.3.5. O calendário é para quando a data **não é sabida**.
> **(c) USWDS** — faz os dois (campo + botão de calendário), e monta o intervalo como **dois
> seletores independentes**, com `data-min-date`/`data-max-date`. Admite duas coisas: que **não
> valida a coerência** entre início e fim, e que o componente passa no SC 3.3.2 **com ressalva** —
> falta instrução visível de como usar o botão de calendário.
>
> **R3 normas:** SC 3.3.2 (o formato esperado tem de estar **visível**, não só no placeholder) ·
> SC 1.3.5 (identificar o propósito do campo) · **SC 3.3.7 Redundant Entry, nível A** (o que o
> usuário já informou na sessão não se pede de novo).

### 61.1 A régua: pergunte se o usuário JÁ SABE a data

A divergência não tem "jeito certo" — tem **dois problemas diferentes** que a mesma forma serve, e
foi assim que o §60 se resolveu. Aqui a pergunta é outra:

| Se o usuário… | Então o caminho primário é… | E o outro… |
|---|---|---|
| **já sabe** a data (nota fiscal, nascimento, prazo em contrato) | **digitar** — teclado é mais rápido que caçar num calendário | o calendário fica disponível, e ninguém é obrigado a abri-lo |
| **não sabe** e precisa do contexto (que dia da semana? quantos dias faltam? cai no fim de semana?) | **o calendário** — a pergunta que ele responde não cabe num campo de texto | o campo continua lá, aceitando digitação |

> **Os dois existem SEMPRE, e nenhum é opcional.** O GOV.UK está certo sobre a data sabida e o APG
> está certo sobre a data descoberta; escolher um dos dois seria acertar metade dos casos.
> **No ERP da SEED os dois casos convivem na mesma tela:** a data de emissão de uma nota o usuário
> sabe e digita; o agendamento de uma OS depende de que dia da semana cai e de quem está livre.

### 61.2 Os contratos

| # | Contrato | O que ele descarta, e por quê |
|---|---|---|
| **DH1** | **O campo de TEXTO existe sempre e aceita digitação.** O calendário é complemento, nunca substituto | Calendário sozinho. Para data sabida, obriga a navegar meses para chegar onde a digitação chegaria em 8 teclas |
| **DH2** | **O calendário existe sempre e é alcançável por teclado.** Gatilho com nome próprio, não um ícone mudo | Campo de texto sozinho. Ele não responde "que dia da semana é" nem "quantos dias faltam" |
| **DH3** | **O formato esperado é VISÍVEL** (SC 3.3.2) — em texto de apoio, não só no placeholder, que **some ao digitar** justamente quando o usuário mais precisa dele | Formato só no placeholder. É a ressalva que o próprio USWDS registrou contra si |
| **DH4** | **pt-BR: entrada em `dd/mm/aaaa`**, `inputmode="numeric"`, e o parser aceita separador `/`, `.` ou `-`. Exibição pode ser compacta; **entrada não** | Aceitar `mm/dd`. Herda o **VD5** — em pt-BR `1240.5` é doze mil quatrocentos e cinco, e a mesma armadilha de locale vale para data |
| **DH5** | **A grade é `role="grid"` sobre `<table>`**, com `<th>` para os dias da semana e `abbr` com o nome por extenso | Pilha de `<button>`. É exatamente o que o produto de referência faz (**C122**) |
| **DH6** | **O nome acessível de cada dia é COMPLETO** — dia, mês, ano e dia da semana —, nunca só o número | `button "2"`. **Contraexemplo medido no C122:** o leitor de tela anuncia "botão 2", sem mês, sem ano, sem saber o que já está escolhido |
| **DH7** | **`aria-selected="true"` só na célula escolhida**; **hoje** se marca por `aria-current="date"` — são coisas diferentes e precisam de marcas diferentes | Marcar hoje e o escolhido do mesmo jeito. Quem não vê perde a diferença entre "onde estou" e "o que escolhi" |
| **DH8** | **Teclado do APG, inteiro:** ←/→ dia · ↑/↓ semana · Home/End na semana · PageUp/PageDown mês · Shift+PageUp/Down ano · Enter/Espaço escolhe · Esc fecha **sem escolher** | Só setas. Sem PageUp/Down, mudar de ano custa dezenas de teclas |
| **DH9** | **A grade tem UM tab stop** (roving), como o SG1 | Um tab stop por dia. Quarenta e dois tab stops para atravessar um calendário |
| **DH10** | **Intervalo é UM controle: dois campos de texto e UM calendário compartilhado** | **Dois seletores independentes** (USWDS). Separados, ninguém é dono da relação — e o próprio USWDS admite que **não valida a coerência entre início e fim** |
| **DH11** | **A coerência início ≤ fim é validada, e a mensagem diz QUAL dos dois corrigir** e sugere a correção | "Intervalo inválido". Herda o **VD11**: erro que identifica o problema E sugere a saída |
| **DH12** | **O vão entre os extremos é DESENHADO na grade**, e os dois extremos se distinguem do meio | Marcar só as pontas. *Contrato **decidido sem leitura** — ver §61.4* |
| **DH13** | **A hora é campo SEPARADO e opt-in**; não existir hora não é erro, e existir o campo não a torna obrigatória | Data e hora no mesmo campo. **C118**: no produto de referência a hora é um terceiro campo de texto, e a data não a carrega por padrão |
| **DH14** | **ISO 8601 na camada de dado; a string ISO NUNCA passa por `new Date(string)`** | Confiar no parser do agente de usuário. Regra já canônica do projeto — `new Date("2026-08-16")` desloca por UTC e devolve o dia anterior a oeste de Greenwich |
| **DH15** | **Atalho relativo mostra a data ABSOLUTA que resolve**, ao lado do rótulo | "2 semanas" sozinho. **C119**: o relativo é ambíguo, e o produto responde mostrando o resultado antes do clique. Irmão do **FC5** — o número é a prova de que o comando fez o que diz |
| **DH16** | **"Hoje" é o hoje do USUÁRIO, e o fuso fica declarado** quando o dado é compartilhado | Hoje do servidor. Numa empresa em MG, ES e BA o fuso é o mesmo, mas o dado que sai em relatório não pode depender disso |
| **DH17** | **Recorrência NÃO é deste componente** | Regra de recorrência dentro do seletor. **C124**: até o produto de referência a põe atrás de um passo a mais |
| **DH18** | **Data já informada na sessão não se pede de novo** (SC 3.3.7, nível A): o segundo campo pré-carrega ou oferece o valor | Redigitar. É critério de nível A, o mais baixo — falhar nele é falhar no piso |

### 61.3 A fronteira: o que este componente NÃO decide

* **Regra de negócio de prazo** — o que conta como atraso, se sábado é dia útil, qual feriado vale.
  O componente exibe e coleta; quem decide é o produto.
* **Recorrência** (DH17) · **fuso como configuração** · **calendário de trabalho**.
* **Conversão de unidade de tempo** — herdado do VD15: conversão é regra de engenharia.

### 61.4 O contrato que nasce SEM LEITURA, e isso está dito

O **DH12** — como o seletor desenha o vão entre início e fim — **não pôde ser observado**. A tarefa
aberta tinha só a data de vencimento, e **preencher a data inicial seria escrita**, fora do modo
autorizado. Não havia outra instância à mão com os dois extremos.

> **Achado negativo é achado.** O DH12 fica marcado como **decidido por canon e norma, sem leitura
> visual** — e é o único dos dezoito nessa condição. Se uma volta futura achar uma instância com
> intervalo preenchido, ele é o primeiro a ser reconferido. *Registrar de qual contrato não se tem
> leitura é o que separa uma spec incompleta de uma spec que não sabe onde está incompleta.*

### 61.5 Números — a MEDIR na produção da bancada

Método do §55: a seção nasce só com **relações**. Ficam a medir: altura e alvo da célula de dia ·
largura da grade · espaçamento entre semanas · o par de cor de hoje, do escolhido, do vão, do
hover e do foco, **nos dois temas e em `forced-colors`** (herdando o **SG6-b**) · alvo do gatilho do
calendário · e a distinção entre dia do mês corrente e dia vizinho.

**Nenhuma medida é afirmada aqui.**

### 61.6 A bancada — e as três decisões que ela obrigou

**`banco-data.html` · `suite-data.mjs` 25 PASS · 0 FAIL · 1 `[n/a]`.**

#### (a) O "hoje" da bancada é FIXO, e isso é decisão, não conveniência

Um calendário que consulta o relógio **muda de bytes todo dia**. Isso quebraria a âncora
(bytes + MD5) que este projeto usa para provar que um arquivo é o que se pensa que ele é, e nenhuma
guarda poderia afirmar *"o dia 16 está marcado como hoje"*. A data de referência entra pelo
**gerador, declarada** — nunca de `Date.now()`.

> *É a mesma razão pela qual as suítes esperam por CONDIÇÃO e não por tempo: estado que depende do
> relógio não é verificável.* O selo da bancada diz qual é o "hoje" dela, na primeira linha.

E o intervalo de exemplo é escolhido por **asserção**, não por gosto: o gerador **aborta** se `hoje`
não cair **dentro** do intervalo, porque é a única forma de provar, **na mesma imagem**, que "hoje" e
"escolhido" têm marcas diferentes (DH7).

#### (b) Dois alvos abaixo do piso, e o motivo do primeiro vale como regra

O gatilho do calendário media **40px**. A caixa declarava `min-height: 44px` — mas isso é a altura
**externa**: descontadas as bordas e o alinhamento, o botão ficava com 40. A célula de dia media
**42px**.

> **Regra: alvo se mede no retângulo do CONTROLE, não no contêiner que o abriga.** Declarar 44 no pai
> é a versão sutil do defeito do `::before` da SG-P7 — o número certo, no elemento errado.

#### (c) A ambiguidade que o DH15 existe para expor apareceu na própria bancada

Dois atalhos de nomes diferentes — **"Amanhã"** e **"Próxima segunda"** — resolvem para a **mesma
data**, porque o "hoje" fixado cai num domingo. A suíte registra isso como medida, não como falha:
*é exatamente a ambiguidade que torna a data resolvida necessária.* Sem ela, o usuário clicaria em
dois botões diferentes esperando resultados diferentes.

### 61.7 O gate achou um calendário inoperável — com 25 PASS · 0 FAIL

**Verbatim, 2026-08-16:** *"não consegui ter ação no calendário. não consegui fazer seleção de
intervalo de data com o mouse, nem clicar em nenhuma data, quanto mais fazer o teste com tab"*.

A `banco-data.html` v0.1 tinha a grade **estática**, emitida em HTML pelo gerador. O clique num dia
movia o foco e escrevia numa live region — **nada mudava na tela**. Não dava para escolher um
intervalo, não dava para mudar de mês, e o gatilho do calendário não abria nada.

> **Uma grade estática não é um seletor de data — é a FOTO de um.** E a foto passou em vinte e cinco
> guardas, porque todas elas mediam **marcação**: papel, nome, estado, alvo, teclado sob foco
> programático. *Nenhuma perguntou se o usuário consegue usar.*

#### E a guarda que devia pegar isso tinha sido escrita para não olhar ali

A `suite-data.mjs` v0.1 tinha uma guarda `BTN` — *"nenhum botão morto"*, regra do projeto desde
sempre. E ela excluía, por escrito:

    !b.closest('table[role="grid"]') && !b.closest('.cal__nav') &&
    !b.classList.contains('cal__hoje') && !b.classList.contains('cd__gatilho')

**Os quatro lugares onde o defeito estava.** Eu escrevi a exclusão porque aqueles botões "não são
CTA comum" — e com isso removi do exame exatamente o que precisava ser examinado.

> **Regra nova: guarda escrita para NÃO OLHAR onde o defeito mora é pior que guarda nenhuma.** Sem
> guarda, a pergunta continua aberta. Com uma guarda que desvia o olhar, o verde **impede a
> pergunta**. *Toda exceção numa guarda precisa de motivo escrito — e o motivo não pode ser "esse
> caso é chato de medir".*
>
> **E há exclusão legítima:** a guarda nova exclui `[disabled]`, porque a plataforma **define** que
> botão desabilitado não responde. *Excluir pelo que o contrato diz é método; excluir por onde o
> defeito mora é fuga.*

#### As cinco guardas que nascem disso

| # | O que mede, AGINDO |
|---|---|
| **DH-OP1** | clicar num dia muda estado **observável** — não só a live region |
| **DH-OP2** | o vão é **pré-visualizado no ponteiro**, antes do segundo clique |
| **DH-OP3** | o segundo clique fecha o intervalo **e escreve nos campos de texto** |
| **DH-OP4** | a navegação de mês **muda o mês**, e "Hoje" volta |
| **DH-OP5** | o atalho relativo **preenche**, não só anuncia |

E a `BTN` passa a clicar em **todo** botão do componente, zerando a live region antes de cada clique.

#### Dois defeitos de instrumento a mais, e um de artefato achado pelo teste

**Nono (instrumento):** a exclusão da `BTN`, acima. **Décimo (instrumento):** a primeira versão da
`BTN` nova media *"o texto do anúncio MUDOU"* — e dois campos de mesmo rótulo dizem legitimamente a
**mesma frase**. Ela acusou quatro botões corretos de mudos. *Comparar com o valor anterior confunde
"não respondeu" com "respondeu igual".* Agora a região é **zerada** antes de cada clique: o teste é
**presença**, não diferença.

**E um defeito de artefato que só um teste de comportamento acha:** a prévia do vão chamava
`desenha()` no `mouseenter`, e `desenha()` reescreve o `innerHTML` — **o elemento sob o cursor era
destruído**, o `mouseenter` disparava de novo no elemento novo, e o calendário entrava em laço,
tremendo. *Redesenhar em resposta ao ponteiro destrói o alvo do próprio ponteiro.* A prévia passou a
**mutar atributos** das células existentes, sem recriar nada.

#### E o calendário foi para o TOPO da página

Ele vinha depois de sete campos de exemplo — **cerca de trinta e três tab stops**. Agora são
**quinze**, e a grade é a primeira coisa substantiva do arquivo. *O que a bancada existe para provar
vem primeiro; o catálogo de estados vem depois.*

### 61.8 Nível de prova, declarado

Aplicando a régua da v10.2 — *ao promover, declare o NÍVEL de prova de cada contrato*:

| Nível | Contratos |
|---|---|
| **1 · Consumidor em produção** | **nenhum.** Nenhum artefato do acervo tem seletor de data |
| **2 · Bancada** | DH1–DH16 — provados pela `banco-data.html`, que **nós** construímos para prová-los |
| **3 · Ausência de violação** | DH17 (recorrência não vive no componente) |
| **Fora do componente** | DH18 — SC 3.3.7 é contrato de TELA: o componente aceita valor inicial; quem o pré-carrega é a tela |

> **A seção segue `rascunho`, e não é formalidade.** Sem consumidor em produção e sem gate visual,
> o que existe é um componente que passa nos testes que ele mesmo trouxe. *Placar verde não diz se o
> contrato sobreviveu ao mundo ou só ao caso que escrevemos para ele.*

### 61.8 Pendências

> **Aviso de supersede (2026-08-17):** a linha **DH-P6** desta tabela está **SUPERSEDIDA** pelo
> **§64.10.4** — ela FECHOU com o re-gate **observado** da `banco-data` **v0.4**. A tabela abaixo fica
> como histórico; o estado vigente é o do §64.10.4.

| # | Pendência | Por que fica aberta |
|---|---|---|
| **DH-P1** | Bancada `banco-data.html` | ✅ **FECHADA** — 25 · 0 · 1 `[n/a]`. Nível de prova: **2 (bancada)** |
| **DH-P5** | Gate visual na `banco-data.html` **v0.1** | ✅ **FECHADA — e REPROVOU.** *"não consegui ter ação no calendário"*. Cinco guardas de operabilidade nasceram do achado |
| **DH-P6** | **RE-gate** da `banco-data.html` — hoje **v0.4** | O calendário funciona e passa em 31 guardas — mas quem disse que a v0.1 estava quebrada foi o olho, não o placar. Além do conserto de operabilidade, a v0.4 traz barra fixa (BT1), seletor de largura (BT2) e o conserto do **vão branco no tema escuro**, que media **1,02** e passou a medir **10,52 / 7,98** (§64.2). **Nada promove antes.** Mesma pendência que a **BT-P1** |
| **DH-P2** | **DH12 sem leitura visual** | O vão do intervalo não pôde ser observado sem escrever. Reconferir na próxima volta que achar instância |
| **DH-P3** | **Calendário de trabalho e feriado** | Parâmetro do produto, não do DS — irmão do VD-P2 (jornada). Fica nomeado para não voltar como surpresa |
| **DH-P4** | **Máscara durante a digitação** | Mesma pendência do VD-P4: a máscara ao vivo não está implementada, e a decisão de fazê-la vale para os dois |

---


