Skip to content

fix(isISO8601): validate week dates in strict mode - #2869

Open
yfwmaniish wants to merge 2 commits into
validatorjs:masterfrom
yfwmaniish:fix/iso8601-strict-week53
Open

fix(isISO8601): validate week dates in strict mode#2869
yfwmaniish wants to merge 2 commits into
validatorjs:masterfrom
yfwmaniish:fix/iso8601-strict-week53

Conversation

@yfwmaniish

Copy link
Copy Markdown

What

isISO8601(str, { strict: true }) never actually validates week dates (YYYY-Www / YYYY-Www-D). isValidDate() has no branch for them, so a week-date string falls through to the ordinal/calendar-date branch:

const match = str.match(/(\d{4})-?(\d{0,2})-?(\d*)/).map(Number);

Against "2019-W53", this loose regex only captures the year ("W53" isn't digits, so month/day capture empty strings → NaN after Number()). With month/day falsy, the function skips the date-object comparison entirely and returns true unconditionally:

if (month && day) { ... }
return true;

So every syntactically-valid week-date string passes strict mode regardless of whether the year actually has that many weeks. The main iso8601 regex already constrains the week field to 01-53 syntactically, but only weeks 01-52 exist in every ISO week-numbering year — week 53 exists only in "long" years (years whose 31 December falls in week 53 rather than week 1 of the next year). 2019-W53-1, for example, is not a real date, but strict mode accepts it today.

Fix

Added hasISOWeek53(year), using the standard ISO week-number algorithm (move 31 December to the Thursday of its own ISO week, then compare that Thursday's year-relative week number), and a weekMatch branch in isValidDate that applies it:

const weekMatch = str.match(/^([\+-]?\d{4})-?W(\d{2})/);
if (weekMatch) {
  const wYear = Number(weekMatch[1]);
  const week = Number(weekMatch[2]);
  return week <= 52 || hasISOWeek53(wYear);
}

Testing

  • Added 8 cases to the existing 'should validate ISO 8601 dates, with strict = true' test block: 4 valid (2015-W53-1, 2015-W53, 2020-W53-7, 2026-W53 — all real long years) and 4 invalid (2019-W53-1, 2019-W53, 2021-W53-7, 2022-W53 — all real short years, so week 53 doesn't exist).
  • Verified the week-53 algorithm standalone against known long/short ISO week-numbering years before wiring it in.
  • Negative control: reverted just the isISO8601.js fix (kept the new tests) and reran — the strict = true block fails exactly as expected, on the first new invalid case (isISO8601("2019-W53-1", {strict:true}) passed but should have failed). Restored the fix and reran clean.
  • Full suite after restoring the fix: npm run build && npm run lint && mocha292/292 passing, lint clean.

Fixes #2859.

Related-but-separate issues in the same cluster (not addressed by this PR):

@codecov

codecov Bot commented Aug 25, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (a79ff98) to head (b8035a9).

Additional details and impacted files
@@            Coverage Diff            @@
##            master     #2869   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files          114       114           
  Lines         2599      2611   +12     
  Branches       658       661    +3     
=========================================
+ Hits          2599      2611   +12     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

yfwmaniish and others added 2 commits August 25, 2026 21:26
isValidDate() had no branch for week dates (YYYY-Www[-D]), so
isISO8601(str, { strict: true }) never actually validated them --
it fell through to the ordinal/calendar-date branch, which always
returned true for any string matching the loose /(\d{4})-?(\d{0,2})-?(\d*)/
capture (week strings capture only the year, since "Www" isn't digits).

The main iso8601 regex already constrains the week field to 01-53
syntactically, but only weeks 01-52 exist in every ISO week-numbering
year -- week 53 exists only in "long" years (53 ISO weeks). Added
hasISOWeek53() using the standard algorithm (move 31 Dec to the
Thursday of its own ISO week, compare that Thursday's year-relative
week number) and a weekMatch branch in isValidDate that applies it.

Fixes validatorjs#2859.
codecov flagged the strict week-date patch at 91.66% -- one of the three new
branches was never taken. Two of the added lines short-circuit on data the
existing cases never supply:

- `week <= 52 || hasISOWeek53(year)` only ever evaluated the right-hand side,
  because every new case used week 53. Added '2020-W10' and '2020-W10-3'.
- `dec31.getUTCDay() || 7` only remaps Sunday, and 31 December falls on a
  Sunday in none of the years tested so far. Added '2017-W53' -- 31 Dec 2017
  is a Sunday and 2017 is a short year, so it exercises the remap and stays
  correctly invalid.

isISO8601.js is now at 100% statement, branch, function and line coverage.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@yfwmaniish
yfwmaniish force-pushed the fix/iso8601-strict-week53 branch from 114df15 to b8035a9 Compare August 26, 2026 06:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

isISO8601 strict mode never validates week dates

1 participant