// Fuso de REFERÊNCIA do armazenamento. As colunas de horário (agendamentos.start_time) // são `timestamp` naive; o backend (container) roda em America/Sao_Paulo, então o node-pg // serializa o wall-clock naive nesse fuso. Para exibir o horário LITERAL (o mesmo que a // Secretária ofereceu/gravou) em qualquer navegador, formatamos SEMPRE neste fuso — e não // no fuso local do navegador (que causaria o deslocamento de ±1h). export const STORAGE_TZ = 'America/Sao_Paulo'; const D = (v?: string | number | Date | null) => (v === null || v === undefined || v === '' ? null : new Date(v)); export const fmtHora = (v?: string | number | Date | null): string => { const d = D(v); return d ? d.toLocaleTimeString('pt-BR', { hour: '2-digit', minute: '2-digit', timeZone: STORAGE_TZ }) : '—'; }; export const fmtDataCurta = (v?: string | number | Date | null): string => { const d = D(v); return d ? d.toLocaleDateString('pt-BR', { weekday: 'short', day: 'numeric', month: 'short', timeZone: STORAGE_TZ }) : '—'; }; export const fmtDataHora = (v?: string | number | Date | null): string => { const d = D(v); return d ? d.toLocaleString('pt-BR', { day: '2-digit', month: '2-digit', hour: '2-digit', minute: '2-digit', timeZone: STORAGE_TZ }) : '—'; }; // Converte um instante (ISO/Date) para o WALL-CLOCK naive no fuso canônico, no formato // "YYYY-MM-DDTHH:mm:ss" (SEM offset). Uso: alimentar o FullCalendar, que — sem o plugin // de timezone (luxon) — IGNORA o prop `timeZone` nomeado e cai no fuso do NAVEGADOR. // Passando a string naive, o calendário exibe o horário literal em qualquer navegador // (mesma garantia do fmtHora, mas para os eventos do grid). Retorna undefined se vazio. export const toCalendarNaive = (v?: string | number | Date | null): string | undefined => { const d = D(v); if (!d) return undefined; // 'sv-SE' produz "YYYY-MM-DD HH:mm:ss" (ISO-like); trocamos o espaço por 'T'. return d.toLocaleString('sv-SE', { timeZone: STORAGE_TZ, hour12: false }).replace(' ', 'T'); };