Skip to content
native-dates

Plugins / Reference

month-day plugin

Month-and-day values for birthdays, anniversaries, and annual holidays, with leap-year handling built in.

import { monthDay } from '@native-dates/plugins/month-day'1.2 kB min+br

Reading month-day values

Import the plugin to hold a recurring date without inventing a placeholder year. Loading it adds .monthDay and as('monthDay') to calendar dates and zoned datetimes, and lets next() accept a month-day.

month-day.js
import { today } from 'native-dates';
import { dayMonth, monthDay } from '@native-dates/plugins/month-day';

const birthday = monthDay('10/17');
const sameDay = dayMonth('17/10');

birthday.equals(sameDay); // true
birthday.in(2027).toString(); // '2027-10-17'
birthday.next(); // upcoming CalendarDate from today
today().next(birthday); // same upcoming occurrence

monthDay()

monthDay(input, options?): MonthDay
monthDay(month, day): MonthDay
new MonthDay(input, options?)

Reads month-first strings, two whole numbers, a fields object, or any date or timestamp with its year dropped. With the loose plugin, it also reads English month names and returns null when unreadable.

inputMonthDayInput | numberrequired

Month-day string, fields object, existing date or timestamp, or 1-indexed month.

optionsZone | MonthDayOptions | number

Day of the month when passing two numbers, or a time zone or options object.

3 options
zoneZone

Time zone used to determine the calendar day of an instant string, DateTime, or Date.

dayFirstbooleandefault false

Read human-written strings like '17/10' day-first, matching dayMonth().

loosebooleandefault false

Read named months like 'Oct 17' and return null instead of throwing when unreadable.

MonthDay

An immutable MonthDay, or null when loose mode cannot read input.

monthDay('10/17').toString(); // '10-17'
monthDay(2, 29).toString(); // '02-29'
monthDay({ month: 10, day: 17 }).toString(); // '10-17'
monthDay('1990-10-17').toString(); // '10-17'

dayMonth()

dayMonth(input, options?): MonthDay
dayMonth(day, month): MonthDay

Reads human-written strings and two-number pairs day-first into the same MonthDay class, regardless of global loose settings. Zero-padded ISO strings with two digits on each side of a dash always read month-first under both functions so JSON output round-trips cleanly.

inputMonthDayInput | numberrequired

Day-first string such as '17/10', day of the month, or any MonthDayInput.

optionsZone | MonthDayOptions | number

1-indexed month when passing two numbers, or a zone or options object.

MonthDay

An immutable MonthDay, or null when loose mode cannot read input.

dayMonth('17/10').toString(); // '10-17'
dayMonth('17.10').toString(); // '10-17'
dayMonth(17, 10).toString(); // '10-17'
dayMonth('10-17').toString(); // '10-17'

Properties

Every MonthDay instance exposes its formatted label and numeric parts.

Property Type Description
text string Locale-formatted month and day, such as 'Oct 17'.
month number 1-indexed calendar month from 1 through 12.
day number Day of the month from 1 through 31.

Placing in a year and stepping

in()

md.in(year): CalendarDate

Returns the CalendarDate this month-day falls on in the given year. February 29 falls on February 28 in non-leap years.

yearnumber | stringrequired

Whole-number calendar year, such as 2027.

CalendarDate

Occurrence of this month-day in year.

monthDay('10-17').in(2027).toString(); // '2027-10-17'
monthDay('02-29').in(2028).toString(); // '2028-02-29'
monthDay('02-29').in(2027).toString(); // '2027-02-28'

next() / previous()

md.next(day?): CalendarDate
md.previous(day?): CalendarDate
d.next(md): CalendarDate
dt.next(md): DateTime

Finds the upcoming or most recent occurrence around a reference day, defaulting to today. If the reference day is already that occurrence, it steps a full year ahead or back. Passing a MonthDay to a date or datetime steps the same way while preserving clock time and zone.

dayCalendarDateInputdefault today()

Reference date or timestamp to step from.

CalendarDate

Upcoming or previous CalendarDate occurrence.

import { date, datetime } from 'native-dates';

const birthday = monthDay('10-17');

