CodeGym /Java blog /Tilfældig /Sådan farer du ikke vild i tide: DateTime og Kalender
John Squirrels
Niveau
San Francisco

Sådan farer du ikke vild i tide: DateTime og Kalender

Udgivet i gruppen
Hej! I dag begynder vi at arbejde med en ny datatype, vi ikke har stødt på før, nemlig datoer. Sådan farer du ikke vild i tide: DateTime og Kalender - 1Jeg tror ikke, jeg behøver at forklare, hvad en date er. :) I princippet kunne vi gemme den aktuelle dato og klokkeslæt i en almindelig Java-streng.

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

       String date = "June 11, 2018";
       System.out.println(date);
   }
}
Men denne tilgang har mange ulemper. Klassen Stringer designet til at arbejde med tekst, og dens metoder er passende til denne opgave. Hvis vi har brug for at manipulere en dato på en eller anden måde (tilføj f.eks. 2 timer), Stringfungerer det ikke så godt. Eller hvis vi ønsker at vise den aktuelle dato og klokkeslæt, når programmet er kompileret. Stringhjælper heller ikke her: Når du skriver koden og kører den, vil tiden være ændret, og konsollen vil vise de forkerte oplysninger. Det er grunden til, at Javas skabere sørgede for flere klasser til at arbejde med datoer og klokkeslæt. Den første af disse erjava.util.Date

Dato klasse

Vi specificerede dets fulde navn, fordi en anden Java-pakke har klassen java.sql.Date. Bland dem ikke sammen! Det første du skal vide om det er, at det gemmer datoen som antallet af millisekunder , der er gået siden 1. januar 1970. Dette tidssystem har endda sit eget navn: " Unix-time " En ret interessant tilgang, ville'' er du enig? :) Den anden ting, der er værd at huske, er denne: Hvis du opretter et Dateobjekt ved hjælp af standardkonstruktøren, repræsenterer resultatet den aktuelle dato og klokkeslæt i det øjeblik, objektet blev oprettet . Kan du huske, at vi sagde, at en dato repræsenteret som en Stringville kæmpe med sådan en opgave? Klassen Datehåndterer det med lethed.

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

       Date date = new Date();
       System.out.println(date);
   }
}
Kør denne kode flere gange, og du vil se tiden ændre sig gentagne gange. :) Dette er muligt, fordi tiden er gemt som millisekunder: de er ekstremt små tidsenheder, så resultaterne er meget nøjagtige. Klassen Dateen anden konstruktør: du kan overføre det nøjagtige antal millisekunder siden 00:00 den 1. januar 1970 til den krævede dato, og et tilsvarende datoobjekt vil blive oprettet:

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

       Date date = new Date(1212121212121L);
       System.out.println(date);
   }
}
Konsoloutput: Fre 30. maj 04:20:12 GMT 2008 Vi får 30. maj 2008. "Fredag" angiver ugedagen (fredag, duh), og GMT er tidszonen (Greenwich Mean Time). Millisekunder passeres som longs, fordi antallet af millisekunder normalt ikke passer ind i en int. Så hvilke operationer med datoer skal vi muligvis udføre? Nå, det mest oplagte er selvfølgelig sammenligning . For at afgøre, om en date kommer før eller efter en anden. Dette kan gøres på flere måder. For eksempel kan du kalde Date.getTime()metoden, som returnerer antallet af millisekunder, der er forløbet siden midnat den 1. januar 1970. Kald den bare på to Dato-objekter og sammenlign resultaterne:

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: dato1 er tidligere end dato2 Men der er også en mere bekvem måde, dvs. ved at bruge specielle metoder fra Dato-klassen: before(), after()og equals(). Alle returnerer en boolesk værdi. Metoden before()kontrollerer, om vores dato er tidligere end den dato, der blev sendt 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.before(date2));
   }
}
Konsoloutput: sand På samme måde after()kontrollerer metoden, om vores dato er senere end den dato, der blev sendt 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));
   }
}
Konsoludgang: falsk I vores eksempler "sætter vi programmet i dvale" i 2 sekunder, så de to datoer er garanteret forskellige. På hurtige computere kan tiden mellem oprettelsen af date1​​og date2være mindre end et millisekund, hvilket forårsager, at både before()og after()returnerer falsk. Men i dette tilfælde equals()vil metoden vende tilbage sand! Den sammenligner trods alt antallet af millisekunder siden 00:00 den 1. januar 1970 for hver dato. Objekterne betragtes kun som ens, hvis de matcher millisekundet :

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));
}
Her er en anden ting, du skal være opmærksom på. Hvis du åbner dokumentationen for Dateklassen på Oracle- webstedet, vil du se, at mange af dens metoder og konstruktører er blevet markeret som forældet (dvs. ikke anbefalet til brug). Her er, hvad Javas skabere har at sige om dele af klasser, der er blevet forældet:
"Et programelement, der er kommenteret @Deprecated, er noget, programmører ikke anbefales at bruge, normalt fordi det er farligt, eller fordi der er et bedre alternativ."
Det betyder ikke, at disse metoder slet ikke kan bruges. Hvis du forsøger at køre kode ved hjælp af forældede metoder i en IDE, vil det højst sandsynligt virke Overvej f.eks. den forældede Date.getHours()metode, som returnerer det antal timer, der er knyttet til et Dateobjekt.

public static void main(String[] args) {

   Date date1 = new Date();

   System.out.println(date1.getHours());
}
Hvis du starter koden klokken 14:21 (14:21), vil den vise tallet 14. Som du kan se, er den forældede metode streget over, men den virker stadig. Disse metoder fjernes ikke for ikke at ødelægge den enorme mængde eksisterende kode, der bruger dem. Disse metoder er med andre ord hverken "brudt" eller "fjernet". De anbefales simpelthen ikke til brug, fordi der findes et mere bekvemt alternativ. I øvrigt nævner dokumentationen specifikt dette alternativ:
Sådan farer du ikke vild i tide: DateTime og Kalender - 2
De fleste af Dateklassens metoder er blevet flyttet til den forbedrede og udvidede Calendarklasse. Vi stifter bekendtskab med den klasse næste gang. :)

Kalender klasse

JDK 1.1 introducerede en ny klasse: Calendar. Det gjorde arbejdet med datoer i Java noget nemmere end før. Den eneste implementering af klassen Calendar, som vi vil arbejde med, er GregorianCalendarklassen. Den implementerer den gregorianske kalender, som observeres af de fleste lande i verden. Dens største fordel er, at den kan arbejde med datoer i et mere bekvemt format. Det kan for eksempel:
  • Tilføj en måned eller dag til den aktuelle dato
  • Tjek om året er et skudår;
  • Returner individuelle komponenter af datoen (udtræk f.eks. månedsnummeret fra en hel dato)
  • Den indeholder også et meget praktisk system af konstanter (hvoraf mange vil se nedenfor).
En anden vigtig forbedring af Calendarklassen er dens Calendar.ERA- konstant: du kan angive en dato før den almindelige æra (BC - før Kristus) eller i den almindelige æra (AD - Anno Domini). Lad os se på alt dette med eksempler. Lad os oprette et calendarobjekt med datoen 25. januar 2017:

public static void main(String[] args) {

  Calendar calendar = new GregorianCalendar(2017, 0 , 25);
}
I Calendarklassen (såvel som Dateklassen for den sags skyld) starter måneder fra nul , så vi sender tallet 0 som det andet argument. Når du arbejder med Calendarklassen, er det vigtigt at forstå, at dette netop er det, en kalender , ikke en individuel dato. Sådan farer du ikke vild i tide: DateTime og Kalender - 3 En dato er blot nogle få tal, der angiver et bestemt tidsinterval. En kalender er et helt system, der lader dig gøre en masse ting med datoer. :) Dette er meget tydeligt, hvis du prøver at vise 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_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, hvor meget information du får! En kalender har en masse egenskaber, som en normal dato ikke har, og alle vises (sådantoString()fungerer metoden iCalendarklassen). Hvis du blot skal have en simpel dato fra kalenderen, altså etDateobjekt, så brugCalendar.getTime()metode (navnet er ikke det mest logiske, men hvad kan du gøre?):

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 Nu har vi taget kalenderen og "reduceret den" til en almindelig dato. Lad os gå videre. Ud over at angive måneder efter deres antal, kan du bruge Calendarklassens konstante feltværdier . Disse konstanter er statiske felter i Calendarklassen med en forudindstillet værdi, som ikke kan ændres. Dette er faktisk en endnu bedre mulighed, fordi at bruge dem forbedrer læsbarheden af ​​din kode.

