CodeGym /Blog Java /Aleatoriu /Cum să nu te pierzi în timp: DateTime și Calendar
John Squirrels
Nivel
San Francisco

Cum să nu te pierzi în timp: DateTime și Calendar

Publicat în grup
Bună! Astăzi vom începe să lucrăm cu un nou tip de date pe care nu l-am întâlnit până acum, și anume datele. Cum să nu te pierzi în timp: DateTime și Calendar - 1Nu cred că trebuie să explic ce este o întâlnire. :) În principiu, am putea stoca data și ora curentă într-un șir Java obișnuit.

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

       String date = "June 11, 2018";
       System.out.println(date);
   }
}
Dar această abordare are multe dezavantaje. Clasa Stringeste concepută pentru a lucra cu text, iar metodele sale sunt adecvate pentru această sarcină. Dacă trebuie să manipulăm o dată într-un fel (adăugăm 2 ore, de exemplu), Stringnu funcționează atât de bine. Sau dacă vrem să afișăm data și ora curentă când programul este compilat. Stringnici aici nu ajută: până când scrieți codul și îl rulați, ora se va fi schimbat și consola va afișa informațiile greșite. De aceea, creatorii Java au oferit mai multe clase pentru lucrul cu datele și ora. Prima dintre acestea estejava.util.Date

Clasa de date

Am specificat numele complet, deoarece un alt pachet Java are clasa java.sql.Date. Nu le amesteca! Primul lucru pe care trebuie să-l știți despre el este că stochează data ca număr de milisecunde care au trecut de la 1 ianuarie 1970. Acest sistem de timp are chiar propriul nume: „ Unix-time ” O abordare destul de interesantă, nu ar fi nu esti de acord? :) Al doilea lucru care merită reținut este următorul: Dacă creați un Dateobiect utilizând constructorul implicit, rezultatul reprezintă data și ora curente în momentul în care obiectul a fost creat . Îți amintești că am spus că o dată reprezentată ca Strings-ar lupta cu o astfel de sarcină? Clasa Datese descurcă cu ușurință.

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

       Date date = new Date();
       System.out.println(date);
   }
}
Rulați acest cod de mai multe ori și veți vedea că ora se schimbă în mod repetat. :) Acest lucru este posibil deoarece timpul este stocat ca milisecunde: sunt unități de timp extrem de mici, deci rezultatele sunt foarte precise. Clasa Datealt constructor: puteți trece numărul exact de milisecunde de la 00:00 pe 1 ianuarie 1970 până la data necesară și va fi creat un obiect data corespunzător:

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

       Date date = new Date(1212121212121L);
       System.out.println(date);
   }
}
Ieșire din consolă: Vineri , 30 mai 04:20:12 GMT 2008. Primim 30 mai 2008. „Vineri” indică ziua săptămânii (vineri, duh), iar GMT este fusul orar (Greenwich Mean Time). Milisecundele sunt trecute ca longs, deoarece numărul de milisecunde nu se încadrează de obicei într-un int. Așadar, ce operațiuni cu datele ar putea fi nevoie să le facem? Ei bine, cea mai evidentă, desigur, este comparația . Pentru a determina dacă o dată vine înainte sau după alta. Acest lucru se poate face în mai multe moduri. De exemplu, puteți apela Date.getTime()metoda, care returnează numărul de milisecunde care au trecut de la miezul nopții de 1 ianuarie 1970. Apelați-o pe două obiecte Date și comparați rezultatele:

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");
   }
}
Ieșire: data1 este anterioară datei2 Dar există și o modalitate mai convenabilă, adică prin utilizarea metodelor speciale oferite de clasa Date before(): after()și equals(). Toate returnează o valoare booleană. Metoda before()verifică dacă data noastră este anterioară datei trecute ca argument:

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));
   }
}
Ieșire din consolă: true În mod similar, after()metoda verifică dacă data noastră este mai târziu decât data trecută ca argument:

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));
   }
}
Ieșire din consolă: false În exemplele noastre, „punem programul în repaus” timp de 2 secunde, astfel încât cele două date sunt garantate a fi diferite. Pe computerele rapide, timpul dintre crearea date1și date2poate fi mai mic de o milisecundă, determinând ambele before()și after()să revină false. Dar în acest caz, equals()metoda va reveni adevărată! La urma urmei, compară numărul de milisecunde de la 00:00 pe 1 ianuarie 1970 pentru fiecare dată. Obiectele sunt considerate egale numai dacă se potrivesc cu milisecunda :

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));
}
Iată un alt lucru la care trebuie să fii atent. Dacă deschideți documentația pentru Dateclasă pe site-ul Oracle , veți vedea că multe dintre metodele și constructorii acesteia au fost marcați ca Deprecated (adică nu sunt recomandate pentru utilizare). Iată ce au de spus creatorii Java despre părțile claselor care au fost depreciate:
„Un element de program adnotat @Deprecated este ceva ce programatorilor nu li se recomandă să folosească, de obicei pentru că este periculos sau pentru că există o alternativă mai bună.”
Acest lucru nu înseamnă că aceste metode nu pot fi utilizate deloc. Dacă încercați să rulați cod folosind metode depreciate într-un IDE, cel mai probabil va funcționa. De exemplu, luați în considerare Date.getHours()metoda depreciată, care returnează numărul de ore asociat unui Dateobiect.

public static void main(String[] args) {

   Date date1 = new Date();

   System.out.println(date1.getHours());
}
Dacă începeți codul la 14:21 (2:21 PM), acesta va afișa numărul 14. După cum puteți vedea, metoda depreciată este tăiată, dar încă funcționează. Aceste metode nu sunt eliminate pentru a nu sparge corpul imens de cod existent care le folosește. Cu alte cuvinte, aceste metode nu sunt nici „rupte”, nici „eliminate”. Pur și simplu nu sunt recomandate pentru utilizare, deoarece este disponibilă o alternativă mai convenabilă. De altfel, documentația menționează în mod specific această alternativă:
Cum să nu te pierzi în timp: DateTime și Calendar - 2
Cele mai multe dintre Datemetodele clasei au fost mutate în Calendarclasa îmbunătățită și extinsă. Ne vom familiariza cu acea clasă în continuare. :)

Clasa de calendar

JDK 1.1 a introdus o nouă clasă: Calendar. A făcut lucrul cu date în Java oarecum mai ușor decât înainte. Singura implementare a clasei Calendarcu care vom lucra este GregorianCalendarclasa. Implementează calendarul gregorian, care este respectat de majoritatea țărilor lumii. Principalul său avantaj este că poate lucra cu date într-un format mai convenabil. De exemplu, poate:
  • Adăugați o lună sau o zi la data curentă
  • Verificați dacă anul este un an bisect;
  • Returnează componentele individuale ale datei (de exemplu, extrageți numărul lunii dintr-o dată întreagă)
  • Conține, de asemenea, un sistem de constante foarte convenabil (dintre care multe le vom vedea mai jos).
O altă îmbunătățire importantă a Calendarclasei este constanta Calendar.ERA : puteți indica o dată înaintea erei comune (î.Hr. - înainte de Hristos) sau în era comună (AD - Anno Domini). Să ne uităm la toate acestea cu exemple. Să creăm un calendarobiect cu data de 25 ianuarie 2017:

public static void main(String[] args) {

  Calendar calendar = new GregorianCalendar(2017, 0 , 25);
}
În Calendarclasă (precum și în Dateclasă), lunile încep de la zero , așa că trecem numărul 0 ca al doilea argument. Când lucrați cu Calendarclasa, este important să înțelegeți că acesta este doar un calendar , nu o dată individuală. Cum să nu te pierzi în timp: DateTime și Calendar - 3 O dată este doar câteva numere care indică un interval de timp specific. Un calendar este un întreg sistem care vă permite să faceți o mulțime de lucruri cu date. :) Acest lucru este evident dacă încercați să afișați obiectul Calendar: Ieșire: java.util.GregorianCalendar[time=?,areFieldsSet=false,areAllFieldsSet=false,lenient=true,zone=sun.util.calendar.ZoneInfo[id="Europe/London",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,? ,DAY_OF_WEEK_IN_MONTH=?,AM_PM=0,HOUR=0,HOUR_OF_DAY=0,MINUTE=0,SECOND=0,MILLISECOND=?,ZONE_OFFSET=?,DST_OFFSET=?] Vedeți câte informații obțineți ! Un calendar are o grămadă de proprietăți pe care o dată normală nu le are și toate sunt afișate (așatoString()funcționează metoda înCalendarclasă). Dacă trebuie doar să obțineți o dată simplă din calendar, adică unDateobiect, utilizațiCalendar.getTime()metoda (numele nu este cel mai logic, dar ce poți face?):

public static void main(String[] args) {

   Calendar calendar = new GregorianCalendar(2017, 0 , 25);
   Date date = calendar.getTime();
   System.out.println(date);
}
Ieșire: miercuri 25 ianuarie 00:00:00 GMT 2017 Acum am luat calendarul și l-am „redus” la o dată obișnuită. Să mergem mai departe. Pe lângă desemnarea lunilor după numărul lor, puteți utiliza valorile constante ale câmpuluiCalendar clasei . Aceste constante sunt câmpuri statice ale clasei cu o valoare prestabilită care nu poate fi modificată. Aceasta este de fapt o opțiune și mai bună, deoarece utilizarea lor îmbunătățește lizibilitatea codului dvs. Calendar

public static void main(String[] args) {
   GregorianCalendar calendar = new GregorianCalendar(2017, Calendar.JANUARY , 25);
}
Calendar.IANUARIE este una dintre constantele care reprezintă lunile anului. Folosind aceste constante numite, nimeni nu va uita, de exemplu, că numărul 3 înseamnă aprilie, și nu luna a treia, pe care ne place să o numim martie. Scrieți Calendar.APRIL și ați terminat. :) Toate câmpurile calendarului (număr, lună, minute, secunde etc.) pot fi specificate separat folosindset()metoda. Această metodă este foarte convenabilă, deoareceCalendarclasa are o constantă pentru fiecare câmp, iar codul rezultat este foarte ușor de citit. În ultimul exemplu, am creat o dată, dar nu am stabilit o oră pentru aceasta. Să setăm 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());
}
Ieșire: Miercuri 25 ianuarie 19:42:12 GMT 2017 Apelăm set()metoda, trecând o constantă (în funcție de câmpul pe care vrem să-l schimbăm) și noua valoare pentru câmp. Se pare că această set()metodă este un fel de „super-setter” care știe să stabilească valoarea nu doar pentru un câmp, ci pentru mai multe câmpuri. :) CalendarClasa folosește add()metoda pentru a adăuga și scădea valori. Treci în câmpul pe care vrei să-l schimbi și un număr (exact cât vrei să adaugi/scădezi din valoarea curentă). De exemplu, să obținem o dată care este cu 2 luni înainte de data pe care am creat-o:

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());
}
Ieșire: vineri, 25 noiembrie 19:42:12 GMT 2016 Foarte bine! Am primit data acum 2 luni. Acest lucru nu a determinat doar schimbarea lunii: și anul s-a schimbat din 2017 în 2016. Desigur, la conversia datelor, anul curent este calculat automat, fără a fi nevoie să-l urmăriți manual. Dar dacă dintr-un motiv oarecare trebuie să dezactivați acest comportament, puteți face acest lucru. Metoda roll()poate adăuga și scădea valori fără a afecta valorile rămase . De exemplu, așa:

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());
}
Am făcut exact același lucru ca în exemplul anterior: am luat 2 luni de la data curentă. Dar acum codul face ceva diferit: luna s-a schimbat din ianuarie până în noiembrie, dar anul rămâne neschimbat — 2017! Ieșire: sâmb. 25 noiembrie 10:42:12 GMT 2017 În mișcare. După cum am spus mai sus, putem obține toate Calendarcâmpurile separat. Facem asta cu get()metoda:

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));

}
Rezultat: Anul: 2017 Luna: 0 Săptămâna din lună: 5 Ziua: 25 Ore: 10 Minute: 42 Secunde: 12 Milisecunde: 0 Deci, pe lângă Calendar„super-setter” al clasei, există și un „super-getter”. ". :) Desigur, un alt aspect interesant al acestei clase este lucrul cu epoci. Pentru a crea o dată „BC”, va trebui să utilizați câmpul Calendar.ERA De exemplu, să creăm o dată pentru Bătălia de la Cannae, în care Hannibal a învins armata romană. Acest lucru s-a întâmplat pe 2 august 216 î.Hr.:

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()));
}
Aici am folosit SimpleDateFormatclasa pentru a tipări data într-un format care este mai ușor de înțeles pentru noi (literele „GG” indică că vrem ca epoca să fie afișată). Ieșire: 02 august 216 î.Hr. Clasa Calendarare mult mai multe metode și constante. Puteți citi despre ele în documentație . Dacă nu vă place acest format de dată Sâmbătă, 25 noiembrie 10:42:12 GMT 2017, îl puteți utiliza SimpleDateFormatpentru a face cu ușurință ceea ce doriți să fie.

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()));
}
Ieșire: sâmbătă, 25 noiembrie 2017 E mult mai bine, nu-i așa? :)
Comentarii
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION