@dayex/dayex
v1.0.0
Published
2KB immutable date time library alternative to Moment.js with the same modern API
Downloads
184
Maintainers
Readme
Dayex
A modern date kernel for product work — not a calendar widget, not a Moment clone.
Dayex is a tiny, immutable JavaScript date library. The core stays under 3 KB gzip. Everything else — locales, time zones, durations, business calendars, date ranges — loads only when you ask for it.
The name is deliberate: day + next. A date you can chain, a range you can hold, a working calendar you can actually ship.
Documentation · npm · API
import dayex from 'dayex'
dayex('2026-01-15')
.startOf('month')
.add(1, 'week')
.format('YYYY-MM-DD')
// '2026-01-08'Why Dayex
Classic date libraries treated time as a single mutable instant. Dayex treats time as values you compose.
| You need | Dayex gives you |
| --- | --- |
| A point in time | dayex() — parse, format, add, query |
| A working calendar | businessDay — holidays, weekends, SLA offsets |
| An interval | range — overlap, intersect, iterate, range sets |
| A locale or zone | On-demand modules. Unused code never ships |
The parse / format / add surface will feel familiar if you have used Dayex. The model is not the same. Instances never mutate. Ranges are first-class objects. Business days are a real calendar, not day() !== 0.
Zero runtime dependencies. Time zones go through Intl, not a bundled tz database.
Install
npm install dayeximport dayex from 'dayex'
// or
const dayex = require('dayex')Core
Every call returns a new instance.
const due = dayex('2026-03-01T09:00:00')
due.add(2, 'week').subtract(1, 'day')
due.startOf('month').endOf('week')
due.set('hour', 18).hour() // 18
due.isBefore(dayex(), 'day')
due.format('YYYY-MM-DD HH:mm')Parse a value, display it, move it, or compare it. Units accept long, short, and plural forms (day, d, days).
dayex() // now
dayex('2026-09-11')
dayex(Date.now())
dayex.unix(1773129600)Locales
Nothing locale-specific is in the default build. Import what the product actually shows.
import 'dayex/locale/ko'
import 'dayex/locale/ja'
dayex.locale('ko')
dayex().format('YYYY년 MMMM D일 dddd')
dayex('2026-01-01').locale('ja').format('LL')Plugins
Extend the kernel only for the features you use.
import dayex from 'dayex'
import utc from 'dayex/plugin/utc'
import timezone from 'dayex/plugin/timezone'
import duration from 'dayex/plugin/duration'
import relativeTime from 'dayex/plugin/relativeTime'
dayex.extend(utc)
dayex.extend(timezone)
dayex.extend(duration)
dayex.extend(relativeTime)
dayex('2026-01-01T00:00:00Z')
.tz('Asia/Seoul')
.from(dayex())Other official modules include customParseFormat, isoWeek, isBetween, minMax, localizedFormat, advancedFormat, quarterOfYear, and calendar.
Two modules define the current Dayex surface — the parts a modern app actually argues about.
Business days
Weekends and holidays are not the same thing. businessDay keeps them separate, then lets you move and count on the result.
import businessDay from 'dayex/plugin/businessDay'
dayex.extend(businessDay, {
workingWeekdays: [1, 2, 3, 4, 5],
holidays: ['2026-01-01', { date: '12-25', name: 'Christmas' }]
})
dayex('2026-01-02T17:00:00').addBusinessDays(3)
// 2026-01-07T17:00:00 — weekend skipped, time kept
dayex('2026-01-03').toBusinessDay('nearest')
dayex('2026-01-31').businessDiff('2026-01-01')
dayex().businessDaysInMonth()Override the calendar per call when one process serves more than one jurisdiction.
dayex('2026-07-03').isBusinessDay({ holidays: usFederal })Ranges
Two timestamps are not an interval. range is a value: contains, overlaps, intersect, walk, split.
import range from 'dayex/plugin/range'
dayex.extend(range)
const leave = dayex.range('2026-01-05', '2026-01-09')
const sprint = dayex('2026-01').toRange('month')
leave.contains(dayex())
leave.overlaps(sprint)
leave.each('day').map((d) => d.format('MM/DD'))
// checkout day can be reused
const a = dayex.range('2026-01-01', '2026-01-03')
const b = dayex.range('2026-01-03', '2026-01-05')
a.overlaps(b, 'day', '[)') // false
a.adjacent(b, 'day', '[)') // trueDisconnected pieces become a RangeSet — merge, subtract, query as one calendar.
dayex.rangeSet(leave, dayex.range('2026-02-01', '2026-02-03'))Design
- Immutable.
addnever changes the instance you already hold. - Composable. Points, ranges, and working days are separate types that plug together.
- Paid for only once. Core has no
dependencies. Plugins and locales are import-level. - Host Intl for zones. No shipped timezone dump.
- Typed. Official plugins ship declaration files.
The chainable grammar is intentionally close to the ecosystem people already type. The types you get back — especially DayexRange and a configured business calendar — are the modern part.
Docs
Full parse, display, and plugin reference: dayex.org
License
MIT. See LICENSE.
