Sto realizzando questa routine. Penso che in un software in cui vengono inseriti molti dati debba essere creato un sistema di controllo dei dati digitati. Vorrei saperne di piu' per realizzare una routine generale addìttabile..Veniamo alla data per quanto riguarda la data ho realizzato una routine per capire se una data è corretta, se l'anno è bisestile e se il mese è di 30 giorni. Il mio problema è creare un pattern di verifica del formato della data, che deve essere del tipo:
Questa è la funzione da replicare, mi manca parte iniziale ereg:
FUNCTION ControlloData($data){
If(!ereg("^[0-9]{2}/[0-9]{2}/[0-9]{4}$", $data)){
RETURN FALSE;
} ELSE {
$arrayData = explode("/", $data);
$Giorno = $arrayData[0];
$Mese = $arrayData[1];
$Anno = $arrayData[2];
If(!checkdate($Mese, $Giorno, $Anno)){
RETURN FALSE;
} ELSE {
RETURN TRUE;
}
}
}
La funzione che controlla se un anno è bisestile:
PRIVATE FUNCTION AnnoBisestile(iAnno AS Integer) AS Boolean
DIM risultato AS Boolean
IF (iAnno MOD 4) = 0 THEN risultato = TRUE
RETURN risultato
END
la funzione di controllo del numero dei giorni:
PRIVATE FUNCTION NumeroGiorniDelMese(iMM AS Integer, iYYYY AS Integer) AS Integer
DIM risultato AS Integer
IF iMM = 1 THEN risultato = 31
IF iMM = 3 THEN risultato = 31
IF iMM = 5 THEN risultato = 31
IF iMM = 7 THEN risultato = 31
IF iMM = 8 THEN risultato = 31
IF iMM = 10 THEN risultato = 31
IF iMM = 12 THEN risultato = 31
IF iMM = 2 AND AnnoBisestile(iYYYY) = FALSE THEN risultato = 28
IF iMM = 2 AND AnnoBisestile(iYYYY) = TRUE THEN risultato = 29
IF iMM = 4 THEN risultato = 30
IF iMM = 6 THEN risultato = 30
IF iMM = 9 THEN risultato = 30
IF iMM = 11 THEN risultato = 30
RETURN risultato
END
Per verificare il formato della data puoi usare LIKE:
PUBLIC SUB Main()
DIM alcuneDate AS String
DIM unaData AS String
alcuneDate = "12/01/96,1/10/1980,13/12/1990"
FOR EACH unaData IN Split(alcuneDate)
IF unadata LIKE "[0-9][0-9]/[0-9][0-9]/[0-9][0-9][0-9][0-9]" THEN
PRINT unadata; " : formato valido"
ELSE
PRINT unaData; " : formato NON valido"
ENDIF
NEXT
END
L'idea è buona se non che il sistema considera valida anche una data 99/99/9999.
Anche limitando i campi nel seguente modo:
IF unadata LIKE "[0-3][0-9]/[0-1][0-9]/[0-9][0-9][0-9][0-9]" THEN
il problema rimane, limitato ma rimane:39/19/9999
Però si può utilizzare la tecnica di Giulio e con pochi controlli if..then verificarne la correttezza.
Ciao
Credo che questa soluzione sia la più rapida:
aprite una form ed inserite l'oggetto datechooser (che si può rendere anche invisibile), una textbox ed un bottone.
all'interno del bottone mettete questo codice
PUBLIC SUB Button1_Click()
DIM Datainiziale AS String[]
DIM Datafinale AS String
Datainiziale = Split(TextBox1.Text, "/")
Datafinale = Datainiziale[1] & "/" & Datainiziale[0] & "/" & Datainiziale[2]
DateChooser1.Value = Datafinale
CATCH
Message.Warning("Data non valida")
TextBox1.SetFocus()
END
Ora scrivete una data qualsiasi all'interno della textbox e premete il bottone.
Se la data è valida bene, altrimenti viene mostrato un errore ed il controllo ritorna all'inserimento data.
Siccome il datechooser è in formato mese/giorno/anno, ho messo 2 righe di codice per il ribaltamento italiano giorno/mese/anno.
Ciao
Edit:
Per verificare se un anno è bisestile sarà sufficiente provare ad inserire il giorno 29/mese/anno, se arriva l'errore non è bisestile :-D
In aggiunta a quanto scritto dal Forum, posto quanto scritto da Benoit:
===
What do you need to do exactly?
If you want to know if a string can be interpreted as a date, then you must do
something like that:
DIM vDate AS Variant
DIM sStr AS String
vDate = Val(sStr)
IF IsDate(vDate) THEN
' OK, I got a date
ELSE
' Bad, I didn't go a date
ENDIF
Ho raccolto il materiale, vi ringrazio x le risposte, questo weekend vedo di lavorarci su.
@md9327
L'idea di creare una routine valida x qualunque formato di data mi trova d'accordo, pero' non ho proprio tempo x dedicarmici, vedremo in futuro.
Apprezzo moltissimo i tuoi post, mi dai sempre nuovi spunti di riflessione.
Ancora, sul SELECT CASE hai ragione, vedo di modificare il codice.
@giulio
Grazie per il pattern era proprio quello che cercavo x chiudere la routine
La funzione per il calcolo dell'anno bisestile non è corretta.
Infatti un anno è bisestile se è divisibile per 4. Ma se è divisibile per 100 non lo è a meno che non sia divisibile per 400.
PRIVATE FUNCTION AnnoBisestile(Anno AS Integer) AS Boolean
IF (((Anno MOD 4 = 0) AND (Anno MOD 100 <> 0)) OR Anno MOD 400 = 0) THEN
RETURN True
ELSE
RETURN False
ENDIF
END
Quindi 1900 non è stato bisestile anche se era divisibile per 4 e 100. Ma lo è stato il 2000 perché era divisibile per 400.
Per quanto riguarda il problema della verifica della data (formato dd/mm/yyyy) io ho risolto applicando questo codice, che ho inserito nel modulo di startup del programma. Questa è la funzione principale che replica l'analoga funzione php:
PUBLIC FUNCTION ControlloData(sData AS String) AS Boolean
DIM sDati AS String[]
DIM sValori AS Variant[]
DIM errore AS Boolean
sDati = Split(sData, "/")
IF sData LIKE "[0-9][0-9]/[0-9][0-9]/[0-9][0-9][0-9][0-9]" THEN
IF CheckDate(sDati[0], sDati[1], sDati[2]) = TRUE THEN
errore = FALSE
ELSE
errore = TRUE
ENDIF
ELSE
errore = TRUE
ENDIF
RETURN errore
END
ancora:
PRIVATE FUNCTION CheckDate(iGiorno AS Integer, iMese AS Integer, iAnno AS Integer) AS Boolean
DIM bValore AS Boolean
bValore = TRUE
IF iAnno > 0 AND iAnno < 32768 THEN
bValore = TRUE
'controllo del mese
IF iMese > 0 AND iMese < 13 THEN
bValore = TRUE
ELSE
bValore = FALSE
ENDIF
'controllo del numero dei giorni
IF iGiorno > NumeroGiorniDelMese(iMese, iAnno) THEN
bValore = FALSE
ELSE
bValore = TRUE
ENDIF
ELSE
bValore = FALSE
ENDIF
RETURN bValore
END
la funzione rettificata grazie a Leo:
PRIVATE FUNCTION AnnoBisestile(iAnno AS Integer) AS Boolean
DIM risultato AS Boolean
IF (((iAnno MOD 4 = 0) AND (iAnno MOD 100 <> 0)) OR iAnno MOD 400 = 0) THEN
risultato = TRUE
ELSE
risultato = FALSE
ENDIF
RETURN risultato
END
Questa funzione calcola il numero dei giorni del mese, rettificata rispetto alla prima versione grazie ai consigli di md9327..
PRIVATE FUNCTION NumeroGiorniDelMese(iMM AS Integer, iYYYY AS Integer) AS Integer
DIM risultato AS Integer
SELECT CASE iMM
CASE 1, 3, 5, 7, 8, 10, 12
risultato = 31
CASE 2
IF AnnoBisestile(iYYYY) = FALSE THEN
risultato = 28
ENDIF
IF AnnoBisestile(iYYYY) = TRUE THEN
risultato = 29
ENDIF
CASE 4, 6, 9, 11
risultato = 30
END SELECT
RETURN risultato
END
Un po' di teoria..
Un anno è bisestile se il suo numero è divisibile per 4, con l'eccezione che gli anni secolari (quelli divisibili per 100) sono bisestili solo se divisibili per 400. Sono cio è bisestili tutti gli anni la cui numerazione termina con le due cifre 04, 08, 12...fino a 6.Gli anni che terminano con 00 sono bisestili solo se l 'anno è divisibile per 400, cioè il 1600, il 2000, il 2400 eccetera i mesi dispari sono sempre di 31gg i pari di 30 (o 28 nel caso di Febbraio o 29 negli anni bisestili).
:-D Auguri!
ps. allego schermata della mia fatica del mese..