CodeGym /Java Blog /Random-IT /Come non perdersi nel tempo: DateTime e Calendario
John Squirrels
Livello 41
San Francisco

Come non perdersi nel tempo: DateTime e Calendario

Pubblicato nel gruppo Random-IT
CIAO! Oggi inizieremo a lavorare con un nuovo tipo di dati che non abbiamo mai incontrato prima, vale a dire le date. Come non perdersi nel tempo: DateTime e Calendario - 1Non credo di dover spiegare cos'è un appuntamento. :) In linea di principio, potremmo memorizzare la data e l'ora correnti in una normale stringa Java.

public class Main {
   public static void main(String[] args) {

       String date = "June 11, 2018";
       System.out.println(date);
   }
}
Ma questo approccio ha molti inconvenienti. La Stringclasse è progettata per lavorare con il testo ei suoi metodi sono appropriati per questo compito. Se abbiamo bisogno di manipolare una data in qualche modo (aggiungere 2 ore, per esempio), Stringnon funziona molto bene. Oppure se vogliamo visualizzare la data e l'ora corrente quando il programma viene compilato. Stringnon aiuta neanche qui: nel momento in cui scrivi il codice e lo esegui, l'ora sarà cambiata e la console visualizzerà le informazioni sbagliate. Ecco perché i creatori di Java hanno fornito diverse classi per lavorare con date e orari. Il primo di questi èjava.util.Date

Data classe

Abbiamo specificato il suo nome completo, perché un altro pacchetto Java ha la java.sql.Dateclasse. Non confonderli! La prima cosa che devi sapere è che memorizza la data come il numero di millisecondi trascorsi dal 1 gennaio 1970. Questo sistema di tempo ha anche un suo nome: " Unix-time " Un approccio piuttosto interessante, non sarebbe sei d'accordo? :) La seconda cosa che vale la pena ricordare è questa: se crei un Dateoggetto usando il costruttore predefinito, il risultato rappresenta la data e l'ora correnti nel momento in cui l'oggetto è stato creato . Ricordi che abbiamo detto che una data rappresentata come Stringfarebbe fatica con un tale compito? La Dateclasse lo gestisce con facilità.

public class Main {
   public static void main(String[] args) {

       Date date = new Date();
       System.out.println(date);
   }
}
Esegui questo codice più volte e vedrai l'ora cambiare ripetutamente. :) Questo è possibile perché il tempo è memorizzato in millisecondi: sono unità di tempo estremamente piccole, quindi i risultati sono estremamente accurati. La Dateclasse un altro costruttore: puoi passare il numero esatto di millisecondi dalle 00:00 del 1 gennaio 1970 alla data richiesta e verrà creato un oggetto data corrispondente:

public class Main {
   public static void main(String[] args) {

       Date date = new Date(1212121212121L);
       System.out.println(date);
   }
}
Output della console: Fri May 30 04:20:12 GMT 2008 Otteniamo il 30 maggio 2008. "Fri" indica il giorno della settimana (Friday, duh) e GMT è il fuso orario (Greenwich Mean Time). I millisecondi vengono passati come longs, perché il numero di millisecondi di solito non rientra in un int. Quindi, quali operazioni con le date potremmo dover eseguire? Bene, il più ovvio, ovviamente, è il confronto . Per determinare se una data viene prima o dopo un'altra. Questo può essere fatto in diversi modi. Ad esempio, puoi chiamare il Date.getTime()metodo, che restituisce il numero di millisecondi trascorsi dalla mezzanotte del 1 gennaio 1970. Basta chiamarlo su due oggetti Date e confrontare i risultati:

public class Main {
   public static void main(String[] args) {

       Date date1 = new Date();

       Date date2 = new Date();

       System.out.println((date1.getTime() > date2.getTime())?
               "date1 is later than date2" : "date1 is earlier than date2");
   }
}
Output: date1 è precedente a date2 Ma c'è anche un modo più conveniente, cioè usando metodi speciali forniti dalla classe Date: before(), after()e equals(). Tutti restituiscono un valore booleano. Il before()metodo controlla se la nostra data è precedente alla data passata come argomento:

public class Main {
   public static void main(String[] args) throws InterruptedException {

       Date date1 = new Date();

       Thread.sleep(2000);// Suspend the program for 2 seconds
       Date date2 = new Date();

       System.out.println(date1.before(date2));
   }
}
Output della console: true Allo stesso modo, il after()metodo verifica se la nostra data è successiva alla data passata come argomento:

