JavaRush /Java Blog /Random-IT /Come non perdersi nel tempo - DateTime e Calendar

Come non perdersi nel tempo - DateTime e Calendar

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 - 1Penso che non sia necessario spiegare cos'è una data :) In linea di principio, è del tutto possibile scrivere la data e l'ora correnti in Java in una stringa normale.
public class Main {
   public static void main(String[] args) {

       String date = "June 11, 2018";
       System.out.println(date);
   }
}
Ma questo approccio presenta molti svantaggi. La classe Stringè stata creata per funzionare con il testo e dispone di metodi appropriati. Se dobbiamo in qualche modo gestire la data (aggiungervi 2 ore, ad esempio), Stringqui non funzionerà. Oppure, ad esempio, visualizzare la data e l'ora attuali nel momento in cui il programma è stato compilato nella console. QuiString : mentre scrivi il codice e lo esegui, l'ora cambierà e l'irrilevante verrà visualizzato nella console. Pertanto, in Java, i suoi creatori hanno fornito diverse classi per lavorare con date e orari. Il primo è la classejava.util.Date

Classe di date Java

Gli abbiamo dato il nome completo perché esiste anche una classe in un altro pacchetto in Java java.sql.Date. Non confonderti! La prima cosa che devi sapere è che memorizza la data in millisecondi trascorsi dal 1 gennaio 1970. C'è anche un nome separato per questa data: "Unix time". Un modo piuttosto interessante, non sei d'accordo? :) La seconda cosa da ricordare: se crei un oggetto Datecon un costruttore vuoto, il risultato sarà la data e l'ora correnti al momento della creazione dell'oggetto . StringRicordi come abbiamo scritto che un'attività del genere sarebbe problematica per un formato di data ? La classe Datelo risolve facilmente.
public class Main {
   public static void main(String[] args) {

       Date date = new Date();
       System.out.println(date);
   }
}
Esegui questo codice più volte e vedrai come cambierà l'ora ogni volta :) Questo è possibile proprio perché è memorizzato in millisecondi: sono l'unità di tempo più piccola, motivo per cui i risultati sono così accurati. Esiste un altro costruttore per Date: puoi specificare il numero esatto di millisecondi trascorsi dalle 00:00 del 1 gennaio 1970 alla data richiesta e verrà creato:
public class Main {
   public static void main(String[] args) {

       Date date = new Date(1212121212121L);
       System.out.println(date);
   }
}
Uscita console:

Fri May 30 08:20:12 MSD 2008
L'abbiamo ottenuto il 30 maggio 2008. "Ven" indica il giorno della settimana - "Venerdì" (venerdì) e MSD - "Ora legale di Mosca" (ora legale di Mosca). I millisecondi vengono trasmessi nel formato long, poiché il loro numero molto spesso non rientra nel formato int. Quindi, di che tipo di operazioni sulla data potremmo aver bisogno nel nostro lavoro? Ebbene, la cosa più ovvia, ovviamente, è il confronto . Determina se una data è successiva o precedente a un'altra. Questo può essere fatto in diversi modi. Ad esempio, puoi chiamare il metodo . Date.getTime(), che restituirà il numero di millisecondi trascorsi dalla mezzanotte del 1 gennaio 1970. Chiamiamolo semplicemente su due oggetti Date e confrontiamoli tra loro:
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");
   }
}
Conclusione:

date1 раньше date2
Ma esiste un modo più conveniente, ovvero utilizzare metodi speciali della classe Date: before(), after()e equals(). Tutti restituiscono il risultato in formato boolean. Il metodo before()controlla se la nostra data è precedente a quella che passiamo come argomento:
public class Main {
   public static void main(String[] args) throws InterruptedException {

       Date date1 = new Date();

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

       System.out.println(date1.before(date2));
   }
}
Uscita console:

true
Il metodo funziona in modo simile after(); controlla se la nostra data è successiva a quella che passiamo come argomento:
public class Main {
   public static void main(String[] args) throws InterruptedException {

       Date date1 = new Date();

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

       System.out.println(date1.after(date2));
   }
}
Uscita console:

false
Nei nostri esempi, mettiamo il programma in pausa per 2 secondi in modo che le due date siano sicuramente diverse. Sui computer veloci, il tempo tra la creazione date1e date2può essere inferiore a un millisecondo, nel qual caso entrambi e before()e after()restituiranno false. Ma il metodo equals()in una situazione del genere tornerà true! Dopotutto, confronta esattamente il numero di millisecondi trascorsi dalle 00:00 del 1 gennaio 1970 per ciascuna data. Gli oggetti verranno 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 qualcos'altro a cui devi prestare attenzione. Se apri la documentazione della classe Datesul sito Web di Oracle, vedrai che molti dei suoi metodi e costruttori sono stati designati come Deprecated("deprecati"). Ecco, guarda: Data della classe Ecco cosa dicono gli stessi creatori di Java riguardo quelle parti delle classi che sono diventate deprecate: “Un elemento di programma annotato con @Deprecated è qualcosa che i programmatori sono scoraggiati dall'utilizzare, solitamente perché è pericoloso, o perché c’è un’alternativa migliore.” Ciò non significa che questi metodi non possano essere utilizzati affatto. Inoltre, se provi tu stesso a eseguire il codice utilizzandoli in IDEA, molto probabilmente funzionerà, prendiamo ad esempio il metodo deprecato Date.getHours(), che restituisce il numero di ore dall'oggetto Date.
public static void main(String[] args) {

   Date date1 = new Date();

   System.out.println(date1.getHours());

}
Se all'ora in cui esegui il codice, ad esempio, sono le 14:21, verrà visualizzato il numero 14. Come puoi vedere, il metodo deprecato è barrato, ma funziona abbastanza bene. Questi metodi non sono stati rimossi completamente, per non danneggiare un mucchio di codice già scritto utilizzandoli. Cioè, questi metodi non sono "rotti" o "rimossi", semplicemente non sono consigliati per l'uso a causa della disponibilità di un'alternativa più conveniente. A proposito, è scritto proprio nella documentazione: Come non perdersi nel tempo - DateTime e Calendario - 2la maggior parte dei metodi della classe Date sono stati spostati nella sua versione migliorata ed estesa: la classe Calendar. Lo conosceremo meglio :)

Calendario Java

Java 1.1 ha introdotto una nuova classe - Calendar. Ha reso il lavoro con le date in Java un po' più semplice di quanto sembrasse prima. L'unica implementazione della classe Calendarcon cui lavoreremo è la classe GregorianCalendar(implementa il calendario gregoriano, secondo il quale vive la maggior parte dei paesi del mondo). La sua principale comodità è che può funzionare con le date in un formato più conveniente. Ad esempio, può:
  • Aggiungi un mese o un giorno alla data corrente
  • Controlla se l'anno è bisestile;
  • Ottieni singoli componenti della data (ad esempio, ottieni il numero del mese da una data intera)
  • Inoltre, al suo interno è stato sviluppato un sistema di costanti molto comodo (ne vedremo molte di seguito).
Un'altra differenza importante della classe Calendarè che implementa una costante Calendar.Era: è possibile impostare la data sull'era AC (“Prima di Cristo” - prima della nascita di Cristo, cioè “prima della nostra era”) o AC (“Dopo Cristo” - “ nostra epoca"). Diamo un'occhiata a tutto questo con esempi. Creiamo un calendario con la data 25 gennaio 2017:
public static void main(String[] args) {

  Calendar calendar = new GregorianCalendar(2017, 0 , 25);
}
I mesi nella classe Calendar(come in Date, tra l'altro) iniziano da zero, quindi abbiamo passato il numero 0 come secondo argomento. La cosa principale quando si lavora con una classe Calendarè capire che si tratta di un calendario e non di una data separata. Come non perdersi nel tempo - DateTime e Calendario - 3Una data è semplicemente una serie di numeri che rappresentano uno specifico periodo di tempo. E un calendario è un intero dispositivo con il quale puoi fare molte cose con le date :) Questo può essere visto abbastanza chiaramente se provi a inviare l'oggetto Calendario alla console: Output:

java.util.GregorianCalendar[time=?,areFieldsSet=false,areAllFieldsSet=false,lenient=true,zone=sun.util.calendar.ZoneInfo[id="Europe/Moscow",offset=10800000,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 ci sono! Il calendario ha un sacco di proprietà che una data normale non ha e tutte vengono inviate alla console (questo è il modo in cui funziona il metodo toString()nella classe Calendar). Se, mentre lavori, hai solo bisogno di ottenere una semplice data dal calendario, ad es. oggetto Date: questo viene fatto utilizzando un metodo Calendar.getTime()(il nome non è il più logico, ma non si può fare nulla):
public static void main(String[] args) {

   Calendar calendar = new GregorianCalendar(2017, 0 , 25);
   Date date = calendar.getTime();
   System.out.println(date);
}
Conclusione:

Wed Jan 25 00:00:00 MSK 2017
Ora abbiamo “semplificato” il calendario trasformandolo in una data normale. Andiamo avanti. Oltre ai simboli numerici per i mesi, Calendarin classe è possibile utilizzare le costanti. Le costanti sono campi statici di una classe Calendarcon un valore già impostato che non può essere modificato. Questa opzione è in realtà migliore, poiché migliora la leggibilità del codice.
public static void main(String[] args) {
   GregorianCalendar calendar = new GregorianCalendar(2017, Calendar.JANUARY , 25);
}
Calendar.JANUARY— una delle costanti per indicare il mese. Con questa opzione di denominazione, nessuno dimenticherà, ad esempio, che il numero "3" significa aprile e non il terzo mese a cui siamo abituati: marzo. Basta scrivere Calendar.APRILe il gioco è fatto :) Tutti i campi del calendario (giorno, mese, minuti, secondi, ecc.) possono essere impostati individualmente utilizzando il metodo set(). È molto conveniente, poiché Calendarogni campo ha la propria costante nella classe e il codice finale apparirà il più semplice possibile. Ad esempio, nell'esempio precedente, abbiamo creato una data, ma non abbiamo impostato l'ora corrente. Impostiamo l'ora alle 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());
}
Conclusione:

Wed Jan 25 19:42:12 MSK 2017
Chiamiamo il metodo set(), gli passiamo una costante (a seconda del campo che vogliamo modificare) e un nuovo valore per questo campo. Si scopre che il metodo set()è una sorta di "super-setter" che può impostare un valore non per un campo, ma per molti campi :) L'aggiunta e la sottrazione di valori in una classe Calendarvengono eseguite utilizzando il metodo add(). Devi passarci il campo che vuoi modificare e il numero, esattamente quanto vuoi aggiungere/sottrarre dal valore corrente. Ad esempio, impostiamo la data di creazione su 2 mesi fa:
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 a value - a negative number must be passed to the method
   System.out.println(calendar.getTime());
}
Conclusione:

Fri Nov 25 19:42:12 MSK 2016
Grande! Abbiamo fissato la data a 2 mesi fa. Di conseguenza, non solo il mese, ma anche l'anno è cambiato, dal 2017 al 2016. Il calcolo dell'anno corrente quando si spostano le date, ovviamente, viene eseguito automaticamente e non è necessario controllarlo manualmente. Ma se per qualche scopo hai bisogno di disabilitare questo comportamento, puoi farlo. Un metodo speciale roll()può aggiungere e sottrarre valori senza influenzare altri valori. 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 sottratto 2 mesi dalla data corrente. Ma ora il codice funzionava diversamente: il mese cambiava da gennaio a novembre, ma l’anno rimaneva lo stesso del 2017! Conclusione:

Sat Nov 25 10:42:12 MSK 2017
Ulteriore. Come abbiamo detto sopra, tutti i campi di un oggetto Calendarpossono essere ottenuti separatamente. Il metodo è responsabile di questo get():
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("Number of the week in the month: " + calendar.get(Calendar.WEEK_OF_MONTH));// serial number of the week in the month

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

   System.out.println("Watch: " + 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));

}
Conclusione:

Год: 2017 
Месяц: 0 
Порядковый номер недели в месяце: 4 
Число: 25 
Часы: 10 
Минуты: 42 
Секунды: 12 
Миллисекунды: 0
Cioè, oltre al "super-setter" nella classe Calendarc'è anche un "super-getter" :) Un altro punto interessante è, ovviamente, lavorare con le ere. Per creare una data “a.C.” è necessario utilizzare il campo Calendar.Era Ad esempio, creiamo una data che indichi la Battaglia di Canne, in cui Annibale sconfisse l'esercito di Roma. Ciò accadde il 2 agosto 216 a.C. e.:
public static void main(String[] args) {
   GregorianCalendar cannes = new GregorianCalendar(216, Calendar.AUGUST, 2);
   cannes.set(Calendar.ERA, GregorianCalendar.BC);

   DateFormat df = new SimpleDateFormat("dd MMM yyy GG");
   System.out.println(df.format(cannes.getTime()));
}
Qui abbiamo utilizzato la classe SimpleDateFormatper visualizzare la data in un formato per noi più comprensibile (le lettere “GG” sono responsabili della visualizzazione dell'era). Conclusione:

02 авг 216 до н.э.
CalendarCi sono molti altri metodi e costanti nella classe , leggili nella documentazione:

Nuova riga fino ad oggi

Per convertire String in Date, puoi utilizzare la classe helper Java - SimpleDateFormat . Questa è la classe necessaria per convertire una data in un formato da te definito. Come non perdersi nel tempo - DateTime e Calendario - 5A sua volta, è molto simile a DateFormat . L'unica differenza degna di nota tra i due è che SimpleDateFormat può essere utilizzato per la formattazione (conversione di una data in una stringa) e l'analisi della stringa in una data compatibile con le impostazioni locali, mentre DateFormat non supporta le impostazioni locali. Inoltre, DateFormat è una classe astratta che fornisce il supporto di base per la formattazione e l'analisi delle date, mentre SimpleDateFormat è una classe concreta che estende la classe DateFormat. Ecco come appare un esempio di creazione di un oggetto SimpleDateFormat e formattazione di una data:
SimpleDateFormat formater = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = new Date(1212121212121L);

System.out.println(formatter.format(date));
Nell'esempio sopra abbiamo utilizzato il modello "aaaa-MM-gg HH:mm:ss" che significa:
  • 4 cifre per l'anno (aaaa);
  • 2 cifre per il mese (MM);
  • 2 cifre per il giorno (dd);
  • 2 cifre per le ore nel formato 24 ore (HH);
  • 2 cifre per i minuti (mm);
  • 2 cifre per i secondi (ss).
I segni di separazione e l'ordine dei simboli del modello vengono conservati. Uscita console:
2008-05-30 08:20:12
Sono disponibili numerose lettere modello per la classe SimpleDateFormat . Per non farti confondere, li abbiamo raccolti in una tabella:
Simbolo Descrizione Esempio
G era (nella localizzazione inglese - d.C. e a.C.) ANNO DOMINI
anno (numero a 4 cifre) 2020
aa anno (ultime 2 cifre) 20
aaaa anno (numero a 4 cifre) 2020
M numero del mese (senza zeri iniziali) 8
MM numero del mese (con zeri iniziali se il numero del mese è < 10) 04
MMM abbreviazione del mese di tre lettere (secondo la localizzazione) Gen
MMMM nome completo del mese Giugno
w settimana dell'anno (senza zeri iniziali) 4
ww settimana dell'anno (con zeri iniziali) 04
W settimana nel mese (senza zeri iniziali) 3
WW settimana nel mese (con zero iniziale) 03
D giorno dell'anno 67
D giorno del mese (senza zeri iniziali) 9
gg giorno del mese (con zeri iniziali) 09
F giorno della settimana del mese (senza zeri iniziali) 9
FF giorno della settimana del mese (con zeri iniziali) 09
E giorno della settimana (abbreviazione) W
EEEE giorno della settimana (completo) Venerdì
tu numero del giorno della settimana (senza zeri iniziali) 5
uu numero del giorno della settimana (con zeri iniziali) 05
UN Indicatore AM/PM SONO.
H ore nel formato 24 ore senza zeri iniziali 6
HH orologio nel formato 24 ore con zero iniziale 06
K numero di ore nel formato 24 ore 18
K numero di ore nel formato 12 ore 6
H l'ora nel formato 12 ore senza zeri iniziali 6
eh ora nel formato 12 ore con zero iniziale 06
M minuti senza zeri iniziali 32
mm minuti con zero iniziale 32
S secondi senza zeri iniziali undici
ss secondi con zero iniziale undici
S millisecondi 297
z Fuso orario EET
Z fuso orario nel formato RFC 822 300
Esempi di combinazioni di caratteri del modello:
Campione Esempio
gg-MM-aaaa 01-11-2020
aaaa-MM-gg 2019-10-01
HH:mm:ss.SSS 23:59.59.999
aaaa-MM-gg HH:mm:ss 2018-11-30 03:09:02
aaaa-MM-gg HH:mm:ss.SSS 2016-03-01 01:20:47.999
aaaa-MM-gg HH:mm:ss.SSS Z 2013-13-13 23:59:59.999 +0100
Se commetti un piccolo errore con il formato, puoi diventare il proprietario di una java.text.ParseException, e questo non è un risultato particolarmente piacevole. Bene, la breve escursione in SimpleDateFormat è terminata: torniamo alla traduzione di java string fino ad oggi . SimpleDateFormat ci offre tali funzionalità e seguiremo questo processo passo dopo passo.
  1. Crea una riga da cui devi impostare la data:

    String strDate = "Sat, April 4, 2020";
  2. Creiamo un nuovo oggetto SimpleDateFormat con un template che corrisponda a quello che abbiamo nella stringa (altrimenti non saremo in grado di analizzarlo):

    SimpleDateFormat formatter = new SimpleDateFormat("EEE, MMMM d, yyyy", Locale.ENGLISH);

    Come puoi vedere, qui abbiamo un argomento Locale. Se lo omettiamo, utilizzerà la Locale predefinita, che non è sempre l'inglese.

    Se la locale non corrisponde alla stringa di input, i dati della stringa associati alla lingua, come la nostra Mon o April , non verranno riconosciuti e genereranno una java.text.ParseException, anche se il modello corrisponde.

    Tuttavia, non dobbiamo specificare il formato se utilizziamo un modello che non è specifico della lingua. Ad esempio: aaaa-MM-gg HH:mm:ss

  3. Creiamo una data utilizzando un formattatore, che a sua volta la analizza dalla stringa di input:

    try {
      Date date = formatter.parse(strDate);
      System.out.println(date);
    }
    catch (ParseException e) {
      e.printStackTrace();
    }

    Uscita console:

    
    Sat Apr 04 00:00:00 EEST 2020

    Hmmm... Ma il formato non è più lo stesso!

    Per creare lo stesso formato, utilizziamo nuovamente il formattatore:

    System.out.println(formatter.format(date));

    Uscita console:

    
    Sat, April 4, 2020

SimpleDateFormat e calendario

SimpleDateFormat ti consente di formattare tutti gli oggetti Data e Calendario creati per un uso successivo. Consideriamo un punto così interessante come lavorare con le epoche. Per creare una data “AC” è necessario utilizzare il campo Calendar.Era. Ad esempio, creiamo una data che indichi la battaglia di Canne, in cui Annibale sconfisse l'esercito di Roma. Ciò accadde il 2 agosto 216 a.C. e.:
public static void main(String[] args) {
   GregorianCalendar cannes = new GregorianCalendar(216, Calendar.AUGUST, 2);
   cannes.set(Calendar.ERA, GregorianCalendar.BC);

   DateFormat df = new SimpleDateFormat("dd MMM yyy GG");
   System.out.println(df.format(cannes.getTime()));
}
Qui abbiamo utilizzato la classe SimpleDateFormat per visualizzare la data in un formato per noi più comprensibile (come indicato sopra, le lettere "GG" sono responsabili della visualizzazione dell'era). Conclusione:

02 авг 216 до н.э.

Formato data Java

Ecco un altro caso. Supponiamo che questo formato di data non sia adatto a noi:

Sat Nov 25 10:42:12 MSK 2017
Quindi eccolo qui. Utilizzando le nostre funzionalità nel formato data Java, puoi modificarlo nel tuo senza troppe difficoltà:
public static void main(String[] args) {

   SimpleDateFormat dateFormat = new SimpleDateFormat("EEEE, d MMMM 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()));
}
Conclusione:

суббота, 25 Ноябрь 2017
Molto meglio, vero? :)
Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION