CodeGym /Java blogg /Slumpmässig /Hur du inte går vilse i tid: DateTime och Kalender
John Squirrels
Nivå
San Francisco

Hur du inte går vilse i tid: DateTime och Kalender

Publicerad i gruppen
Hej! Idag börjar vi arbeta med en ny datatyp som vi inte har stött på tidigare, nämligen datum. Hur du inte går vilse i tid: DateTime och Kalender - 1Jag tror inte att jag behöver förklara vad en dejt är. :) I princip skulle vi kunna lagra aktuellt datum och tid i en vanlig Java-sträng.

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

       String date = "June 11, 2018";
       System.out.println(date);
   }
}
Men detta tillvägagångssätt har många nackdelar. Klassen Stringär designad för att arbeta med text, och dess metoder är lämpliga för denna uppgift. Om vi ​​behöver manipulera ett datum på något sätt (lägg till 2 timmar till exempel), Stringfungerar inte så bra. Eller om vi vill visa aktuellt datum och tid när programmet kompileras. Stringhjälper inte här heller: när du skriver koden och kör den kommer tiden att ha ändrats och konsolen kommer att visa fel information. Det är därför Javas skapare gav flera klasser för att arbeta med datum och tid. Den första av dessa ärjava.util.Date

Datum klass

Vi angav dess fullständiga namn, eftersom ett annat Java-paket har java.sql.Dateklassen. Blanda inte ihop dem! Det första du behöver veta om det är att det lagrar datumet som antalet millisekunder som har gått sedan 1 januari 1970. Det här tidssystemet har till och med ett eget namn: " Unix-time " Ett ganska intressant tillvägagångssätt, skulle' håller du med? :) Det andra värt att komma ihåg är detta: Om du skapar ett Dateobjekt med standardkonstruktorn, representerar resultatet aktuellt datum och tid då objektet skapades . Kommer du ihåg att vi sa att en dejt representerad som en Stringskulle kämpa med en sådan uppgift? Klassen Datehanterar det med lätthet.

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

       Date date = new Date();
       System.out.println(date);
   }
}
Kör den här koden flera gånger så kommer du att se tiden ändras upprepade gånger. :) Detta är möjligt eftersom tiden lagras som millisekunder: de är extremt små tidsenheter, så resultaten är mycket exakta. Klassen Dateen annan konstruktor: du kan skicka det exakta antalet millisekunder sedan 00:00 den 1 januari 1970 till det önskade datumet, och ett motsvarande datumobjekt kommer att skapas:

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

       Date date = new Date(1212121212121L);
       System.out.println(date);
   }
}
Konsolutdata: Fre 30 maj 04:20:12 GMT 2008 Vi får 30 maj 2008. "Fre" indikerar veckodagen (fredag, duh), och GMT är tidszonen (Greenwich Mean Time). Millisekunder skickas som longs, eftersom antalet millisekunder vanligtvis inte passar in i en int. Så, vilka operationer med datum kan vi behöva utföra? Tja, det mest uppenbara är förstås jämförelse . För att avgöra om ett datum kommer före eller efter ett annat. Detta kan göras på flera sätt. Du kan till exempel anropa Date.getTime()metoden, som returnerar antalet millisekunder som har förflutit sedan midnatt den 1 januari 1970. Kalla den bara på två Date-objekt och jämför resultaten:

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");
   }
}
Utdata: datum1 är tidigare än datum2 Men det finns också ett bekvämare sätt, t.ex. genom att använda speciella metoder som tillhandahålls av klassen Date: before(), after()och equals(). Alla returnerar ett booleskt värde. Metoden before()kontrollerar om vårt datum är tidigare än det datum som passerade som ett 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));
   }
}
Konsolutdata: sant På samma sätt after()kontrollerar metoden om vårt datum är senare än det datum som skickades som 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));
   }
}
Konsolutgång: false I våra exempel "ställer vi programmet i vila" i 2 sekunder, så att de två datumen garanterat är olika. På snabba datorer kan tiden mellan skapandet av date1och date2vara mindre än en millisekund, vilket gör att både before()och after()returnerar false. Men i det här fallet equals()kommer metoden att returnera sant! När allt kommer omkring jämför den antalet millisekunder sedan 00:00 den 1 januari 1970 för varje datum. Objekten anses vara lika endast om de matchar millisekunden :

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));
}
Här är en annan sak du måste vara uppmärksam på. Om du öppnar dokumentationen för Dateklassen på Oracle -webbplatsen ser du att många av dess metoder och konstruktörer har markerats som föråldrade (dvs. rekommenderas inte för användning). Här är vad Javas skapare har att säga om delar av klasser som har fasats ut:
"Ett programelement som är kommenterat @Föråldrat är något som programmerare inte rekommenderas att använda, vanligtvis för att det är farligt eller för att det finns ett bättre alternativ."
Detta betyder inte att dessa metoder inte kan användas alls. Om du försöker köra kod med föråldrade metoder i en IDE, kommer det med största sannolikhet att fungera. Tänk till exempel på den föråldrade Date.getHours()metoden, som returnerar antalet timmar som är associerade med ett Dateobjekt.