birthday.next('2026-10-17').toString(); // '2027-10-17'
birthday.previous('2026-10-17').toString(); // '2025-10-17'
date('2026-11-11').next(birthday).toString(); // '2027-10-17'
datetime('2026-11-11T09:30', 'America/New_York').next(monthDay('03-08')).hour; // 9

after() / before()

md.after(day): CalendarDate
md.before(day): CalendarDate

Explicit required-argument forms of next() and previous(), returning the occurrence earlier or later than the given day.

dayCalendarDateInputrequired

Reference date or timestamp.

CalendarDate

Occurrence earlier or later than day.

const leapBirthday = monthDay('02-29');

leapBirthday.after('2027-02-27').toString(); // '2027-02-28'
leapBirthday.after('2027-02-28').toString(); // '2028-02-29'
leapBirthday.before('2027-03-01').toString(); // '2027-02-28'

Matching dates and equality

equals() vs. fallsOn()

Use equals() to check for the exact same month and day. Use fallsOn() for annual occurrences, where February 29 lands on February 28 in common years.

fallsOn()

md.fallsOn(day): boolean

Returns true when the given day is this month-day’s occurrence in that date’s own year, placing February 29 on February 28 in years without a leap day.

dayCalendarDateInputrequired

Calendar date or timestamp to test.

boolean

true when this month-day lands on day in that year.

const leapDay = monthDay('02-29');

leapDay.fallsOn('2027-02-28'); // true
leapDay.fallsOn('2028-02-28'); // false
leapDay.fallsOn('2028-02-29'); // true

equals()

md.equals(other): boolean

Returns true when the other input carries the same month and day. Accepts another month-day, an ISO month-day string, a fields object, or a date whose year is dropped. Ambiguous slash or dot strings throw so you read them with a month-first or day-first factory first.

otherMonthDayInputrequired

MonthDay, ISO 'MM-DD' string, fields object, or date.

boolean

true when both values name the same month and day.

monthDay('10/17').equals(dayMonth('17/10')); // true
monthDay('10-17').equals('1990-10-17'); // true
monthDay('02-29').equals('2027-02-28'); // false

isToday() / isTomorrow() / isYesterday()

md.isToday(zone?): boolean
md.isTomorrow(zone?): boolean
md.isYesterday(zone?): boolean

Checks whether this month-day falls on today, tomorrow, or yesterday in the given zone or the configured default time zone.

zoneZone

Time zone used to determine today's calendar date.

boolean

Boolean check result.

today().monthDay.isToday(); // true
today().plus(1, 'day').monthDay.isTomorrow(); // true
today().minus(1, 'day').monthDay.isYesterday(); // true

Formatting and conversion

format()

md.format(spec?, locale?): string

Formats the month and day in the order locale writes them, ignoring year, weekday, clock, and zone options. Accepts any preset name, an options object, custom entries in MonthDay.presets, or token patterns when the tokens plugin is loaded.

specFormatSpecdefault 'medium'

Preset name such as 'short' or 'long', Intl.DateTimeFormatOptions, or token pattern.

localestring

BCP 47 locale tag overriding the configured default for this call.

string

Localized month and day string.

import '@native-dates/plugins/tokens';

const birthday = monthDay('10-17');

birthday.format('short', 'en-US'); // '10/17'
birthday.format('short', 'en-GB'); // '17/10'
birthday.format('long', 'de'); // '17. Oktober'
birthday.format('MMM Do', 'en-US'); // 'Oct 17th'

isMonthDay()

isMonthDay(value): value is MonthDay

Returns true when the given value is a MonthDay instance, including across realms and bundles. Core kindOf() returns 'monthDay' for these instances.

import { kindOf } from 'native-dates';
import { isMonthDay } from '@native-dates/plugins/month-day';

isMonthDay(monthDay('10/17')); // true
isMonthDay('10-17'); // false
kindOf(monthDay('10/17')); // 'monthDay'

Serialization and interop

Method Return Description
as('monthDay') MonthDay Returns this MonthDay in generic conversion chains, matching d.as('monthDay') and dt.as('monthDay').
toString(), toJSON() string ISO 8601 'MM-DD' string, such as '10-17'.
toTemporal() Temporal.PlainMonthDay Underlying ISO Temporal.PlainMonthDay instance.
valueOf() never Throws a RangeError because a month-day has no position on the number line.
Edit this pageUpdated Nov 12, 2026