@guxtaa1/worktime
v0.2.2
Published
Business time & SLA-ready date math for Node/Edge, TZ & DST safe. ISO durations, i18n, ESM+CJS.
Readme
@guxtaa1/worktime
📅 SLA-ready date math: calcule tempo útil com fuso IANA, feriados, intervalos e ISO 8601.
Node / Deno / Bun / Edge. Zero deps pesadas. ESM + CJS, typings TS e CLI. 🚀
✨ Por que?
Calcular “dias/horas/minutos” é fácil. O difícil é prazo real de negócio:
- ⏰ considerar só tempo útil (seg–sex, 08–17)
- 🍽️ pular feriados e intervalos (ex.: almoço)
- 🌎 respeitar fuso IANA e horário de verão
- 💻 DX top: TS, ESM/CJS, simples de usar
worktime resolve isso direto: SLA, suporte, logística, saúde, jurídico.
⚡ Instalação
npm i @guxtaa1/worktime
# ou
pnpm add @guxtaa1/worktime
# ou
bun add @guxtaa1/worktime
## 🔥 TL;DR (2 minutos)
ts
Copiar
Editar
import {
diff,
businessDiff,
addBusinessTime,
formatHuman
} from '@guxtaa1/worktime';
// 24/7
const d = diff(new Date(), '2025-12-31T23:59:59', { units: ['days','hours','minutes'] });
// -> { days, hours, minutes }
// Horário útil (seg–sex 08–17, almoço 12–13, fuso São Paulo)
const opts = {
timezone: 'America/Sao_Paulo',
businessHours: [
{ day: 1, start: '08:00', end: '17:00', breaks: [{ start: '12:00', end: '13:00' }] },
{ day: 2, start: '08:00', end: '17:00', breaks: [{ start: '12:00', end: '13:00' }] },
{ day: 3, start: '08:00', end: '17:00', breaks: [{ start: '12:00', end: '13:00' }] },
{ day: 4, start: '08:00', end: '17:00', breaks: [{ start: '12:00', end: '13:00' }] },
{ day: 5, start: '08:00', end: '17:00', breaks: [{ start: '12:00', end: '13:00' }] },
],
holidays: ['2025-09-07']
};
const sla = businessDiff('2025-08-22T16:00Z', '2025-08-25T16:30Z', opts);
// -> só minutos úteis, pulando fds e almoço
console.log(formatHuman(sla, { locale: 'pt-BR', style: 'long' }));
// "1 dia, 3 horas e 30 minutos úteis"
const due = addBusinessTime('2025-08-22T16:00Z', { hours: 4 }, opts);
// -> próxima segunda ~12:00 local (com almoço e fds considerados)
## ✅ Features
📊 diff 24/7 com unidades e arredondamento
🏢 Business time (SLA): businessDiff e addBusinessTime
⏱️ ISO 8601 durations (parseISODuration, formatISODuration)
🗣️ formatHuman (compact/long; pt-BR/en-US)
🧩 ESM + CJS, typings TS, tree-shakeable
💻 CLI opcional (npx worktime)
## 📚 API (resumo)
ts
Copiar
Editar
type Units = Array<'days'|'hours'|'minutes'|'seconds'|'milliseconds'>;
interface Duration {
years?: number; months?: number; days?: number;
hours?: number; minutes?: number; seconds?: number; milliseconds?: number;
}
interface WeekdayRange {
day: 0|1|2|3|4|5|6; // 0=domingo ... 6=sábado
start: string; end: string; // 'HH:mm'
breaks?: Array<{ start: string; end: string }>;
}
type Holiday = string | { date: string; name?: string };
interface CalendarOptions {
timezone?: string; // IANA ('America/Sao_Paulo')
locale?: string; // 'pt-BR', 'en-US'...
businessHours?: WeekdayRange[]; // default: seg–sex 09–17
holidays?: Holiday[]; // 'YYYY-MM-DD'
excludeWeekends?: boolean; // default: true
maintenanceWindows?: Array<{ startCron: string; endCron: string }>;
}
interface DiffOptions extends CalendarOptions {
business?: boolean; // se true, delega p/ businessDiff
units?: Units; // default: ['days','hours','minutes']
rounding?: 'floor'|'ceil'|'round' // default: 'floor'
}
function diff(from: Date|string, to: Date|string, opts?: DiffOptions): Duration;
function businessDiff(from: Date|string, to: Date|string, opts: CalendarOptions): Duration;
function addBusinessTime(base: Date|string, duration: Duration, opts: CalendarOptions): Date;
function parseISODuration(iso: string): Duration; // 'P1DT2H30M'
function formatISODuration(d: Duration): string; // 'P1DT2H30M'
function formatHuman(d: Duration, opts?: { locale?: string; style?: 'long'|'compact' }): string;
👉 Veja Receitas abaixo.
## 🍳 Receitas de uso (prontas)
1) SLA 8h úteis entre abertura e fechamento
ts
Copiar
Editar
const sla = businessDiff(open, close, opts);
2) Somar 4h úteis a partir de agora
ts
Copiar
Editar
const due = addBusinessTime(new Date(), { hours: 4 }, opts);
3) ISO 8601 durations
ts
Copiar
Editar
parseISODuration('P1DT2H30M'); // { days:1, hours:2, minutes:30 }
4) Formatar humano
ts
Copiar
Editar
formatHuman({ days:1, hours:3, minutes:30 }, { locale:'pt-BR', style:'long' });
// "1 dia, 3 horas e 30 minutos"
## 🛠️ CLI
bash
Copiar
Editar
npx worktime diff --from "2025-08-22 16:00Z" --to "2025-08-25 16:30Z" --units days,hours,minutes
## 🗺️ Roadmap
nextBusinessMoment(after, opts)
isBusinessTime(date, opts) público
DST intra-dia (recalcular offset por janela)
“Dia útil” calculado a partir das janelas configuradas
Adaptadores de feriados (BR/US/EU)
maintenanceWindows
Benchmarks + docs site
## 🤝 Contribuindo
PRs e issues são super bem-vindos 🙌
bash
Copiar
Editar
npm test # testes
npm run lint # lint
npm run build # build
## 📜 Licença
ISC © Gustavo Rodrigues Oliveira