public class Main {
   public static void main(String[] args) throws InterruptedException {

       Date date1 = new Date();

       Thread.sleep(2000);// Suspend the program for 2 seconds
       Date date2 = new Date();

       System.out.println(date1.after(date2));
   }
}
Output della console: false Nei nostri esempi, "mettiamo il programma in sospensione" per 2 secondi, in modo che le due date siano sicuramente diverse. Su computer veloci, il tempo tra la creazione di date1e date2potrebbe essere inferiore a un millisecondo, causando la restituzione di entrambi before()e false. after()Ma in questo caso, il equals()metodo restituirà true! Dopotutto, confronta il numero di millisecondi dalle 00:00 del 1° gennaio 1970 per ciascuna data. Gli oggetti sono considerati uguali solo se corrispondono al millisecondo :

public static void main(String[] args) {

   Date date1 = new Date();
   Date date2 = new Date();

   System.out.println(date1.getTime());
   System.out.println(date2.getTime());

   System.out.println(date1.equals(date2));
}
Ecco un'altra cosa a cui devi prestare attenzione. Se apri la documentazione per la Dateclasse sul sito Web di Oracle , vedrai che molti dei suoi metodi e costruttori sono stati contrassegnati come deprecati (cioè non consigliati per l'uso). Ecco cosa hanno da dire i creatori di Java su parti di classi che sono state deprecate:
"Un elemento di programma annotato @Deprecated è qualcosa che i programmatori non dovrebbero usare, di solito perché è pericoloso o perché esiste un'alternativa migliore."
Ciò non significa che questi metodi non possano essere utilizzati affatto. Se provi a eseguire codice utilizzando metodi deprecati in un IDE, molto probabilmente funzionerà. Ad esempio, considera il Date.getHours()metodo deprecato, che restituisce il numero di ore associate a un Dateoggetto.

public static void main(String[] args) {

   Date date1 = new Date();

   System.out.println(date1.getHours());
}
Se inizi il codice alle 14:21 (14:21), verrà visualizzato il numero 14. Come puoi vedere, il metodo deprecato è barrato, ma funziona ancora. Questi metodi non vengono rimossi per non interrompere l'enorme corpo di codice esistente che li utilizza. In altre parole, questi metodi non sono né "interrotti" né "rimossi". Semplicemente non sono raccomandati per l'uso perché è disponibile un'alternativa più conveniente. Per inciso, la documentazione menziona specificamente questa alternativa:
Come non perdersi nel tempo: DateTime e Calendario - 2
La maggior parte dei Datemetodi della classe sono stati spostati nella Calendarclasse migliorata ed estesa. Faremo conoscenza con quella classe dopo. :)

Classe di calendario

JDK 1.1 ha introdotto una nuova classe: Calendar. Ha reso il lavoro con le date in Java un po' più semplice di prima. L'unica implementazione della classe Calendarcon cui lavoreremo è la GregorianCalendarclasse. Implementa il calendario gregoriano, che è osservato dalla maggior parte dei paesi del mondo. Il suo principale vantaggio è che può lavorare con le date in un formato più conveniente. Ad esempio, può:
  • Aggiungi un mese o un giorno alla data corrente
  • Controlla se l'anno è un anno bisestile;
  • Restituisci i singoli componenti della data (ad esempio, estrai il numero del mese da una data intera)
  • Contiene anche un sistema di costanti molto conveniente (molte delle quali vedremo in seguito).
Un'altra importante valorizzazione della Calendarclasse è la costante Calendar.ERA : è possibile indicare una data anteriore all'era volgare (BC - avanti Cristo) o all'era volgare (AD - Anno Domini). Diamo un'occhiata a tutto questo con esempi. Creiamo un calendaroggetto con la data del 25 gennaio 2017:

public static void main(String[] args) {

  Calendar calendar = new GregorianCalendar(2017, 0 , 25);
}
Nella Calendarclasse (così come nella Dateclasse del resto), i mesi iniziano da zero , quindi passiamo il numero 0 come secondo argomento. Quando si lavora con la Calendarclasse, è importante capire che si tratta proprio di un calendario , non di una singola data. Come non perdersi nel tempo: DateTime e Calendario - 3 Una data è costituita da pochi numeri che indicano un intervallo di tempo specifico. Un calendario è un intero sistema che ti consente di fare molte cose con le date. :) Questo è abbondantemente evidente se provi a visualizzare l' Calendaroggetto: Output: java.util.GregorianCalendar[time=?,areFieldsSet=false,areAllFieldsSet=false,lenient=true,zone=sun.util.calendar.ZoneInfo[id="Europa/Londra",offset=0,dstSavings=0,useDaylight= false,transitions=79,lastRule=null],firstDayOfWeek=2,minimalDaysInFirstWeek=1,ERA=?,YEAR=2017,MONTH=0,WEEK_OF_YEAR=?,WEEK_OF_MONTH=?,DAY_OF_MONTH=25,DAY_OF_YEAR=?,DAY_OF_WEEK=? ,DAY_OF_WEEK_IN_MONTH=?,AM_PM=0,HOUR=0,HOUR_OF_DAY=0,MINUTE=0,SECOND=0,MILLISECOND=?,ZONE_OFFSET=?,DST_OFFSET=?] Guarda quante informazioni ottieni ! Un calendario ha una serie di proprietà che una data normale non ha e vengono visualizzate tutte (questo è il modo in cui iltoString()metodo funziona nellaCalendarclasse). Se hai solo bisogno di ottenere una semplice data dal calendario, cioè unDateoggetto, usa il fileCalendar.getTime()metodo (il nome non è il più logico, ma cosa puoi fare?):

public static void main(String[] args) {

   Calendar calendar = new GregorianCalendar(2017, 0 , 25);
   Date date = calendar.getTime();
   System.out.println(date);
}
Output: Wed Jan 25 00:00:00 GMT 2017 Ora abbiamo preso il calendario e "ridotto" a una data ordinaria. Andiamo oltre. Oltre a designare i mesi in base al loro numero, puoi utilizzare i valoriCalendar dei campi costanti della classe . Queste costanti sono campi statici della classe con un valore predefinito che non può essere modificato. Questa è in realtà un'opzione ancora migliore, perché usarli migliora la leggibilità del tuo codice. Calendar

public static void main(String[] args) {
   GregorianCalendar calendar = new GregorianCalendar(2017, Calendar.JANUARY , 25);
}
Calendar.JANUARY è una delle costanti che rappresentano i mesi dell'anno. Usando queste costanti denominate, nessuno dimenticherà, ad esempio, che il numero 3 significa aprile, e non il terzo mese, che ci piace chiamare marzo. Basta scrivere Calendar.APRIL e il gioco è fatto. :) Tutti i campi del calendario (numero, mese, minuti, secondi, ecc.) possono essere specificati separatamente utilizzando ilset()metodo. Questo metodo è molto conveniente, perché laCalendarclasse ha una costante per ogni campo e il codice risultante è molto facile da leggere. Nell'ultimo esempio, abbiamo creato una data, ma non abbiamo impostato un orario. Impostiamo l'ora 19:42:12

public static void main(String[] args) {
   Calendar calendar = new GregorianCalendar();
   calendar.set(Calendar.YEAR, 2017);
   calendar.set(Calendar.MONTH, 0);
   calendar.set(Calendar.DAY_OF_MONTH, 25);
   calendar.set(Calendar.HOUR_OF_DAY, 19);
   calendar.set(Calendar.MINUTE, 42);
   calendar.set(Calendar.SECOND, 12);

   System.out.println(calendar.getTime());
}
Output: Wed Jan 25 19:42:12 GMT 2017 Chiamiamo il set()metodo, passando una costante (a seconda del campo che vogliamo modificare) e il nuovo valore per il campo. Si scopre che questo set()metodo è una sorta di "super-setter" che sa impostare il valore non solo per un campo, ma per molti campi. :) La Calendarclasse usa il add()metodo per sommare e sottrarre valori. Passi nel campo che vuoi modificare e un numero (esattamente quanto vuoi aggiungere/sottrarre dal valore corrente). Ad esempio, prendiamo una data che è 2 mesi prima della data che abbiamo creato:

public static void main(String[] args) {
   Calendar calendar = new GregorianCalendar(2017, Calendar.JANUARY , 25);
   calendar.set(Calendar.HOUR, 19);
   calendar.set(Calendar.MINUTE, 42);
   calendar.set(Calendar.SECOND, 12);

   calendar.add(Calendar.MONTH, -2); // To subtract, pass a negative number
   System.out.println(calendar.getTime());
}
Uscita: ven nov 25 19:42:12 GMT 2016 Ottimo! Abbiamo la data 2 mesi fa. Questo non ha fatto cambiare solo il mese: anche l'anno è cambiato dal 2017 al 2016. Ovviamente, quando si convertono le date, l'anno corrente viene calcolato automaticamente senza che tu debba tenerne traccia manualmente. Ma se per qualche motivo hai bisogno di disabilitare questo comportamento, puoi farlo. Il roll()metodo può aggiungere e sottrarre valori senza influire sui valori rimanenti . Ad esempio, in questo modo:

public static void main(String[] args) {
   Calendar calendar = new GregorianCalendar(2017, Calendar.JANUARY , 25);
   calendar.set(Calendar.HOUR, 10);
   calendar.set(Calendar.MINUTE, 42);
   calendar.set(Calendar.SECOND, 12);

   calendar.roll(Calendar.MONTH, -2);
   System.out.println(calendar.getTime());
}
Abbiamo fatto esattamente la stessa cosa dell'esempio precedente: abbiamo impiegato 2 mesi dalla data corrente. Ma ora il codice fa qualcosa di diverso: il mese è cambiato da gennaio a novembre, ma l'anno rimane invariato: 2017! Uscita: Sab Nov 25 10:42:12 GMT 2017 Andando avanti. Come abbiamo detto sopra, possiamo ottenere tutti i Calendarcampi separatamente. Lo facciamo con il get()metodo:

public static void main(String[] args) {
   GregorianCalendar calendar = new GregorianCalendar(2017, Calendar.JANUARY , 25);
   calendar.set(Calendar.HOUR, 10);
   calendar.set(Calendar.MINUTE, 42);
   calendar.set(Calendar.SECOND, 12);

   System.out.println("Year: " + calendar.get(Calendar.YEAR));
   System.out.println("Month: " + calendar.get(Calendar.MONTH));
   System.out.println("Week in the month: " + calendar.get(Calendar.WEEK_OF_MONTH));// Week in this month?

   System.out.println("Day: " + calendar.get(Calendar.DAY_OF_MONTH));

   System.out.println("Hours: " + calendar.get(Calendar.HOUR));
   System.out.println("Minutes: " + calendar.get(Calendar.MINUTE));
   System.out.println("Seconds: " + calendar.get(Calendar.SECOND));
   System.out.println("Milliseconds: " + calendar.get(Calendar.MILLISECOND));

}
Output: Anno: 2017 Mese: 0 Settimana del mese: 5 Giorno: 25 Ore: 10 Minuti: 42 Secondi: 12 Millisecondi: 0 Quindi, oltre al Calendar"super-setter" della classe, c'è anche un "super-getter" ". :) Naturalmente, un altro aspetto interessante di questa classe è lavorare con le ere. Per creare una data "BC", dovrai utilizzare il campo Calendar.ERA Ad esempio, creiamo una data per la battaglia di Canne, dove Annibale sconfisse l'esercito romano. Questo accadde il 2 agosto 216 a.C.:

public static void main(String[] args) {
   GregorianCalendar cannae = new GregorianCalendar(216, Calendar.AUGUST, 2);
   cannae.set(Calendar.ERA, GregorianCalendar.BC);

   DateFormat df = new SimpleDateFormat("MMM dd, yyy GG");
   System.out.println(df.format(cannae.getTime()));
}
Qui abbiamo utilizzato la SimpleDateFormatclasse per stampare la data in un formato per noi più facile da capire (le lettere "GG" indicano che vogliamo visualizzare l'era). Uscita: 02 agosto 216 a.C. La Calendarclasse ha molti più metodi e costanti. Puoi leggere su di loro nella documentazione . Se non ti piace questo formato di data Sat Nov 25 10:42:12 GMT 2017 , puoi usarlo SimpleDateFormatper renderlo facilmente quello che vuoi che sia.

public static void main(String[] args) {

   SimpleDateFormat dateFormat = new SimpleDateFormat("EEEE, MMMM d, yyyy");
   Calendar calendar = new GregorianCalendar(2017, Calendar.JANUARY , 25);
   calendar.set(Calendar.HOUR, 10);
   calendar.set(Calendar.MINUTE, 42);
   calendar.set(Calendar.SECOND, 12);

   calendar.roll(Calendar.MONTH, -2);
   System.out.println(dateFormat.format(calendar.getTime()));
}
Uscita: sabato 25 novembre 2017 Molto meglio, no? :)
Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION