javascript - Sjekk om en streng er en datoverdi
Hva er en enkel måte å sjekke om en verdi er en gyldig dato, uansett kjent datoformat som er tillatt.
For eksempel har jeg verdiene 10-11-2009, 10/11/2009, 2009-11-10T07:00:00+0000 som alle bør bli gjenkjent som datoverdier, og verdiene 200, 10, 350, som ikke bør bli gjenkjent som en datoverdi. Hva er den enkleste måten å sjekke dette på, hvis det i det hele tatt er mulig? Fordi tidsstempler også ville være tillatt.
Svar #1
2015-oppdatering
Det er et gammelt spørsmål, men andre nye spørsmål som:
- Hvordan validere om en streng er en gyldig dato i js
blir lukket som duplikater av dette, så jeg tror det er viktig å legge til litt ny informasjon her. Jeg skriver det fordi jeg ble redd da jeg tenkte at folk faktisk kopierer og limer inn noe av koden som er lagt ut her og bruker den i produksjon.
De fleste av svarene her enten bruker noen komplekse regulære uttrykk som bare matcher noen veldig spesifikke formater og faktisk gjør det feil (som å matche 32. januar mens de ikke matcher faktisk ISO-dato som annonsert - se demo) eller de prøver å sende hva som helst til Date-konstruktøren og håper på det beste.
Bruke Moment
Som jeg forklarte i dette svaret, finnes det for øyeblikket et bibliotek tilgjengelig for det: Moment.js
Det er et bibliotek for å analysere, validere, manipulere og vise datoer i JavaScript, som har et mye rikere API enn de standard JavaScript-funksjonene for datohåndtering.
Den er 12 kB minifisert/gzippet og fungerer i Node.js og andre steder:
bower install moment --save # bower
npm install moment --save # npm
Install-Package Moment.js # NuGet
spm install moment --save # spm
meteor add momentjs:moment # meteor
Med Moment kan du være veldig spesifikk når du sjekker gyldige datoer. Noen ganger er det veldig viktig å legge til noen ledetråder om hvilket format du forventer. For eksempel ser en dato som 22.06.2015 ut som en gyldig dato, med mindre du bruker formatet DD/MM/YYYY, i så fall bør denne datoen avvises som ugyldig. Det finnes noen måter du kan fortelle Moment hvilket format du forventer, for eksempel:
moment("06/22/2015", "MM/DD/YYYY", true).isValid(); // true
moment("06/22/2015", "DD/MM/YYYY", true).isValid(); // false
Argumentet true er der slik at Moment ikke prøver å tolke inputen hvis den ikke nøyaktig samsvarer med et av formatene som er oppgitt (det burde være en standardoppførsel etter min mening).
Du kan bruke et internt levert format:
moment("2015-06-22T13:17:21+0000", moment.ISO_8601, true).isValid(); // true
Og du kan bruke flere formater som et array:
var formats = [
moment.ISO_8601,
"MM/DD/YYYY :) HH*mm*ss"
];
moment("2015-06-22T13:17:21+0000", formats, true).isValid(); // true
moment("06/22/2015 :) 13*17*21", formats, true).isValid(); // true
moment("06/22/2015 :( 13*17*21", formats, true).isValid(); // false
Se: DEMO.
Andre biblioteker
Hvis du ikke vil bruke Moment.js, finnes det også andre biblioteker:
- XDato
- DateJS
2016-oppdatering
Jeg laget immoment-modulen som er som (et delsett av) Moment, men uten overraskelser forårsaket av mutasjon av eksisterende objekter (se dokumentasjonen for mer informasjon).
2018-oppdatering
I dag anbefaler jeg å bruke Luxon for dato-/tidsbehandling i stedet for Moment, som (i motsetning til Moment) gjør alle objekter uforanderlige, slik at det ikke oppstår ubehagelige overraskelser knyttet til implisitt endring av datoer.
Mer info
Se også:
- Håndtering av datoer og klokkeslett ved bruk av Moment.js av Jay Raj
- Å jobbe med JavaScript-datoer ved å bruke Moment.js av Bradley Holbrook
En serie artikler av Rob Gravelle om JavaScript-biblioteker for datoanalyse:
- En oversikt over populære JavaScript-datoparsingsbiblioteker: Moment.js
- En oversikt over populære JavaScript-datoparsingsbiblioteker: Datejs
- En oversikt over populære JavaScript-datoparsingsbiblioteker: XDate
Bunnlinje
Selvfølgelig kan hvem som helst prøve å gjenoppfinne hjulet, skrive et regulært uttrykk (men vær så snill å faktisk lese ISO 8601 og RFC 3339 før du gjør det) eller kalle innebygde konstruktører med tilfeldige data for å parse feilmeldinger som 'Invalid Date' (Er du sikker på at denne meldingen er helt den samme på alle plattformer? På alle lokaliteter? I fremtiden?) eller du kan bruke en testet løsning og bruke tiden din på å forbedre den, ikke gjenoppfinne den. Alle bibliotekene som er listet her er åpen kildekode, gratis programvare.
Svar #2
Slik løste jeg dette problemet i en app jeg jobber med akkurat nå:
oppdatert basert på tilbakemeldinger fra krillgar:
var isDate = function(date) {
return (new Date(date) !== "Invalid Date") && !isNaN(new Date(date));
}
Svar #3
Vil Date.parse() være tilstrekkelig?
Se den tilhørende MDN-dokumentasjonssiden.
Date.parse returnerer et tidsstempel hvis datoen i strengformat er gyldig. Her er noen bruksområder:
// /!\ from now (2021) date interpretation changes a lot depending on the browser
Date.parse('01 Jan 1901 00:00:00 GMT') // -2177452800000
Date.parse('01/01/2012') // 1325372400000
Date.parse('153') // NaN (firefox) -57338928561000 (chrome)
Date.parse('string') // NaN
Date.parse(1) // NaN (firefox) 978303600000 (chrome)
Date.parse(1000) // -30610224000000 from 1000 it seems to be treated as year
Date.parse(1000, 12, 12) // -30610224000000 but days and month are not taken in account like in new Date(year, month,day...)
Date.parse(new Date(1970, 1, 0)) // 2588400000
// update with edge cases from comments
Date.parse('4.3') // NaN (firefox) 986248800000 (chrome)
Date.parse('2013-02-31') // NaN (firefox) 1362268800000 (chrome)
Date.parse("My Name 8") // NaN (firefox) 996616800000 (chrome)
Svar #4
new Date(date) === 'Invalid Date' fungerer bare i Firefox og Chrome. IE8 (den jeg har på maskinen min for testformål) gir NaN.
Som ble uttalt til det aksepterte svaret, vil Date.parse(date) også fungere for tall. Så for å komme rundt det, kan du også sjekke at det ikke er et tall (hvis det er noe du vil bekrefte).
var parsedDate = Date.parse(date);
// You want to check again for !isNaN(parsedDate) here because Dates can be converted
// to numbers, but a failed Date parse will not.
if (isNaN(date) && !isNaN(parsedDate)) {
/* do your work */
}
Svar #5
Fungerer ikke konsekvent, vær forsiktig!
isDate('Leyweg 1') returnerer true på Chrome (Firefox returnerer false) 🤔
Les: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/parse (Date.parse blir kalt under panseret når man kaller slik: new Date(someDateString).
Originalt svar:
function isDate(dateStr) {
return !isNaN(new Date(dateStr).getDate());
}
- Dette vil fungere på hvilken som helst nettleser siden det ikke er avhengig av "Ugyldig dato"-sjekk.
- Dette vil fungere med eldre kode før ES6.
- Dette vil fungere uten noe bibliotek.
- Dette vil fungere uavhengig av hvilken datoformat som brukes.
- Dette er ikke avhengig av Date.parse, som feiler formålet når verdier som "Spiderman 22" er i datostrengen.
- Dette ber oss ikke om å skrive noen RegEx.
Svar #6
Ingen av svarene her tar for seg å sjekke om datoen er ugyldig, for eksempel 31. februar. Denne funksjonen tar for seg det ved å sjekke om den returnerte måneden er lik den opprinnelige måneden og sørge for at et gyldig år ble oppgitt.
//expected input dd/mm/yyyy or dd.mm.yyyy or dd-mm-yyyy
function isValidDate(s) {
var separators = ['\\.', '\\-', '\\/'];
var bits = s.split(new RegExp(separators.join('|'), 'g'));
var d = new Date(bits[2], bits[1] - 1, bits[0]);
return d.getFullYear() == bits[2] && d.getMonth() + 1 == bits[1];
}
Svar #7
Hva med noe som dette? Det vil teste om det er et Date-objekt eller en dato-streng:
function isDate(value) {
var dateFormat;
if (toString.call(value) === '[object Date]') {
return true;
}
if (typeof value.replace === 'function') {
value.replace(/^\s+|\s+$/gm, '');
}
dateFormat = /(^\d{1,4}[\.|\\/|-]\d{1,2}[\.|\\/|-]\d{1,4})(\s*(?:0?[1-9]:[0-5]|1(?=[012])\d:[0-5])\d\s*[ap]m)?$/;
return dateFormat.test(value);
}
Jeg bør nevne at dette ikke tester for ISO-formaterte strenger, men med litt mer arbeid på RegExp-en burde du være i orden.
Svar #8
Bruk regulært uttrykk for å validere det.
isDate('2018-08-01T18:30:00.000Z');
isDate(_date){
const _regExp = new RegExp('^(-?(?:[1-9][0-9]*)?[0-9]{4})-(1[0-2]|0[1-9])-(3[01]|0[1-9]|[12][0-9])T(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])(.[0-9]+)?(Z)?$');
return _regExp.test(_date);
}
