mercoledì 31 agosto 2011

Formattare date con MySql



In MySql le date hanno questo formato: AAAA-MM-GG, mentre i datetime AAAA-MM-GG OO:MM:SS (i millisecondi non sono ancora gestiti, nemmeno dal campo timestamp)

Sono due le funzioni per giocare con le date in MySql:

  • DATE_FORMAT che serve per formattare la data dal formato di MySql a quello che vogliamo noi;
  • STR_TO_DATE che serve ad eseguire l’operazione contraria, ossia data la nostra stringa con la data rappresentata secondo le nostre esigenze la converte nel formato che piace a MySql.


DATE_FORMAT (data da formattare,pattern)

La funzione prense in input la data o il timestamp in formato MySql e restituisce un varchar con la formattazione desiderata esplicitata nel pattern.
Il pattern è una stringa con caratteri speciali preceduti dal %.

Vediamo la lista completa di questi caratteri speciali, presa dalla documentazione ufficiale di MySql:

           
CARATTERE
DESCRIZIONE
%a
Giorno della settimana abbreviato (Sun..Sat)
%b
Giorno del mese abbreviato (Jan..Dec)

%c
Mese numerico (0..12)
%D
Giorno del mese con suffisso inglese (0th, 1st, 2nd, 3rd, …)

%d
Giorno del mese numerico (00..31)
%e
Giorno del mese numerico (0…31)
%f
Microsecondo (000000..999999)
%H
Ora (00,…23)
%h
Ora (01,….12)
%I
Ora (01,….12)
%i
Minuti (00,..59)
%j
Giorno dell’anno (00,…366)
%k
Ora (00,….23)

%l
Ora (1,…12)
%M
Nome del mese (January..December)
%m
Nome del mese (00,..12)
%p
AM o PM
%r
Hh:mm:ss seguito da AM o PM
%S
Secondi (00,..59)
%s
Secondi (00,..59)
%T
Orario (hh:mm:ss con le 24 ore)
%U
Settimana (00..53) dove Domenica è il primo giorno della settimana
%u
Settimana (00..53) dove Lunedì è il primo giorno della settimana
%V
Settimana (01..53) dove Domenica è il primo giorno della settimana, è usato assieme alla %X
%v
Settimana (01..53) dove Domenica è il primo giorno della settimana, è usato assieme alla %x
%W
Giorno della settimana (Sunday…Saturday)
%w
Giorno della settimana (0= Sunday,….6=Saturday)
%X
Anno per la settimana dove Domenica è il primo giorno  della settimana, numerico, 4 cifre usato con %V
%x
Anno per la settimana dove Domenica è il primo giorno  della settimana, numerico, 4 cifre usato con %v
%Y
Anno, numerico, 4 cifre
%y
Anno, numerico 2 cifre



Esempi:

select DATE_FORMAT(current_timestamp,'%d-%m-%Y %h:%i:%s') as 'data formattata';

Produce '31-08-2011 12:13:07'

select DATE_FORMAT(current_timestamp,'%d-%m-%Y %r') as 'data formattata';

Produce '31-08-2011 12:14:21 PM'


STR_TO_DATE (stringa_da_formattare,pattern)
  
Questa funzione torna una data in formato mysql data la nostra stringa e specificato il pattern di decifrazione della stessa.
Le regole per il pattern fanno riferimento alla tabella prima descritta.

Esempi:

select STR_TO_DATE('31/08/2011','%d/%m/%Y');

Produce '2011-08-31'


select STR_TO_DATE('31/08/2011 Ora:12 Minuto:23 Secondo:50 PM','%d/%m/%Y Ora:%h Minuto:%i Secondo:%s %p');

Produce: '2011-08-31 12:23:50'

sabato 27 agosto 2011

Un esempio di utilizzo delle annotazioni in Java


In questo post vediamo un esempio di creazione e di utilizzo delle annotazioni in Java.
Introdotte fin dalla versione 1.5, le annotazioni sono utilizzate in maniera massiccia dagli Ejb 3.0 in poi e costituiscono un punto di forza anche di JPA, l’interfaccia per la persistenza dati introdotta dalla Sun.
Tuttavia possono anche essere utilizzate e create dagli sviluppatori per le più svariate ragioni, sia per commentare meglio il codice che per utilizzarle via reflection.
Vediamo un semplice esempio.
Definiamo una annotazione (n.b. si definiscono come le interfacce)

package it.test;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Info {
public String nome();
public String versione();

}




 






Le regole da seguire per i metodi definiti all’interno di una annotation sono le seguenti:
  1. Per definire una annotazione bisogna anteporre @interface al nome dell’annotazione;
  2. Le dichiarazioni dei metodi non devono contenere parametri di input;
  3. Le dichiarazioni dei metodi non devono dichiarare la throw di una Exception;
  4. I tipi di ritorno devono essere primitive,String,class enum oppure array dei tipi precedentemente elencati.
  
L’annotation @Target indica a cosa posso applicare l’annotazione all’interno di una classe Java.
I valori ammissibili sono

  1. TYPE: Classi, interfacce, oppure  enum (non annotation)
  2. FIELD: campi  (inclusi valori enum)
  3. METHOD: metodi (non  costruttori)
  4. PARAMETER: parametri di un metodo
  5. CONSTRUCTOR: costruttori
  6. LOCAL_VARIABLE: variabile locale
  7. ANNOTATION_TYPE: tipo annotation
  8. PACKAGE: java package

Se non mettiamo nulla l’annotazione può essere utilizzata ovunque.
NB: è un errore specificare più volte lo stesso valore , ad esempio @Target({ElementType.FIELD, ElementType.METHOD, ElementType.FIELD}) non compila.

L’annotation @Retention indica invece letteralmente per quanto tempo devono essere “mantenute” (to retain in inglese significa appunto mantenere).
I valori ammissibili sono:

  1. RUNTIME, indica che il valore dell’annotazione è visibile nel compilato e accedibile a runtime dalla JVM;
  2. CLASS, indica che il valore dell’annotazione è visibile nel compilato ma non accedibile a Runtime;
  3. SOURCE, indica che il valore dell’annotazione non è visibile nel compilato né accedibile a RunTime.

Il valore di default è class.
Di seguito vediamo come via reflection è possibile ispezionare le annotazioni presenti su una classe e quindi, una volta trovata l’annotazione di nostro interesse stamparne a video i valori.


import java.lang.annotation.Annotation;
@Info(nome="mario rossi",versione="1.0")
public class InfoTest {
public static void main(String[] args) throws Exception{
      Annotation[] annotazioni=InfoTest.class.getAnnotations();
      for(Annotation ann: annotazioni){
            if(ann instanceof Info){
                  Info i=(Info)ann;
                  System.out.println(i.nome());
                  System.out.println(i.versione());
            }
      }
}
}

 


Se eseguiamo il codice il risultato è il seguente:

mario rossi
1.0

Per capire meglio l’importanza e il significato dell’annotazione @Retention proviamo adesso a cambiare il valore da RUNTIME a CLASS.

Eseguendo la nostra classe InfoTest vediamo che in output non è stampato nulla, in quanto l’annotazione non è visibile a runtime alla JVM.

Se decompiliamo il codice vediamo che nella classe InfoTest l’annotazione @Info(nome=”mario rossi”,versione=”1.0”) è presente.
Se modifichamo ancora cambiando il valore di @Retention da CLASS a SOURCE oltre a non avere stampato nulla in output se decompiliamo il .class della classe InfoTest non abbiamo più traccia dell’annotazione.








giovedì 25 agosto 2011

Java errore java.lang.OutOfMemoryError

L'errore java.lang.OutOfMemoryError si verifica quando il processo java in esecuzione arriva a saturare la memoria disponibile.
Per aumentare la memoria bisogna far partire il programma specificando memoria minima e massima allocata.
La sintassi è questa:

java -Xms512M -Xmx1024M [NOME_CLASSE_CON_MAIN]

In questo modo allochiamo minimo 512 MB e massimo 1024MB.
Da ricordare che :

  1. Bisogna specificare il parametro m dopo il numero di Mega altrimenti li intende come bytes (e si rischia di andare in overflow anche con semplici programmi);
  2. Il valore numerico deve essere attaccato all'ammontare di Mega specificato (es è errato scrivere java -Xms 512);
  3. Di default il massimo valore dell'heap size è bassino, 64 Mega, occhio che se si specifica solo il valore minimo mettendo un valore superiore al massimo il programma non parte;
  4. Scriver m o M è analogo, è errato scrivere invece mb;
  5. Per allocare direttamente in giga scrivere g (es java -Xms1g -Xmx2g ). Non è possibile allocare più memoria di quella fisicamente disponibile, il messaggio indicato è could not reserve enough space for object heap;
  6. Si devono specificare valori interi, quindi se si vuole dedicare 1,5 gigabytes è scorretto scrivere  1.5g ma bisogna scrivere 1536M.
 Per alzare il valore su Jboss editare il file $JBOSS_HOME/bin/run.conf ricercando JAVA_OPTS e scrivendo qualcosa del tipo
JAVA_OPTS="-server -Xms128m -Xmx128m"
 


lunedì 22 agosto 2011

Confrontare date in Java

Nell’effettuare una comparazione tra due date bisogna stare attenti all’utilizzo del metodo getTime().
Spesso infatti quello che ci serve è soltanto paragonare le date in base a giorno mese e anno mentre il metodo getTime() tiene conto anche delle ore minuti secondi e millisecondi.

Può essere fuoriviante il seguente codice:

Date d1=new Date();
Date d2=new Date();
System.out.println(d1.getTime()==d2.getTime());

Se si prova ad eseguirlo il risultato sarà quasi sempre true, poiché d1 e d2 vengono create praticamente nello stesso istante, millisecondo compreso.
Se proviamo ad inserire però un Thread.sleep(1000) tra le due dichiarazioni di date vediamo che il risultato torna false, in quanto d2 ha 1 secondo in più di d1.

Anche se ci costruiamo una data usando l’oggetto Calendar in questo modo (come visto in un precedente post )


public static Date creaData(int giorno,int mese,int anno){
              Calendar c=Calendar.getInstance();
              c.set(Calendar.YEAR, anno);
              c.set(Calendar.MONTH, mese-1);
              c.set(Calendar.DAY_OF_MONTH, giorno);
              return c.getTime();
          }


Si verifica lo stesso problema se tra d1 e d2 passa anche solo un millisecondo di differenza.

Le soluzioni possono essere due:
  1. Utilizzare  Joda , una api appositamente creata per velocizzare le operazioni sulle Date, da sempre un tallone d’Achille del linguaggio Java (su cui conto di fare un post a breve);
  2. Modificare il metodo creaData inserendo anche ore minuti secondi e millisecondi

Se usiamo il metodo 2 e riscriviamo così il metodo creaData:


public static Date creaData(int giorno,int mese,int anno){
            Calendar c=Calendar.getInstance();
            c.set(Calendar.YEAR, anno);
            c.set(Calendar.MONTH, mese-1);
            c.set(Calendar.DAY_OF_MONTH, giorno);
            c.set(Calendar.HOUR_OF_DAY, 0);
            c.set(Calendar.MINUTE, 0);
            c.set(Calendar.SECOND, 0);
            c.set(Calendar.MILLISECOND, 0);
            return c.getTime();
      }



Il problema è risolto, e le date saranno finalmente paragonate senza tener conto dei loro diversi istanti di creazione.


venerdì 5 agosto 2011

Zippare File in Java


Una semplice classe di utilità per zippare dei file.
Ha due costruttori, in uno passiamo la lista dei file (il percorso completo) da zippare e il nome (percorso incluso) dello zip risultante, l’altro invece accetta come parametri la Stringa contenente il singolo file da zippare
e il nome dell’output.




      
package it.test;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.LinkedList;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
public class ZipFile {
    private List<String> listaFiles;
    private String nomeZip;
       public ZipFile(List<String> listaFile,String nomeZip){
             this.nomeZip=nomeZip;
             this.listaFiles=listaFile;
       }
       public ZipFile(String nomeFile,String nomeZip){
             listaFiles=new LinkedList<String>();
             listaFiles.add(nomeFile);
             this.nomeZip=nomeZip;
       }
       public static void main(String[] args) {
             try
             {
                    ZipFile zf=new ZipFile("out/AMF050_test_20100601_20110228.txt", "out/test.zip");
                    zf.zippa();
             }
             catch(Exception ex){
                    ex.printStackTrace();
             }           
       }
       /**
        * Per evitare che dentro lo zip sia ricreata <br>
        * la eventuale struttura delle directory e sottodirectory del file di origine
        * @param nome
        * @return
        */
       private String nomeFile(String nome){
             StringBuffer sb=new StringBuffer();
             if(nome.indexOf("/")>0){
                    sb.append(nome.substring(nome.lastIndexOf("/")+1));
             }
             else if(nome.indexOf(File.separator)>0){
                    sb.append(nome.substring(nome.lastIndexOf(File.separator)+1));
             }
             else
             {
                    sb.append(nome);
             }
             return sb.toString();
       }
       public void zippa() throws Exception
       {
             byte[] buf = new byte[1024];
              ZipOutputStream out = new ZipOutputStream(new FileOutputStream(nomeZip));
              for(String file:listaFiles){
                     FileInputStream in = new FileInputStream(file);
                     out.putNextEntry(new ZipEntry(nomeFile(file)));
                     int len;
                     while ((len = in.read(buf)) > 0) {
                         out.write(buf, 0, len);
                     }
                     out.closeEntry();
                     in.close();

              }
              out.close();
       }
}