Files
2026-05-27 23:29:53 +01:00

3.2 KiB

datetime

Purpose

Timezone-aware date/time utilities with business-day arithmetic, recurrence rules, calendar math, and relative time formatting. Provides custom-holiday-aware business-day functions, RRule subset (FREQ/INTERVAL/COUNT/UNTIL/BYDAY/BYMONTHDAY), and i18n-keyed relative-time output, all with an injectable Clock so tests run deterministically.

Requirements

DT-01 — DateInput acceptance

Every function that accepts a date parameter MUST accept DateInput = Date | string | number. Strings must be ISO-8601; numbers are Unix milliseconds. Invalid inputs throw DatetimeError with code DATETIME.PARSE.INVALID_INPUT.

DT-02 — Injectable clock

Every function that reads current time (e.g. timeAgo, isBusinessDay for "today") MUST accept an optional { clock?: Clock } option. The Clock interface is sourced from @suaveplan/types. Zero-config default uses Date.now(). No Date.now() or new Date() calls at module scope.

DT-03 — Business day arithmetic

addBusinessDays, subtractBusinessDays, nextBusinessDay, previousBusinessDay, isBusinessDay, businessDaysBetween MUST all accept BusinessDayOptions including a custom holidays?: Date[] list and weekendDays?: Weekday[] array (defaults: Saturday and Sunday). businessDaysBetween MUST check AbortSignal every 256 days to support large ranges.

DT-04 — Calendar math correctness

addDuration and subtractDuration MUST correctly handle month rollover (e.g. Jan 31 + 1 month = Feb 28/29) and DST transitions without double-counting hours. daysInMonth MUST return correct values for all months including February in leap years.

DT-05 — Recurrence rules

parseRRule MUST parse a simplified RRULE string supporting FREQ, INTERVAL, COUNT, UNTIL, BYDAY, BYMONTHDAY. expandRecurrence MUST require either count or until in the rule; rules missing both MUST throw DatetimeError with code DATETIME.RECURRENCE.INFINITE_EXPANSION. AbortSignal is checked every 64 occurrences.

DT-06 — Structured errors

All thrown errors MUST extend DatetimeError which extends SuaveplanError. Error codes are namespaced under DATETIME.*. The error includes { code, message, cause?, context? }.

DT-07 — Zod schemas

Every exported public type that carries runtime data MUST have a corresponding Zod schema in a sibling *.schemas.ts file. Schemas are exported directly (not via a schema-registry package).

DT-08 — i18n-ready output

formatRelative, timeAgo, and timeUntil MUST produce output via i18n-keyed strings. The default locale is English pass-through. The key system is compatible with a future @suaveplan/i18n adapter.

DT-09 — OTel instrumentation

expandRecurrence and businessDaysBetween MUST emit OpenTelemetry histograms tracking call duration and output size. All instruments are registered via @opentelemetry/api and are no-ops when no exporter is registered.

DT-10 — sideEffects: false

The package MUST set "sideEffects": false in package.json. A tree-shake test MUST verify no side effects leak at import time.

DT-11 — Coverage gate

Vitest thresholds MUST be set to 100/100/100/100 (statement/branch/function/line). No istanbul ignore pragmas. No .skip or .only in src/.