dayjs icon indicating copy to clipboard operation
dayjs copied to clipboard

Incorrect year with localized month in date

Open Vansinnesvisor opened this issue 1 year ago • 6 comments

Describe the bug When use customParseFormat plugin and localized string with latest month of year e.g. "1 декабря 2023" I'm getting the wrong year (+1).

Base code

import dayjs from "dayjs"
import customParseFormat from "dayjs/plugin/customParseFormat"
import "dayjs/locale/ru"

dayjs.extend(customParseFormat)
dayjs.locale("ru")

Example

//Check various months
console.log("JAN:", dayjs("1 января 2023", "D MMMM YYYY").format("DD.MM.YYYY")); //JAN: 01.01.2023
console.log("NOV:", dayjs("1 ноября 2023", "D MMMM YYYY").format("DD.MM.YYYY")); //NOV: 01.11.2023
console.log("DEC:", dayjs("1 декабря 2023", "D MMMM YYYY").format("DD.MM.YYYY")); //DEC: 01.12.2024
// Check end of year
console.log("END:", dayjs().endOf("year").format("DD.MM.YYYY")); //END: 31.12.2023

Expected behavior

console.log("DEC:", dayjs("1 декабря 2023", "D MMMM YYYY").format("DD.MM.YYYY")); //Must be: 01.12.2023

Information

  • Day.js Version [v1.11.10]
  • OS: [macOS Sonoma 14.1]
  • Browser [Chrome 119.0.6045.159]
  • Time zone: [GMT+7 Novosibirsk/Russia]

Vansinnesvisor avatar Nov 21 '23 05:11 Vansinnesvisor

I've debug the issue related to date parsing mentioned above, and found out it exist at least in Russian and Ukrainian. Please note that I am not a language expert; my observations are based on the behavior I encountered in the code.

Observed Behavior The issue occurs when parsing dates in Russian and Ukrainian languages. Here are the console logs demonstrating the problem:

console.log("DEC:", dayjs("1 декабря 2023", "D MMMM YYYY").format("DD.MM.YYYY")); console.log("DEC:", dayjs("1 грудня 2023", "D MMMM YYYY").format("DD.MM.YYYY")

Temporary Workaround A quick fix, for those needing an immediate solution without a formal fix from the dayjs library, is to adjust the function call as follows:

console.log("DEC:", dayjs("1 декабрь 2023", "D MMMM YYYY г."));

My understanding is that both "декабрь" and "декабря" are variants of December in Russian.

Potential Code-Level Issue Upon investigating the dayjs library's code, specifically in the /src/plugin/customParseFormat/index.js file, I believe I've located the potential source of the issue:

The parseFormattedInput function internally calls const parser = makeParser(format). The issue seems to be rooted in how the parser processes the month format. Here’s the relevant snippet:

MMMM: [ matchWord, function(input) { const months = getLocalePart('months'); const matchIndex = months.indexOf(input) + 1; if (matchIndex < 1) { throw new Error(); } this.month = matchIndex % 12 || matchIndex; } ]

The getLocalePart function retrieves a list of 24 items, representing stand-alone months and formatted months. The parser's handling of December (декабря in the example) returns an index of 24, which is incorrectly interpreted as the month number. As a result, the parser output becomes { day: 1, month: 24, year: 2023 }, inadvertently shifting the year to 2024.

Request for Confirmation and Priority Assignment I request the repository maintainers to confirm this as a bug and determine its priority for fixing. My findings suggest a potential solution would involve adjusting the month parsing logic to correctly handle language-specific month variations.

kavish5 avatar Dec 09 '23 05:12 kavish5

@kavish5 thank you for your detailed answer. The word "декабрь" in Russian directly denotes the name of the month - December. In combination with the day of the month we use the word "декабря". So the string "1 декабря" is correct, but "1 декабрь" is not. Therefore, we came up with a simple but rough solution to this issue until an official fix comes out.

let raw_date = "1 декабря 2023";
raw_date = raw_date.replace("декабря", "декабрь");
let correct_date = dayjs(raw_date, "D MMMM YYYY").format("DD.MM.YYYY"); //return 01.12.2023

We only replace the last month because other months are always converted correctly.

Vansinnesvisor avatar Dec 09 '23 06:12 Vansinnesvisor

Just for the curiosity, was the replace solution already implemented at your end before this @Vansinnesvisor?

I do have check the code and it looks fixable but not sure should I create a PR without @iamkun confirmation. This issue has been raised before for Polish language as well.

kavish5 avatar Dec 09 '23 06:12 kavish5

@kavish5 this temporary solution has been implemented in our project immediately after we discovered a problem with incorrect date conversion. I checked the issue with Polish language and I think is relevant for most slavic languages.

Vansinnesvisor avatar Dec 09 '23 07:12 Vansinnesvisor

I agree the issue #2483 is quite similar to this one

ahujamoh avatar Dec 12 '23 11:12 ahujamoh

The corresponding Pull Request is waiting for merge since March 3, 2023 (https://github.com/iamkun/dayjs/pull/2251).

Hope the maintainer will react to this ASAP. It would probably be cool if everyone interested in this fix approves this PR.

artischockee avatar Dec 13 '23 10:12 artischockee