public static void main(String[] args) {

   Date date1 = new Date();

   System.out.println(date1.getHours());
}
Om du startar koden klockan 14:21 (14:21) kommer den att visa siffran 14. Som du kan se är den föråldrade metoden överstruken, men den fungerar fortfarande. Dessa metoder tas inte bort för att inte bryta den enorma mängden befintlig kod som använder dem. Med andra ord är dessa metoder varken "trasiga" eller "borttagna". De rekommenderas helt enkelt inte för användning eftersom det finns ett bekvämare alternativ. För övrigt nämner dokumentationen specifikt detta alternativ:
Hur du inte går vilse i tid: DateTime och Kalender - 2
De flesta av Dateklassens metoder har flyttats till den förbättrade och utökade Calendarklassen. Vi ska bekanta oss med den klassen härnäst. :)

Kalenderklass

JDK 1.1 introducerade en ny klass: Calendar. Det gjorde arbetet med datum i Java något enklare än tidigare. Den enda implementeringen av klassen Calendarsom vi kommer att arbeta med är GregorianCalendarklassen. Den implementerar den gregorianska kalendern, som observeras av de flesta länder i världen. Dess främsta fördel är att den kan arbeta med datum i ett mer bekvämt format. Det kan till exempel:
  • Lägg till en månad eller dag till det aktuella datumet
  • Kontrollera om året är ett skottår;
  • Returnera enskilda komponenter av datumet (extrahera till exempel månadsnumret från ett helt datum)
  • Den innehåller också ett mycket bekvämt system av konstanter (av vilka många kommer att se nedan).
En annan viktig förbättring av Calendarklassen är dess Calendar.ERA- konstant: du kan ange ett datum före den vanliga eran (BC - före Kristus) eller i den vanliga eran (AD - Anno Domini). Låt oss titta på allt detta med exempel. Låt oss skapa ett calendarobjekt med datumet 25 januari 2017:

public static void main(String[] args) {

  Calendar calendar = new GregorianCalendar(2017, 0 , 25);
}
I Calendarklassen (liksom Dateklassen för den delen) börjar månader från noll , så vi skickar siffran 0 som andra argument. När du arbetar med klassen Calendarär det viktigt att förstå att detta är just det, en kalender , inte ett individuellt datum. Hur du inte går vilse i tid: DateTime och Kalender - 3 Ett datum är bara några siffror som indikerar ett specifikt tidsintervall. En kalender är ett helt system som låter dig göra många saker med datum. :) Detta är rikligt uppenbart om du försöker visa objektet Calendar: Output: 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_DAY=DAY_OF_YEAR? ,DAY_OF_WEEK_IN_MONTH=?,AM_PM=0,HOUR=0,HOUR_OF_DAY=0,MINUTE=0,SECOND=0,MILLISECOND=?,ZONE_OFFSET=?,DST_OFFSET=?] Se hur mycket information du får! En kalender har ett gäng egenskaper som ett normalt datum inte har, och alla visas (så härtoString()fungerar metoden iCalendarklassen). Om du bara behöver få ett enkelt datum från kalendern, dvs ettDateobjekt, användCalendar.getTime()metod (namnet är inte det mest logiska, men vad kan du göra?):

public static void main(String[] args) {

   Calendar calendar = new GregorianCalendar(2017, 0 , 25);
   Date date = calendar.getTime();
   System.out.println(date);
}
Utdata: Wed Jan 25 00:00:00 GMT 2017 Nu har vi tagit kalendern och "förminskat den" till ett vanligt datum. Låt oss gå längre. Förutom att ange månader efter deras antal kan du använda Calendarklassens konstanta fältvärden . Dessa konstanter är statiska fält i Calendarklassen med ett förinställt värde som inte kan ändras. Detta är faktiskt ett ännu bättre alternativ, eftersom att använda dem förbättrar läsbarheten för din kod.

public static void main(String[] args) {
   GregorianCalendar calendar = new GregorianCalendar(2017, Calendar.JANUARY , 25);
}
Kalender.JANUARI är en av konstanterna som representerar årets månader. Med dessa namngivna konstanter kommer ingen att glömma till exempel att siffran 3 betyder april och inte tredje månaden, som vi gärna kallar mars. Skriv bara Kalender.APRIL så är du klar. :) Alla kalenderfält (antal, månad, minuter, sekunder, etc.) kan specificeras separat med metodenset(). Denna metod är mycket bekväm, eftersomCalendarklassen har en konstant för varje fält, och den resulterande koden är mycket lätt att läsa. I det sista exemplet skapade vi ett datum, men satte ingen tid för det. Låt oss ställa in tiden 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());
}
Utdata: Wed Jan 25 19:42:12 GMT 2017 Vi kallar set()metoden och skickar en konstant (beroende på vilket fält vi vill ändra) och det nya värdet för fältet. Det visar sig att denna set()metod är en slags "super-setter" som vet hur man ställer in värdet inte bara för ett fält, utan för många fält. :) CalendarKlassen använder add()metoden för att addera och subtrahera värden. Du skickar i fältet du vill ändra, och ett tal (exakt hur mycket du vill lägga till/subtrahera från det aktuella värdet). Låt oss till exempel få ett datum som ligger 2 månader före det datum vi skapade:

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());
}
Utdata: fre 25 nov 19:42:12 GMT 2016 Mycket bra! Vi fick datumet för 2 månader sedan. Detta ledde inte bara till att månaden ändrades: året ändrades också från 2017 till 2016. Naturligtvis, vid konvertering av datum, beräknas det aktuella året automatiskt utan att du behöver hålla reda på det manuellt. Men om du av någon anledning behöver inaktivera detta beteende kan du göra det. Metoden roll()kan addera och subtrahera värden utan att påverka de återstående värdena . Till exempel, så här:

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());
}
Vi gjorde exakt samma sak som i föregående exempel: vi tog 2 månader från det aktuella datumet. Men nu gör koden något annorlunda: månaden har ändrats från januari till november, men året förblir oförändrat—2017! Utdata: lör 25 nov 10:42:12 GMT 2017 Går vidare. Som vi sa ovan kan vi få alla Calendarfält separat. Vi gör detta med get()metoden:

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

}
Utdata: År: 2017 Månad: 0 Vecka i månaden: 5 Dag: 25 Timmar: 10 minuter: 42 sekunder: 12 millisekunder: 0 Så, förutom klassens Calendar"super-setter", finns det också en "super-getter" ". :) Naturligtvis är en annan intressant aspekt av den här klassen att arbeta med epoker. För att skapa ett "BC"-datum måste du använda fältet Calendar.ERA Låt oss till exempel skapa ett datum för slaget vid Cannae, där Hannibal besegrade den romerska armén. Detta hände den 2 augusti 216 f.Kr.

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()));
}
Här använde vi SimpleDateFormatklassen för att skriva ut datumet i ett format som är lättare för oss att förstå (bokstäverna "GG" indikerar att vi vill att eran ska visas). Utgång: 2 augusti 216 f.Kr. Klassen Calendarhar många fler metoder och konstanter. Du kan läsa om dem i dokumentationen . Om du inte gillar det här datumformatet Sat Nov 25 10:42:12 GMT 2017 kan du använda SimpleDateFormatför att enkelt göra det till vad du vill att det ska vara.

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()));
}
Utdata: Lördagen den 25 november 2017 Det är mycket bättre, eller hur? :)
Kommentarer
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION