en-US: parsing narrow noon "n" (bbbbb) silently yields 00:00 instead of 12:00
Human note: this is a new issue not currently in the backlog, it seems.
Description
In the en-US locale, formatting noon with the narrow b token produces "n", but parsing that same string back maps it to no day period at all, and the date silently comes out at hour 0 (the midnight value) instead of 12 — a format → parse round-trip that succeeds but produces the wrong time, with no Invalid Date signal.
The cause appears to be a mismatch in src/locale/en-US/_lib/match/index.ts: matchDayPeriodPatterns.narrow accepts "n", but parseDayPeriodPatterns.any.noon is /^no/i, which cannot match the single character "n" that the narrow pattern just consumed. This produces a match result whose value is undefined, and dayPeriodEnumToHours(undefined) falls through to its default case, which returns 0.
Reproduction
import { format, parse } from "date-fns";
const ref = new Date(2024, 0, 1);
format(new Date(2024, 0, 1, 12, 0), "bbbbb"); //=> "n" (narrow noon)
parse("n", "bbbbb", ref); //=> Mon Jan 01 2024 00:00:00 ❌ (expected 12:00)
// The abbreviated form and narrow midnight both work:
parse("noon", "b", ref); //=> Mon Jan 01 2024 12:00:00 ✅
parse("mi", "bbbbb", ref); //=> Mon Jan 01 2024 00:00:00 ✅ (midnight)// The internal matcher consumes "n" but maps it to no value:
import { enUS } from "date-fns/locale";
enUS.match.dayPeriod("n", { width: "narrow" }); //=> { value: undefined, rest: "" }
enUS.match.dayPeriod("noon", { width: "narrow" }); //=> { value: undefined, rest: "oon" }The a token family accepts "n" with the same silent hour-0 result (parse("n", "aaaaa", ref) → 00:00), though for a the round-trip framing doesn't apply — format(noon, "aaaaa") produces "p", since a only distinguishes AM/PM.
Note on fix direction
I'm not proposing a specific fix — options include making the parser able to map the narrow noon form (e.g. accepting "n" for noon), or having the parser treat a match that maps to no known day period as a failure (Invalid Date) rather than silently defaulting to hour 0. Which is intended is a maintainer decision; it's also possible other locales' narrow day-period data has the same shape of mismatch.
Environment
- date-fns: reproduced against current
main. - Node.js: v24.12.0
Source: date-fns/date-fns