Autore Topic: Routine di controllo di validità della data  (Letto 4674 volte)

Offline andy60

  • Senatore Gambero
  • ******
  • Post: 1.255
    • Mostra profilo
    • https://www.linkedin.com/in/andbertini
Routine di controllo di validità della data
« il: 21 Marzo 2008, 09:32:02 »
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:

Codice: [Seleziona]
dd/mm/yyyy


Questa è la funzione da replicare, mi manca parte iniziale ereg:

Codice: [Seleziona]


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:

Codice: [Seleziona]

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:

Codice: [Seleziona]

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

g.paolo

  • Visitatore
Re: Routine di controllo di validità della data
« Risposta #1 il: 21 Marzo 2008, 10:17:04 »
Non sono in grado di aiutarti, ma ti faccio solo notare che c'è uno scambio del valore per i giorni di ottobre e novembre

Offline md9327

  • Moderatore
  • Senatore Gambero
  • *****
  • Post: 2.840
    • Mostra profilo
Re: Routine di controllo di validità della data
« Risposta #2 il: 21 Marzo 2008, 11:33:19 »
Ciao andy,

l'idea è buona, magari vedi di farci una piccola classe generica, magari derivata da Date, in cui ci aggiungi quelle funzioni come metodi.
Un piccolo consiglio, dovuto ad un piccolo problema di velocità, ti consiglio di usare ELSE IF oppure SELECT CASE per il controllo multiplo su uno stesso valore, altrimenti l'interprete è costretto a eseguire i controlli comunque in tutti i casi; se inserisci queste istruzioni, il controllo termina alla prima condizione valida. Se il valore è l'ultimo della serie, ovviamente si deve scorrere tutto, ma almeno riduci i tempi medi.

Un'latra idea sarebbe anche quella di verificare diversi formati Date, e non fermarsi ad un formato preciso. Tieni conto che il formato dipende dal paese e dalla lingua impostata nel sistema; inoltre, anche se poco usato, sarebbe importante capire se l'anno è a due cifre o meno... Diciamo che forse sarebbe il caso di mettere due parametri, di cui il primo è il formato di lettura, mentre il secondo è il valore da testare. SI potrebbe anche prevedere una funzione di conversione...

Insomma ti ho dato un pochino di idee... :-)

Offline giulio

  • Maestro Gambero
  • ****
  • Post: 280
    • Mostra profilo
Re: Routine di controllo di validità della data
« Risposta #3 il: 21 Marzo 2008, 11:53:11 »
Per verificare il formato della data puoi usare LIKE:

Codice: [Seleziona]
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

Offline Pixel

  • Amministratore
  • Maestro Gambero
  • *****
  • Post: 414
    • Mostra profilo
    • http://www.gambas-it.org
Re: Routine di controllo di validità della data
« Risposta #4 il: 21 Marzo 2008, 12:18:19 »
L'idea è buona se non che il sistema considera valida anche una data 99/99/9999.

Anche limitando i campi nel seguente modo:
Codice: [Seleziona]
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
Ubuntu Italian Member Ubuntu User 4683
Il mio Blog

Offline md9327

  • Moderatore
  • Senatore Gambero
  • *****
  • Post: 2.840
    • Mostra profilo
Re: Routine di controllo di validità della data
« Risposta #5 il: 21 Marzo 2008, 15:05:52 »
Un'altra alternativa potrebbe essere quella di farla analizzare dal sistema operativo, ma questo comporterebbe due cose: non si usa gambas (almeno non per tutto), dipende dal sistema operativo (la momento è linux, ma chissà in futuro...).

Offline Pixel

  • Amministratore
  • Maestro Gambero
  • *****
  • Post: 414
    • Mostra profilo
    • http://www.gambas-it.org
Re: Routine di controllo di validità della data
« Risposta #6 il: 21 Marzo 2008, 15:29:53 »
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

Codice: [Seleziona]
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
Ubuntu Italian Member Ubuntu User 4683
Il mio Blog

Offline andy60

  • Senatore Gambero
  • ******
  • Post: 1.255
    • Mostra profilo
    • https://www.linkedin.com/in/andbertini
Re: Routine di controllo di validità della data
« Risposta #7 il: 21 Marzo 2008, 17:06:52 »
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:

Codice: [Seleziona]
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

Offline andy60

  • Senatore Gambero
  • ******
  • Post: 1.255
    • Mostra profilo
    • https://www.linkedin.com/in/andbertini