public static void main(String[] args) {
   GregorianCalendar calendar = new GregorianCalendar(2017, Calendar.JANUARY , 25);
}
Kalender.JANUAR er en af ​​de konstanter, der repræsenterer årets måneder. Ved at bruge disse navngivne konstanter vil ingen for eksempel glemme, at tallet 3 betyder april, og ikke den tredje måned, som vi gerne kalder marts. Bare skriv Kalender.APRIL , og du er færdig. :) Alle kalenderfelter (antal, måned, minutter, sekunder osv.) kan angives separat ved hjælp afset()metoden. Denne metode er meget praktisk, fordiCalendarklassen har en konstant for hvert felt, og den resulterende kode er meget let at læse. I det sidste eksempel oprettede vi en dato, men satte ikke et tidspunkt for den. Lad os sætte tiden til 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 Vi kalder set()metoden og sender en konstant (afhængigt af det felt, vi ønsker at ændre) og den nye værdi for feltet. Det viser sig, at denne set()metode er en slags "super-setter", der ved, hvordan man indstiller værdien ikke kun for et felt, men for mange felter. :) CalendarKlassen bruger add()metoden til at addere og trække værdier fra. Du sender det felt ind, du vil ændre, og et tal (præcis hvor meget du vil lægge til/fratrække fra den aktuelle værdi). Lad os f.eks. få en dato, der er 2 måneder før den dato, vi oprettede:

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());
}
Output: Fre Nov 25 19:42:12 GMT 2016 Meget godt! Vi fik datoen for 2 måneder siden. Dette fik ikke kun måneden til at ændre sig: Årstallet ændrede sig også fra 2017 til 2016. Når du konverterer datoer, beregnes det aktuelle år naturligvis automatisk, uden at du behøver at holde styr på det manuelt. Men hvis du af en eller anden grund har brug for at deaktivere denne adfærd, kan du gøre det. Metoden roll()kan tilføje og trække værdier fra uden at påvirke de resterende værdier . For eksempel sådan her:

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 præcis det samme som i det foregående eksempel: vi tog 2 måneder fra den nuværende dato. Men nu gør koden noget anderledes: Måneden har ændret sig fra januar til november, men året forbliver uændret—2017! Output: Lør 25. nov 10:42:12 GMT 2017 Bevæger dig. Som vi sagde ovenfor, kan vi få alle Calendarfelterne separat. Det gør vi 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));

}
Output: År: 2017 Måned: 0 Uge i måneden: 5 Dag: 25 Timer: 10 Minutter: 42 Sekunder: 12 Millisekunder: 0 Så udover klassens Calendar"super-setter" er der også en "super-getter" ". :) Selvfølgelig er et andet interessant aspekt af denne klasse at arbejde med epoker. For at oprette en "BC"-dato skal du bruge feltet Calendar.ERA Lad os f.eks. oprette en dato for slaget ved Cannae, hvor Hannibal besejrede den romerske hær. Dette skete den 2. august 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()));
}
Her brugte vi SimpleDateFormatklassen til at udskrive datoen i et format, der er lettere for os at forstå (bogstaverne "GG" angiver, at vi ønsker, at æraen skal vises). Output: 02. august 216 f.Kr. Klassen Calendarhar mange flere metoder og konstanter. Dem kan du læse om i dokumentationen . Hvis du ikke kan lide dette datoformat Sat Nov 25 10:42:12 GMT 2017, så kan du bruge det SimpleDateFormattil nemt at gøre det til det, du vil have det til.

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()));
}
Output: Lørdag den 25. november 2017 Det er meget bedre, ikke? :)
Kommentarer
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION