#4271·date-fns

en-US: parsing narrow noon "n" (bbbbb) silently yields 00:00 instead of 12:00

Author: cozuyaCreated Jul 22, 2026Updated Aug 25, 2026

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

javascript
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)
javascript
// 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