2

I need to validate UK dates, I'm using moment.js. The UK date format is "dd/mm/yyyy". The following code reports false validating the date "25/03/2021", why? How can I solve?

moment.locale("en");
const since = "25/03/2021";
let date = moment(since, "L");
let isValid = date.isValid();
console.log(isValid);
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js"></script>

Update: I tried the solution of msmolcic but the problem is that I'm validating dates taken from the browser and when UK English is set the locale is "en" and not "en-GB". The following code fails.

How can I fix it?

moment.locale("en");
const since = "25/03/2021";
let date = moment(since, "L");
console.log(date);
let isValid = date.isValid();
console.log(isValid);
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment-with-locales.min.js"></script>
cdarwin
  • 4,141
  • 9
  • 42
  • 66
  • If you need to check input dates with `dd/mm/yyyy` only then why can't you use `moment("25/03/2021", "DD/MM/YYYY")`. Any specific reason to set locale dynamically? – Ravikumar Apr 09 '21 at 14:00
  • You're right a solution is to use `moment("25/03/2021", "DD/MM/YYYY")`. I thought a solution existed that allowed me to check the date "automatically". I set the locale dynamically in the example because in the real code I check the date dynamically depending on the user locale set. – cdarwin Apr 09 '21 at 23:33

4 Answers4

1

There are two things wrong with your example:

  1. You included moment.min.js, but to work with locales you have to include moment-with-locales.min.js.
  2. You have to set locale to en-GB instead of just en.

moment.locale("en-GB");
const since = "25/03/2021";
let date = moment(since, "L");
console.log(date);
let isValid = date.isValid();
console.log(isValid);
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment-with-locales.min.js"></script>
msmolcic
  • 6,407
  • 8
  • 32
  • 56
  • Your code is ok, but the problem is that the browser says "en" and not "en-GB" as the timezone when I select UK english (with Chrome, for example). I'm using the following function to detect the user languge: var userLang = navigator.language || navigator.userLanguage; – cdarwin Apr 01 '21 at 23:30
  • @cdarwin well, "en" is not UK English. It's US English, if you want to process the date string using "en" locale then you have to reverse the places of your days and months since "en" long date format equals "MM/DD/YYYY" unlike "en-GB" which has "DD/MM/YYYY" format. I can't magically resolve your issue, you either have to change the date format or locale, that's it. :) – msmolcic Apr 07 '21 at 19:09
  • I'm sorry but when I set the language to UK English in Chrome I get the locale "en". If I set the language to US English I get "en-us". Maybe I can consider "en" as "en-GB" and validate the date with this locale. I'm getting the locale with the getLang function as in https://stackoverflow.com/a/31135571/472317 – cdarwin Apr 07 '21 at 22:43
1

In addition to @msmolcic I would add that you could also use the ISO standard, which will be validated. If you're creating a more serious app with a backend, simply store the Date object in ISO format and in the front end simply execute moment(dateHere).format("dd/mm/yyyy");

1

The Magic happens inside the constructor. If you pass a pattern into it then moment will parse it correctly.

 const since = "25/03/2021";
let date = moment(since, "DD/MM/YYYY");
console.log(date);
let isValid = date.isValid();
console.log(isValid);
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js"></script>
Tim S.
  • 391
  • 1
  • 5
0

Having read the comments and the exact nature of your problem I think you want to achieve the following:

  1. Get the user's xx-XX style locale from the browser
  2. Check a date for validity using moment.js

As you've read in the other answers, the locale en resolves to en-US for moment.js. Therefore we want the user's preferred xx-XX style locale. Instead of just getting navigator.language, we can check all preferred locales in order using navigator.languages (note the extra s). To get the xx-XX style locale:

const locales = navigator.languages || [navigator.language] // since navigator.languages may be undefined
console.log(locales)

const preferredLocale = locales.filter(lang => lang.match(/\S+-\S+/))[0]
console.log(`The user's preferred locale is ${preferredLocale}`)

Of course, the browser may not have any xx-XX style locale set in its list of preferred locales. In that case, the only way would be to check either the Accept-Language HTTP header, or through IP geolocation. However, those may be a bit farfetched for this purpose. But feel free to check here for more information on this.

Consequentially, you can then use @msmolcic's answer to combine this for your solution:

const locales = navigator.languages || [navigator.language] // since navigator.languages may be undefined
const preferredLocale = locales.filter(lang => lang.match(/\S+-\S+/))[0]

moment.locale(preferredLocale)
const since = "25/03/2021"
let date = moment(since, "L")

let isValid = date.isValid()
console.log(`The date is ${isValid ? 'valid' : 'not valid'}`)
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment-with-locales.min.js"></script>
Remy Kabel
  • 946
  • 1
  • 7
  • 15