moment / moment

Parse, validate, manipulate, and display dates in javascript.
momentjs.com
MIT License
47.96k stars 7.05k forks source link

moment giving wrong month #5600

Open shubhambatra opened 4 years ago

shubhambatra commented 4 years ago

moment.locale('hr'); moment(moment().format('DD MMMM YYYY'), 'DD MMMM YYYY').format('DD MMMM YYYY') let's suppose current date is 16 june 2020

expected output: 16 lipanj 2020

current output: 16 siječnja 2020

MinusFour commented 4 years ago

Saw this on SO the other day and got me curious. From what I can gather, locale.monthsRegex does not honor format styles that use monthsParseExact and have both date styles. For example, the ca locale also suffers from this but less so since most of the standalone regex will match for the months on the format regex.

The problem is with computeMonthsParse which calls localeMonths with an empty format:

https://github.com/moment/moment/blob/dca02edaeceda3fcd52b20b51c130631a058a022/src/lib/units/month.js#L323

That always gets you back a regex that only includes standalone styles.

I suppose you would need to drag down the format all the way from here:

https://github.com/moment/moment/blob/615212478ce087aeb995699ce5a827dab9daf9ec/src/lib/create/from-string-and-format.js#L51

Although that would be a little bit ugly since only the MMMM token would need the format.

marwahaha commented 4 years ago

@MinusFour Perhaps the locale can be updated with a monthsParse: function?

MinusFour commented 4 years ago

I don't think so. Maybe someone can clarify how nominative and accusative month names are supposed to be parsed. From what I can gather on code and on website documentation, depending on the format string given it would either parse in it's standalone form or the format form. Which is nominative and which is accusative I'm not entirely sure (but if I had to guess format form is accusative).

So using es as an example (even though current es locale is not set up for this) . Today's date (9/16) with the month in its accusative form would be 16 de Septiembre and in its nominative form it would be Septiembre 16. Now, as I understand it, moment should be able to parse these correctly:

moment("16 de Septiembre", "DD MMMM");
moment("Septiembre 16", "MMMM DD");

But not:

moment("16 Septiembre", "DD MMMM")

As the format supplied would make moment parse the string with the month being in it's accusative form (de Septiembre). Likewise I believe it wouldn't parse:

moment("de Septiembre 16", "MMMM DD", true);

But do notice the strict flag set on. This is because the nominative form (Septiembre) is part of the accusative form so without the strict flag it would just ignore de.

The way moment works right now (with monthsParseExact set to true) is completely discarding it's accusative form:

moment.locale('ca');
let m1 = moment("16 de juliol", "DD MMMM"); // 07/16
console.log(m1.format('MM / DD')); // 09/16

The test in a jsfiddle with moment-with-locales@2.28.0.

I initially thought moment would just ignore the token de and keep parsing the juliol as July but it doesn't, so not even accusative forms that include their nominative forms in their regular expressions are safe. It just doesn't work.

What these locales can do is turn off monthsParseExact and let moment match the month tokens by a much more broad regular expression. It seems to be working OK on other locales with separate forms though I'm unsure if that would allow improper use of its date forms (something I need to check if it's possible on other locales).

The way I see it, the matching regular expression that extracts the months from the strings is predicated on the format string used. So monthsRegex should give a different regular expression depending on which format string is given.

Maybe someone can someone clarify me if DD MMMM is valid if MMMM is using it's nominative form (standalone)?

mayralgr commented 3 years ago

@marwahaha is this good to go? I want to give it a try

soham-sagade commented 2 years ago

can I work on this?

sanyamgandhak commented 1 year ago

Can i work on this