Per Javascript Datum auf Gültigkeit prüfen
coder1979
- javascript
Hi zusammen,
ich machs kurz ;-)
Der folgende Code bringt beim Firefox "Ungültig" und beim Opera "Gültig"
var dt = new Date("2022-06-31");
var day_no=dt.getDay();
if (isNaN(day_no)) {
alert("ungültig!");
} else {
alert("Gültig!");
}
Habt ihr ne Idee, wie ich auch beim Opera beim 31.06. (oder bei anderen, nicht gültigen Tagen) ein ungültig bekomme?
LG Daniel
Hallo,
Der folgende Code bringt beim Firefox "Ungültig" und beim Opera "Gültig"
var dt = new Date("2022-06-31"); var day_no=dt.getDay(); if (isNaN(day_no)) { alert("ungültig!"); } else { alert("Gültig!"); }
das Problem hier ist, dass du die Zwischenschritte nicht überprüfst. Denn bereits die erste Zeile ist falsch. Wird dem Date-Konstruktor ein Datum in String-Format übergeben, muss es in einem bestimmten Format vorliegen. Das von dir verwendete ISO-8610-Format (das mir auch viel sympathischer ist), passt hier nicht.
Ich bin aber auch gerade etwas überrascht, dass das Date-Objekt anscheinend keine Methode anbietet, ein falsches Datum zu erkennen.
Einen schönen Tag noch
Martin
@@Der Martin
Wird dem Date-Konstruktor ein Datum in String-Format übergeben, muss es in einem bestimmten Format vorliegen. Das von dir verwendete ISO-8610-Format (das mir auch viel sympathischer ist), passt hier nicht.
Sagt wer? SELFHTML? 🤣
Bei dem, was im Wiki steht, ist es oft ratsam, eine zweite Meinung einzuholen. Was im Wiki steht, könnte falsch sein.
Schauen wir doch mal, was MDN sagt.
“A string value representing a date, in a format recognized by the Date.parse() method. (The ECMA262 spec specifies a simplified version of ISO 8601, but other formats can be implementation-defined, which commonly include IETF-compliant RFC 2822 timestamps.)”
Wer hat im Zweifelsfall wohl recht?
Ich bin aber auch gerade etwas überrascht, dass das Date-Objekt anscheinend keine Methode anbietet, ein falsches Datum zu erkennen.
Tut es doch.
Sowohl im Firefox als auch im Chrome. Da Opera auch ein Chromium ist, wird es da wohl auch so sein? Es sei denn, coder1979 hat einen Prä-Chromium-Opera ausgegraben, also ein Museumsstück.
🖖 Живіть довго і процвітайте
@@Der Martin Es sei denn, coder1979 hat einen Prä-Chromium-Opera ausgegraben, also ein Museumsstück.
Hi,
ich habe es mit der folgenden Opera-Version gerade eben getestet: 87.0.4390.25
Da bekomm ich ein "Gültig" für den 31.06.2022 denn Opera mach daraus automatisch den 01.07.2022. Probiert es gerne aus.
Aber: Ich hab die folgende Funktion ergoogelt und die macht genau das, was sie soll:
function isValidDateCheck(dString) {
// test it is nn/nn/nnnn or nn/nn/nn
var dRe = /^(\d{1,2})([\-\/])(\d{1,2})\2(\d{4}|\d{2})$/
if (!dRe.exec(dString)) {
return false;
}
// make sure it parses as date
// replace this part if you do not allow dashes
dString.replace(/-/g,"/");
var date = new Date(dString); // create a date object
if (!isNaN(date)) { // it may give NaN - if not test the parts
var parts = dString.split("/"); // split on slash
var dd = parseInt(parts[1],10); // day number
var mm = parseInt(parts[0],10)-1; // month - JS months start at 0
var yyyy = parseInt(parts[2],10); // year
// return true if all parts match
return dd===date.getDate() && mm === date.getMonth() && yyyy===date.getFullYear();
}
// here the date was not parsed as a date
return false;
}
Ich bin aber noch nicht genau dahinter gestiegen, was diese Funktion anders macht. Werd mich morgen nochmal gedanklich damit beschäftigen, heut ist irgendwie der Wurm drin ;-)
@@coder1979
ich habe es mit der folgenden Opera-Version gerade eben getestet: 87.0.4390.25
Da bekomm ich ein "Gültig" für den 31.06.2022 denn Opera mach daraus automatisch den 01.07.2022.
Das glaube ich dir. Ja, jetzt seh ich’s auch. Opera wie andere Chromia (Chrome, Edge, …) auch.
Aber: Ich hab die folgende Funktion ergoogelt und die macht genau das, was sie soll:
Das glaube ich dir nicht. Die Funktion erwartet einen Datumstring im amerikanischen Format Monat/Tag/Jahr.
Sagtest du nicht, dein Datumstring wäre im Format Jahr–Monat–Tag?
Ich bin aber noch nicht genau dahinter gestiegen, was diese Funktion anders macht.
Sie vergleicht die Bestandteile des Datumstrings mit dem daraus ermittelten Datum. Für 06/30/2022 ist 6 = 6 und 30 = 30. Für 06/31/2022 ist 6 ≠ 7 und 31 ≠ 1.
Es sollte aber genügen, die Tage zu vergleichen. Monate und Jahre braucht man nicht.
🖖 Живіть довго і процвітайте
@@coder1979
ich habe es mit der folgenden Opera-Version gerade eben getestet: 87.0.4390.25
Da bekomm ich ein "Gültig" für den 31.06.2022 denn Opera mach daraus automatisch den 01.07.2022.
Das glaube ich dir. Ja, jetzt seh ich’s auch. Opera wie andere Chromia (Chrome, Edge, …) auch.
Aber: Ich hab die folgende Funktion ergoogelt und die macht genau das, was sie soll:
Das glaube ich dir nicht. Die Funktion erwartet einen Datumstring im amerikanischen Format Monat/Tag/Jahr.
Sagtest du nicht, dein Datumstring wäre im Format Jahr–Monat–Tag?
Ja, so hatte ich das ursprünglich, habs aber für dieses Beispiel kurzfristig aufs amerikanische Format geändert. Kann man ja aber auch wieder entsprechend umschreiben / in der Funktion entsprechend anpassen.
Ich bin aber noch nicht genau dahinter gestiegen, was diese Funktion anders macht.
Sie vergleicht die Bestandteile des Datumstrings mit dem daraus ermittelten Datum. Für 06/30/2022 ist 6 = 6 und 30 = 30. Für 06/31/2022 ist 6 ≠ 7 und 31 ≠ 1.
Es sollte aber genügen, die Tage zu vergleichen. Monate und Jahre braucht man nicht.
Dankeschön, nun hab ichs kapiert und bin erstmal happy mit der Lösung.
LG Daniel
@@coder1979
function isValidDateCheck(dString) { // test it is nn/nn/nnnn or nn/nn/nn var dRe = /^(\d{1,2})([\-\/])(\d{1,2})\2(\d{4}|\d{2})$/ if (!dRe.exec(dString)) { return false; } // make sure it parses as date // replace this part if you do not allow dashes dString.replace(/-/g,"/");
Wenn man da schon mit regulären Ausdrücken rumhantiert, kann man auch gleich damit prüfen, ob der String ein gültiges Datum darstellt. 🤓
🖖 Живіть довго і процвітайте
PS: Nein, nicht machen, Kinder!
PS2: Das hab ich letztens auch den Kollegen präsentiert – zusammen mit anderen Dingen, die ihren Ursprung hier im Forum haben.
Moin
Der folgende Code bringt beim Firefox "Ungültig" und beim Opera "Gültig"
var dt = new Date("2022-06-31");
Wenn ich das in der Browser-Konsole eintippe, sagt mir der Firefox bereits „Invalid Date“.
var day_no=dt.getDay(); if (isNaN(day_no)) { alert("ungültig!"); } else { alert("Gültig!"); }
das Problem hier ist, dass du die Zwischenschritte nicht überprüfst. Denn bereits die erste Zeile ist falsch. Wird dem Date-Konstruktor ein Datum in String-Format übergeben, muss es in einem bestimmten Format vorliegen. Das von dir verwendete ISO-8610-Format (das mir auch viel sympathischer ist), passt hier nicht.
In meinem Firefox passt ISO 8601:
let dt = new Date('2022-06-30');
dt.getDay(); // 4
Ich bin aber auch gerade etwas überrascht, dass das Date-Objekt anscheinend keine Methode anbietet, ein falsches Datum zu erkennen.
Doch.
Viele Grüße
Robert
@@Robert B.
var dt = new Date("2022-06-31");
Wenn ich das in der Browser-Konsole eintippe, sagt mir der Firefox bereits „Invalid Date“.
TIL, dass sich Chromia in der Browser-Konsole und außerhalb anders verhalten. Scheint was mit dem Schlüsselwort var
zu tun zu haben. (Selbes Verhalten bei const
und let
.)
Das mal weggelassen:
Und im normalen Programmablauf kommt das in Chromia auch mit Schlüsselwort var
, const
oder let
raus. dt.getDay()
liefert den truthy Wert 5
. (Der 1. Juli 2022 ist ein Freitag.)
Firefox hingegen macht aus dem 31. Juni nicht den 1. Juli, sondern liefert null
. dt.getDay()
ergibt dann NaN
(falsy).
🖖 Живіть довго і процвітайте
// file: test.js
var dt = new Date("2022-06-31");
console.log(dt);
Ausführen:
node test.js
2022-07-01T00:00:00.000Z
Nicht wundern:
console.log( dt.toString() );
liefert
Fri Jul 01 2022 02:00:00 GMT+0200 (Mitteleuropäische Sommerzeit)
Aktuell?
node -v
v12.22.9
Ok: nodejs mag bei 16.15.1 sein, aber das ist „distributionsaktuell“.
Nächster Test: Im Browser (Chromium, Version 101.0.4951.15 (Entwickler-Build) Ubuntu 22.04 (64-Bit)):
<html>
<body>
<div id="output"></div>
<script>
var dt = new Date("2022-06-31");
document.getElementById("output").innerHTML=dt.toString();
</script>
</body>
</html>
Ausgabe:
Fri Jul 01 2022 02:00:00 GMT+0200 (Mitteleuropäische Sommerzeit)
Fazit: JS kann das Datum (die Zeit) wie angegeben verarbeiten. Aber genau wie PHP wertet es dieses so aus, dass bei formal ungültigen Datumsangaben (wie hier der 31. Juno) dieses so ausgewertet wird, dass ein gültigiger Zeitpunkt (1. Julei) berechnet wird.
Das ist oft nützlich.
Naja. Wenn man das will, dann muss man wohl das Datum selbst zerlegen und prüfen oder aber etwas wie Moment.js verwenden. Das kann angeblich solche „ungültigen“ Angaben erkennen.
Naja. Wenn man das will, dann muss man wohl das Datum selbst zerlegen und prüfen oder aber etwas wie Moment.js verwenden. Das kann angeblich solche „ungültigen“ Angaben erkennen.
Wenn Du das selbst machen willst, dann sei Dir folgender Ansatz empfohlen:
Du prüfst, ob sich der String zerlegen lässt, ob da auch 3 Elemente herauskommen - wenn nicht ist das Datum ungültig
Dann checkst Du,
Ausgaben:
false
Achso:
Ein paar Tests mit gültigen und ungültigen Angaben habe ich eingebaut. Es wird sich vorhersehbar Kritik daran entzünden, dass mein Vorgehen wie auch die Notation antiquiert, gar altmodisch sei. Naja: Ich kann das eben noch…
function dateCheckerYmd( input ) {
var ar=input.split(/[^0-9]/);
if ( 3 != ar.length ) {
return false;
}
var y = parseInt( ar[0] );
var m = parseInt( ar[1] );
var d = parseInt( ar[2] );
var m31 = new Array( 1, 3, 5, 7, 8, 10, 12 );
var m30 = new Array( 4, 6, 9, 11 );
if ( m31.indexOf( m ) != -1 ) {
if ( ( d > 0 ) && ( d < 32 ) ) {
return new Array( y, m, d );
}
}
if ( m30.indexOf( m ) != -1 ) {
if ( ( d > 0 ) && ( d < 31 ) ) {
return new Array( y, m, d );
}
}
if ( m == 2 && d > 0 && d < 29 ) {
return new Array( y, m, d );
}
var Feb29 = false;
if (
Number.isInteger( y/4 )
&& (
false == Number.isInteger( y/100 )
|| true == Number.isInteger( y/400 )
)
) {
Feb29 = true;
}
if ( ( Feb29 == true ) && ( d > 0 ) && ( d < 30 ) ) {
return new Array( y, m, d );
}
if ( Feb29 == false && ( d > 0 ) && ( d < 29 ) ) {
return new Array( y, m, d );
}
return false;
}
function teste( s ) {
console.log( s + ': ' + dateCheckerYmd( s ) );
}
tests = new Array (
'2000-02-29',
'2001-02-29',
'2020-02-29',
'2100-02-29',
'2000-13-01',
'2000-12-31',
'2000 12 31',
'2000-12-32',
'2000-12',
'2000-12-01-1'
);
tests.forEach ( teste );
Ausgaben:
2000-02-29: 2000,2,29
2001-02-29: false
2020-02-29: 2020,2,29
2100-02-29: false
2000-13-01: 2000,13,1
2000-12-31: 2000,12,31
2000 12 31: 2000,12,31
2000-12-32: false
2000-12: false
2000-12-01-1: false
@@Raketenwilli
Wenn Du das selbst machen willst, dann sei Dir folgender Ansatz empfohlen:
Du prüfst, ob sich der String zerlegen lässt, ob da auch 3 Elemente herauskommen - wenn nicht ist das Datum ungültig
Dann checkst Du,
- ob der Monat 31 Tage hat und der Tag kleiner als 32 ist, sodann
- ob der Monat 30 Tage hat und der Tag kleiner als 31 ist, sodann
- ob es der Februar ist und der Tag kleiner als 29 ist.
- wenn der Monat der Februar ist, ob es denn ein Schaltjahr ist und der Tag kleiner als 30 ist.
Den Ansatz würde ich nicht empfehlen. Zu aufwendig.
Ob da 3 Zahlen herauskommen – klar.
Dann kann man die aber gleich als Datum interpretieren und prüfen, ob der Tag des so ermittelten Datums mit der entsprechenden Zahl im String übereinstimmt. Das sollte genügen.
🖖 Живіть довго і процвітайте
Zu aufwendig.
Dann kann man die aber gleich als Datum interpretieren und prüfen, ob der Tag des so ermittelten Datums mit der entsprechenden Zahl im String übereinstimmt. Das sollte genügen.
Für Dich sind das ein paar Zeilen weniger - aber im Hintergrund wird dann die Eingabe geparst, unter Berücksichtigung von Schaltjahren und sogar Schaltsekunden in eine Zahl von Millissekunden seit dem 1.1.1970 00:00:00 GMT umgerechnet, und dann - erneut unter Berücksichtigung von Schaltjahren und sogar Schaltsekunden - daraus wieder das Jahr, der Monat und der Tag berechnet.
Für mich klingt das nach hohen Aufwand und nach Verwendung von ziemlich viel Speicher und vor allem Prozessortakten…
Dafür ist das die date-Klasse freilich schon kompiliert. Allerdings verwendet mein Skript ausgesprochen primitive (also schnelle) Anweisungen.
Also: Ohne umfangreiche Tests und eine vorherige, sachangemsssene Definition von „Aufwand“ würde ich keine Aussage darüber treffen wollen, was „aufwändiger“ ist.
Hallo Raketenwilli,
sachangemsssene Definition von „Aufwand“
Die muss man vorher treffen, sicher. Dazu gehört zumeist aber auch der Programmier- und Testaufwand. Der Verarbeitungsaufwand ist, so weh das einem mit Assembler digitalisierten Boomer wie Dir und mir auch tut, vernachlässigbar. Außer in wenigen Ausnahmefällen…
Rolf
Der Verarbeitungsaufwand ist, so weh das einem mit Assembler digitalisierten Boomer wie Dir und mir auch tut, vernachlässigbar.
Ah! Deshalb wird heutzutage rein verbal „optimiert“. Und erwartet, dass alles unendlich groß sein darf.
Zu aufwendig? Man messe wie folgt:
function dateCheckerYmd( input ) {
var ar = input.split( /[^0-9]/ );
if ( 3 != ar.length ) {
return false;
}
var y = parseInt( ar[0] );
var m = parseInt( ar[1] );
var d = parseInt( ar[2] );
var m31 = new Array( 1, 3, 5, 7, 8, 10, 12 );
if ( m31.indexOf( m ) != -1 ) {
if ( ( d > 0 ) && ( d < 32 ) ) {
return new Array( y, m, d );
}
}
var m30 = new Array( 4, 6, 9, 11 );
if ( m30.indexOf( m ) != -1 ) {
if ( ( d > 0 ) && ( d < 31 ) ) {
return new Array(y, m, d);
}
}
if ( m == 2 && d > 0 && d < 29 ) {
return new Array( y, m, d );
}
var Feb29 = false;
if (
Number.isInteger( y/4 )
&& (
false == Number.isInteger( y/100 )
|| true == Number.isInteger( y/400 )
)
) {
Feb29 = true;
}
if ( ( Feb29 == true ) && ( d > 0 ) && ( d < 30 ) ) {
return new Array(y, m, d);
}
if ( Feb29 == false && ( d > 0 ) && ( d < 29 ) ) {
return new Array( y, m, d );
}
return false;
}
output='';
function teste( s ) {
output = output + s + ': ' + dateCheckerYmd( s ) + "\n";
}
tests = new Array (
'2000-02-29',
'2001-02-29',
'2020-02-29',
'2100-02-29',
'2000-13-01',
'2000-12-31',
'2000 12 31',
'2000-12-32',
'2000-12',
'2000-12-01-1'
);
const { performance } = require('perf_hooks');
t = performance.now();
tests.forEach ( teste );
console.log( t = performance.now() - t + ' Millisekunden' );
console.log( output );
vers.
function dateCheckerYmd( input ) {
var ar = input.split( /[^0-9]/ );
if ( 3 != ar.length ) {
return false;
}
dto = new Date( input );
var d = parseInt( ar[2] );
if ( dto.getDate() != d ) { return false; }
var m = parseInt( ar[1] ) - 1;
if ( dto.getMonth() != m ) { return false; }
var y = parseInt( ar[0] );
if ( dto.getFullYear() != y ) { return false; }
return dto;
}
output='';
function teste( s ) {
output = output + s + ': ' + dateCheckerYmd( s ) + "\n";
}
tests = new Array (
'2000-02-29',
'2001-02-29',
'2020-02-29',
'2100-02-29',
'2000-13-01',
'2000-12-31',
'2000 12 31',
'2000-12-32',
'2000-12',
'2000-12-01-1'
);
const { performance } = require('perf_hooks');
t = performance.now();
tests.forEach ( teste );
console.log( t = performance.now() - t + ' Millisekunden' );
console.log( output );
Dann kann man die aber gleich als Datum interpretieren und prüfen, ob der Tag des so ermittelten Datums mit der entsprechenden Zahl im String übereinstimmt. Das sollte genügen.
Mit der Messmethode ist das Skript gemäß Deiner Vorgehensweise auf dem Raspi400 (mit nodejs v12.22.9) um den Faktor 1,7 langsamer als meine „zu Fuß-Methode“:
1.051170002669096 Millisekunden
vers.
1.861379001289606 Millisekunden
(Macht man die Ausgaben einzeln erhöht sich die Zeit auf unverschämte 15 Millisekunden - das das Öffnen und schließen des Ausgabekanals „teuer“ ist habe ich - glaub ich - mal von Dir gelernt.)