CodeGym /Java blog /Véletlen /Hogyan ne tévedj el az időben: DateTime és Calendar
John Squirrels
Szint
San Francisco

Hogyan ne tévedj el az időben: DateTime és Calendar

Megjelent a csoportban
Szia! Ma egy új adattípussal kezdünk dolgozni, amivel korábban nem találkoztunk, nevezetesen a dátumokkal. Hogyan ne tévedj el az időben: Dátum, idő és naptár - 1Azt hiszem, nem kell magyaráznom, mi az a randevú. :) Elvileg egy közönséges Java Stringben tárolhatnánk az aktuális dátumot és időt.

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

       String date = "June 11, 2018";
       System.out.println(date);
   }
}
De ennek a megközelítésnek számos hátránya van. Az Stringosztály szöveggel való munkára készült, módszerei megfelelőek erre a feladatra. Ha valamilyen módon módosítanunk kell egy dátumot (például hozzáadunk 2 órát), az Stringnem működik olyan jól. Vagy ha az aktuális dátumot és időt szeretnénk megjeleníteni a program összeállításakor. Stringitt sem segít: mire megírod a kódot és lefuttatod, addigra megváltozik az idő, és a konzol rossz információt jelenít meg. Ezért a Java készítői több osztályt is biztosítottak a dátummal és idővel való munkavégzéshez. Ezek közül az első azjava.util.Date

Időpont osztály

Megadtuk a teljes nevét, mert egy másik Java csomagban van az java.sql.Dateosztály. Ne keverd össze őket! Az első dolog, amit tudnia kell róla, hogy a dátumot az 1970. január 1-je óta eltelt ezredmásodpercek számában tárolja. Ennek az időrendszernek még saját neve is van: " Unix-idő " Elég érdekes megközelítés, nem értesz egyet? :) A második dolog, amit érdemes megjegyezni, a következő: Ha létrehoz egy Dateobjektumot az alapértelmezett konstruktorral, az eredmény az objektum létrehozásának pillanatában érvényes dátumot és időt jelenti . Emlékszel arra, hogy azt mondtuk, hogy egy randevúként ábrázolt dátum Stringmegküzd egy ilyen feladattal? Az Dateosztály könnyedén kezeli.

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

       Date date = new Date();
       System.out.println(date);
   }
}
Futtassa ezt a kódot többször, és látni fogja, hogy az idő többször változik. :) Ez azért lehetséges, mert az időt ezredmásodpercben tárolják: rendkívül kis időegységek, így az eredmények nagyon pontosak. Az Dateosztály másik konstruktora: 1970. január 1-je 00:00 óta pontosan hány ezredmásodperc van átadva a kívánt dátumnak, és létrejön a megfelelő dátumobjektum:

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

       Date date = new Date(1212121212121L);
       System.out.println(date);
   }
}
Konzol kimenet: 2008. május 30. péntek 04:20:12 GMT 2008. május 30. A "Péntek" a hét napját jelöli (péntek, duh), a GMT pedig az időzónát (greenwichi idő). A ezredmásodperceket s-ként adjuk át long, mivel az ezredmásodpercek száma általában nem fér bele egy int. Tehát milyen műveleteket kell végrehajtanunk a dátumokkal? Nos, a legnyilvánvalóbb természetesen az összehasonlítás . Annak megállapítására, hogy az egyik dátum a másik előtt vagy után jön-e. Ezt többféleképpen is meg lehet tenni. Például meghívhatja a Date.getTime()metódust, amely visszaadja az 1970. január 1-je éjfél óta eltelt ezredmásodpercek számát. Csak hívja meg két dátum objektumon, és hasonlítsa össze az eredményeket:

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");
   }
}
Kimenet: a dátum1 korábbi, mint a dátum2 De van egy kényelmesebb módja is, például a Date osztály által biztosított speciális metódusok használatával: before(), after()és equals(). Mindegyik logikai értéket ad vissza. A before()metódus ellenőrzi, hogy a dátumunk korábbi, mint az argumentumként átadott dátum:

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));
   }
}
Konzol kimenet: true Hasonlóképpen, a after()metódus ellenőrzi, hogy a dátumunk későbbi-e, mint az argumentumként átadott dátum:

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));
   }
}
Konzol kimenet: false Példáinkban 2 másodpercre "alvó állapotba helyezzük" a programot, így garantáltan különbözik a két dátum. date1Gyors számítógépeken a és a létrehozása közötti idő date2egy milliszekundumnál rövidebb lehet, ami azt eredményezi, hogy a before()és mindkettő after()hamis értéket ad vissza. De ebben az esetben a equals()metódus igaz lesz! Végül is összehasonlítja az 1970. január 1-jei 00:00 óta eltelt ezredmásodpercek számát minden dátumhoz. Az objektumok csak akkor tekinthetők egyenlőnek, ha ezredmásodpercnek felelnek meg :

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));
}
Itt van még egy dolog, amire figyelnie kell. Ha megnyitja az Dateosztály dokumentációját az Oracle webhelyén, látni fogja, hogy számos metódusa és konstruktora elavultként van megjelölve ( azaz nem ajánlott a használata). A Java alkotói a következőket mondják az osztályok elavult részeiről:
"A @Deprecated megjegyzéssel ellátott programelemek használata nem ajánlott a programozóknak, általában azért, mert veszélyes, vagy mert van jobb alternatíva."
Ez nem jelenti azt, hogy ezek a módszerek egyáltalán nem használhatók. Ha egy IDE-ben elavult metódusokkal próbál kódot futtatni, az valószínűleg működni fog. Vegyük például az elavult Date.getHours()metódust, amely az objektumhoz társított órák számát adja vissza Date.

public static void main(String[] args) {

   Date date1 = new Date();

   System.out.println(date1.getHours());
}
Ha 14:21-kor (14:21-kor) indítja el a kódot, a 14-es szám jelenik meg. Amint látja, az elavult módszer át van húzva, de továbbra is működik. Ezeket a metódusokat nem távolítják el annak érdekében, hogy ne törjenek meg az őket használó meglévő kódok hatalmas tömege. Más szóval, ezek a módszerek nem „töröttek” és nem „eltávolítottak”. Egyszerűen nem ajánlott őket használni, mert létezik kényelmesebb alternatíva. Egyébként a dokumentáció kifejezetten megemlíti ezt az alternatívát:
Hogyan ne tévedj el az időben: Dátum, idő és naptár - 2
Az osztály legtöbb Datemetódusa átkerült a továbbfejlesztett és kiterjesztett Calendarosztályba. Legközelebb azzal az órával fogunk megismerkedni. :)

Naptári osztály

A JDK 1.1 új osztályt vezetett be: Calendar. Valamivel könnyebbé tette a dátumokkal való munkát Java nyelven, mint korábban. Az osztály egyetlen megvalósítása, Calendaramellyel dolgozni fogunk, az az GregorianCalendarosztály. A Gergely-naptárt hajtja végre, amelyet a világ legtöbb országa betart. Fő előnye, hogy kényelmesebb formátumban tud dolgozni dátumokkal. Például:
  • Adjon hozzá egy hónapot vagy napot az aktuális dátumhoz
  • Ellenőrizze, hogy az év szökőév-e;
  • A dátum egyes összetevőinek visszaadása (például a hónap számának kinyerése egy teljes dátumból)
  • Tartalmaz egy nagyon kényelmes konstansrendszert is (amelyek közül sokat az alábbiakban látni fogunk).
CalendarAz osztály másik fontos fejlesztése a Calendar.ERA konstans: a közös korszak előtti (Kr.e. - Krisztus előtti) vagy a közös korszakban (Kr. u. - Anno Domini) dátumot jelezhet. Nézzük mindezt példákkal. Hozzunk létre egy calendarobjektumot 2017. január 25-i dátummal:

public static void main(String[] args) {

  Calendar calendar = new GregorianCalendar(2017, 0 , 25);
}
Az Calendarosztályban (és az Dateosztályban is) a hónapok nulláról indulnak , ezért a 0-t adjuk át második argumentumként. Amikor az Calendarosztállyal dolgozik, fontos megértenie, hogy ez csak egy naptár , nem pedig egy egyéni dátum. Hogyan ne tévedj el az időben: Dátum, idő és naptár - 3 A dátum csak néhány szám, amelyek egy adott időintervallumot jeleznek. A naptár egy egész rendszer, amely sok mindent lehetővé tesz a dátumokkal. :) Ez jól látszik, ha megpróbálod megjeleníteni az Calendarobjektumot: Kimenet: 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_MONTH=WEEK_AY_OF,_Y_AY_DAY ,DAY_OF_WEEK_IN_MONTH=?,AM_PM=0,HOUR=0,HOUR_OF_DAY=0,MINUTE=0,SECOND=0,MILLISECOND=?,ZONE_OFFSET=?,DST_OFFSET=?] Nézze meg, mennyi információt kap ! Egy naptárnak van egy csomó olyan tulajdonsága, amivel egy normál dátum nem rendelkezik, és mindegyik megjelenik (toString()az osztálybanCalendar). Ha csak egy egyszerű dátumot, azaz egy tárgyat kell lekérnie a naptárbólDate, használja aCalendar.getTime()módszer (a név nem a leglogikusabb, de mit tehetsz?):

public static void main(String[] args) {

   Calendar calendar = new GregorianCalendar(2017, 0 , 25);
   Date date = calendar.getTime();
   System.out.println(date);
}
Kimenet: 2017. január 25. szerda, 00:00:00 GMT Most vettük a naptárat, és "lecsökkentettük" egy hétköznapi dátumra. Menjünk tovább. A hónapok számuk szerinti megjelölése mellett használhatja az Calendarosztály állandó mezőértékeit . Ezek az állandók az osztály statikus mezői, Calendarelőre beállított értékkel, amely nem módosítható. Ez valójában még jobb lehetőség, mert ezek használata javítja a kód olvashatóságát.

public static void main(String[] args) {
   GregorianCalendar calendar = new GregorianCalendar(2017, Calendar.JANUARY , 25);
}
A naptár.JANUÁR az egyik állandó, amely az év hónapjait jelenti. Ezeket a megnevezett konstansokat használva senki sem felejti el például, hogy a 3-as szám áprilist jelent, és nem a harmadik hónapot, amit szeretünk márciusnak nevezni. Csak írja be a Calendar.APRIL -t , és kész. :) Minden naptár mező (szám, hónap, perc, másodperc, stb.) külön-külön megadható aset()metódus segítségével. Ez a módszer nagyon kényelmes, mert azCalendarosztálynak minden mezőhöz van egy állandója, és az így kapott kód nagyon könnyen olvasható. Az utolsó példában létrehoztunk egy dátumot, de nem állítottunk be időpontot. Állítsuk be az időt 19:42:12-re

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());
}
Kimenet: Sze Jan 25 19:42:12 GMT 2017 Meghívjuk a set()metódust, átadva egy konstanst (attól függően, hogy melyik mezőt szeretnénk megváltoztatni) és a mező új értékét. Kiderült, hogy ez set()a módszer egyfajta "szuper-beállító", amely nem csak egy mezőre, hanem sok mezőre tudja beállítani az értéket. :) Az Calendarosztály a metódust használja az add()értékek összeadására és kivonására. Átad a módosítani kívánt mezőt, és egy számot (pontosan mennyit szeretne hozzáadni/kivonni az aktuális értékből). Például vegyünk egy dátumot, amely 2 hónappal az általunk létrehozott dátum előtt van:

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());
}
Kimenet: P Nov 25 19:42:12 GMT 2016 Nagyon jó! 2 hónapja kaptuk meg a dátumot. Ez nem csak a hónap változását okozta: az év is változott 2017-ről 2016-ra. Természetesen a dátumok konvertálásakor az aktuális év automatikusan kiszámításra kerül, anélkül, hogy azt manuálisan kellene nyomon követni. De ha valamilyen oknál fogva le kell tiltania ezt a viselkedést, megteheti. A roll()módszer hozzáadhat és kivonhat értékeket anélkül, hogy befolyásolná a fennmaradó értékeket . Például így:

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());
}
Pontosan ugyanazt tettük, mint az előző példában: 2 hónapot vettünk el az aktuális dátumtól. De most a kód mást csinál: a hónap januárról novemberre változott, de az év változatlan marad – 2017! Kimenet: Szo Nov 25, 10:42:12 GMT 2017 Tovább haladva. Mint fentebb említettük, az összes mezőt külön-külön is megkaphatjuk Calendar. Ezt a következő módszerrel tesszük 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("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));

}
Kimenet: Év: 2017 Hónap: 0 A hónap hete: 5 Nap: 25 Óra: 10 Perc: 42 Másodperc: 12 Ezredmásodperc: 0 Tehát az osztály „szuper-beállítóján” kívül Calendarvan egy „szuper-beállító” is ". :) Természetesen ennek az osztálynak egy másik érdekessége a korszakokkal való munka. A "BC" dátum létrehozásához a Calendar.ERA mezőt kell használnia. Például hozzunk létre egy dátumot a cannae-i csatához, ahol Hannibál legyőzte a római hadsereget. Ez Kr.e. 216. augusztus 2-án történt:

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()));
}
Itt az osztály segítségével SimpleDateFormatnyomtattuk ki a dátumot számunkra könnyebben érthető formátumban (a „GG” betűk azt jelzik, hogy a korszakot szeretnénk megjeleníteni). Kiadás: Kr.e. 216. augusztus 02. Az Calendarosztálynak sokkal több metódusa és állandója van. A dokumentációban olvashat róluk . Ha nem tetszik ez a dátumformátum: Szo Nov 25, 10:42:12 GMT 2017 , akkor könnyedén elkészítheti SimpleDateFormatolyanná, amilyenné szeretné.

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()));
}
Kimenet: 2017. november 25., szombat, ez sokkal jobb, nem? :)
Hozzászólások
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION