Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial

Java: gestione delle date

Impariamo a gestire e formattare le date in Java, quali classi utilizzare e quali sono i formati supportati nelle varie versioni del linguaggio.
Impariamo a gestire e formattare le date in Java, quali classi utilizzare e quali sono i formati supportati nelle varie versioni del linguaggio.
Link copiato negli appunti

Prima dell'introduzione di Java 8, la gestione delle date si concretizzava nell'utilizzo delle classi java.text.DateFormat e java.text.SimpleDateFormat per avere, rispettivamente, un formato di base (DateFormat) oppure uno più avanzato (SimpleDateFormat). L'introduzione della classe java.time.format.DateTimeFormatter nelle API Java 8 ha confinato queste classi nella categoria legacy.

In questo articolo vedremo esempi di formattazione delle date sia con stile Java 8 che antecedente ad esso. Con DateFormat abbiamo essenzialmente una formattazione riassunta dalle seguenti tipologie:

    Formato Descrizione
    SHORT Completamente numerica, ad esempio 12/01/19.
    MEDIUM Più lunga con elementi testuali, ad esempio Jan 12, 1952.
    LONG Simile alla MEDIUM ma con un estensione testuale maggiore, ad esempio January 12, 1952.
    FULL La specifica del formato più lunga e completa, ad esempio Tuesday, April 12, 1952 AD.

    Se il formato di cui abbiamo bisogno rientra in uno di questi tipi, possiamo creare un formattatore di date attraverso un'istanza della classe DateFormat specificando un formato per la data stessa ed una posizione geografica:

    DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT, Locale.ITALY);
     System.out.println(df.format(new Date()));
     System.out.println(df.parse("12/11/19"));
     df = DateFormat.getDateInstance(DateFormat.MEDIUM, Locale.ITALY);
     System.out.println(df.format(new Date()));
     System.out.println(df.parse("12-gen-2019"));
     df = DateFormat.getDateInstance(DateFormat.LONG, Locale.ITALY);
     System.out.println(df.format(new Date()));
     System.out.println(df.parse("12 gennaio 2019"));
     df = DateFormat.getDateInstance(DateFormat.FULL, Locale.ITALY);
     System.out.println(df.format(new Date()));
     System.out.println(df.parse("sabato 12 gennaio 2019"));

    Ottenendo in stampa:

    12/01/19
    Tue Nov 12 00:00:00 CET 2019
    12-gen-2019
    Sat Jan 12 00:00:00 CET 2019
    12 gennaio 2019
    Sat Jan 12 00:00:00 CET 2019
    sabato 12 gennaio 2019
    Sat Jan 12 00:00:00 CET 2019

    Notiamo come la stampa della stringa, ottenuta dal metodo parse(), non segua il tipo di Locale specificato (ITALY). Questo comportamento Locale independent del metodo toString() della classe Date, non consente di fare affidamento ad esso, in generale, per la stampa di una data ottenuta come parsing di una stringa.

    Un altro aspetto evidente è l'orario non specificato fisso sulla mezzanotte di ogni giorno. Per poter gestire date con ore, minuti e secondi dobbiamo utilizzare il metodo getDateTimeInstance(int dateStyle, int timeStyle, Locale aLocale). Vediamo un esempio con il formato SHORT per data e orario:

    DateFormat df = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, Locale.ITALY);
    System.out.println(df.format(new Date()));
    System.out.println(df.parse("12/11/19 12.00.00"));

    La precedente stampa, relativamente al formato SHORT, cambia quindi in:

    12/01/19 14.45
    Tue Nov 12 12:00:00 CET 2019

    In cui appare evidente l'orario corrente e quello successivo da noi impostato. Quando il formato di cui abbiamo bisogno non rientra nelle categorie gestite dalla classe DateFormat, possiamo utilizzare la sua classe di estensione SimpleDateFormat.

    La descrizione Javadoc di questa classe, suggerisce di utilizzare il metodo getDateInstance() o getDateTimeInstance() per ottenere un formattatore di default, da personalizzare successivamente con il metodo applyPattern() specifico della classe SimpleDateFormat.

    L'operazione preliminare di costruzione di un oggetto SimpleDateFormat è realizzabile con il seguente frammento di codice:

    SimpleDateFormat dateFormat = (SimpleDateFormat)SimpleDateFormat.getDateInstance(DateFormat.SHORT, Locale.ITALY);

    Prima di procedere è opportuna un piccola considerazione sulle sigle che evidenziano il fuso orario (in Java rappresentato dalla classe TimeZone). L'UTC è il tempo coordinato universale corrispondente al fuso orario di Greenwich. In questo punto è stato posto il meridiano 0 e le ore 12 in punto arrivano quando il sole si trova esattamente a picco della linea del meridiano.

    La vecchia sigla GMT, che significa tempo medio di Greenwich, ha lasciato il posto alla UTC. Il nuovo sistema è basato su orologi atomici e non più su fenomeni celesti. Il CET (Central European Time), il fuso orario che comprende anche l'Italia, nei mesi invernali può essere indicato con la sigla UTC+1, l'orario UTC corrisponde solo all'ora solare e non a quella legale.

    Di conseguenza, per quanto riguarda il fuso orario che comprende anche l'Italia, in estate si passa da UTC+1 a UTC+2 e da CET a CEST (Central European Summer Time). Nelle stringhe di formattazione che vedremo, la parte finale indica proprio l'offset dall'ora UTC o GMT. Un esempio:

    dateFormat.setTimeZone(TimeZone.getTimeZone("Europe/Rome"));
        dateFormat.applyPattern("yyyy.MM.dd E 'at' HH:mm:ss z");
        System.out.println(dateFormat.format(new Date()));  
        dateFormat.applyPattern("yyyy.MM.dd E 'at' HH:mm:ss Z");
        System.out.println(dateFormat.format(new Date()));

    Che produce in output:

    2019.01.12 sab at 15:27:07 CET
    2019.01.12 sab at 15:27:07 +0100

    Nel codice di esempio abbiamo utilizzato un formato per la stringa della data che evidenzia in modo abbastanza intuitivo anno, giorno, mese, ore, minuti e secondi. Ma cosa rappresenta la z finale in minuscolo o maiuscolo? Ebbene la z è proprio la lettera che consente la stampa delle informazioni di fuso orario. Con la lettera z richiediamo la stampa dell'informazione del fuso orario di tipo General time zone ovvero un fuso orario espresso come offset rispetto all'orario di Greenwich GMT.

    La lettera z rappresenta invece il formato conforme alla RFC 822 time zone in cui l'offset GMT è espresso secondo il formato Sign TwoDigitHours Minutes in cui si specifica il segno di somma/sottrazione e la quantità in ore e minuti da sottrarre o sommare all'orario GMT. Nel nostro caso +0100 indica la somma di un'ora e zero minuti all'orario GMT per ottenere l'orario correntemente stampato.

    Elenchiamo alcuni esempi di formato di date più comuni:

    Formato Esempio di data
    dd-MM-yy 12-01-2019
    dd-MM-yyyy 12-01-2019
    MM-dd-yyyy 01-12-2019
    yyyy-MM-dd 2019-01-12
    yyyy-MM-dd HH:mm:ss 2019-01-12 23:59:59
    yyyy-MM-dd HH:mm:ss.SSS 2019-01-12 23:59:59.999
    yyyy-MM-dd HH:mm:ss.SSSZ 2019-01-12 23:59:59.999+0100
    EEEEE MMMMM yyyy HH:mm:ss.SSSZ Saturday January 2019 13:45:00.720+0100

    Se stiamo utilizzando la versione 8 o superiore di Java è consigliabile fare uso della nuova classe java.time.format.DateTimeFormatter. Un formattatore con DateTimeFormatter si ottiene attraverso l'uso del metodo statico ofPattern():

    DateTimeFormatter formatter = DateTimeFormatter.
                    ofPattern("yyyy.MM.dd",Locale.ITALY).withZone(ZoneId.of("Europe/Rome"));

    Possiamo notare come con una singola istruzione riusciamo ad ottenere un formattatore compreso di definizione del formato geografico e del fuso orario (classe java.time.ZoneId). Successivamente, utilizzando la classe java.time.LocalDate, possiamo ottenere la data corrente, formattarla e parsarla con il pattern appena definito:

    LocalDate date = LocalDate.now();
     String text = date.format(formatter);
     System.out.println(text);
     LocalDate parsedDate = LocalDate.parse(text, formatter);
     System.out.println(parsedDate);

    Il codice precedente fornisce in stampa:

    2019.01.12
    2019-01-12

    Con la seconda stampa che produce un formato indipendente dal Locale definito a causa del comportamento del metodo toString(). La classe LocalDate è utilizzabile per la formattazione di date che non prevedono l'utilizzo di ore, minuti e secondi. Se abbiamo bisogno di date estese, dobbiamo sostituirla con la classe LocalDateTime:

    DateTimeFormatter formatter = DateTimeFormatter.
                    ofPattern("yyyy.MM.dd HH:mm:ss z",Locale.ITALY).withZone(ZoneId.of("Europe/Rome"));
      LocalDateTime dateTime = LocalDateTime.now();
      String text = dateTime.format(formatter);
      System.out.println(text);
      LocalDateTime  parsedDateTime = LocalDateTime.parse(text, formatter);
      System.out.println(parsedDateTime);

    Il cui output è:

    2019.01.12 16:30:47 CET
    2019-01-12T16:30:47

    Concludiamo l'articolo sottolineando come DateTimeFormatter sia una classe immutabile e Thread safe, caratteristica non presente nelle classi DateFormat e SimpleDateFormat.

Ti consigliamo anche