Month-Day Values
A month-day is a month and a day with no year. Use it for a birthday, an anniversary or a
recurring holiday, where the year would only drift. gmt writes it as --MM-DD, the ISO 8601
truncated form that RFC 3339 and RFC 6350 also use.
What a month-day is
Section titled “What a month-day is”import { isValidMonthDay } from "@northguild/gmt";
isValidMonthDay("--12-25"); // trueisValidMonthDay("12-25"); // true — the leading -- is optional on inputisValidMonthDay("--02-29"); // true — 29 February exists, in leap yearsisValidMonthDay("--1225"); // false — the basic form is refusedgmt reads --MM-DD and MM-DD, and always writes --MM-DD. The basic form --MMDD is
refused, as isValidDate refuses 20241225.
Validate and read
Section titled “Validate and read”import { isValidMonthDay, parseMonthDay } from "@northguild/gmt";
isValidMonthDay("--02-30"); // false — February has no 30thisValidMonthDay("--12-25[u-ca=gregory]"); // false — without a year, only the ISO calendar is read
parseMonthDay("12-25"); // "--12-25"parseMonthDay("--12-25[u-ca=iso8601]"); // "--12-25" — the annotation is droppedparseMonthDay("--12-25[u-ca=gregory]"); // ""parseMonthDay("--02-30"); // ""parseMonthDay returns "" for anything isValidMonthDay refuses, so the two always agree.
From a date or a date-time
Section titled “From a date or a date-time”import { parseMonthDayFromDate, parseMonthDayFromDateTime } from "@northguild/gmt";
parseMonthDayFromDate("2024-12-25"); // "--12-25"parseMonthDayFromDate("2024-02-29"); // "--02-29" — the leap day is keptparseMonthDayFromDate("2024-12-25T10:00:00"); // "" — a date-time is not a date
parseMonthDayFromDateTime("2024-02-29T23:59:59.999999999"); // "--02-29" — the time never moves the dayparseMonthDayFromDateTime("2024-12-25"); // "" — a date has no timeFrom a producer’s pattern
Section titled “From a producer’s pattern”parseMonthDayWithPattern reads a month-day a producer wrote in its own layout. The locale
matters for month names:
import { parseMonthDayWithPattern } from "@northguild/gmt";
parseMonthDayWithPattern("December 25", "MMMM d", "en-US"); // "--12-25"parseMonthDayWithPattern("25 декабря", "d MMMM", "ru-RU"); // "--12-25"parseMonthDayWithPattern("12月25日", "M月d日", "ja-JP"); // "--12-25"parseMonthDayWithPattern("25 décembre 2024", "d MMMM yyyy", "fr-FR"); // "" — a year token is refusedSome languages inflect a month name when a day comes with it (25 декабря) and write the bare
name another way (декабрь). The MMMM token reads either form, and so does its stand-alone
twin LLLL. A pattern with a year token is refused: use parseDateWithPattern for those.
Format
Section titled “Format”import { formatMonthDay } from "@northguild/gmt";
formatMonthDay("--12-25", "en-US"); // "12/25"formatMonthDay("--12-25", "en-US", { month: "long", day: "numeric" }); // "December 25"formatMonthDay("--12-25", "en-US", { dateStyle: "medium" }); // "Dec 25"
formatMonthDay("--12-25", "de-DE"); // "25.12."formatMonthDay("--12-25", "de-DE", { month: "long", day: "numeric" }); // "25. Dezember"formatMonthDay("--12-25", "de-DE", { dateStyle: "medium" }); // "25.12."
formatMonthDay("--12-25", "ja-JP"); // "12/25"formatMonthDay("--12-25", "ja-JP", { month: "long", day: "numeric" }); // "12月25日"formatMonthDay("--12-25", "ja-JP", { dateStyle: "long" }); // "12/25"A dateStyle takes the month and day widths from the locale’s own date pattern, as the
specification says and as native Temporal.PlainMonthDay#toLocaleString does. So de-DE medium
is 25.12., and ja-JP writes the month as a number in every style. formatMonthDay formats
through the Gregorian calendar, whatever calendar the locale tag names. A year or weekday option is dropped, and a
timeStyle gives "".
Compare and sort
Section titled “Compare and sort”Order is by month, then by day. 29 February sorts between 28 February and 1 March.
import { compareMonthDays, areMonthDaysEqual } from "@northguild/gmt";
compareMonthDays("--01-01", "--12-31"); // -1 — month firstcompareMonthDays("--02-29", "--03-01"); // -1compareMonthDays("12-25", "--12-25"); // 0 — both input formscompareMonthDays("--02-30", "--03-01"); // null — an invalid month-day
areMonthDaysEqual("12-25", "--12-25"); // trueareMonthDaysEqual("--02-29", "--02-28"); // false — 29 February is not constrained
["--12-25", "--02-29", "--01-01", "--03-01", "--02-28"].sort((a, b) => compareMonthDays(a, b) ?? 0);// ["--01-01", "--02-28", "--02-29", "--03-01", "--12-25"]compareMonthDays returns null for an invalid value, so a sort callback maps it to 0.
A date in a given year
Section titled “A date in a given year”monthDayToDate puts a month-day in a year:
import { monthDayToDate } from "@northguild/gmt";
monthDayToDate("--12-25", 2024); // "2024-12-25"monthDayToDate("--02-29", 2024); // "2024-02-29" — a leap yearmonthDayToDate("--02-29", 2023); // "2023-02-28" — not a leap yearmonthDayToDate("--02-29", 1900); // "1900-02-28" — a century that is not a leap yearmonthDayToDate("--02-29", 2000); // "2000-02-29" — divisible by 400In a year with no 29 February, the date is moved back to the last day of February. Some rules and contracts use 1 March instead. That is your policy to apply: see a 29 February birthday in a common year.
See also
Section titled “See also”- Parsing — token patterns and the other parsers
- Formatting — locale-aware display
- Comparisons — ordering and equality for dates
- Validation — checking a string before parsing
- A 29 February birthday in a common year
monthDayToDatereference
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.