From eddb03853ddbc36b82433039e1a3cce8ebae8134 Mon Sep 17 00:00:00 2001 From: Yarchik Date: Thu, 2 Jul 2026 10:42:03 +0100 Subject: [PATCH] Fix %V (ISO week) parse to honor %u (ISO weekday) The %V reconstruction (if ("V" in d)) computed the day from d.w only and defaulted d.w = 1 when %w was absent, ignoring a parsed %u (ISO weekday). So the canonical ISO 8601 week-date pattern %G-W%V-%u parsed every weekday to the Monday of its ISO week. The %U/%W branch already reads d.u % 7; apply the same to the %V branch. --- src/locale.js | 2 +- test/parse-test.js | 11 +++++++++++ test/utcParse-test.js | 12 ++++++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/locale.js b/src/locale.js index cc0dac2..a15e7d2 100644 --- a/src/locale.js +++ b/src/locale.js @@ -218,7 +218,7 @@ export default function formatLocale(locale) { // Convert day-of-week and week-of-year to day-of-year. if ("V" in d) { if (d.V < 1 || d.V > 53) return null; - if (!("w" in d)) d.w = 1; + if (!("w" in d)) d.w = "u" in d ? d.u % 7 : 1; if ("Z" in d) { week = utcDate(newDate(d.y, 0, 1)), day = week.getUTCDay(); week = day > 4 || day === 0 ? utcMonday.ceil(week) : utcMonday(week); diff --git a/test/parse-test.js b/test/parse-test.js index 105bb88..027100b 100644 --- a/test/parse-test.js +++ b/test/parse-test.js @@ -77,6 +77,17 @@ it("timeParse(\"%w %V %G\")(date) parses numeric weekday, week number (ISO) and assert.deepStrictEqual(p("1 01 2019"), local(2018, 11, 31)); }); +it("timeParse(\"%u %V %G\")(date) parses numeric weekday (ISO), week number (ISO) and corresponding year", () => { + const p = timeParse("%u %V %G"); + assert.deepStrictEqual(p("1 01 1990"), local(1990, 0, 1)); + assert.deepStrictEqual(p("7 01 1990"), local(1990, 0, 7)); + assert.deepStrictEqual(p("4 53 1992"), local(1992, 11, 31)); + assert.deepStrictEqual(p("5 53 1992"), local(1993, 0, 1)); + assert.deepStrictEqual(p("1 01 2019"), local(2018, 11, 31)); + assert.deepStrictEqual(p("2 01 2019"), local(2019, 0, 1)); + assert.deepStrictEqual(p("7 01 2019"), local(2019, 0, 6)); +}); + it("timeParse(\"%w %V %g\")(date) parses numeric weekday, week number (ISO) and corresponding two-digits year", () => { const p = timeParse("%w %V %g"); assert.deepStrictEqual(p("1 01 90"), local(1990, 0, 1)); diff --git a/test/utcParse-test.js b/test/utcParse-test.js index 482e9bd..fac0461 100644 --- a/test/utcParse-test.js +++ b/test/utcParse-test.js @@ -143,6 +143,18 @@ it("utcParse(\"%w %V %G\")(date) parses numeric weekday, week number (ISO) and c assert.strictEqual(p("X 03 2010"), null); }); +it("utcParse(\"%u %V %G\")(date) parses numeric weekday (ISO), week number (ISO) and corresponding year", () => { + const p = utcParse("%u %V %G"); + assert.deepStrictEqual(p("1 01 1990"), utc(1990, 0, 1)); + assert.deepStrictEqual(p("7 01 1990"), utc(1990, 0, 7)); + assert.deepStrictEqual(p("4 53 1992"), utc(1992, 11, 31)); + assert.deepStrictEqual(p("5 53 1992"), utc(1993, 0, 1)); + assert.deepStrictEqual(p("1 01 2019"), utc(2018, 11, 31)); + assert.deepStrictEqual(p("2 01 2019"), utc(2019, 0, 1)); + assert.deepStrictEqual(p("7 01 2019"), utc(2019, 0, 6)); + assert.strictEqual(p("X 03 2010"), null); +}); + it("utcParse(\"%V %Y\")(date) week number (ISO) and year", () => { const p = utcParse("%V %Y"); assert.deepStrictEqual(p("01 1990"), utc(1990, 0, 1));