iamkun / dayjs

⏰ Day.js 2kB immutable date-time library alternative to Moment.js with the same modern API
https://day.js.org
MIT License
46.77k stars 2.29k forks source link

Validation fails for valid input with textual months followed by period (MMM. and MMMM.) #1980

Open Elgeneinar opened 2 years ago

Elgeneinar commented 2 years ago

Describe the bug In our date field, formats including MMM and MMMM cause the dayjs(value, format, strict=true).isValid() to return false for all values. image

Expected behavior IsValid() should return true

Information

BePo65 commented 2 years ago

Tested it with the following code in chrome and Firefox on WIndows 10 with dayjs 1.11.3 and the result for 'isValid' was 'true':

<!DOCTYPE html>
<html lang="de">
  <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <meta http-equiv="X-UA-Compatible" content="ie=edge">
  </head>
  <body style="font-family:sans-serif">
    <main>
      <div><span style="  margin-right:1em;">Parse strict '2017 September 5'</span><span id="formattedDate01"></span></div>
      <div><span style="  margin-right:1em;">&nbsp;isValid</span><span id="isValid01"></span></div>
    </main>   
    <script src="https://unpkg.com/dayjs@1.11.3/dayjs.min.js"></script>
    <script>
      const input = '2017 September 5'
      const parsedDate01 = dayjs(input, 'YYYY MMMM D', true)
      const isValid01 = parsedDate01.isValid()
      const formattedDate01 = parsedDate01.format('DD-MM-YYYY')

      const targetIsValid01 = document.getElementById('isValid01');
      targetIsValid01.textContent = isValid01.toString();
      const targetFormattedDate01 = document.getElementById('formattedDate01');
      targetFormattedDate01.textContent = formattedDate01;
    </script>
  </body>
</html>
Elgeneinar commented 2 years ago

Tested it with the following code in chrome and Firefox on WIndows 10 with dayjs 1.11.3 and the result for 'isValid' was 'true':

<!DOCTYPE html>
<html lang="de">
  <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <meta http-equiv="X-UA-Compatible" content="ie=edge">
  </head>
  <body style="font-family:sans-serif">
    <main>
      <div><span style="  margin-right:1em;">Parse strict '2017 September 5'</span><span id="formattedDate01"></span></div>
      <div><span style="  margin-right:1em;">&nbsp;isValid</span><span id="isValid01"></span></div>
    </main>   
    <script src="https://unpkg.com/dayjs@1.11.3/dayjs.min.js"></script>
    <script>
      const input = '2017 September 5'
      const parsedDate01 = dayjs(input, 'YYYY MMMM D', true)
      const isValid01 = parsedDate01.isValid()
      const formattedDate01 = parsedDate01.format('DD-MM-YYYY')

      const targetIsValid01 = document.getElementById('isValid01');
      targetIsValid01.textContent = isValid01.toString();
      const targetFormattedDate01 = document.getElementById('formattedDate01');
      targetFormattedDate01.textContent = formattedDate01;
    </script>
  </body>
</html>

Why are you formatting the date? I need it to be valid with the month name

BePo65 commented 2 years ago

As you see, the parsed date is valid (parsedDate01.isValid()); the rest is just to see what was parsed (it is a web page 😄 )

Elgeneinar commented 2 years ago

As you see, the parsed date is valid (parsedDate01.isValid()); the rest is just to see what was parsed (it is a web page 😄 )

Ahh yes I see. I can't figure out why it does not give us isValid() = true. Maybe because of locales. I'll try using it your way and report back if it passes And I'll update the post with the exact formats that fail

BePo65 commented 2 years ago

m locale would be 'de' but I suppose it is using the default ('en').

Elgeneinar commented 2 years ago

YYYY MMMM D

This format seems to be passing for me, but with a period after the month it does not. I'm not sure if that is intended or not? so: YYYY MMMM. D - .isValid = false YYYY MMMM D - .isValid = true

I'm trying to figure out which date formats cause errors. Here are the results so far: D-MMM-YYYY - .isValid = true

BePo65 commented 2 years ago

aah, you got it; the dot is handled by dayjs parsing as a format token and not as a 'separator'.

At the moment I cannot test it on my sytem, so would you please try, if the dot in the format string can be escaped (surrounded by square brackets)?

Elgeneinar commented 2 years ago

aah, you got it; the dot is handled by dayjs parsing as a format token and not as a 'separator'.

At the moment I cannot test it on my sytem, so would you please try, if the dot in the format string can be escaped (surrounded by square brackets)?

Tried it now, here are the results: MMM[.] - valid = false MMM [.] - valid = true (however the space is also there in the output as seen below)

image image

Jul is an abbreviation, so it would be correct to have a dot after it, so I would say even though this is minor it is still worth preserving support for such a dot.

BePo65 commented 2 years ago

So I will take a look at the code, if the dot can be handled in such a scenario - perhaps my pt #1940 can help - but we will have to leave the 'chat mode' for this 😃 .

BePo65 commented 2 years ago

I've made some tests and the issue could be easily fixed by adding a dot to the regex of matchWord (line 12 in customParseFormat.js). The line should be: const matchWord = /\d*[^-_:/.,()\s\d]+/0.

But there is a problem with this solution: unluckily the definitions for monthsShort in the locale definition files are not consistent. Some have a dot at the end, some not; I think that is the reason, why until now the dot is not part of the matchWord regex.

The customization example in the documentation does not have a dot after the monthShort so this looks like a recommendation to me.

There are a few issues concerning the parsing of dots, so perhaps it would be a good idea to make this change. But then we have to remove the dot from the monthShort in all locales (or remove the trailing dot by code in the function getLocalePart in 'customParseFormat.js' what would be my recommendation).

This is a decision to be made by @iamkun.

micahjsmith commented 1 year ago

I'm also experiencing this with dayjs 1.11.8 (tested both in browser and in node)

reproduction:

<!DOCTYPE html>
<html lang="en">
  <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <meta http-equiv="X-UA-Compatible" content="ie=edge">
  </head>
  <body style="font-family:sans-serif">
    <main>
      <div><span style="  margin-right:1em;">Parse strict 'Jun. 5, 2023'</span><span id="formattedDate01"></span></div>
      <div><span style="  margin-right:1em;">&nbsp;isValid</span><span id="isValid01"></span></div>
    </main>
    <script src="https://unpkg.com/dayjs@1.11.8/dayjs.min.js"></script>
    <script src="https://unpkg.com/dayjs@1.11.8/plugin/customParseFormat.js"></script>
    <script>
      dayjs.extend(window.dayjs_plugin_customParseFormat)

      const input = 'Jun. 5, 2023'
      const parsedDate01 = dayjs(input, 'MMM. D, YYYY', true)
      const isValid01 = parsedDate01.isValid()
      const formattedDate01 = parsedDate01.format('DD-MM-YYYY')

      const targetIsValid01 = document.getElementById('isValid01');
      targetIsValid01.textContent = isValid01.toString();
      const targetFormattedDate01 = document.getElementById('formattedDate01');
      targetFormattedDate01.textContent = formattedDate01;
    </script>
  </body>
</html>

Produces


Parse strict 'Jun. 5, 2023'Invalid Date
 isValidfalse