Skip to content

format() โ€‹

Token-based date and time formatting for any Temporal object โ€” Moment.js muscle memory, Temporal-native engine.

Signature โ€‹

ts
function format(
  temporalObj: FormattableTemporalType,
  formatString: string,
  options?: FormatOptions
): string

type FormattableTemporalType =
  | Temporal.PlainDate
  | Temporal.PlainTime
  | Temporal.PlainDateTime
  | Temporal.ZonedDateTime
  | Temporal.Instant

interface FormatOptions {
  /**
   * BCP 47 locale tag used for month and weekday *names* (MMMM, MMM, dddd, ddd).
   * Defaults to the runtime's default locale.
   * @example 'fr', 'es', 'ja', 'de', 'zh-TW'
   */
  locale?: string
}

Token reference โ€‹

Tokens are matched longest-first (MMMM before MMM before MM before M; Do before DD before D; HH before H), so format strings are never ambiguous. Any sequence that is not a token โ€” including unrecognized letters and all punctuation โ€” is emitted literally.

Date tokens โ€‹

TokenExampleDescription
YYYY2026Full 4-digit year
YY262-digit year, zero-padded
MMMMAprilFull month name (locale-aware)
MMMAprAbbreviated month name (locale-aware)
MM04Numeric month, zero-padded (01โ€“12)
M4Numeric month, no padding (1โ€“12)
Do9thDay of month with ordinal suffix
DD09Day of month, zero-padded (01โ€“31)
D9Day of month, no padding (1โ€“31)
ddddThursdayFull weekday name (locale-aware)
dddThuAbbreviated weekday name (locale-aware)

Time tokens โ€‹

TokenExampleDescription
HH1424-hour clock, zero-padded (00โ€“23)
H1424-hour clock, no padding (0โ€“23)
hh0212-hour clock, zero-padded (01โ€“12)
h212-hour clock, no padding (1โ€“12)
mm05Minutes, zero-padded (00โ€“59)
ss30Seconds, zero-padded (00โ€“59)
SSS042Milliseconds, zero-padded (000โ€“999)
APMAM/PM uppercase
apmam/pm lowercase

Offset & timestamp tokens โ€‹

TokenExampleDescription
Z+05:30UTC offset, with colon (ZonedDateTime / Instant only)
ZZ+0530UTC offset, no colon
X1775736000Unix timestamp in seconds
x1775736000000Unix timestamp in milliseconds

Escape syntax โ€‹

Wrap any literal text in [square brackets] so its characters are never read as tokens โ€” essential for words that contain token letters.

InputOutput
[Today is] ddddToday is Thursday
h:mm A [at] MMM D2:05 PM at Apr 9
YYYY-MM-DD[T]HH:mm[Z]2026-04-09T14:05Z (literal T and Z)

Single letters are tokens. D, M, H, h, A, a, Z, X, x are all interpreted. To print a literal word like Day or a trailing Z, wrap it: [Day], [Z]. There are no m, s, d, or z tokens โ€” those characters pass through untouched.

Which tokens work on which type? โ€‹

A Temporal object only carries the fields its type makes sense for. Using a token a type can't provide throws a descriptive Error.

Token groupPlainDatePlainTimePlainDateTimeZonedDateTimeInstantยน
Year / month / dayโœ…โŒโœ…โœ…โœ…
Weekday (dddd ddd)โœ…โŒโœ…โœ…โœ…
Time (HH h mm ss SSS A/a)โŒโœ…โœ…โœ…โœ…
Offset (Z ZZ)โŒโŒโŒโœ…โœ…
Timestamp (X x)โŒโŒโŒโœ…โœ…

ยน An Instant is normalized to a UTC ZonedDateTime before formatting, so every field is available and the offset is always +00:00.

Examples by Temporal type โ€‹

PlainDate โ€‹

ts
import { format } from 'moment-less'

const date = Temporal.PlainDate.from('2026-04-09')

format(date, 'YYYY-MM-DD')      // โ†’ "2026-04-09"
format(date, 'MMMM Do, YYYY')   // โ†’ "April 9th, 2026"
format(date, 'ddd, D MMM YYYY') // โ†’ "Thu, 9 Apr 2026"
format(date, 'DD/MM/YYYY')      // โ†’ "09/04/2026"

Time tokens (HH, mm, A, โ€ฆ) throw on a PlainDate โ€” there is no clock component.

PlainDateTime โ€‹

ts
import { format } from 'moment-less'

const dt = Temporal.PlainDateTime.from('2026-04-09T14:05:30.042')

format(dt, 'YYYY-MM-DD[T]HH:mm:ss') // โ†’ "2026-04-09T14:05:30"
format(dt, 'MMMM Do, YYYY h:mm A')  // โ†’ "April 9th, 2026 2:05 PM"
format(dt, 'dddd [at] H:mm')        // โ†’ "Thursday at 14:05"
format(dt, 'HH:mm:ss.SSS')          // โ†’ "14:05:30.042"

PlainTime โ€‹

ts
import { format } from 'moment-less'

const time = Temporal.PlainTime.from('14:05:30')

format(time, 'HH:mm')    // โ†’ "14:05"
format(time, 'h:mm A')   // โ†’ "2:05 PM"
format(time, 'hh:mm a')  // โ†’ "02:05 pm"

Date tokens (YYYY, MMMM, dddd, โ€ฆ) throw on a PlainTime.

ZonedDateTime โ€‹

ts
import { format } from 'moment-less'

const zdt = Temporal.ZonedDateTime.from('2026-04-09T14:05:30+05:30[Asia/Kolkata]')

format(zdt, 'YYYY-MM-DD HH:mm Z')  // โ†’ "2026-04-09 14:05 +05:30"
format(zdt, 'ZZ')                  // โ†’ "+0530"
format(zdt, 'MMMM Do, YYYY')       // โ†’ "April 9th, 2026"
format(zdt, 'x')                   // โ†’ "1775723730000"

Instant โ€‹

ts
import { format } from 'moment-less'

const inst = Temporal.Instant.from('2026-04-09T08:35:30Z')

// An Instant is always displayed in UTC
format(inst, 'YYYY-MM-DD[T]HH:mm:ssZ') // โ†’ "2026-04-09T08:35:30+00:00"
format(inst, 'HH:mm [UTC]')            // โ†’ "08:35 UTC"
format(inst, 'X')                      // โ†’ "1775723730"

To display an Instant in a specific time zone, convert it first: inst.toZonedDateTimeISO('America/New_York').

Locale option โ€‹

options.locale affects month names (MMMM, MMM) and weekday names (dddd, ddd). Numeric output โ€” including the Do ordinal suffix and A/a โ€” always renders in English.

ts
import { format } from 'moment-less'

const date = Temporal.PlainDate.from('2026-04-09')

format(date, 'MMMM', { locale: 'fr' })       // โ†’ "avril"
format(date, 'dddd', { locale: 'fr' })       // โ†’ "jeudi"
format(date, 'dddd D MMMM', { locale: 'ja' })// โ†’ "ๆœจๆ›œๆ—ฅ 9 4ๆœˆ"
format(date, 'MMMM', { locale: 'de' })       // โ†’ "April"

Error behavior โ€‹

format() throws a standard Error with a descriptive message when a token's required field is missing for the given type:

ts
format(Temporal.PlainDate.from('2026-04-09'), 'HH:mm')
// Error: Token "HH" requires an hour field
//        (not available on PlainDate โ€” use PlainDateTime or ZonedDateTime)

Unrecognized sequences are passed through as literal text โ€” format(date, 'Q1') returns "Q1" because Q is not a token.

Released under the MIT License.