Lars Olesen <lsolesen@hotmail.com> writes:
> Jeg har et datefield i en formular, og jeg vil gerne gøre det let for
> brugeren, så det på onblur laver sig om til det rigtige format.
Jeg har selv haft en lignende idé, men har manglet en god grund til at
lave det ... så tak :)
> Dvs. input skal fx være åååå-mm-dd,
Godt valg. ISO-standard og alt muligt.
> men brugeren kan jo finde på mange ting, fx
>
> 140676
> 14061976
> 19760614
> 14-06-1976
> 14-06-76
Ja, og med andre valg af datoer er der ikke nogen måde at se hvilken
dag 030405 (med eller uden -'er) eller 20032004 egentlig er. Derfor
er der *god* grund til at vise brugeren hvordan hans input vil blive
fortolket af serveren. Så kan han lære det, HA! Ups.
> Kan man lave en onblur, som tager disse rimelige forslag og
> formatterer dem, eller er det en dum ide, hvis man til sidst alligevel
> validerer feltet?
Jeg ville bruge onchange, men ellers, er det klart muligt og fornuftigt.
Problemet er at bestemme sig for hvordan man vil tolke datoer der er
tvetydige.
Mit forslag er:
Forsøg følgende formater i rækkefølge, og opgive hvis resultatet ikke
er en lovlig dato (den klarer vi senere).
(Y er et årstal på 1 eller flere cifre, etc.)
Y/M/D ("/" kan være vilkårlig streng der ikke indeholder cifre)
D/M/Y
M/D/Y (for at tækkes amerikanerne, kan droppes ellers)
yyyymmdd
ddmmyyyy
mmddyyyy
yymmdd
ddmmyy
mmddyy
Hvis alle disse fejler, så kan man sende input igennem Date, det giver
altid et resultat, bare ikke altid det man forventer.
Man skal beslutte sig for hvordan man fortolker to-cifrede årstal.
Fx kan man skifte ved 1970, så 67 er 2067, mens 72 er 1972. Eller
hvornår det nu passer en (straffen for at forsøge at give fire cifres
information med to!).
Man kan vælge kun at acceptere årstal inden for en bestemt periode. Så
vil fortolkninger der giver 20 marts 3004 (af fx 30042003) blive droppet.
Godt så! Lad os kode!
Først en funktion til at teste om et forsøg er en lovlig dato overhovedet
(udelukker 30 februar og den slags):
---
function validDate(year,mth,day) {
mth --; // january == 0
var date = new Date(0);
date.setFullYear(year,mth,day);
return date.getDate() == day && date.getMonth() == mth && date;
}
---
Den returnerer date-objektet hvis datoen er lovlig.
(det er nok at teste vilkårlige to af de tre, fordi en ulovlig dato
vil betyde at mindst to bliver forkerte).
Man skal passe på fordi Date-objekter kan finde på at opføre sig underligt
for årstal mellem 0 og 100 - det er bagudkombatabilitet med browsere der
kun brugte to cifre. Derfor bruger jeg setFullYear til at sætte tiden,
den er år-2000-sikker (men findes ikke i alt for gamle browsere).
Og testen:
---
function LZ(n,size) { //leading zero
size = size || 2; // default 2
var str = String(n);
while(str.length < size) {str = "0"+str;}
return str;
}
var TWO_DIGIT_YEAR_MIN = 1970;
function extendYear(year) { // two-digit year
if (year >= 0 && year < 100) {
var centyear = TWO_DIGIT_YEAR_MIN % 100;
var century = TWO_DIGIT_YEAR_MIN - centyear;
return century + year + ((year < centyear)?100:0);
} else {
return year;
}
}
function formatDate(year,mth,day) {
return LZ(year,4)+"-"+LZ(mth)+"-"+LZ(day);
}
function checkAndFormatDate(year,mth,day) {
if (validDate(year,mth,day)) {
return formatDate(year,mth,day);
} else {
return false;
}
}
function correctDate(string) {
var match;
var result;
var year,mth,day;
if (match=string.match(/^\s*(\d+)\D+(\d+)\D+(\d+)\s*$/)) {
fst = Number(match[1]);
snd = Number(match[2]);
trd = Number(match[3]);
// yyyy-mm-dd
if (result = checkAndFormatDate(match[1].length==2?extendYear(fst):fst,
snd,trd)) {
return result;
}
// dd-mm-yyyy
if (result = checkAndFormatDate(match[3].length==2?extendYear(trd):trd,
snd,fst)) {
return result;
}
// mm-dd-yyyy
if (result = checkAndFormatDate(match[3].length==2?extendYear(trd):trd,
fst,snd)) {
return result;
}
}
// eight digits
if (match = string.match(/^\s*(\d{4})(\d\d)(\d\d)\s*$/)) {
fst = Number(match[1]);
snd = Number(match[2]);
trd = Number(match[3]);
// yyyymmdd
if (result = checkAndFormatDate(fst,snd,trd)) {
return result;
}
}
if (match = string.match(/^\s*(\d\d)(\d\d)(\d{4})\s*$/)) {
fst = Number(match[1]);
snd = Number(match[2]);
trd = Number(match[3]);
// ddmmyyyy
if (result = checkAndFormatDate(trd,snd,fst)) {
return result;
}
// mmddyyyy
if (result = checkAndFormatDate(trd,fst,snd)) {
return result;
}
}
// six digits
if (match = string.match(/^\s*(\d\d)(\d\d)(\d\d)\s*$/)) {
fst = Number(match[1]);
snd = Number(match[2]);
trd = Number(match[3]);
// yymmdd
if (result = checkAndFormatDate(extendYear(fst),snd,trd)) {
return result;
}
// ddmmyy
if (result = checkAndFormatDate(extendYear(trd),snd,fst)) {
return result;
}
// mmddyy
if (result = checkAndFormatDate(extendYear(trd),fst,snd)) {
return result;
}
}
// ok, nothing works, try Date: (or don't, because result is probably bad)
// var date = new Date(string);
// return formatDate(date.getFullYear(),date.getMonth()+1,date.getDate());
return("(invalid)"+string);
}
---
Den kan så bruges:
---
<input type="text" onchange="this.value=correctDate(this.value)">
---
--
Lasse Reichstein Nielsen - lrn@hotpop.com
DHTML Death Colors: <URL:
http://www.infimum.dk/HTML/rasterTriangleDOM.html>
'Faith without judgement merely degrades the spirit divine.'