Documentation | Demo | npm
A modern TypeScript date formatting library. Zero dependencies. Own your code.
| Feature | Whenny | date-fns | Day.js | Luxon | Tempo |
|---|---|---|---|---|---|
| Own your code (shadcn-style install) | Yes | No | No | No | No |
| Size-based formatting (.xs .sm .md .lg .xl) | Yes | No | No | No | No |
| Configurable voice (one config for all strings) | Yes | No | No | No | No |
| Pre-built themes (slack, github, discord, etc.) | 8 themes | No | No | No | No |
| React hooks (useRelativeTime, useCountdown) | Yes | No | No | No | No |
| MCP server (AI assistant integration) | Yes | No | No | No | No |
| Server/client timezone sync (Transfer Protocol) | Yes | No | No | No | No |
| Smart contextual formatting (auto-picks best) | Yes | No | No | No | No |
| Zero production dependencies | Yes | Yes | Yes | Yes | Yes |
| TypeScript native | Yes | Yes | Yes | Yes | Yes |
| Locales | 10 | 60+ | 100+ | Intl | Intl |
| Temporal API support | Yes | No | No | No | No |
Whenny is not trying to replace date-fns or Day.js. It sits on top of the Date API and solves the display layer — how dates appear to users. The part every team builds custom.
npx create-whenny init
npx create-whenny add relative smart calendarCode is copied to src/lib/whenny/. You own it. Your AI assistant can read and modify it.
npm install whenny whenny-reactLike Tailwind for dates. Simple properties instead of cryptic format strings:
import { whenny } from 'whenny'
whenny(date).xs // "2/3"
whenny(date).sm // "Feb 3"
whenny(date).md // "Feb 3, 2026"
whenny(date).lg // "February 3rd, 2026"
whenny(date).xl // "Tuesday, February 3rd, 2026"
whenny(date).clock // "3:45 PM"
whenny(date).sortable // "2026-02-03"
whenny(date).log // "2026-02-03 15:45:30"Compare with date-fns: format(date, "EEEE, MMMM do, yyyy") vs whenny(date).xl
// Automatically picks the best representation based on distance from now
whenny(date).smart()
// → "just now" (< 1 min)
// → "5 minutes ago" (< 1 hour)
// → "Yesterday at 3:45 PM"
// → "Monday at 9:00 AM" (this week)
// → "Jan 15" (this year)
// → "Jan 15, 2024" (older)
// Classic relative time
whenny(date).relative() // "5 minutes ago"One line changes how every date in your app looks:
import { themes } from 'whenny/themes'
import { configure } from 'whenny'
configure(themes.slack)| Theme | "5 min ago" | "Yesterday" | Best For |
|---|---|---|---|
casual |
"5 minutes ago" | "Yesterday at 3:45 PM" | Consumer apps |
formal |
"5 minutes ago" | "Yesterday at 15:45" | Business apps |
slack |
"5m" | "Yesterday 3:45 PM" | Chat/messaging |
twitter |
"5m" | "Yesterday" | Social feeds |
discord |
"Today at 3:45 PM" | "Yesterday at 3:45 PM" | Community |
github |
"5 minutes ago" | "yesterday" | Developer tools |
minimal |
"5 min" | "1d" | Dashboards |
technical |
"300s" | "86400s" | Monitoring |
import { duration } from 'whenny'
duration(3661).long() // "1 hour, 1 minute, 1 second"
duration(3661).compact() // "1h 1m 1s"
duration(3661).clock() // "1:01:01"
duration(3661).timer() // "01:01:01"
duration(7200).human() // "2 hours"import { calendar } from 'whenny'
calendar.isToday(date) // true
calendar.isWeekend(date) // false
calendar.isBusinessDay(date) // true
calendar.daysUntil(futureDate) // 7
calendar.addBusinessDays(date, 5) // Date (skips weekends)import { compare } from 'whenny'
compare(dateA, dateB).smart() // "2 days before"
compare(dateA, dateB).days() // 2
compare(dateA, dateB).hours() // 48Auto-updating, SSR-safe hooks for React:
import { useRelativeTime, useCountdown } from 'whenny-react'
function Comment({ createdAt }) {
const time = useRelativeTime(createdAt) // auto-updates
return <span>{time}</span> // "5 minutes ago"
}
function Sale({ endsAt }) {
const { days, hours, minutes, seconds } = useCountdown(endsAt)
return <span>{days}d {hours}h {minutes}m {seconds}s</span>
}Solves the #1 timezone bug in SSR apps — server renders UTC, browser shows local time, user sees garbage:
// Server: serialize with timezone context
import { createTransfer } from 'whenny'
const payload = createTransfer(event.date, { timezone: 'America/New_York' })
// → { iso: "2026-03-15T15:00:00", originZone: "America/New_York", originOffset: -300 }
// Client: deserialize and format correctly
import { fromTransfer, whenny } from 'whenny'
const { date, originZone } = fromTransfer(payload)
whenny(date).inZone(originZone).clock // "3:00 PM" ← always correctOne file controls every string in your app:
// whenny.config.ts
import { defineConfig } from 'whenny/config'
export default defineConfig({
locale: 'en-US',
relative: {
justNow: 'moments ago',
minutesAgo: (n) => `${n}m ago`,
hoursAgo: (n) => `${n}h ago`,
},
styles: {
xs: 'D/M',
sm: 'D MMM',
md: 'D MMM YYYY',
lg: 'D MMMM YYYY',
xl: 'dddd, D MMMM YYYY',
},
calendar: {
weekStartsOn: 'monday',
businessDays: ['monday', 'tuesday', 'wednesday', 'thursday', 'friday'],
},
})AI assistants like Claude can use Whenny's date functions directly via MCP:
{
"mcpServers": {
"whenny": {
"command": "npx",
"args": ["create-whenny", "mcp"]
}
}
}10 tools available: whenny, format_datewind, format_smart, format_relative, format_duration, compare_dates, calendar_check, add_business_days, parse_natural, create_transfer.
import { parse } from 'whenny/natural'
parse('tomorrow at 3pm') // Date object
parse('next friday') // Date object
parse('in 2 hours') // Date object
parse('december 25th') // Date object10 built-in locales: en, es, fr, de, ja, zh, pt, it, ko, ar
import { getLocale, registerLocale } from 'whenny'
const spanish = getLocale('es')
// Or register your own
registerLocale('custom', {
justNow: 'right now',
minutesAgo: (n) => `${n} min ago`,
// ...
})Whenny accepts Temporal.Instant and Temporal.ZonedDateTime as inputs, forward-compatible with the TC39 Temporal API (shipping in Chrome 144 and Firefox 139):
const instant = Temporal.Now.instant()
whenny(instant).lg // works seamlesslynpx create-whenny init # Initialize in your project
npx create-whenny add smart # Add specific modules
npx create-whenny list # List available modules
npx create-whenny diff # Show changes from latest version
npx create-whenny mcp # Start the MCP server
npx create-whenny test-install # Full integration test| Package | Description | npm |
|---|---|---|
whenny |
Core date library (zero deps) | |
whenny-react |
React hooks (SSR-safe) | |
create-whenny |
CLI (shadcn-style install) |
They're great libraries. Use them if you need 60+ locales or 200+ manipulation functions.
Use Whenny if you want:
- Code you own — shadcn-style, in your repo, readable by AI
- Consistent date voice — one config instead of scattered format strings
- Smart formatting — automatic "just now" / "yesterday" / "Jan 15" without building it yourself
- React hooks —
useRelativeTimeanduseCountdownout of the box - Themes — match Slack, GitHub, Discord style with one line
- Timezone sync — Transfer Protocol solves SSR timezone bugs
- 374 tests, TypeScript strict mode, zero production dependencies
- 10 locales, 8 themes, 10 MCP tools
- Supports native
Date, ISO strings, Unix timestamps, andTemporalobjects
MIT
Built by ZVN DEV. Own your code. Configure your voice.