Skip to content

Getting Started

moment-less is a zero-dependency TypeScript library that brings Moment.js-style token formatting to the native TC39 Temporal API. If you already know YYYY-MM-DD format strings, you already know moment-less.

Installation

sh
npm install moment-less
sh
pnpm add moment-less
sh
yarn add moment-less

Temporal availability: Node 22+, Chrome 127+, Firefox 139+, Safari 18.2+, and Deno 2.1+ all ship Temporal natively. For older environments, see Browser & Runtime Support.

Your First Format

ts
import { format } from 'moment-less'

const date = Temporal.PlainDate.from('2026-04-09')
console.log(format(date, 'MMMM Do, YYYY'))
// → "April 9th, 2026"

That's it. No configuration, no locale setup, no timezone wrangling.

All Five Functions

format(temporalObj, formatString, options?)

Token-based formatting for any Temporal type.

ts
import { format } from 'moment-less'

const dt = Temporal.PlainDateTime.from('2026-04-09T14:05:30')
format(dt, 'YYYY-MM-DD')           // → "2026-04-09"
format(dt, 'h:mm A')               // → "2:05 PM"
format(dt, 'dddd, MMMM Do, YYYY')  // → "Thursday, April 9th, 2026"
format(dt, 'ddd MMM D YYYY')       // → "Thu Apr 9 2026"

// Escape literal text with square brackets
format(dt, '[Today is] dddd')      // → "Today is Thursday"

fromNow(temporalObj, reference?, locale?)

Human-readable relative time string.

ts
import { fromNow } from 'moment-less'

const now = Temporal.Now.plainDateTimeISO()
const posted = now.subtract({ hours: 3 })

fromNow(posted)        // → "3 hours ago"  (uses Temporal.Now internally)
fromNow(posted, now)   // → "3 hours ago"  (explicit reference — great for tests)

const future = now.add({ days: 2 })
fromNow(future, now)   // → "in 2 days"

// Locale support
fromNow(posted, now, 'fr')  // → "il y a 3 heures"
fromNow(posted, now, 'ja')  // → "3時間前"

calendar(temporalObj, reference?, options?)

Context-aware calendar label, like chat apps and file managers use.

ts
import { calendar } from 'moment-less'

const now = Temporal.Now.plainDateTimeISO()
const today    = now.subtract({ hours: 2 })
const yesterday = now.subtract({ days: 1 })
const lastWeek  = now.subtract({ days: 4 })
const oldDate   = Temporal.PlainDate.from('2025-11-15')

calendar(today, now)      // → "Today at 12:05 PM"
calendar(yesterday, now)  // → "Yesterday"
calendar(lastWeek, now)   // → "Sunday"
calendar(oldDate, now)    // → "Nov 15, 2025"

humanizeDuration(duration, locale?)

Converts a Temporal.Duration to a human-readable string, picking the most significant unit.

ts
import { humanizeDuration } from 'moment-less'

humanizeDuration(new Temporal.Duration(0, 0, 0, 0, 0, 45))  // → "45 minutes"
humanizeDuration(new Temporal.Duration(0, 0, 0, 0, 2, 30))  // → "3 hours"
humanizeDuration(new Temporal.Duration(0, 0, 0, 3))          // → "3 days"
humanizeDuration(new Temporal.Duration(1, 2))                // → "a year"

// Localized
humanizeDuration(new Temporal.Duration(0, 0, 0, 0, 2), 'fr') // → "2 heures"
humanizeDuration(new Temporal.Duration(0, 0, 0, 0, 2), 'es') // → "2 horas"

fromDate(date)

Bridges a legacy JavaScript Date object to a Temporal.Instant.

ts
import { format, fromDate } from 'moment-less'

const inst = fromDate(new Date('2026-04-09T14:05:00Z'))
format(inst, 'YYYY-MM-DD HH:mm')  // → "2026-04-09 14:05"

// Works with Date.now() too
const now = fromDate(new Date(Date.now()))

Token Quick Reference

TokenOutput exampleDescription
YYYY20264-digit year
YY262-digit year
MMMMAprilFull month name
MMMAprShort month name
MM04Month, zero-padded
M4Month, no padding
Do9thDay of month with ordinal suffix
DD09Day, zero-padded
D9Day, no padding
ddddThursdayFull weekday name
dddThuShort weekday name
HH1424-hour hour, zero-padded
H1424-hour hour, no padding
hh0212-hour hour, zero-padded
h212-hour hour, no padding
mm05Minutes, zero-padded
ss30Seconds, zero-padded
APMAM/PM uppercase
apmam/pm lowercase
Z+05:30UTC offset (ZonedDateTime/Instant only)
[…]literal textEscaped literal characters

See the full format() API reference for details on which tokens are available for each Temporal type.

Next Steps

Released under the MIT License.