Skip to content

Leap-Day Birthday

  • The core functions, which every industry uses.

A birthday, a renewal or an anniversary repeats every year, so it is stored without one: --02-29. monthDayToDate puts it in a year and, where the year has no such day, gives the nearest earlier one.

Type a date, pick a locale and a year, or press one of the presets. The plates show the stored form, how it reads in the locale and the date in your year. The table shows eight years in a row, and two alternatives beside the library’s answer. Section 2 prints every call made. Every date on the page is a library result.

1. A date with no year

A full date of birth is read for its month and day only. In a common year the library gives 28 February.

The date in eight consecutive years
YeargmtVerdictYear pasted on (naive)1 March rule (your policy)
-⟨ NO SIGNAL ⟩no date⟨ NO SIGNAL ⟩⟨ NO SIGNAL ⟩
-⟨ NO SIGNAL ⟩no date⟨ NO SIGNAL ⟩⟨ NO SIGNAL ⟩
-⟨ NO SIGNAL ⟩no date⟨ NO SIGNAL ⟩⟨ NO SIGNAL ⟩
-⟨ NO SIGNAL ⟩no date⟨ NO SIGNAL ⟩⟨ NO SIGNAL ⟩
-⟨ NO SIGNAL ⟩no date⟨ NO SIGNAL ⟩⟨ NO SIGNAL ⟩
-⟨ NO SIGNAL ⟩no date⟨ NO SIGNAL ⟩⟨ NO SIGNAL ⟩
-⟨ NO SIGNAL ⟩no date⟨ NO SIGNAL ⟩⟨ NO SIGNAL ⟩
-⟨ NO SIGNAL ⟩no date⟨ NO SIGNAL ⟩⟨ NO SIGNAL ⟩

2. The calls

Every call behind the plates and the first row
isValidMonthDay("2024-02-29T08:30:00"); // false
parseMonthDay("2024-02-29T08:30:00"); // ""
parseMonthDayFromDate("2024-02-29T08:30:00"); // ""
parseMonthDayFromDateTime("2024-02-29T08:30:00"); // "--12-25"
formatMonthDay("--12-25", "zh-TW", { month: "long", day: "numeric" }); // "December 25"
monthDayToDate("--12-25", -271821); // "+275760-09-13"
parseMonthDayFromDate("+275760-09-13"); // "--12-25"
areMonthDaysEqual("--12-25", "--12-25"); // false
compareMonthDays("--12-25", "--12-25"); // 1
isValidDate("-271821-12-25"); // false
addDate("+275760-09-13", { days: 1 }); // "+275760-09-13"
parseMonthDayFromDate("+275760-09-13"); // "--12-25"
areMonthDaysEqual("--12-25", "--12-25"); // false
compareMonthDays("--12-25", "--12-25"); // 1

Stored as. parseMonthDay reads --MM-DD or MM-DD. A full date of birth goes through parseMonthDayFromDate, and a date-time through parseMonthDayFromDateTime. Each returns the canonical --MM-DD, or an empty string when it cannot read the input.

Reads as. formatMonthDay writes the month-day in a locale, with no year to invent.

gmt. monthDayToDate gives the date in the year. For --02-29 in a common year the answer is 28 February.

Verdict. areMonthDaysEqual says whether the date kept its month and day, and compareMonthDays says whether it moved earlier or later.

Year pasted on. Pasting the year onto the stored string and asking isValidDate is what a caller without a month-day type does. For 2023-02-29 the answer is no, and the cell reads NO SIGNAL. That is the failure this column shows, not a result of GMT.

1 March rule. Some contracts move the date to 1 March instead. That is a policy, and GMT has no mode for it: the column builds it from addDate on the library’s answer. Pick the rule your own agreement states and write it in your code.

See month-day values and a 29 February birthday in a common year.

Worth trying:

Code examples: MIT-0. Packages: MIT. Third-party data and components: their own licences, credited where they appear. Everything else:© 2026 NorthGuild, all rights reserved.