Re: Routine di controllo di validità della data
« Risposta #8 il: 21 Marzo 2008, 17:11:37 »
Grazie! in effetti al controllo nascosto non avevo pensato, era mia intenzione risolvere la cosa con semplice codice. Comunque questa è una strada, ed anche veloce. :-)

Offline leo72

  • Amministratore
  • Senatore Gambero
  • *****
  • Post: 2.163
    • Mostra profilo
    • http://www.leonardomiliani.com
Re: Routine di controllo di validità della data
« Risposta #9 il: 21 Marzo 2008, 18:04:08 »
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.

Codice: [Seleziona]

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.
Visita il mio sito personale: http://www.leonardomiliani.com

Offline md9327

  • Moderatore
  • Senatore Gambero
  • *****
  • Post: 2.840
    • Mostra profilo
Re: Routine di controllo di validità della data
« Risposta #10 il: 21 Marzo 2008, 19:35:15 »
Esatto !!!

Comunque, a mio parere, il controllo nascosto, anche se veloce, è comunque una cosa un pò artefatta... sempre a mio parere.

Ovviamente, se non esistono alternative, può essere un'idea.

Ad ogni modo, credo che costruire una classe, come suggerito inizialmente da andy, sia la strada più pulita.

Offline Pixel

  • Amministratore
  • Maestro Gambero
  • *****
  • Post: 414
    • Mostra profilo
    • http://www.gambas-it.org
Re: Routine di controllo di validità della data
« Risposta #11 il: 21 Marzo 2008, 22:07:36 »
Citazione

Comunque, a mio parere, il controllo nascosto, anche se veloce, è comunque una cosa un pò artefatta... sempre a mio parere.
Ovviamente, se non esistono alternative, può essere un'idea.
Ad ogni modo, credo che costruire una classe, come suggerito inizialmente da andy, sia la strada più pulita.


Mah.. non sono molto convinto... dal mio punto di vista preferisco usare quello che mette a disposizione nativamente Gambas invece di avventurarmi in scrittura di codice, cioè, non credo abbia molto senso reinventare la bicicletta per farci un giro...
In pratica è come se l'oggetto fosse una classe.. inoltre il componente in questione è presente sia in QT che GTK, ha un sacco di sotto opzioni, può essere richiamato per la visualizzazione all'interno del programma ecc..ecc..
Se invece mi poni il problema con un software (esempio) testuale beh.. ovviamente il discorso cambia, e ben venga una classe.
Tra l'altro la soluzione al problema ha innescato un mezzo putiferio nella ML ufficiale con varie soluzioni.
Io non sono un gran conoscitore di Gambas e della programmazione in generale, ma da ignorante penso che il sistema che ho evidenziato possa essere una soluzione alquanto indolore e con ulteriori vantaggi che una classe difficilmente potrebbe avere.
Ovviamente parlo dal basso (bassissimo) delle mie conoscenze informatiche.
Ciao
Ubuntu Italian Member Ubuntu User 4683
Il mio Blog

Offline andy60

  • Senatore Gambero
  • ******
  • Post: 1.255
    • Mostra profilo
    • https://www.linkedin.com/in/andbertini
Re: Routine di controllo di validità della data
« Risposta #12 il: 21 Marzo 2008, 23:01:14 »
@leo

Giusto, non avevo verificato sta cosa. Grazie a nome mio e degli altri.

Offline md9327

  • Moderatore
  • Senatore Gambero
  • *****
  • Post: 2.840
    • Mostra profilo
Re: Routine di controllo di validità della data
« Risposta #13 il: 22 Marzo 2008, 01:06:07 »
Ripeto, non voglio criticare assolutamente il modus operandi, solo che che a mio parere forse è il caso di cercare qualcosa di più pulito.

Se poi mi dici che nel forum di Gambas stanno facendo un putiferio, ben venga, vuol dire che prima o poi si troverà la soluzione.

Ad ogni modo, ogni modo è lecito per arrivare ad una soluzione, almeno in informatica; questo può essere un'alternativa veloce per una risoluzione veloce del problema... diciamo una toppetta, và... :-)

...eheheh, ne vedo parecchie in giro...

Offline andy60

  • Senatore Gambero
  • ******
  • Post: 1.255
    • Mostra profilo
    • https://www.linkedin.com/in/andbertini
Re: Routine di controllo di validità della data
« Risposta #14 il: 22 Marzo 2008, 20:24:14 »
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:

Codice: [Seleziona]
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:
Codice: [Seleziona]

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:
Codice: [Seleziona]

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..
Codice: [Seleziona]

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..